Bug #428 mysql_execute() problem
Submitted: 13 May 2003 16:29 Modified: 7 Jun 2003 8:23
Reporter: Philippe Brand Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.1 OS:Linux (Linux)
Assigned to: Alexey Botchkov CPU Architecture:Any

[13 May 2003 16:29] Philippe Brand
Description:
mysql_execute() reports "Lost connection to MySQL server during query" when repeatadly inserting rows into a table. First call get 31 inserts, subsequents calls fails at index = 2. Application's logic and values passed are known to be 100% correct, function works with "standard" calls to mysql_query();

Log extract:

Wed May 14 00:42:27 [INTEGR] (insertTM) EXECUTE(31): Lost connection to MySQL server during query
Wed May 14 00:42:37 [INTEGR] (insertTM) EXECUTE(2): Lost connection to MySQL server during query
Wed May 14 00:42:57 [INTEGR] (insertTM) EXECUTE(2): Lost connection to MySQL server during query

Next run:

1 array insert ok,then
Wed May 14 01:03:28 [INTEGR] (insertTM) EXECUTE(17): Lost connection to MySQL server during query

Using 4.1-alpha binaries from mysql.com, the following piece of code fails on Linux-2.4.19 Mandrake 8.1:

(no_depeche is a global, declared as long).

bool insertTM (int index)
{
  MYSQL_BIND bind[3];
  MYSQL_STMT *stmt=NULL;
  char query[255];
  char mot[22];
  short pos;

    strcpy(query, "INSERT INTO Tmots (mot, no_depeche, position) VALUES (?,?,?)");
    if (!(stmt = mysql_prepare(&integr_mysql, query, strlen(query)))) {
      testErrSGBD(nomFct, &integr_mysql, "PREPARE");
      return(FALSE);
    }
    if (mysql_param_count(stmt) != 3) {
      Log("(insertTM) invalid parameter count");
      return(FALSE);
    }
    bind[0].buffer_type = MYSQL_TYPE_VAR_STRING;
    bind[0].buffer= (char *)mot;
    bind[0].buffer_length= sizeof(mot);
    bind[0].is_null= 0;
    bind[0].length= 0;

    bind[1].buffer_type= MYSQL_TYPE_LONG;
    bind[1].buffer= (char *)&no_depeche;
    bind[1].is_null= 0;
    bind[1].length= 0;

    bind[2].buffer_type= MYSQL_TYPE_SHORT;
    bind[2].buffer= (char *)&pos;
    bind[2].is_null= 0;
    bind[2].length= 0;

    if (mysql_bind_param(stmt, bind)) {
      Log("(insertTM) BIND: %s", mysql_stmt_error(stmt));
      return(FALSE);
    }

  for (i=0; i<index; i++)  {
    strcpy(mot, motsTxt[i]);
    pos = position[i];
    if (mysql_execute(stmt)) {
      Log("(insertTM) EXECUTE(%ld): %s", i, mysql_stmt_error(stmt));
      return(FALSE);
    }
  }
  return(TRUE);
}

How to repeat:
Reproducable on my system, data flow in application makes it difficult to reduce example showing bug. Data injected comes from a file, so same data is always tested. No NULL values.

CREATE TABLE Tmots
        (mot            CHAR(20) NOT NULL,
         no_depeche     INT UNSIGNED REFERENCES Tdepeches (no_depeche) ON DELETE CASCADE,
         position       SMALLINT UNSIGNED,
         INDEX Imots (no_depeche),
         INDEX ImotsDep (mot))
  TYPE = MyISAM;

Working code:

  char *queryfmt="INSERT INTO Tmots (mot, no_depeche, position) VALUES ('%s',%ld,%ld)";
  char *query = malloc(strlen(queryfmt)+((22+10+5+4)*index)+1);
  char *ptquery = query;
    
  ptquery += sprintf(query, queryfmt, motsTxt[0], no_depeche, position[0]);
  for (i=1; i<index; i++)
    ptquery += sprintf(ptquery, ",('%s',%ld,%ld)", motsTxt[i], no_depeche, position[i]);
  if (mysql_query(&integr_mysql, query)) {
    testErrSGBD(nomFct, &integr_mysql, insertCmd);
    return(FALSE);
  }
  free(query);
  return(TRUE);
[2 Jun 2003 10:02] Michael Widenius
Sorry, but your bug report doesn't have enough information for us to
be able to repeat it

Could you help us locate the problem by doing the following:

In the MySQL source directory we have a file:

tests/client_test.c

that test a lot of the new prepared statement protocol.

If you can add a function to it that can repeat the problem and send
us a patch, we will fix it in the next 4.1 release.

Another possibility is to compile MySQL 4.1 for debugging and use gdb
to find out where mysqld dies (if this is the problem).

You can find more information about this at:

http://www.mysql.com/doc/en/Debugging_server.html
[6 Jun 2003 2:57] Philippe Brand
Sorry for delay (hollidays), here is a context diff:
Problem is that compiling and running example with:

gcc -v -I../include -DDBUG_OFF -o client_test client_test.c -lmysqlclient
Reading specs from /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/specs
Configured with: ../configure --prefix=/usr --libdir=/usr/lib --with-slibdir=/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --enable-long-long --enable-__cxa_atexit --enable-languages=c,c++,ada,f77,objc,java --host=i586-mandrake-linux-gnu --with-system-zlib
Thread model: posix
gcc version 3.2 (Mandrake Linux 9.0 3.2-1mdk)
 /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/cc1 -lang-c -v -I../include -D__GNUC__=3 -D__GNUC_MINOR__=2 -D__GNUC_PATCHLEVEL__=0 -D__GXX_ABI_VERSION=102 -D__ELF__ -Dunix -D__gnu_linux__ -Dlinux -D__ELF__ -D__unix__ -D__gnu_linux__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i586__ -D__tune_pentium__ -DDBUG_OFF client_test.c -quiet -dumpbase client_test.c -version -o /root/tmp/cc3yD1XZ.s
GNU CPP version 3.2 (Mandrake Linux 9.0 3.2-1mdk) (cpplib) (i386 Linux/ELF)
GNU C version 3.2 (Mandrake Linux 9.0 3.2-1mdk) (i586-mandrake-linux-gnu)
        compiled by GNU C version 3.2 (Mandrake Linux 9.0 3.2-1mdk).
ignoring nonexistent directory "/usr/i586-mandrake-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 ../include
 /usr/local/include
 /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/include
 /usr/include
End of search list.
 as -V -Qy -o /root/tmp/ccANF65G.o /root/tmp/cc3yD1XZ.s
GNU assembler version 2.12.90.0.15 (i586-mandrake-linux-gnu) using BFD version 2.12.90.0.15 20020717
 /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o client_test /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/../../../crt1.o /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/../../../crti.o /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/crtbegin.o -L/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2 -L/usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/../../.. /root/tmp/ccANF65G.o -lmysqlclient -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/crtend.o /usr/lib/gcc-lib/i586-mandrake-linux-gnu/3.2/../../../crtn.o

gives:

...
#####################################
11 of (1/1): test_fetch_double  
#####################################

 total parameters in stmt: `7` (expected: `7`)
 [MySQL-4.1.0-alpha-Max-log][2013] Lost connection to MySQL server during query
client_test: client_test.c:2829: bind_fetch: Assertion `rc == 0' failed.
Aborted (core dumped)
(gdb) bt
#0  0x420288b1 in kill () from /lib/i686/libc.so.6
#1  0x420286a8 in raise () from /lib/i686/libc.so.6
#2  0x42029a96 in abort () from /lib/i686/libc.so.6
#3  0x42021b15 in __assert_fail () from /lib/i686/libc.so.6
#4  0x0805378f in bind_fetch ()
#5  0x080551df in test_fetch_double ()
#6  0x08060266 in main ()
#7  0x42015b17 in __libc_start_main () from /lib/i686/libc.so.6

Mandrake 9.0 using glibc 2.3.1 and mysql 4.1 RPMS from mysql.com.
rpm -q -l MySQL-shared-4.1.0-0   
/usr/lib/libmysqlclient.so
/usr/lib/libmysqlclient.so.14
/usr/lib/libmysqlclient.so.14.0.0
/usr/lib/libmysqlclient_r.so
/usr/lib/libmysqlclient_r.so.14
/usr/lib/libmysqlclient_r.so.14.0.0

So maybe there is another problem ?

*** client_test.c.orig  2003-05-16 11:49:45.000000000 +0200
--- client_test.c       2003-06-06 11:19:18.000000000 +0200
***************
*** 6377,6380 ****
--- 6377,6449 ----
  
  
+ /*
+   To test EXECUTE bug
+   bug #428 (reported by hf@mysql.com & philippe@brand.nom.fr).
+ */
+ 
+ #define LMAXMOT               20              /* Max word length in agency wire */
+ #define NBMAXMOTS     500             /* Max significant words in agency wire */
+ #define TTABLESQL     NBMAXMOTS+1
+ char motsTxt[TTABLESQL][LMAXMOT+1] = {
+  "THIS","SHOULD","SHOW","AN","EXECUTE","BUG","FOR","MYSQL","WHICH","COMES",
+  "WHEN","CALLING","SEVERAL","TIMES","THE","FUNCTION","INSERTING","AGENCY","WIRE",
+  "WORDS","INTO","MYISAM","TABLE","MYSQL","REPORTS","LOST","CONNECTION","TO","SERVER",
+  "THIS","CODE","USED","TO","WORD","WITHOUT","USING","THIS","NEW","MYSQL","FEATURE"
+ };
+ long position[TTABLESQL] = {          /* word position into text */
+   1,10,65,78,654,234,453,789,54,52,65,896,54,123,65,87,456,54,984,32,
+   1,10,65,78,654,234,453,789,54,52,65,896,54,123,65,87,456,54,984,32,
+ };
+ long no_depeche = 123456;
+ 
+ static void test_execute_bug(int index)
+ {
+   static MYSQL_BIND bind[3];
+   static MYSQL_STMT *stmt=NULL;
+   char query[255];
+   static char mot[LMAXMOT+1];
+   static short pos;
+   int rc;
+   int i;
+ 
+   myheader("test_execute_bug");
+ 
+   if (1) {            /* was !stmt bug another problem rise */
+     mysql_autocommit(mysql,TRUE);
+ 
+     rc = mysql_query(mysql, "DROP TABLE IF EXISTS test_execute");
+     myquery(rc);
+ 
+     rc = mysql_query(mysql, "CREATE TABLE test_execute(mot char(20) not null, no_depeche int unsigned, position smallint, INDEX Imots(no_depeche), INDEX ImotsDep(mot)) TYPE = MyISAM");
+     myquery(rc);
+ 
+     strcpy(query, "INSERT DELAYED INTO test_execute (mot, no_depeche, position) VALUES (?,?,?)");
+     stmt = mysql_prepare(mysql, query, strlen(query));
+     mystmt_init(stmt);
+ 
+     bind[0].buffer_type   = MYSQL_TYPE_VAR_STRING;
+     bind[0].buffer        = (char *)mot;
+     bind[0].buffer_length = sizeof(mot);
+     bind[0].is_null       = 0;
+     bind[0].length        = 0;
+ 
+     bind[1].buffer_type   = MYSQL_TYPE_LONG;
+     bind[1].buffer        = (char *)&no_depeche;
+     bind[1].is_null       = 0;
+     bind[1].length        = 0;
+                 
+     bind[2].buffer_type   = MYSQL_TYPE_SHORT;
+     bind[2].buffer        = (char *)&pos;
+     bind[2].is_null       = 0;
+     bind[2].length        = 0;
+ 
+     myassert(mysql_bind_param(stmt, bind));
+   }
+   for (i=0; i<index; i++)  {
+     strcpy(mot, motsTxt[i]);
+     pos = position[i];
+     myassert(mysql_execute(stmt));
+   }
+ }
  
  /*
***************
*** 6601,6604 ****
--- 6670,6675 ----
      test_explain_bug();     /* test for the EXPLAIN, bug #115 */
      test_decimal_bug();     /* test for the decimal bug */
+     test_execute_bug(40);   /* test for the EXECUTE bug #428, first run */
+     test_execute_bug(40);   /* test for the EXECUTE bug #428, second run, aborting */
  
      end_time= time((time_t *)0);
[7 Jun 2003 8:23] Alexey Botchkov
I tested this with last developer's 4.1 tree on my RH8.0 Linux
Only problem i found was about your line 
+     myassert(mysql_bind_param(stmt, bind));
we return 0 if the function succeed, so here should be
+     myassert(mysql_bind_param(stmt, bind) == 0);

All other code works well - so i can't repeat the problem with mysql_execute