This patch fixes the fact that DBD::mysql doesn't clear out the
sth attribute cache when switching between result sets, and doesn't
adjust NUM_OF_FIELDS.

Other driver authors please note the new 'official way' to adjust
NUM_OF_FIELDS, as per this patch. DBI >= 1.54 will now automatically
adjust the row buffer width when you adjust NUM_OF_FIELDS in this way.
(And it does it in a way that preserves column bindings.)

The patch also adds some tests to the test suite.

Tim.
diff -ru DBD-mysql-4.001/dbdimp.c DBD-mysql-4.001.gofer1/dbdimp.c
--- DBD-mysql-4.001/dbdimp.c    2007-01-08 00:39:05.000000000 +0000
+++ DBD-mysql-4.001.gofer1/dbdimp.c     2007-02-23 15:14:40.000000000 +0000
@@ -2785,6 +2785,7 @@
     }
     else
     {
+      AV *av;
       /* We have a new rowset */
       imp_sth->currow=0;
 
@@ -2806,8 +2807,32 @@
                       mysql_affected_rows(svsock));
       }
 
-      /* Store the result in the current statement handle */
-      DBIc_NUM_FIELDS(imp_sth)= mysql_num_fields(imp_sth->result);
+      /* delete cached handle attributes */
+      /* XXX should be driven by a list to ease maintenance */
+      hv_delete((HV*)SvRV(sth), "NAME", 4, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "NULLABLE", 8, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "NUM_OF_FIELDS", 13, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "PRECISION", 9, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "SCALE", 5, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "TYPE", 4, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_insertid", 14, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_is_auto_increment", 23, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_is_blob", 13, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_is_key", 12, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_is_num", 12, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_is_pri_key", 16, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_length", 12, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_max_length", 16, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_table", 11, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_type", 10, G_DISCARD);
+      hv_delete((HV*)SvRV(sth), "mysql_type_name", 15, G_DISCARD);
+
+      /* Adjust NUM_OF_FIELDS - which also adjusts the row buffer size */
+      DBIc_NUM_FIELDS(imp_sth)= 0; /* for DBI <= 1.53 */
+      DBIS->set_attr_k(sth, sv_2mortal(newSVpvn("NUM_OF_FIELDS",13)), 0,
+          sv_2mortal(newSViv(mysql_num_fields(imp_sth->result)))
+      );
+
       DBIc_ACTIVE_on(imp_sth);
 
       if (dbis->debug >= 5)
diff -ru DBD-mysql-4.001/t/80procs.t DBD-mysql-4.001.gofer1/t/80procs.t
--- DBD-mysql-4.001/t/80procs.t 2006-12-24 13:35:46.000000000 +0000
+++ DBD-mysql-4.001.gofer1/t/80procs.t  2007-02-23 15:10:14.000000000 +0000
@@ -113,6 +113,8 @@
     Test($state or $sth->execute()) or 
       DbiError($dbh->err, $dbh->errstr);
 
+    $sth->finish;
+
     my $proc_select = 'SELECT @a';
     Test($state or $sth = $dbh->prepare($proc_select)) or
     DbiError($dbh->err, $dbh->errstr);
@@ -120,6 +122,8 @@
     Test($state or $sth->execute()) or 
       DbiError($dbh->err, $dbh->errstr);
 
+    $sth->finish;
+
   Test($state or ($sth=$dbh->prepare("DROP PROCEDURE testproc"))) or
     DbiError($dbh->err, $dbh->errstr);
 
@@ -148,6 +152,9 @@
 
   my $dataset;
 
+  Test($state or ($sth->{NUM_OF_FIELDS} == 1)) or
+    DbiError($dbh->err, $dbh->errstr);
+
   Test($state or $dataset = $sth->fetchrow_arrayref()) or 
     DbiError($dbh->err, $dbh->errstr);
   
@@ -159,6 +166,9 @@
   Test($state or $more_results =  $sth->more_results()) or
     DbiError($dbh->err, $dbh->errstr);
 
+  Test($state or ($sth->{NUM_OF_FIELDS} == 2)) or
+    DbiError($dbh->err, $dbh->errstr);
+
   Test($state or $dataset = $sth->fetchrow_arrayref()) or
     DbiError($dbh->err, $dbh->errstr);
 
@@ -168,6 +178,9 @@
   Test($state or $more_results =  $sth->more_results()) or
     DbiError($dbh->err, $dbh->errstr);
 
+  Test($state or ($sth->{NUM_OF_FIELDS} == 3)) or
+    DbiError($dbh->err, $dbh->errstr);
+
   Test($state or $dataset = $sth->fetchrow_arrayref()) or
     DbiError($dbh->err, $dbh->errstr);
 
@@ -177,7 +190,7 @@
   Test($state or !($more_results =  $sth->more_results())) or
     DbiError($dbh->err, $dbh->errstr);
 
-  $SIG{__WARN__} = sub { die @_ };
+  local $SIG{__WARN__} = sub { die @_ };
 
   Test($state or $dbh->disconnect()) or 
     DbiError($dbh->err, $dbh->errstr);
diff -ru DBD-mysql-4.001/t/lib.pl DBD-mysql-4.001.gofer1/t/lib.pl
--- DBD-mysql-4.001/t/lib.pl    2006-12-23 18:03:30.000000000 +0000
+++ DBD-mysql-4.001.gofer1/t/lib.pl     2007-02-23 15:06:52.000000000 +0000
@@ -11,6 +11,7 @@
 use strict;
 use vars qw($mdriver $dbdriver $childPid $test_dsn $test_user $test_password);
 
+$| = 1; # flush stdout asap to keep in sync with stderr
 
 #
 #   Driver names; EDIT THIS!
@@ -166,7 +167,8 @@
                print "ok $::numTests\n";
                return 1;
            } else {
-               printf("not ok $::numTests%s\n",
+               my ($pack, $file, $line) = caller();
+               printf("not ok $::numTests%s at line $line\n",
                        (defined($error) ? " $error" : ""));
                return 0;
            }
Only in DBD-mysql-4.001.gofer1: x
Only in DBD-mysql-4.001.gofer1: {mysql_errno}

Reply via email to