mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
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
This commit is contained in:
commit
ca8be36f3a
9 changed files with 130 additions and 19 deletions
|
@ -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;
|
||||
|
|
|
@ -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 ;
|
||||
|
|
|
@ -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;
|
||||
|
|
39
sql/item.cc
39
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;
|
||||
}
|
||||
|
||||
|
|
17
sql/item.h
17
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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue