List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:February 14 2008 8:42pm
Subject:bk commit into 5.0 tree (davi:1.2578) BUG#32265
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of davi.  When davi 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@stripped, 2008-02-14 17:42:46-02:00, davi@stripped +2 -0
  Bug#32265 Server returns different metadata if prepared statement is used
  
  Executing a prepared statement associated with a materialized
  cursor yields to the client a metadata packet with wrong table
  and database names. The problem was occurring because the server
  was sending the the name of the temporary table used by the cursor
  instead of the table name of the original table. The same problem
  occurs when selecting from views, in which case the table name was
  being sent and not the name of the view.
  
  The solution is to backup the table and database names of the fields
  of the original tables or views and restore then later into the
  fields of the temporary table.

  sql/sql_cursor.cc@stripped, 2008-02-14 17:42:44-02:00, davi@stripped +108 -5
    Backup the field's names and restore it when the metadata
    needs to be sent to the client. This is done this way to
    avoid the convoluted issue of creating the item list in
    the send_fields method.

  tests/mysql_client_test.c@stripped, 2008-02-14 17:42:44-02:00, davi@stripped +82 -0
    Add test case for Bug#32265

diff -Nrup a/sql/sql_cursor.cc b/sql/sql_cursor.cc
--- a/sql/sql_cursor.cc	2006-12-30 18:02:07 -02:00
+++ b/sql/sql_cursor.cc	2008-02-14 17:42:44 -02:00
@@ -70,6 +70,17 @@ public:
 
 
 /*
+  Table and database name of a item before the temp table is created.
+*/
+
+typedef struct
+{
+  const char *db_name;
+  const char *table_name;
+} Field_tuple;
+
+
+/*
   Materialized_cursor -- an insensitive materialized server-side
   cursor. The result set of this cursor is saved in a temporary
   table at open. The cursor itself is simply an interface for the
@@ -83,10 +94,14 @@ class Materialized_cursor: public Server
   SELECT_LEX_UNIT fake_unit;
   TABLE *table;
   List<Item> item_list;
+  List<Field_tuple> *name_list;
   ulong fetch_limit;
   ulong fetch_count;
+private:
+  void restore_fields_names(void);
 public:
-  Materialized_cursor(select_result *result, TABLE *table);
+  Materialized_cursor(select_result *result, TABLE *table,
+                      List<Field_tuple> *name_list);
 
   virtual bool is_open() const { return table != 0; }
   virtual int open(JOIN *join __attribute__((unused)));
@@ -108,9 +123,14 @@ public:
 class Select_materialize: public select_union
 {
   select_result *result; /* the result object of the caller (PS or SP) */
+  List<Field_tuple> *name_list;
+private:
+  bool backup_fields_names(List<Item> &item_list);
 public:
-  Select_materialize(select_result *result_arg) :result(result_arg) {}
+  Select_materialize(select_result *result_arg)
+    : result(result_arg), name_list(NULL) {}
   virtual bool send_fields(List<Item> &list, uint flags);
+  List<Field_tuple> *get_fields_names(void) { return name_list; }
 };
 
 
@@ -207,9 +227,12 @@ int mysql_open_cursor(THD *thd, uint fla
     Materialized_cursor *materialized_cursor;
     TABLE *table= result_materialize->table;
     MEM_ROOT *mem_root= &table->mem_root;
+    List<Field_tuple> *name_list= result_materialize->get_fields_names();
+
+    DBUG_ASSERT(name_list != NULL);
 
     if (!(materialized_cursor= new (mem_root)
-                               Materialized_cursor(result, table)))
+                               Materialized_cursor(result, table, name_list)))
     {
       rc= 1;
       goto err_open;
@@ -533,9 +556,11 @@ Sensitive_cursor::~Sensitive_cursor()
 ****************************************************************************/
 
 Materialized_cursor::Materialized_cursor(select_result *result_arg,
-                                         TABLE *table_arg)
+                                         TABLE *table_arg,
+                                         List<Field_tuple> *list_arg)
   :Server_side_cursor(&table_arg->mem_root, result_arg),
   table(table_arg),
+  name_list(list_arg),
   fetch_limit(0),
   fetch_count(0)
 {
@@ -544,6 +569,41 @@ Materialized_cursor::Materialized_cursor
 }
 
 
+static inline Item_ident *get_ident_item(Item *item)
+{
+  Item::Type type= item->type();
+
+  if (type == Item::FIELD_ITEM || type == Item::REF_ITEM)
+    return (Item_ident *) item;
+
+  type= item->real_item()->type();
+
+  if (type == Item::FIELD_ITEM || type == Item::REF_ITEM)
+    return (Item_field *) item->real_item();
+
+  return NULL;
+}
+
+
+void Materialized_cursor::restore_fields_names(void)
+{
+  Item *item;
+  Item_ident *ident;
+  Field_tuple *tuple;
+  List_iterator_fast<Item> it(item_list);
+  List_iterator_fast<Field_tuple> name_it(*name_list);
+
+  while ((item= it++, tuple= name_it++))
+  {
+    ident= get_ident_item(item);
+    if (!ident)
+      continue;
+    ident->db_name= tuple->db_name;
+    ident->table_name= tuple->table_name;
+  }
+}
+
+
 int Materialized_cursor::open(JOIN *join __attribute__((unused)))
 {
   THD *thd= fake_unit.thd;
@@ -559,6 +619,13 @@ int Materialized_cursor::open(JOIN *join
   if (rc == 0)
   {
     /*
+      Metadata must not contain table and database names of the
+      materialized table (item's table and database name is ""
+      at this point.)
+    */
+    restore_fields_names();
+
+    /*
       Now send the result set metadata to the client. We need to
       do it here, as in Select_materialize::send_fields the items
       for column types are not yet created (send_fields requires
@@ -658,12 +725,48 @@ Materialized_cursor::~Materialized_curso
  Select_materialize
 ****************************************************************************/
 
+
+bool Select_materialize::backup_fields_names(List<Item> &item_list)
+{
+  Item *item;
+  Item_ident *ident;
+  Field_tuple *tuple;
+  List_iterator_fast<Item> it(item_list);
+  MEM_ROOT *mem_root= &table->mem_root;
+
+  if (!(name_list= new (mem_root) List<Field_tuple>))
+    return TRUE;
+
+  while ((item= it++))
+  {
+    if (!(tuple= (Field_tuple *) alloc_root(mem_root, sizeof(Field_tuple))))
+      return FALSE;
+
+    tuple->db_name= tuple->table_name= NULL;
+
+    name_list->push_back(tuple, mem_root);
+
+    if (!(ident= get_ident_item(item)))
+      continue;
+
+    if (ident->db_name)
+      tuple->db_name= strdup_root(mem_root, ident->db_name);
+
+    if (ident->table_name)
+      tuple->table_name= strdup_root(mem_root, ident->table_name);
+  }
+
+  return FALSE;
+}
+
+
 bool Select_materialize::send_fields(List<Item> &list, uint flags)
 {
   DBUG_ASSERT(table == 0);
   if (create_result_table(unit->thd, unit->get_unit_column_types(),
                           FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
     return TRUE;
-  return FALSE;
+
+  return backup_fields_names(list);
 }
 
diff -Nrup a/tests/mysql_client_test.c b/tests/mysql_client_test.c
--- a/tests/mysql_client_test.c	2007-12-01 07:12:28 -02:00
+++ b/tests/mysql_client_test.c	2008-02-14 17:42:44 -02:00
@@ -16152,6 +16152,87 @@ static void test_bug31669()
   DBUG_VOID_RETURN;
 }
 
+
+/**
+  Bug#32265 Server returns different metadata if prepared statement is used
+*/
+
+static void test_bug32265()
+{
+  int rc, i;
+  MYSQL_STMT *stmt;
+  MYSQL_FIELD *field;
+
+  DBUG_ENTER("test_bug32265");
+  myheader("test_bug32265");
+
+  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "CREATE  TABLE t1 (a INTEGER)");
+  myquery(rc);
+  rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
+  myquery(rc);
+  rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1");
+  myquery(rc);
+
+  stmt= open_cursor("SELECT * FROM t1");
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  field= stmt->mysql->fields;
+  DIE_UNLESS(strcmp(field->table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+  mysql_stmt_close(stmt);
+
+  stmt= open_cursor("SELECT a '' FROM t1 ``");
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  field= stmt->mysql->fields;
+  DIE_UNLESS(strcmp(field->table, "") == 0);
+  DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+  mysql_stmt_close(stmt);
+
+  stmt= open_cursor("SELECT a '' FROM t1 ``");
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  field= stmt->mysql->fields;
+  DIE_UNLESS(strcmp(field->table, "") == 0);
+  DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+  mysql_stmt_close(stmt);
+
+  stmt= open_cursor("SELECT * FROM v1");
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  field= stmt->mysql->fields;
+  DIE_UNLESS(strcmp(field->table, "v1") == 0);
+  DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+  mysql_stmt_close(stmt);
+
+  stmt= open_cursor("SELECT * FROM v1 /* SIC */ GROUP BY 1");
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  field= stmt->mysql->fields;
+  DIE_UNLESS(strcmp(field->table, "v1") == 0);
+  DIE_UNLESS(strcmp(field->org_table, "t1") == 0);
+  DIE_UNLESS(strcmp(field->db, "client_test_db") == 0);
+  mysql_stmt_close(stmt);
+
+  rc= mysql_query(mysql, "DROP VIEW v1");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP TABLE t1");
+  myquery(rc);
+
+  DBUG_VOID_RETURN;
+}
+
 /*
   Read and parse arguments and MySQL options from my.cnf
 */
@@ -16446,6 +16527,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug29948", test_bug29948 },
   { "test_bug29306", test_bug29306 },
   { "test_bug31669", test_bug31669 },
+  { "test_bug32265", test_bug32265 },
   { 0, 0 }
 };
 
Thread
bk commit into 5.0 tree (davi:1.2578) BUG#32265Davi Arnaut14 Feb
  • Re: bk commit into 5.0 tree (davi:1.2578) BUG#32265Konstantin Osipov20 Feb
  • Re: bk commit into 5.0 tree (davi:1.2578) BUG#32265Konstantin Osipov20 Feb