Loading mysql-test/r/ps.result +35 −0 Original line number Diff line number Diff line Loading @@ -375,3 +375,38 @@ rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as - 9647622201 3845601374 6211931236 drop table t1; deallocate prepare stmt; create database mysqltest1; create table t1 (a int); create table mysqltest1.t1 (a int); select * from t1, mysqltest1.t1; a a prepare stmt from "select * from t1, mysqltest1.t1"; execute stmt; a a execute stmt; a a execute stmt; a a drop table t1; drop table mysqltest1.t1; drop database mysqltest1; deallocate prepare stmt; select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; a a 1.1 1.2 2.1 2.2 prepare stmt from "select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; execute stmt; a a 1.1 1.2 2.1 2.2 execute stmt; a a 1.1 1.2 2.1 2.2 execute stmt; a a 1.1 1.2 2.1 2.2 deallocate prepare stmt; mysql-test/r/ps_1general.result +1 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,7 @@ f3 int ); insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); execute stmt2 ; ERROR 42S22: Unknown column 't5.a' in 'field list' ERROR 42S22: Unknown column 'test.t5.a' in 'field list' drop table t5 ; prepare stmt1 from ' select * from t1 where a <= 2 ' ; execute stmt1 ; Loading mysql-test/t/ps.test +25 −0 Original line number Diff line number Diff line Loading @@ -390,3 +390,28 @@ set @var=3; execute stmt using @var; drop table t1; deallocate prepare stmt; # # A test case for Bug#6050 "EXECUTE stmt reports ambiguous fieldnames with # identical tables from different schemata" # Check that field name resolving in prepared statements works OK. # create database mysqltest1; create table t1 (a int); create table mysqltest1.t1 (a int); select * from t1, mysqltest1.t1; prepare stmt from "select * from t1, mysqltest1.t1"; execute stmt; execute stmt; execute stmt; drop table t1; drop table mysqltest1.t1; drop database mysqltest1; deallocate prepare stmt; select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; prepare stmt from "select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; execute stmt; execute stmt; execute stmt; deallocate prepare stmt; sql/item.cc +30 −9 Original line number Diff line number Diff line Loading @@ -348,17 +348,39 @@ Item_field::Item_field(Field *f) :Item_ident(NullS, f->table_name, f->field_name) { set_field(f); collation.set(DERIVATION_IMPLICIT); fixed= 1; /* field_name and talbe_name should not point to garbage if this item is to be reused */ orig_table_name= orig_field_name= ""; } Item_field::Item_field(THD *thd, Field *f) :Item_ident(NullS, thd->strdup(f->table_name), thd->strdup(f->field_name)) :Item_ident(f->table->table_cache_key, f->table_name, f->field_name) { /* We always need to provide Item_field with a fully qualified field name to avoid ambiguity when executing prepared statements like SELECT * from d1.t1, d2.t1; (assuming d1.t1 and d2.t1 have columns with same names). This is because prepared statements never deal with wildcards in select list ('*') and always fix fields using fully specified path (i.e. db.table.column). No check for OOM: if db_name is NULL, we'll just get "Field not found" error. We need to copy db_name, table_name and field_name because they must be allocated in the statement memory, not in table memory (the table structure can go away and pop up again between subsequent executions of a prepared statement). */ if (thd->current_arena->is_stmt_prepare()) { if (db_name) orig_db_name= thd->strdup(db_name); orig_table_name= thd->strdup(table_name); orig_field_name= thd->strdup(field_name); } set_field(f); collation.set(DERIVATION_IMPLICIT); fixed= 1; } // Constructor need to process subselect with temporary tables (see Item) Loading @@ -381,6 +403,7 @@ void Item_field::set_field(Field *field_par) db_name=field_par->table->table_cache_key; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); collation.set(field_par->charset(), DERIVATION_IMPLICIT); fixed= 1; } const char *Item_ident::full_name() const Loading Loading @@ -1374,8 +1397,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) field->query_id=thd->query_id; table->used_fields++; table->used_keys.intersect(field->part_of_key); } fixed= 1; } return 0; } Loading Loading @@ -2120,7 +2143,6 @@ bool Item_default_value::fix_fields(THD *thd, def_field->move_field(def_field->table->default_values - def_field->table->record[0]); set_field(def_field); fixed= 1; return 0; } Loading Loading @@ -2178,7 +2200,6 @@ bool Item_insert_value::fix_fields(THD *thd, set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name, tmp_field->table, &my_charset_bin)); } fixed= 1; return 0; } Loading sql/item.h +13 −4 Original line number Diff line number Diff line Loading @@ -310,6 +310,7 @@ class Item_num: public Item class st_select_lex; class Item_ident :public Item { protected: /* We have to store initial values of db_name, table_name and field_name to be able to restore them during cleanup() because they can be Loading Loading @@ -347,7 +348,6 @@ class Item_ident :public Item class Item_field :public Item_ident { void set_field(Field *field); public: Field *field,*result_field; Loading @@ -356,13 +356,21 @@ class Item_field :public Item_ident :Item_ident(db_par,table_name_par,field_name_par), field(0), result_field(0) { collation.set(DERIVATION_IMPLICIT); } // Constructor need to process subselect with temporary tables (see Item) /* Constructor needed to process subselect with temporary tables (see Item) */ Item_field(THD *thd, Item_field *item); /* Constructor used inside setup_wild(), ensures that field and table names will live as long as Item_field (important in prep. stmt.) Constructor used inside setup_wild(), ensures that field, table, and database names will live as long as Item_field (this is important in prepared statements). */ Item_field(THD *thd, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call set_field() before fix_fields() for all fields created this way. */ Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; Loading @@ -373,6 +381,7 @@ class Item_field :public Item_ident longlong val_int_result(); String *str_result(String* tmp); bool send(Protocol *protocol, String *str_arg); void set_field(Field *field); bool fix_fields(THD *, struct st_table_list *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); Loading Loading
mysql-test/r/ps.result +35 −0 Original line number Diff line number Diff line Loading @@ -375,3 +375,38 @@ rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as - 9647622201 3845601374 6211931236 drop table t1; deallocate prepare stmt; create database mysqltest1; create table t1 (a int); create table mysqltest1.t1 (a int); select * from t1, mysqltest1.t1; a a prepare stmt from "select * from t1, mysqltest1.t1"; execute stmt; a a execute stmt; a a execute stmt; a a drop table t1; drop table mysqltest1.t1; drop database mysqltest1; deallocate prepare stmt; select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; a a 1.1 1.2 2.1 2.2 prepare stmt from "select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; execute stmt; a a 1.1 1.2 2.1 2.2 execute stmt; a a 1.1 1.2 2.1 2.2 execute stmt; a a 1.1 1.2 2.1 2.2 deallocate prepare stmt;
mysql-test/r/ps_1general.result +1 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,7 @@ f3 int ); insert into t5( f1, f2, f3) values( 9, 'recreated table', 9); execute stmt2 ; ERROR 42S22: Unknown column 't5.a' in 'field list' ERROR 42S22: Unknown column 'test.t5.a' in 'field list' drop table t5 ; prepare stmt1 from ' select * from t1 where a <= 2 ' ; execute stmt1 ; Loading
mysql-test/t/ps.test +25 −0 Original line number Diff line number Diff line Loading @@ -390,3 +390,28 @@ set @var=3; execute stmt using @var; drop table t1; deallocate prepare stmt; # # A test case for Bug#6050 "EXECUTE stmt reports ambiguous fieldnames with # identical tables from different schemata" # Check that field name resolving in prepared statements works OK. # create database mysqltest1; create table t1 (a int); create table mysqltest1.t1 (a int); select * from t1, mysqltest1.t1; prepare stmt from "select * from t1, mysqltest1.t1"; execute stmt; execute stmt; execute stmt; drop table t1; drop table mysqltest1.t1; drop database mysqltest1; deallocate prepare stmt; select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'; prepare stmt from "select '1.1' as a, '1.2' as a UNION SELECT '2.1', '2.2'"; execute stmt; execute stmt; execute stmt; deallocate prepare stmt;
sql/item.cc +30 −9 Original line number Diff line number Diff line Loading @@ -348,17 +348,39 @@ Item_field::Item_field(Field *f) :Item_ident(NullS, f->table_name, f->field_name) { set_field(f); collation.set(DERIVATION_IMPLICIT); fixed= 1; /* field_name and talbe_name should not point to garbage if this item is to be reused */ orig_table_name= orig_field_name= ""; } Item_field::Item_field(THD *thd, Field *f) :Item_ident(NullS, thd->strdup(f->table_name), thd->strdup(f->field_name)) :Item_ident(f->table->table_cache_key, f->table_name, f->field_name) { /* We always need to provide Item_field with a fully qualified field name to avoid ambiguity when executing prepared statements like SELECT * from d1.t1, d2.t1; (assuming d1.t1 and d2.t1 have columns with same names). This is because prepared statements never deal with wildcards in select list ('*') and always fix fields using fully specified path (i.e. db.table.column). No check for OOM: if db_name is NULL, we'll just get "Field not found" error. We need to copy db_name, table_name and field_name because they must be allocated in the statement memory, not in table memory (the table structure can go away and pop up again between subsequent executions of a prepared statement). */ if (thd->current_arena->is_stmt_prepare()) { if (db_name) orig_db_name= thd->strdup(db_name); orig_table_name= thd->strdup(table_name); orig_field_name= thd->strdup(field_name); } set_field(f); collation.set(DERIVATION_IMPLICIT); fixed= 1; } // Constructor need to process subselect with temporary tables (see Item) Loading @@ -381,6 +403,7 @@ void Item_field::set_field(Field *field_par) db_name=field_par->table->table_cache_key; unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); collation.set(field_par->charset(), DERIVATION_IMPLICIT); fixed= 1; } const char *Item_ident::full_name() const Loading Loading @@ -1374,8 +1397,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) field->query_id=thd->query_id; table->used_fields++; table->used_keys.intersect(field->part_of_key); } fixed= 1; } return 0; } Loading Loading @@ -2120,7 +2143,6 @@ bool Item_default_value::fix_fields(THD *thd, def_field->move_field(def_field->table->default_values - def_field->table->record[0]); set_field(def_field); fixed= 1; return 0; } Loading Loading @@ -2178,7 +2200,6 @@ bool Item_insert_value::fix_fields(THD *thd, set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name, tmp_field->table, &my_charset_bin)); } fixed= 1; return 0; } Loading
sql/item.h +13 −4 Original line number Diff line number Diff line Loading @@ -310,6 +310,7 @@ class Item_num: public Item class st_select_lex; class Item_ident :public Item { protected: /* We have to store initial values of db_name, table_name and field_name to be able to restore them during cleanup() because they can be Loading Loading @@ -347,7 +348,6 @@ class Item_ident :public Item class Item_field :public Item_ident { void set_field(Field *field); public: Field *field,*result_field; Loading @@ -356,13 +356,21 @@ class Item_field :public Item_ident :Item_ident(db_par,table_name_par,field_name_par), field(0), result_field(0) { collation.set(DERIVATION_IMPLICIT); } // Constructor need to process subselect with temporary tables (see Item) /* Constructor needed to process subselect with temporary tables (see Item) */ Item_field(THD *thd, Item_field *item); /* Constructor used inside setup_wild(), ensures that field and table names will live as long as Item_field (important in prep. stmt.) Constructor used inside setup_wild(), ensures that field, table, and database names will live as long as Item_field (this is important in prepared statements). */ Item_field(THD *thd, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call set_field() before fix_fields() for all fields created this way. */ Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; Loading @@ -373,6 +381,7 @@ class Item_field :public Item_ident longlong val_int_result(); String *str_result(String* tmp); bool send(Protocol *protocol, String *str_arg); void set_field(Field *field); bool fix_fields(THD *, struct st_table_list *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); Loading