Skip Menu |

This queue is for tickets about the DBD-DB2 CPAN distribution.

Report information
The Basics
Id: 42185
Status: resolved
Worked: 30 min
Priority: 0/
Queue: DBD-DB2

People
Owner: opendev [...] us.ibm.com
Requestors: appfault [...] hotmail.com
Cc: aff [...] cpan.org
AdminCc:

Bug Information
Severity: Important
Broken in: 1.2
Fixed in: (no value)



Subject: Binding to the return value of a stored procedure silently fails
Binding to the return value of a stored procedure silently fails For instance doing something like: my $bind_value; my $sth = $dbh->prepare("{?=call MYPROC()}"); $sth->bind_param_inout(1, \$bind_value, 100) or die; $sth->execute() or die; print Dumper($bind_value)."\n"; Will show the "$VAR1 = undef;" which is not possible. The variable must be an integer after the statement successfully executes.
Hi.. Thank you for reporting the bug for DBD::DB2. However, to proceed further, I would like to request you to provide me with some additional information. 1. Please send me the output of the following commands $ perl -V $ db2level $ uname -a 2. Please provide me with the CLITrace for your program to help further. Steps to take CLI Trace:- * Make an environment variable named DB2CLIINIPATH and set it to some directory where your local db2cli.ini will reside. eg. in bash, issue export DB2CLIINIPATH=<dir name where the traces will be generated> On Windows, issue set DB2CLIINIPATH=<dir name where the traces will be generated> * issue the following commands ( in windows run these commands in the DB2 command prompt, issue db2cmd for the same) db2 update cli cfg for section COMMON using trace 1 db2 update cli cfg for section COMMON using tracepathname <dir name where the traces will be generated> * Local db2cli.ini file should be generated in mentioned directory. * Run the application. Traces will be generated inside the specified directory. * To disable the CLI trace issue the following command db2 update cli cfg for section COMMON using trace 0 * Remember to put the trace off. -- Thanks Tarun Pasrija IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
Are you saying that you've been unable to reproduce the problem? $ uname -a Linux scorcho.corp.ud.com 2.4.21-32.ELsmp #1 SMP Fri Apr 15 21:17:59 EDT 2005 i686 i686 i386 GNU/Linux $ db2level DB21085I Instance "db2inst1" uses "32" bits and DB2 code release "SQL08027" with level identifier "03080106". Informational tokens are "DB2 v8.1.0.128", "s061108", "MI00175", and FixPak "14". Product is installed at "/opt/IBM/db2/V8.1".
Hi, I have attached a script. I am trying to understand if this is what you are trying to achieve.? Can you please run the attached script and let me know the output of the script. Also, if this is not what you wish to do then can you please send me a reproducible script and your expected output for the same. Thanks. -- Thanks IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
use DBI; use DBD::DB2; use DBD::DB2::Constants; require 'connection.pl'; require 'perldutl.pl'; $DATABASE = "dbname"; $USERID = "user"; $PASSWORD = "password"; $dbh = DBI->connect("dbi:DB2:$DATABASE", "$USERID", "$PASSWORD", {PrintError => 0}); $sth = $dbh->prepare( 'DROP PROCEDURE SP_Example' ); $sth->execute(); $statement = "CREATE PROCEDURE SP_Example () LANGUAGE SQL BEGIN RETURN 5; END"; $sth = $dbh->prepare( $statement ); $sth->execute(); $sth = $dbh->prepare( '{ ? = CALL SP_Example( ) }' ); $sth->bind_param_inout( 1, \$output, 20, { 'db2_param_type' => SQL_PARAM_OUTPUT, 'db2_c_type' => SQL_C_LONG, 'db2_type' => SQL_INTEGER }); $rv = $sth->execute(); printf ( "the output is %d ", $output ); $sth->finish; $dbh->disconnect;
Your script is roughly the same as my example, it outputs: the output is 0 Which is incorrect, as I reported originally. I changed the script slightly to add error checking and put the login params on the command line. Here's my version. When you run that script what do you get as output?
#!/usr/bin/perl use DBI; use DBD::DB2; use DBD::DB2::Constants; my ($DATABASE, $USERID, $PASSWORD) = @ARGV; $dbh = DBI->connect("dbi:DB2:$DATABASE", "$USERID", "$PASSWORD", {PrintError => 1}) or die $DBI::errstr; $sth = $dbh->prepare( 'DROP PROCEDURE SP_Example' ) or die $DBI::errstr; $sth->execute(); $statement = "CREATE PROCEDURE SP_Example () LANGUAGE SQL BEGIN RETURN 5; END"; $sth = $dbh->prepare( $statement ) or die $DBI::errstr; $sth->execute() or die $DBI::errstr; $sth = $dbh->prepare( '{ ? = CALL SP_Example( ) }' ) or die $DBI::errstr; $sth->bind_param_inout( 1, \$output, 20, { 'db2_param_type' => SQL_PARAM_OUTPUT, 'db2_c_type' => SQL_C_LONG, 'db2_type' => SQL_INTEGER }) or die $DBI::errstr; $rv = $sth->execute() or die $DBI::errstr; printf("the output is %d\n", $output); $sth->finish or die $DBI::errstr; $dbh->disconnect or die $DBI::errstr;
On Tue Feb 10 12:01:28 2009, appfault wrote: Show quoted text
> Your script is roughly the same as my example, it outputs: > the output is 0
Bug confirmed in the following environment: * OS: Linux 2.6.18-92.1.22.el5 #1 SMP Tue Dec 16 11:57:43 EST 2008 x86_64 x86_64 x86_64 GNU/Linux * Perl: This is perl, v5.10.0 built for x86_64-linux * DB2: DB21085I Instance "db2inst1" uses "64" bits and DB2 code release "SQL09050" with level identifier "03010107". Informational tokens are "DB2 v9.5.0.0", "s071001", "LINUXAMD6495", and Fix Pack "0". Product is installed at "/opt/ibm/db2/V9.5". * DBD::DB2: Module id = DBD::DB2 INST_VERSION 1.3 Consider using 'strict' and 'warnings' in your perl code. Enabling 'warnings' prints the following: $ perl -w perltest.appfault.pl <DB> <USER> <PASS> Argument "^E\0\0\0" isn't numeric in printf at perltest.appfault.pl line 27. the output is 0
#!perl use strict; use warnings; use DBI; use DBD::DB2; use DBD::DB2::Constants; my ($DATABASE, $USERID, $PASSWORD) = @ARGV; my $dbh = DBI->connect("dbi:DB2:$DATABASE", "$USERID", "$PASSWORD", {PrintError => 1}) or die $DBI::errstr; my $sth = $dbh->prepare( 'DROP PROCEDURE SP_Example' ) or die $DBI::errstr; $sth->execute(); my $statement = "CREATE PROCEDURE SP_Example () LANGUAGE SQL BEGIN RETURN 5; END"; $sth = $dbh->prepare( $statement ) or die $DBI::errstr; $sth->execute() or die $DBI::errstr; my $output = undef; $sth = $dbh->prepare( '{ ? = CALL SP_Example( ) }' ) or die $DBI::errstr; $sth->bind_param_inout( 1, \$output, 20, { 'db2_param_type' => SQL_PARAM_OUTPUT, 'db2_c_type' => SQL_C_LONG, 'db2_type' => SQL_INTEGER }) or die $DBI::errstr; my $rv = $sth->execute() or die $DBI::errstr; printf("the output is %d\n", $output); $sth->finish or die $DBI::errstr; $dbh->disconnect or die $DBI::errstr; __END__
On Wed Jan 07 04:32:35 2009, IBMTORDB2 wrote: Show quoted text
> 2. Please provide me with the CLITrace for your program to help further.
Please find a cli trace file.
Download p9744t-46309872.cli
application/octet-stream 8k

Message body not shown because it is not plain text.

RT-Send-CC: opendev [...] us.ibm.com
Hi Thanks for your reply. I was a little confused before and the clitrace was really helpful to reproduce the scenario. We had added something called as a db2_call_return in version 1.6 which was released mid february which allows you to get a return value from a stored procedure. Thus if your stored procedure is something like CREATE PROCEDURE SP_Example () LANGUAGE SQL BEGIN RETURN 5 and you call the stored proc using { ? = CALL SP_Example( ) } Then I believe that you expect the value 5 as a return. You can get this value now by calling sth->{db2_call_return} However, I am attaching 2 different testcases for your reference. I have also added comments of what would work and what would not. -- Thanks Tarun Pasrija IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
use DBI; use DBD::DB2; $DATABASE="dbname"; $USERID = "username"; $PASSWORD = "password"; my $dbh = DBI->connect("dbi:DB2:$DATABASE", $USERID, $PASSWORD, {PrintError => 1}) or die "Couldn't connect to database: " . DBI->errstr; $sth = $dbh->prepare( "DROP PROCEDURE swap_email_address"); $sth->execute(); $statement = "CREATE PROCEDURE swap_email_address ( INOUT inoutString char(25), INOUT outString char(25) ) P1: BEGIN set inoutString = outString; set outString = inoutString ; return 5; END P1"; $sth = $dbh->prepare( $statement ); $sth->execute(); $sth = $dbh->prepare( "{?=CALL swap_email_address(?,?)}"); my $name = "hello"; my $second_name = "yellow"; my $output=100; print "Values before binding $name, $second_name \n"; $sth->bind_param_inout( 1, \$output, { 'db2_param_type' => SQL_PARAM_INPUT_OUTPUT}) or die; $sth->bind_param_inout( 2, \$name, { 'db2_param_type' => SQL_PARAM_INPUT_OUTPUT}); $sth->bind_param_inout( 3, \$second_name, { 'db2_param_type' => SQL_PARAM_INPUT_OUTPUT }); $sth->execute(); # The following code does not work like in your previous example since DB2 does not return a value for ?=some storedproc # my $nooutput; # $sth->bind_param_inout( 1, \$nooutput, { 'db2_param_type' => SQL_PARAM_OUTPUT}) or die; # print "$nooutput" ; // This would give an undef value since DB2 does not return anything. Thus you would need to use db2_call_return. print "Values after binding $name, $second_name, $output \n"; #This would output 10 print "Value for Call return is $sth->{db2_call_return} \n"; $sth->finish(); $dbh->disconnect;
On Fri Mar 06 07:55:34 2009, IBMTORDB2 wrote: Show quoted text
> We had added something called as a db2_call_return in version 1.6 > which was released mid february which allows you to get a return > value from a stored procedure.
Tarun, Thank you for your prompt and helpful response. Please note that the version 1.6 of DBD::DB2 seems to be incorrectly named, which unfortunately means it is no longer available on CPAN using the normal shell: $ sudo perl -MCPAN -e shell cpan[1]> i DBD::DB2 Strange distribution name [DBD::DB2] Module id = DBD::DB2 DESCRIPTION DB2 Driver for DBI CPAN_USERID IBMTORDB2 (IBM OpenDev <opendev@us.ibm.com>) CPAN_VERSION undef CPAN_FILE Contact Author IBM OpenDev <opendev@us.ibm.com> DSLIP_STATUS MdhOo (mature,developer,hybrid,object-oriented,open-source) MANPAGE DBD::DB2 - DataBase Driver for DB2 UDB INST_FILE /opt/perl/lib/site_perl/5.10.0/x86_64-linux/DBD/DB2.pm INST_VERSION 1.3 The expected output should be: CPAN_VERSION 1.6 There has been filed a bug report for this issue: https://rt.cpan.org/Ticket/Display.html?id=43869 "Perl cpan DBD::DB2 -> DBD::DB216 naming breaks index script" If you are entitled to upload a new version of DBD-DB2 version 1.6, or knows anyone within IBM who are, I encourage you to address this issue as soon as possible. Thanks. Best regards, Andreas --
Thanks I have made the necessary corrections and updated the other ticket. The current version on CPAN is 1.61. -- Thanks IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
On Fri Mar 06 07:55:34 2009, IBMTORDB2 wrote: Show quoted text
> We had added something called as a db2_call_return in version 1.6 > which was released mid february which allows you to get a return > value from a stored procedure.
After upgrade to DBD::DB2 version 1.61, your code example works for me with perl, v5.10.0 built for x86_64-linux, DB2 v9.5.0.0: $ perl -w storedproc.pl Values before binding hello, yellow Values after binding yellow , yellow , 100 Value for Call return is 5 Thanks. Best regards, Andreas --
RT-Send-CC: opendev [...] us.ibm.com
Marking this issue closed. Thanks -- Thanks Tarun Pasrija IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
The existence of $sth->{'db2_call_return'} is nice, but that's not a solution to this ticket. The issue still exists that binding to the return value silently fails. The output from "Sun Mar 08 06:04:14 2009" indicates this is still broken. It said "Values after binding yellow , yellow , 100" but that's wrong - the 100 should have been 5. The attached script tests for this. It does a die() if either style fails. Also note, per the test there are two different ways it can fail. It can fail and return "" or it can fail and return the binary string "\5\0\0\0". The latter is seemingly a failed binary representation of the correct answer 5, though why it's being corrupted is unclear. Checking round 1 db2_call_return value 5 ............... pass Checking round 1 output bind var value "" .............. FAIL Checking round 2 db2_call_return value 5 ............... pass Checking round 2 output bind var value "\5\0\0\0" ...... FAIL failed at ./perltest.pl line 56.
#!/usr/bin/perl -w use warnings; use strict; use DBI; use DBD::DB2; use DBD::DB2::Constants; use Data::Dumper; $Data::Dumper::Useqq = 1; $Data::Dumper::Terse = 1; $Data::Dumper::Indent = 0; my ($DATABASE, $USERID, $PASSWORD) = @ARGV; my $dbh = DBI->connect("dbi:DB2:$DATABASE", "$USERID", "$PASSWORD", {PrintError => 1}) or die $DBI::errstr; my $sth = $dbh->prepare( 'DROP PROCEDURE SP_Example' ) or die $DBI::errstr; $sth->execute(); my $statement = "CREATE PROCEDURE SP_Example () LANGUAGE SQL BEGIN RETURN 5; END"; $sth = $dbh->prepare( $statement ) or die $DBI::errstr; $sth->execute() or die $DBI::errstr; my $failures = 0; sub passfail($$) { my ($msg, $ret) = @_; print($msg.' '.('.'x(55 - length($msg))).' '.($ret ? 'pass' : 'FAIL')."\n"); $failures++ if (!$ret); } my $round = 0; foreach my $binds ( { 'db2_param_type' => SQL_PARAM_OUTPUT }, { 'db2_param_type' => SQL_PARAM_OUTPUT, 'db2_c_type' => SQL_C_LONG }, ) { $round++; $sth = $dbh->prepare( '{ ? = CALL SP_Example( ) }' ) or die $DBI::errstr; my $output; $sth->bind_param_inout( 1, \$output, 20, $binds) or die $DBI::errstr; $sth->execute() or die $DBI::errstr; my $output_dcr = $sth->{'db2_call_return'}; #printf("the output bind is ".Dumper($output)); #printf("the db2_call_return is ".Dumper($output_dcr)); $sth->finish or die $DBI::errstr; passfail('Checking round '.$round.' db2_call_return value '.Dumper($output_dcr), $output_dcr eq 5); passfail('Checking round '.$round.' output bind var value '.Dumper($output), $output eq 5); } $dbh->disconnect or die $DBI::errstr; die 'failed' if $failures;
On Wed Apr 08 18:49:50 2009, appfault wrote: The previous comment was using DBI-1.607 and DBD-DB2-1.71.
Hi Thanks for reporting this. I would get back to you with an update on this one. On Wed Apr 08 18:51:04 2009, appfault wrote: Show quoted text
> On Wed Apr 08 18:49:50 2009, appfault wrote: > > The previous comment was using DBI-1.607 and DBD-DB2-1.71.
-- Thanks Tarun Pasrija IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
From: appfault [...] hotmail.com
Any status on this?
On Tue Dec 21 11:37:19 2010, appfault wrote: Show quoted text
> Any status on this?
Hi, Tarun, who was handling this module, is moved out of the project. I will be looking into to this and would need some time to get back to you. Currently I am able to track down to the cause of the problem and am seeking help from CLI (The underlying layer through which DBD::DB2 talks to DB2) team, as looks like this is a bug in CLI. Will keep you posted on progress made on this defect. -- Thanks Praveen IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
RT-Send-CC: rackapur [...] in.ibm.com, aff [...] cpan.org
Hi, The CLI team sees this is as a defect in their layer. They have asked for some more time on investigating the problem and would get back on which fix pak the fix for the issue will be available. Will keep you posted on the update. ------ Thanks Praveen IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
From: don.silvia [...] gmail.com
Hi, Can you please give a status on this? Thanks, On Mon Jan 03 05:49:20 2011, IBMTORDB2 wrote: Show quoted text
> Hi, > > The CLI team sees this is as a defect in their layer. They have asked > for some more time on investigating the problem and would get back on > which fix pak the fix for the issue will be available. Will keep you > posted on the update.
RT-Send-CC: aff [...] cpan.org, don.silvia [...] gmail.com
Hi, CLI expects that the return value from stored procedure is always bound with variable of type SQL_C_LONG. The reason being the data type of the return value from a Stored Procedure is always of type SQL_INTEGER. To handle this we have fixed the DBD-DB2 driver with the patch below. You can apply the patch and try making a stored procedure call as mentioned below to get the output from a stored procedure. Patch for dbdimp.c =================== diff dbdimp.c_new dbdimp.c_version1.80 2436,2449d2435 < SQLPOINTER datap; < switch (ctype) { < case SQL_C_SHORT: < case SQL_C_LONG: < datap = &phs->ivValue; < break; < case SQL_C_FLOAT: < case SQL_C_DOUBLE: < datap = &phs->dblValue; < break; < default: < datap = phs->buffer; < break; < } 2457c2443 < datap, --- Show quoted text
> phs->buffer,
2462,2464d2447 < < phs->cType = ctype; /*Set the cType of the variable to which the parameter is bound*/ < 2561,2570c2544,2547 < if( phs->cType == SQL_C_LONG || phs->cType == SQL_C_SHORT ) { < sv_setiv(phs->sv, phs->ivValue); < } else if( phs->cType == SQL_C_DOUBLE || phs->cType == SQL_C_FLOAT ) { < sv_setnv(phs->sv, phs->dblValue); < } else { < sv_setpvn( phs->sv, phs->buffer, phs->indp ); < if( phs->indp > phs->bufferSize ) < warn( "Output buffer too small, data truncated " < "for parameter '%s'", key ); < } --- Show quoted text
> sv_setpvn( phs->sv,
phs->buffer, phs->indp ); Show quoted text
> if( phs->indp >
phs->bufferSize ) Show quoted text
> warn( "Output
buffer too small, data truncated " Show quoted text
>
"for parameter '%s'", key ); Patch for dbdimp.h ================== diff dbdimp.h_new dbdimp.h_version1.80 108d107 < SQLSMALLINT cType; /* The parameter cType */ 115,116d113 < IV ivValue; /*integer variable to hold the bound output value */ < double dblValue; /*double variable to hold the bound output value*/ Changes needed in the Perl program ================================== You will need to specify the db2_c_type in the bind_param_inout call as below $sth->bind_param_inout( 1, \$bind_value, 4, {'db2_c_type' => SQL_C_LONG}); Let us know if you need any clarifications or if finding any difficulty applying the patch. -- Thanks Praveen IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
Thanks, but I'm having trouble applying the patch: [DBD-DB2-1.80]$ patch -i dbdimp.c.patch dbdimp.c Looks like a normal diff. Hunk #1 failed at line 2436. Hunk #2 failed at line 2457. Malformed patch at line 23: patch: '< ' expected at start of line. I think there are some line wrapping problems. Is there a way to attach the patch files ? Thanks, On Thu Apr 07 05:17:22 2011, IBMTORDB2 wrote: Show quoted text
> Hi, > > CLI expects that the return value from stored procedure is always bound > with variable of type SQL_C_LONG. The reason being the data type of the > return value from a Stored Procedure is always of type SQL_INTEGER. To > handle this we have fixed the DBD-DB2 driver with the patch below. You > can apply the patch and try making a stored procedure call as mentioned > below to get the output from a stored procedure.
Hi, Find attached below the patch file. Let me know if you are still facing any difficulty. -- Thanks Praveen IBM OpenSource Application Development Team India Software Labs, Bangalore (India)
Subject: sp_return_value.diff
--- 1.80/dbdimp.c Fri Oct 29 12:04:28 2010 +++ 1.80Ppatch/dbdimp.c Thu Apr 07 14:07:29 2011 @@ -2433,6 +2433,20 @@ maxlen, &phs->indp ); #else + SQLPOINTER datap; + switch (ctype) { + case SQL_C_SHORT: + case SQL_C_LONG: + datap = &phs->ivValue; + break; + case SQL_C_FLOAT: + case SQL_C_DOUBLE: + datap = &phs->dblValue; + break; + default: + datap = phs->buffer; + break; + } ret = SQLBindParameter( imp_sth->phstmt, (SQLUSMALLINT)SvIV( param ), phs->paramType, @@ -2440,11 +2454,14 @@ sql_type, phs->bDescribeOK ? phs->descColumnSize : prec, scale, - phs->buffer, + datap, maxlen, &phs->indp ); #endif } + + phs->cType = ctype; /*Set the cType of the variable to which the parameter is bound*/ + CHECK_ERROR(sth, SQL_HANDLE_STMT, imp_sth->phstmt, ret, "Bind Failed"); EOI(ret); @@ -2541,10 +2558,16 @@ } #endif else { - sv_setpvn( phs->sv, phs->buffer, phs->indp ); - if( phs->indp > phs->bufferSize ) - warn( "Output buffer too small, data truncated " - "for parameter '%s'", key ); + if( phs->cType == SQL_C_LONG || phs->cType == SQL_C_SHORT ) { + sv_setiv(phs->sv, phs->ivValue); + } else if( phs->cType == SQL_C_DOUBLE || phs->cType == SQL_C_FLOAT ) { + sv_setnv(phs->sv, phs->dblValue); + } else { + sv_setpvn( phs->sv, phs->buffer, phs->indp ); + if( phs->indp > phs->bufferSize ) + warn( "Output buffer too small, data truncated " + "for parameter '%s'", key ); + } } } } --- 1.80/dbdimp.h Mon Jan 25 13:28:01 2010 +++ 1.80Ppatch/dbdimp.h Thu Apr 07 14:04:39 2011 @@ -105,12 +105,15 @@ void *buffer; /* input and output buffer */ int bufferSize; /* size of buffer */ SQLUSMALLINT paramType; /* INPUT, OUTPUT or INPUT_OUTPUT */ + SQLSMALLINT cType; /* The parameter cType */ SQLINTEGER indp; /* null indicator or length indicator */ int bDescribed; /* already described this parameter */ int bDescribeOK; /* describe was successful */ SQLSMALLINT descSQLType; SQLSMALLINT descDecimalDigits; SQLUINTEGER descColumnSize; + IV ivValue; /*integer variable to hold the bound output value */ + double dblValue; /*double variable to hold the bound output value*/ }; #define dbd_init db2_init
Thanks Praveen, this has fixed the issue for me. My test environment: [~]$ perl -v This is perl 5, version 12, subversion 3 (v5.12.3) built for sun4-solaris [~]$ db2level DB21085I Instance "db2cld1" uses "64" bits and DB2 code release "SQL09054" with level identifier "06050107". Informational tokens are "DB2 v9.5.0.4", "s090429", "U825479", and Fix Pack "4". On Tue Apr 19 00:18:50 2011, IBMTORDB2 wrote: Show quoted text
> Hi, > > Find attached below the patch file. Let me know if you are still facing > any difficulty.
Fix available in release 1.81. Marking the issue resolved. -- Thanks Praveen IBM OpenSource Application Development Team India Software Labs, Bangalore (India)