Commit a97fd193 authored by unknown's avatar unknown
Browse files

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:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - test case
mysql-test/t/insert_update.test:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - test case
sql/item.h:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - save_next_local is not referenced any more outside class methods
sql/sql_base.cc:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - removed a "catch-all" code to cater for correct context initialization
sql/sql_help.cc:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - fixed the name resolution context initialization
sql/sql_insert.cc:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - Fixed the context of resolving the values in INSERT SELECT ON UPDATE
sql/sql_prepare.cc:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - Correct context for name resolution of prepared INSERT .. SELECT
sql/sql_union.cc:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - fixed the name resolution context initialization
sql/sql_yacc.yy:
  Bug #25831: Deficiencies in INSERT ... SELECT ... field name resolving.
   - Set the context here instead of setup_tables()
parent 24903ed5
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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;
+23 −0
Original line number Diff line number Diff line
@@ -139,3 +139,26 @@ INSERT INTO t1 VALUES (45, 1) ON DUPLICATE KEY UPDATE b =
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;
+6 −1
Original line number Diff line number Diff line
@@ -325,10 +325,10 @@ class Name_resolution_context_state
  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. */
@@ -355,6 +355,11 @@ class Name_resolution_context_state
               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;
  }
};

/*************************************************************************/
+2 −15
Original line number Diff line number Diff line
@@ -4498,21 +4498,8 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
  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)
+2 −0
Original line number Diff line number Diff line
@@ -656,6 +656,8 @@ bool mysqld_help(THD *thd, const char *mask)
    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);
Loading