MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:kgeorge Date:February 16 2007 11:10am
Subject:bk commit into 5.0 tree (gkodinov:1.2387) BUG#25831
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of kgeorge. When kgeorge 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, 2007-02-16 13:10:15+02:00, gkodinov@stripped +8 -0
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   Several problems fixed: 
    1. There was a "catch-all" context initialization in setup_tables()
      that was causing the table that we insert into to be visible in the 
      SELECT part of an INSERT .. SELECT .. statement with no tables in
      its FROM clause. This was making sure all the under-initialized
      contexts in various parts of the code are not left uninitialized.
      Fixed by removing the "catch-all" statement and initializing the 
      context in the parser.
    2. Incomplete name resolution context when resolving the right-hand
      values in the ON DUPLICATE KEY UPDATE ... part of an INSERT ... SELECT ...
      caused columns from NATURAL JOIN/JOIN USING table references in the
      FROM clause of the select to be unavailable.
      Fixed by establishing a proper name resolution context.
    3. When setting up the special name resolution context for problem 2
      there was no check for cases where an aggregate function without a
      GROUP BY effectively takes the column from the SELECT part of an 
      INSERT ... SELECT unavailable for ON DUPLICATE KEY UPDATE.
      Fixed by checking for that condition when setting up the name 
      resolution context.

  mysql-test/r/insert_update.result@stripped, 2007-02-16 13:10:03+02:00, gkodinov@stripped +17 -0
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - test case

  mysql-test/t/insert_update.test@stripped, 2007-02-16 13:10:03+02:00, gkodinov@stripped +23 -0
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - test case

  sql/item.h@stripped, 2007-02-16 13:10:04+02:00, gkodinov@stripped +6 -1
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - save_next_local is not referenced any more outside class methods

  sql/sql_base.cc@stripped, 2007-02-16 13:10:05+02:00, gkodinov@stripped +2 -15
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - removed a "catch-all" code to cater for correct context initialization

  sql/sql_help.cc@stripped, 2007-02-16 13:10:05+02:00, gkodinov@stripped +2 -0
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - fixed the name resolution context initialization

  sql/sql_insert.cc@stripped, 2007-02-16 13:10:06+02:00, gkodinov@stripped +39 -38
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - Fixed the context of resolving the values in INSERT SELECT ON UPDATE

  sql/sql_union.cc@stripped, 2007-02-16 13:10:07+02:00, gkodinov@stripped +2 -0
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - fixed the name resolution context initialization

  sql/sql_yacc.yy@stripped, 2007-02-16 13:10:07+02:00, gkodinov@stripped +6 -1
    Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
     - Set the context here instead of setup_tables()

# 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:	gkodinov
# Host:	macbook.gmz
# Root:	/Users/kgeorge/mysql/work/B25831-5.0-opt

--- 1.217/sql/item.h	2007-01-12 23:43:23 +02:00
+++ 1.218/sql/item.h	2007-02-16 13:10:04 +02:00
@@ -325,10 +325,10 @@ private:
   TABLE_LIST *save_first_name_resolution_table;
   TABLE_LIST *save_next_name_resolution_table;
   bool        save_resolve_in_select_list;
+  TABLE_LIST *save_next_local;
 
 public:
   Name_resolution_context_state() {}          /* Remove gcc warning */
-  TABLE_LIST *save_next_local;
 
 public:
   /* Save the state of a name resolution context. */
@@ -354,6 +354,11 @@ public:
       context->first_name_resolution_table->
                next_name_resolution_table= save_next_name_resolution_table;
     context->resolve_in_select_list=       save_resolve_in_select_list;
+  }
+
+  TABLE_LIST *get_first_name_resolution_table()
+  {
+    return save_first_name_resolution_table;
   }
 };
 

--- 1.364/sql/sql_base.cc	2007-01-11 22:20:26 +02:00
+++ 1.365/sql/sql_base.cc	2007-02-16 13:10:05 +02:00
@@ -4498,21 +4498,8 @@ bool setup_tables(THD *thd, Name_resolut
   uint tablenr= 0;
   DBUG_ENTER("setup_tables");
 
-  /*
-    Due to the various call paths that lead to setup_tables() it may happen
-    that context->table_list and context->first_name_resolution_table can be
-    NULL (this is typically done when creating TABLE_LISTs internally).
-    TODO:
-    Investigate all cases when this my happen, initialize the name resolution
-    context correctly in all those places, and remove the context reset below.
-  */
-  if (!context->table_list || !context->first_name_resolution_table)
-  {
-    /* Test whether the context is in a consistent state. */
-    DBUG_ASSERT(!context->first_name_resolution_table && !context->table_list);
-    context->table_list= context->first_name_resolution_table= tables;
-  }
-
+  DBUG_ASSERT ((select_insert && !tables->next_name_resolution_table) || !tables || 
+               (context->table_list && context->first_name_resolution_table));
   /*
     this is used for INSERT ... SELECT.
     For select we setup tables except first (and its underlying tables)

--- 1.214/sql/sql_insert.cc	2007-01-23 12:04:15 +02:00
+++ 1.215/sql/sql_insert.cc	2007-02-16 13:10:06 +02:00
@@ -966,6 +966,8 @@ bool mysql_prepare_insert(THD *thd, TABL
   DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
 		       (ulong)table_list, (ulong)table,
 		       (int)insert_into_view));
+  /* INSERT should have a SELECT or VALUES clause */
+  DBUG_ASSERT (!select_insert || !values);
 
   /*
     For subqueries in VALUES() we should not see the table in which we are
@@ -998,44 +1000,40 @@ bool mysql_prepare_insert(THD *thd, TABL
                                        select_insert))
     DBUG_RETURN(TRUE);
 
-  /* Save the state of the current name resolution context. */
-  ctx_state.save_state(context, table_list);
-
-  /*
-    Perform name resolution only in the first table - 'table_list',
-    which is the table that is inserted into.
-  */
-  table_list->next_local= 0;
-  context->resolve_in_table_list_only(table_list);
 
   /* Prepare the fields in the statement. */
-  if (values &&
-      !(res= check_insert_fields(thd, context->table_list, fields, *values,
-                                 !insert_into_view, &map) ||
-        setup_fields(thd, 0, *values, 0, 0, 0)) &&
-      duplic == DUP_UPDATE)
+  if (values)
   {
-    select_lex->no_wrap_view_item= TRUE;
-    res= check_update_fields(thd, context->table_list, update_fields, &map);
-    select_lex->no_wrap_view_item= FALSE;
+    /* if we have INSERT ... VALUES () we cannot have a GROUP BY clause */
+    DBUG_ASSERT (!select_lex->group_list.elements);
+
+    /* Save the state of the current name resolution context. */
+    ctx_state.save_state(context, table_list);
+
     /*
-      When we are not using GROUP BY we can refer to other tables in the
-      ON DUPLICATE KEY part.
-    */       
-    if (select_lex->group_list.elements == 0)
+      Perform name resolution only in the first table - 'table_list',
+      which is the table that is inserted into.
+     */
+    table_list->next_local= 0;
+    context->resolve_in_table_list_only(table_list);
+
+    if (!(res= check_insert_fields(thd, context->table_list, fields, *values,
+                                 !insert_into_view, &map) ||
+          setup_fields(thd, 0, *values, 0, 0, 0)) 
+        && duplic == DUP_UPDATE)
     {
-      context->table_list->next_local=       ctx_state.save_next_local;
-      /* first_name_resolution_table was set by resolve_in_table_list_only() */
-      context->first_name_resolution_table->
-        next_name_resolution_table=          ctx_state.save_next_local;
+      select_lex->no_wrap_view_item= TRUE;
+      res= check_update_fields(thd, context->table_list, update_fields, &map);
+      select_lex->no_wrap_view_item= FALSE;
     }
+
+    /* Restore the current context. */
+    ctx_state.restore_state(context, table_list);
+
     if (!res)
       res= setup_fields(thd, 0, update_values, 1, 0, 0);
   }
 
-  /* Restore the current context. */
-  ctx_state.restore_state(context, table_list);
-
   if (res)
     DBUG_RETURN(res);
 
@@ -2355,7 +2353,6 @@ select_insert::prepare(List<Item> &value
 
   if (info.handle_duplicates == DUP_UPDATE)
   {
-    /* Save the state of the current name resolution context. */
     Name_resolution_context *context= &lex->select_lex.context;
     Name_resolution_context_state ctx_state;
 
@@ -2371,16 +2368,20 @@ select_insert::prepare(List<Item> &value
                                     *info.update_fields, &map);
     lex->select_lex.no_wrap_view_item= FALSE;
     /*
-      When we are not using GROUP BY we can refer to other tables in the
-      ON DUPLICATE KEY part
+      When we are not using GROUP BY and there are no ungrouped aggregate functions 
+      we can refer to other tables in the ON DUPLICATE KEY part.
+      We use next_name_resolution_table descructively, so check it first (views?)
     */       
-    if (lex->select_lex.group_list.elements == 0)
-    {
-      context->table_list->next_local=       ctx_state.save_next_local;
-      /* first_name_resolution_table was set by resolve_in_table_list_only() */
-      context->first_name_resolution_table->
-        next_name_resolution_table=          ctx_state.save_next_local;
-    }
+    DBUG_ASSERT (!table_list->next_name_resolution_table);
+    if (lex->select_lex.group_list.elements == 0 &&
+        !lex->select_lex.with_sum_func)
+      /*
+        We must make a single context out of the two separate name resolution contexts :
+        the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
+        To do that we must concatenate the two lists
+      */  
+      table_list->next_name_resolution_table= ctx_state.get_first_name_resolution_table();
+
     res= res || setup_fields(thd, 0, *info.update_values, 1, 0, 0);
 
     /* Restore the current context. */

--- 1.501/sql/sql_yacc.yy	2007-01-15 12:06:13 +02:00
+++ 1.502/sql/sql_yacc.yy	2007-02-16 13:10:07 +02:00
@@ -4188,8 +4188,13 @@ select_into:
 	| select_from into;
 
 select_from:
-	  FROM join_table_list where_clause group_clause having_clause
+        FROM join_table_list where_clause group_clause having_clause
 	       opt_order_clause opt_limit_clause procedure_clause
+          {
+            Select->context.table_list=
+              Select->context.first_name_resolution_table= 
+                (TABLE_LIST *) Select->table_list.first;
+          }
         | FROM DUAL_SYM where_clause opt_limit_clause
           /* oracle compatibility: oracle always requires FROM clause,
              and DUAL is system table without fields.

--- 1.136/sql/sql_union.cc	2007-01-11 22:17:41 +02:00
+++ 1.137/sql/sql_union.cc	2007-02-16 13:10:07 +02:00
@@ -147,6 +147,8 @@ st_select_lex_unit::init_prepare_fake_se
   fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
 					   (byte **)
 					   &result_table_list.next_local);
+  fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table= 
+    fake_select_lex->get_table_list();
   for (ORDER *order= (ORDER *)global_parameters->order_list.first;
        order;
        order=order->next)

--- 1.20/mysql-test/r/insert_update.result	2006-09-15 13:02:56 +03:00
+++ 1.21/mysql-test/r/insert_update.result	2007-02-16 13:10:03 +02:00
@@ -219,3 +219,20 @@ SELECT * FROM t1;
 a	b
 45	2
 DROP TABLE t1;
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+INSERT INTO t1 SELECT 1, j;
+ERROR 42S22: Unknown column 'j' in 'field list'
+DROP TABLE t1;
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+CREATE TABLE t2 (a INT, b INT);
+CREATE TABLE t3 (a INT, c INT);
+INSERT INTO t1 SELECT 1, a FROM t2 NATURAL JOIN t3 
+ON DUPLICATE KEY UPDATE j= a;
+DROP TABLE t1,t2,t3;
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t2 VALUES (1), (3);
+INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a;
+ERROR 42S22: Unknown column 'a' in 'field list'
+DROP TABLE t1,t2;

--- 1.20/mysql-test/t/insert_update.test	2006-09-15 12:54:09 +03:00
+++ 1.21/mysql-test/t/insert_update.test	2007-02-16 13:10:03 +02:00
@@ -139,3 +139,26 @@ INSERT INTO t1 VALUES (45, 1) ON DUPLICA
 SELECT * FROM t1;
 
 DROP TABLE t1;
+
+#
+# Bug#25831: Deficiencies in INSERT ... SELECT ... field name resolving.
+#
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+--error ER_BAD_FIELD_ERROR
+INSERT INTO t1 SELECT 1, j;
+DROP TABLE t1;
+
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+CREATE TABLE t2 (a INT, b INT);
+CREATE TABLE t3 (a INT, c INT);
+INSERT INTO t1 SELECT 1, a FROM t2 NATURAL JOIN t3 
+  ON DUPLICATE KEY UPDATE j= a;
+DROP TABLE t1,t2,t3;
+
+CREATE TABLE t1 (i INT PRIMARY KEY, j INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t2 VALUES (1), (3);
+--error ER_BAD_FIELD_ERROR
+INSERT INTO t1 SELECT 1, COUNT(*) FROM t2 ON DUPLICATE KEY UPDATE j= a;
+DROP TABLE t1,t2;

--- 1.53/sql/sql_help.cc	2006-12-23 21:04:27 +02:00
+++ 1.54/sql/sql_help.cc	2007-02-16 13:10:05 +02:00
@@ -656,6 +656,8 @@ bool mysqld_help(THD *thd, const char *m
     Init tables and fields to be usable from items
     tables do not contain VIEWs => we can pass 0 as conds
   */
+  thd->lex->select_lex.context.table_list= 
+    thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
   setup_tables(thd, &thd->lex->select_lex.context,
                &thd->lex->select_lex.top_join_list,
                tables, 0, &leaves, FALSE);
Thread
bk commit into 5.0 tree (gkodinov:1.2387) BUG#25831kgeorge16 Feb