diff options
author | unknown <konstantin@mysql.com> | 2004-10-22 15:59:58 +0400 |
---|---|---|
committer | unknown <konstantin@mysql.com> | 2004-10-22 15:59:58 +0400 |
commit | ca8be36f3abc78206bab3810789c4253ee461308 (patch) | |
tree | 2bcaef6e540885162b62299bf616ab82e1dcbf88 | |
parent | 76b09dd518af0bd480cc00538fc51c5a83d4d23a (diff) | |
parent | 4512a46e655cd3f706b214ada5384205863ecfd8 (diff) | |
download | mariadb-git-ca8be36f3abc78206bab3810789c4253ee461308.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/media/sda1/mysql/mysql-4.1-6050
sql/sql_class.h:
Auto merged
-rw-r--r-- | mysql-test/r/ps.result | 35 | ||||
-rw-r--r-- | mysql-test/r/ps_1general.result | 2 | ||||
-rw-r--r-- | mysql-test/t/ps.test | 25 | ||||
-rw-r--r-- | sql/item.cc | 39 | ||||
-rw-r--r-- | sql/item.h | 17 | ||||
-rw-r--r-- | sql/sql_base.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 24 | ||||
-rw-r--r-- | sql/table.h | 1 |
9 files changed, 130 insertions, 19 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 0aba0c4672e..0950a066e64 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -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; diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 6dcdb0feab1..ccf2945d488 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -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 ; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 7cbcd50245f..04ab8aa62a8 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -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; diff --git a/sql/item.cc b/sql/item.cc index 58143f52aff..d3d2206d02c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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) @@ -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 @@ -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; } - fixed= 1; return 0; } @@ -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; } @@ -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; } diff --git a/sql/item.h b/sql/item.h index 68fa013647c..b3142ec4b06 100644 --- a/sql/item.h +++ b/sql/item.h @@ -310,6 +310,7 @@ public: 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 @@ -347,7 +348,6 @@ public: class Item_field :public Item_ident { - void set_field(Field *field); public: Field *field,*result_field; @@ -356,13 +356,21 @@ public: :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; @@ -373,6 +381,7 @@ public: 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); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2fc0aa62f19..cd7b643e146 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2655,8 +2655,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) strlen(t1_field_name), 0, 0, ¬_used_field_index))) { - Item_func_eq *tmp=new Item_func_eq(new Item_field(*t1_field), - new Item_field(t2_field)); + Item_func_eq *tmp=new Item_func_eq(new Item_field(thd, *t1_field), + new Item_field(thd, t2_field)); if (!tmp) goto err; /* Mark field used for table cache */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 8e3a0b59940..e73b35966a9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -464,6 +464,8 @@ public: inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } + inline bool is_stmt_execute() const + { return state == PREPARED || state == EXECUTED; } inline bool is_conventional_execution() const { return state == CONVENTIONAL_EXECUTION; } inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index fc2d2a3a5e4..cd1127f9683 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -266,14 +266,14 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (first_select->next_select()) { - - // it is not single select + /* This is not a single select */ /* Check that it was possible to aggregate all collations together for UNION. */ List_iterator_fast<Item> tp(types); + Item_arena *arena= thd->current_arena; Item *type; while ((type= tp++)) { @@ -305,7 +305,11 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, thd_arg->lex->current_select= lex_select_save; if (!item_list.elements) { - Item_arena *arena= thd->current_arena, backup; + /* + We're in statement prepare or in execution + of a conventional statement. + */ + Item_arena backup; if (arena->is_stmt_prepare()) thd->set_n_backup_item_arena(arena, &backup); Field **field; @@ -345,6 +349,20 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, fake_select_lex->table_list.empty(); } } + else if (arena->is_stmt_execute()) + { + /* + We're in execution of a prepared statement: reset field items + to point at fields from the created temporary table. + */ + List_iterator_fast<Item> it(item_list); + for (Field **field= table->field; *field; field++) + { + Item_field *item_field= (Item_field*) it++; + DBUG_ASSERT(item_field); + item_field->set_field(*field); + } + } } else first_select->braces= 0; // remove our changes diff --git a/sql/table.h b/sql/table.h index f25b172a0d9..2eb854f553d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -164,6 +164,7 @@ struct st_table { MEM_ROOT mem_root; GRANT_INFO grant; + /* A pair "database_name\0table_name\0", widely used as simply a db name */ char *table_cache_key; char *table_name,*real_name,*path; uint key_length; /* Length of key */ |