Re: FW: DBD::ODBC fetch is returning string for integer
"Martin J. Evans" <[email protected]>
| Newsgroups | gmane.comp.lang.perl.modules.dbi.sybase.devel |
|---|---|
| Message-ID | <[email protected]> |
On 19/05/2012 11:05, Martin J. Evans wrote: > Tim, if you see this could you take a quick look at my comment below > re sql_type_case - thanks. > > On 18/05/2012 19:38, Manikantan, Madhunapanthula_Naaga wrote: >> Forwarding this to DBI dev as well. Any help is very much appreciated !! >> >> Thanks >> >> _____________________________________________ >> From: Manikantan, Madhunapanthula_Naaga >> Sent: Friday, May 18, 2012 7:11 PM >> To: [email protected] >> Cc: [email protected] >> Subject: DBD::ODBC fetch is returning string for integer >> >> >> Hello Evans/DBi-users, >> >> DBD::ODBC is returning strings for integers. This results in >> incorrect values for bit wise operators. (for ex:- $e='16'; $f = >> '32' print $e& $f returns 12 instead of zero ). Is there a setting >> that can help us return integers as 'integers'. >> >> I am using EasySoft Driver via DBD::ODBC to connect to Microsoft SQL >> Server 2008 R2 from Linux RHEL 6.2. >> >> Version information >> --- >> Perl : 5.10.1 >> DBI : 1.609 >> DBD::ODBC : 1.30_5 >> >> Please use the below code to reproduce the issue and let me know if I >> you need more information. >> >> Help much appreciated !! >> >> Thanks >> >> >> >> # Create temp_check and inserted one row with values (100, 10.234 and >> 'test') >> >> CREATE TABLE temp_check >> ( a int, >> b float, >> c varchar (100) >> ) >> INSERT INTO temp_check VALUES (100, 10.234000, 'test') >> >> >> PERL snippet >> ---------------------- >> >> use DBI; >> use Data::Dumper; >> >> $dbh = DBI->connect('dbi:ODBC:DSN=SERVER1','***','***'); >> $dbh->{TraceLevel}=15; >> >> $sth = $dbh->prepare('select * from sandbox..temp_check where a=100'); >> #$sth = $dbh->prepare('select * from sandbox..temp_check where >> a=100', {odbc_describe_parameters => 0}); >> >> $sth->execute(); >> >> for ($i = 1; $i<= $sth->{NUM_OF_FIELDS}; $i++) { >> print "Column $sth->{NAME}->[$i -1] is of type $sth->{TYPE}->[$i >> -1]\n"; >> } >> >> $rows = $sth->fetchall_arrayref(); >> print Dumper($rows); >> >> Column a is of type 4 >> Column b is of type 6 >> Column c is of type 12 >> >> $VAR1 = [ >> [ >> '100', >> '10.234', >> 'test' >> ] >> ]; > Manikantan, sorry if this looks like I'm ignoring your question but to > provide the right answer I may need to fix something in DBD::ODBC. > > My first answer to this was to use the DiscardString attribute when > you bind the column. However, when I tried it, it did not work and I > reported https://rt.cpan.org/Public/Bug/Display.html?id=77283 to > myself. Having looked in to this now I can see why it is happening and > Tim, I could use a quick bit of feedback on 2 points: > > 1. Assuming you ask DBD::ODBC to bind the type as SQL_INTEGER ODBC > returns a 4 byte integer and in this case DBD::ODBC was treating it as > a string by calling sv_setpvn but passing in a pointer to that 4 byte > integer. I fixed this to use sv_setiv but the code to call > sql_type_cast_svpv is still executed. When sql_type_cast_svpv is > called it seg faults because the pv is not set (is the line I added ok > just to safe guard against this?): > > case SQL_INTEGER: > /* sv_2iv is liberal, may return SvIV, SvUV, or SvNV */ > if (!SvPOK(sv)) return 2; /* MJE ADDED THIS LINE TO STOP > segfault */ > sv_2iv(sv); > /* SvNOK will be set if value is out of range for IV/UV. > * SvIOK should be set but won't if sv is not numeric (in which > * case perl would have warn'd already if -w or warnings are > in effect) > */ > cast_ok = (SvIOK(sv) && !SvNOK(sv)); > break; > > Obviously, if the above is ok, I would not add the line there as it > applies to nvs as well. > An alternative, (although I think DBI needs this protection anyway) is that DBD::ODBC does not call sql_type_cast_svpv when the column is bound as an integer (as it simply calls sv_setiv so it knows DiscardString is meaningless). > 2. is simply setting the iv via sv_setiv sufficient in this case so > there is no point in calling sql_type_cast_svpv? > > Martin subversion trunk contains fixes for this and a change in behaviour: =head2 Changes in DBD::ODBC 1.38_1 May 19 2012 [BUG FIXES] Fixed rt 77283. If you overrode the bind type as SQL_INTEGER in a bind_col call AFTER previously binding as another type (or not specifying a type) you would not get the right value back. This also fixes the DiscardString bind_col attribute for SQL_INTEGER binds. Fixed some format specifiers in trace calls. [CHANGE IN BEHAVIOUR] DBD::ODBC allowed you to change the bound column type in bind_col after the column was already bound. It now does not allow this now and issues a warning. This could lead to problems - see above. [OTHER] Added some missing SQL_C_xxx types to S_SqlCTypeToString internal function. This only affects tracing. Some tests in 08bind were skipped when they did not need to be. sql_type_cast tests rewritten due to fixes above. Please test this. If you cannot apply the change to DBI I mention above then you can change DBD::OBDC's dbdimp.c as follows: Index: dbdimp.c =================================================================== --- dbdimp.c (revision 15306) +++ dbdimp.c (working copy) @@ -3308,7 +3308,8 @@ #if DBIXS_REVISION > 13590 /* If a bind type was specified we use DBI's sql_type_cast to cast it - currently only number types are handled */ - if ((fbh->req_type == SQL_INTEGER) || + if ( + /*(fbh->req_type == SQL_INTEGER) || not reqd we already do sv_setiv */ (fbh->req_type == SQL_NUMERIC) || (fbh->req_type == SQL_DECIMAL)) { int sts; Let me know if you have any problems. Martin