MySQL Lists are EOL. Please join:

List:Internals« Previous MessageNext Message »
From:konstantin Date:June 30 2005 12:13pm
Subject:bk commit into 5.0 tree (konstantin:1.1994) BUG#10794
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of kostja. When kostja does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1994 05/06/30 16:13:49 konstantin@stripped +6 -0
  A fix and a test case for Bug#10794 "mysql_stmt_attr_set no 
  open cursor after mysql_stmt_execute" + post-review fixes.
  The bug was caused by wrong flags in stmt->server_status on the client
  side: if there was no cursor, the server didn't send server_status
  flags to the client, and the old flags were used to set up the
  fetch function of a statement. Consequently, stmt_read_row_from_cursor was
  used when there was no cursor. The fix fixes the server to always
  send server flags to the client.

  tests/mysql_client_test.c
    1.130 05/06/30 16:13:08 konstantin@stripped +88 -0
    A test case for Bug#10794 "mysql_stmt_attr_set no open cursor 
    after mysql_stmt_execute"

  sql/protocol.h
    1.29 05/06/30 16:13:08 konstantin@stripped +1 -1
    Remove an unused parameter for send_eof.

  sql/protocol.cc
    1.108 05/06/30 16:13:08 konstantin@stripped +37 -27
    Actual fix for bug#10794: create a function that writes the eof
    packet to network and use it from send_fields. We need to send
    a full eof packet from send_fields to inform the client about
    the cursor status (that there is no cursor in this case).

  libmysqld/lib_sql.cc
    1.100 05/06/30 16:13:08 konstantin@stripped +1 -1
    Update to correspond to the changed signature of send_eof

  libmysql/libmysql.c
    1.219 05/06/30 16:13:07 konstantin@stripped +0 -1
    Remove an extra assignment.

  include/mysql_com.h
    1.99 05/06/30 16:13:07 konstantin@stripped +5 -5
    Update stale comments.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	konstantin
# Host:	dragonfly.local
# Root:	/opt/local/work/mysql-5.0-10794

--- 1.98/include/mysql_com.h	2005-06-17 23:26:17 +04:00
+++ 1.99/include/mysql_com.h	2005-06-30 16:13:07 +04:00
@@ -137,14 +137,14 @@
 #define SERVER_QUERY_NO_GOOD_INDEX_USED 16
 #define SERVER_QUERY_NO_INDEX_USED      32
 /*
-  The server was able to fulfill client request and open read-only
-  non-scrollable cursor for the query.  This flag comes in server
-  status with reply to COM_EXECUTE and COM_EXECUTE_DIRECT commands.
+  The server was able to fulfill the clients request and opened a
+  read-only non-scrollable cursor for a query. This flag comes
+  in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
 */
 #define SERVER_STATUS_CURSOR_EXISTS 64
 /*
-  This flag is sent with last row of read-only cursor, in reply to
-  COM_FETCH command.
+  This flag is sent when a read-only cursor is exhausted, in reply to
+  COM_STMT_FETCH command.
 */
 #define SERVER_STATUS_LAST_ROW_SENT 128
 #define SERVER_STATUS_DB_DROPPED        256 /* A database was dropped */

--- 1.218/libmysql/libmysql.c	2005-06-17 23:26:17 +04:00
+++ 1.219/libmysql/libmysql.c	2005-06-30 16:13:07 +04:00
@@ -2726,7 +2726,6 @@
       set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
       return 1;
     }
-    stmt->server_status= mysql->server_status;
     if (cli_read_binary_rows(stmt))
       return 1;
     stmt->server_status= mysql->server_status;

--- 1.107/sql/protocol.cc	2005-06-23 19:29:06 +04:00
+++ 1.108/sql/protocol.cc	2005-06-30 16:13:08 +04:00
@@ -28,6 +28,7 @@
 #include <stdarg.h>
 
 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
+static void write_eof_packet(THD *thd, NET *net);
 
 #ifndef EMBEDDED_LIBRARY
 bool Protocol::net_store_data(const char *from, uint length)
@@ -362,43 +363,52 @@
 */    
 
 void
-send_eof(THD *thd, bool no_flush)
+send_eof(THD *thd)
 {
   NET *net= &thd->net;
   DBUG_ENTER("send_eof");
   if (net->vio != 0 && !net->no_send_eof)
   {
-    if (thd->client_capabilities & CLIENT_PROTOCOL_41)
-    {
-      uchar buff[5];
-      /* Don't send warn count during SP execution, as the warn_list
-         is cleared between substatements, and mysqltest gets confused */
-      uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
-      buff[0]=254;
-      int2store(buff+1, tmp);
-      /*
-	The following test should never be true, but it's better to do it
-	because if 'is_fatal_error' is set the server is not going to execute
-	other queries (see the if test in dispatch_command / COM_QUERY)
-      */
-      if (thd->is_fatal_error)
-	thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
-      int2store(buff+3, thd->server_status);
-      VOID(my_net_write(net,(char*) buff,5));
-      VOID(net_flush(net));
-    }
-    else
-    {
-      VOID(my_net_write(net,eof_buff,1));
-      if (!no_flush)
-	VOID(net_flush(net));
-    }
+    write_eof_packet(thd, net);
+    VOID(net_flush(net));
     thd->net.no_send_error= 1;
     DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
   }
   DBUG_VOID_RETURN;
 }
 
+
+/*
+  Format EOF packet according to the current protocol and
+  write it to the network output buffer.
+*/
+
+static void write_eof_packet(THD *thd, NET *net)
+{
+  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+  {
+    uchar buff[5];
+    /*
+      Don't send warn count during SP execution, as the warn_list
+      is cleared between substatements, and mysqltest gets confused
+    */
+    uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
+    buff[0]= 254;
+    int2store(buff+1, tmp);
+    /*
+      The following test should never be true, but it's better to do it
+      because if 'is_fatal_error' is set the server is not going to execute
+      other queries (see the if test in dispatch_command / COM_QUERY)
+    */
+    if (thd->is_fatal_error)
+      thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+    int2store(buff+3, thd->server_status);
+    VOID(my_net_write(net, (char*) buff, 5));
+  }
+  else
+    VOID(my_net_write(net, eof_buff, 1));
+}
+
 /*
     Please client to send scrambled_password in old format.
   SYNOPSYS
@@ -640,7 +650,7 @@
   }
 
   if (flags & SEND_EOF)
-    my_net_write(&thd->net, eof_buff, 1);
+    write_eof_packet(thd, &thd->net);
   DBUG_RETURN(prepare_for_send(list));
 
 err:

--- 1.28/sql/protocol.h	2005-06-01 14:17:38 +04:00
+++ 1.29/sql/protocol.h	2005-06-30 16:13:08 +04:00
@@ -179,7 +179,7 @@
 void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
 void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
 	     const char *info=0);
-void send_eof(THD *thd, bool no_flush=0);
+void send_eof(THD *thd);
 bool send_old_password_request(THD *thd);
 char *net_store_length(char *packet,uint length);
 char *net_store_data(char *to,const char *from, uint length);

--- 1.99/libmysqld/lib_sql.cc	2005-06-17 23:26:18 +04:00
+++ 1.100/libmysqld/lib_sql.cc	2005-06-30 16:13:08 +04:00
@@ -773,7 +773,7 @@
 }
 
 void
-send_eof(THD *thd, bool no_flush)
+send_eof(THD *thd)
 {
 }
 

--- 1.129/tests/mysql_client_test.c	2005-06-28 20:52:08 +04:00
+++ 1.130/tests/mysql_client_test.c	2005-06-30 16:13:08 +04:00
@@ -13389,6 +13389,93 @@
   myquery(rc);
 }
 
+/* Bug#10794: cursors, packets out of order */
+
+static void test_bug10794()
+{
+  MYSQL_STMT *stmt, *stmt1;
+  MYSQL_BIND bind[2];
+  char a[21];
+  int id_val;
+  ulong a_len;
+  int rc;
+  const char *stmt_text;
+  int i= 0;
+  ulong type;
+
+  myheader("test_bug10794");
+
+  mysql_query(mysql, "drop table if exists t1");
+  mysql_query(mysql, "create table t1 (id integer not null primary key,"
+                                      "name varchar(20) not null)");
+  stmt= mysql_stmt_init(mysql);
+  stmt_text= "insert into t1 (id, name) values (?, ?)";
+  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+  check_execute(stmt, rc);
+  bzero(bind, sizeof(bind));
+  bind[0].buffer_type= MYSQL_TYPE_LONG;
+  bind[0].buffer= (void*) &id_val;
+  bind[1].buffer_type= MYSQL_TYPE_STRING;
+  bind[1].buffer= (void*) a;
+  bind[1].length= &a_len;
+  rc= mysql_stmt_bind_param(stmt, bind);
+  check_execute(stmt, rc);
+  for (i= 0; i < 34; i++)
+  {
+    id_val= (i+1)*10;
+    sprintf(a, "a%d", i);
+    a_len= strlen(a); /* safety against broken sprintf */
+    rc= mysql_stmt_execute(stmt);
+    check_execute(stmt, rc);
+  }
+  stmt_text= "select name from t1";
+  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+  type= (ulong) CURSOR_TYPE_READ_ONLY;
+  mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+  stmt1= mysql_stmt_init(mysql);
+  mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type);
+  bzero(bind, sizeof(bind));
+  bind[0].buffer_type= MYSQL_TYPE_STRING;
+  bind[0].buffer= (void*) a;
+  bind[0].buffer_length= sizeof(a);
+  bind[0].length= &a_len;
+  rc= mysql_stmt_bind_result(stmt, bind);
+  check_execute(stmt, rc);
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+  rc= mysql_stmt_fetch(stmt);
+  check_execute(stmt, rc);
+  if (!opt_silent)
+    printf("Fetched row from stmt: %s\n", a);
+  /* Don't optimize: an attribute of the original test case */
+  mysql_stmt_free_result(stmt);
+  mysql_stmt_reset(stmt);
+  stmt_text= "select name from t1 where id=10";
+  rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text));
+  check_execute(stmt1, rc);
+  rc= mysql_stmt_bind_result(stmt1, bind);
+  check_execute(stmt1, rc);
+  rc= mysql_stmt_execute(stmt1);
+  while (1)
+  {
+    rc= mysql_stmt_fetch(stmt1);
+    if (rc == MYSQL_NO_DATA)
+    {
+      if (!opt_silent)
+        printf("End of data in stmt1\n");
+      break;
+    }
+    check_execute(stmt1, rc);
+    if (!opt_silent)
+      printf("Fetched row from stmt1: %s\n", a);
+  }
+  mysql_stmt_close(stmt);
+  mysql_stmt_close(stmt1);
+
+  rc= mysql_query(mysql, "drop table t1");
+  myquery(rc);
+}
+
 
 /*
   Read and parse arguments and MySQL options from my.cnf
@@ -13626,6 +13713,7 @@
   { "test_bug11111", test_bug11111 },
   { "test_bug9992", test_bug9992 },
   { "test_bug10736", test_bug10736 },
+  { "test_bug10794", test_bug10794 },
   { 0, 0 }
 };
 
Thread
bk commit into 5.0 tree (konstantin:1.1994) BUG#10794konstantin30 Jun