Commit f38e0a93 authored by dlenev@brandersnatch.localdomain's avatar dlenev@brandersnatch.localdomain

Merge of fix for bug #2050 and bug #3307

parents da3308ef 4122188c
...@@ -26,6 +26,7 @@ bk@admin.bk ...@@ -26,6 +26,7 @@ bk@admin.bk
bk@mysql.r18.ru bk@mysql.r18.ru
carsten@tsort.bitbybit.dk carsten@tsort.bitbybit.dk
davida@isil.mysql.com davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com dlenev@build.mysql.com
dlenev@mysql.com dlenev@mysql.com
gerberb@ou800.zenez.com gerberb@ou800.zenez.com
......
...@@ -103,9 +103,12 @@ void Item::print_item_w_name(String *str) ...@@ -103,9 +103,12 @@ void Item::print_item_w_name(String *str)
Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par) const char *field_name_par)
:changed_during_fix_field(0), db_name(db_name_par), :
table_name(table_name_par), field_name(field_name_par), orig_db_name(db_name_par), orig_table_name(table_name_par),
depended_from(0) orig_field_name(field_name_par), changed_during_fix_field(0),
db_name(db_name_par), table_name(table_name_par),
field_name(field_name_par), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0)
{ {
name = (char*) field_name_par; name = (char*) field_name_par;
} }
...@@ -113,10 +116,15 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, ...@@ -113,10 +116,15 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
// Constructor used by Item_field & Item_ref (see Item comment) // Constructor used by Item_field & Item_ref (see Item comment)
Item_ident::Item_ident(THD *thd, Item_ident *item) Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item(thd, item), :Item(thd, item),
orig_db_name(item->orig_db_name),
orig_table_name(item->orig_table_name),
orig_field_name(item->orig_field_name),
changed_during_fix_field(0), changed_during_fix_field(0),
db_name(item->db_name), db_name(item->db_name),
table_name(item->table_name), table_name(item->table_name),
field_name(item->field_name), field_name(item->field_name),
cached_field_index(item->cached_field_index),
cached_table(item->cached_table),
depended_from(item->depended_from) depended_from(item->depended_from)
{} {}
...@@ -128,6 +136,9 @@ void Item_ident::cleanup() ...@@ -128,6 +136,9 @@ void Item_ident::cleanup()
*changed_during_fix_field= this; *changed_during_fix_field= this;
changed_during_fix_field= 0; changed_during_fix_field= 0;
} }
db_name= orig_db_name;
table_name= orig_table_name;
field_name= orig_field_name;
} }
bool Item_ident::remove_dependence_processor(byte * arg) bool Item_ident::remove_dependence_processor(byte * arg)
...@@ -309,6 +320,15 @@ Item_field::Item_field(Field *f) ...@@ -309,6 +320,15 @@ Item_field::Item_field(Field *f)
fixed= 1; fixed= 1;
} }
Item_field::Item_field(THD *thd, Field *f)
:Item_ident(NullS, thd->strdup(f->table_name),
thd->strdup(f->field_name))
{
set_field(f);
collation.set(DERIVATION_IMPLICIT);
fixed= 1;
}
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_field::Item_field(THD *thd, Item_field *item) Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item), :Item_ident(thd, item),
......
...@@ -257,15 +257,37 @@ public: ...@@ -257,15 +257,37 @@ public:
virtual Item_num *neg()= 0; virtual Item_num *neg()= 0;
}; };
#define NO_CACHED_FIELD_INDEX ((uint)(-1))
class st_select_lex; class st_select_lex;
class Item_ident :public Item class Item_ident :public Item
{ {
/*
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
updated during fix_fields() to values from Field object and life-time
of those is shorter than life-time of Item_field.
*/
const char *orig_db_name;
const char *orig_table_name;
const char *orig_field_name;
Item **changed_during_fix_field; Item **changed_during_fix_field;
public: public:
const char *db_name; const char *db_name;
const char *table_name; const char *table_name;
const char *field_name; const char *field_name;
/*
Cached value of index for this field in table->field array, used by prep.
stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX
if index value is not known.
*/
uint cached_field_index;
/*
Cached pointer to table which contains this field, used for the same reason
by prep. stmt. too in case then we have not-fully qualified field.
0 - means no cached value.
*/
TABLE_LIST *cached_table;
st_select_lex *depended_from; st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par, Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par); const char *field_name_par);
...@@ -297,6 +319,11 @@ public: ...@@ -297,6 +319,11 @@ public:
{ collation.set(DERIVATION_IMPLICIT); } { collation.set(DERIVATION_IMPLICIT); }
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_field(THD *thd, Item_field *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.)
*/
Item_field(THD *thd, Field *field);
Item_field(Field *field); Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; } enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const; bool eq(const Item *item, bool binary_cmp) const;
......
...@@ -552,7 +552,8 @@ extern const Field *not_found_field; ...@@ -552,7 +552,8 @@ extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
TABLE_LIST **where, bool report_error); TABLE_LIST **where, bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid); bool check_grant,bool allow_rowid,
uint *cached_field_index_ptr);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/des.h> #include <openssl/des.h>
struct st_des_keyblock struct st_des_keyblock
......
...@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1); DBUG_RETURN(-1);
while ((column = column_iter++)) while ((column = column_iter++))
{ {
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
if (!find_field_in_table(thd,table,column->column.ptr(), if (!find_field_in_table(thd,table,column->column.ptr(),
column->column.length(),0,0)) column->column.length(),0,0,
&unused_field_idx))
{ {
my_error(ER_BAD_FIELD_ERROR, MYF(0), my_error(ER_BAD_FIELD_ERROR, MYF(0),
column->column.c_ptr(), table_list->alias); column->column.c_ptr(), table_list->alias);
......
...@@ -1793,33 +1793,42 @@ bool rm_temporary_table(enum db_type base, char *path) ...@@ -1793,33 +1793,42 @@ bool rm_temporary_table(enum db_type base, char *path)
#define WRONG_GRANT (Field*) -1 #define WRONG_GRANT (Field*) -1
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grants, bool allow_rowid) bool check_grants, bool allow_rowid,
uint *cached_field_index_ptr)
{ {
Field *field; Field **field_ptr, *field;
if (table->name_hash.records) uint cached_field_index= *cached_field_index_ptr;
{
if ((field=(Field*) hash_search(&table->name_hash,(byte*) name, /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
length))) if (cached_field_index < table->fields &&
goto found; !my_strcasecmp(system_charset_info,
} table->field[cached_field_index]->field_name, name))
field_ptr= table->field + cached_field_index;
else if (table->name_hash.records)
field_ptr= (Field**)hash_search(&table->name_hash,(byte*) name,
length);
else else
{ {
Field **ptr; if (!(field_ptr= table->field))
if (!(ptr=table->field))
return (Field *)0; return (Field *)0;
while ((field = *ptr++)) for (; *field_ptr; ++field_ptr)
{ if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
if (!my_strcasecmp(system_charset_info, field->field_name, name)) break;
goto found;
} }
if (field_ptr && *field_ptr)
{
*cached_field_index_ptr= field_ptr - table->field;
field= *field_ptr;
} }
if (allow_rowid && else
!my_strcasecmp(system_charset_info, name, "_rowid") && {
(field=table->rowid_field)) if (!allow_rowid ||
goto found; my_strcasecmp(system_charset_info, name, "_rowid") ||
!(field=table->rowid_field))
return (Field*) 0; return (Field*) 0;
}
found:
if (thd->set_query_id) if (thd->set_query_id)
{ {
if (field->query_id != thd->query_id) if (field->query_id != thd->query_id)
...@@ -1874,6 +1883,31 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -1874,6 +1883,31 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
uint length=(uint) strlen(name); uint length=(uint) strlen(name);
char name_buff[NAME_LEN+1]; char name_buff[NAME_LEN+1];
if (item->cached_table)
{
/*
This shortcut is used by prepared statements. We assuming that
TABLE_LIST *tables is not changed during query execution (which
is true for all queries except RENAME but luckily RENAME doesn't
use fields...) so we can rely on reusing pointer to its member.
With this optimisation we also miss case when addition of one more
field makes some prepared query ambiguous and so erronous, but we
accept this trade off.
*/
found= find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant.want_privilege),
1, &(item->cached_field_index));
if (found)
{
(*where)= tables;
if (found == WRONG_GRANT)
return (Field*) 0;
return found;
}
}
if (db && lower_case_table_names) if (db && lower_case_table_names)
{ {
/* /*
...@@ -1898,10 +1932,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -1898,10 +1932,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *find=find_field_in_table(thd,tables->table,name,length, Field *find=find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant. test(tables->table->grant.
want_privilege), want_privilege),
1); 1, &(item->cached_field_index));
if (find) if (find)
{ {
(*where)= tables; (*where)= item->cached_table= tables;
if (find == WRONG_GRANT) if (find == WRONG_GRANT)
return (Field*) 0; return (Field*) 0;
if (db || !thd->where) if (db || !thd->where)
...@@ -1955,12 +1989,12 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, ...@@ -1955,12 +1989,12 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *field=find_field_in_table(thd,tables->table,name,length, Field *field=find_field_in_table(thd,tables->table,name,length,
test(tables->table->grant.want_privilege), test(tables->table->grant.want_privilege),
allow_rowid); allow_rowid, &(item->cached_field_index));
if (field) if (field)
{ {
if (field == WRONG_GRANT) if (field == WRONG_GRANT)
return (Field*) 0; return (Field*) 0;
(*where)= tables; (*where)= item->cached_table= tables;
if (found) if (found)
{ {
if (!thd->where) // Returns first found if (!thd->where) // Returns first found
...@@ -2308,7 +2342,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, ...@@ -2308,7 +2342,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
!find_field_in_table(thd, natural_join_table, field->field_name, !find_field_in_table(thd, natural_join_table, field->field_name,
strlen(field->field_name), 0, 0)) strlen(field->field_name), 0, 0))
{ {
Item_field *item= new Item_field(field); Item_field *item= new Item_field(thd, field);
if (!found++) if (!found++)
(void) it->replace(item); // Replace '*' (void) it->replace(item); // Replace '*'
else else
......
...@@ -30,11 +30,11 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, ...@@ -30,11 +30,11 @@ static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
static uint find_field(TABLE *form,uint start,uint length); static uint find_field(TABLE *form,uint start,uint length);
static byte* get_field_name(Field *buff,uint *length, static byte* get_field_name(Field **buff,uint *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
{ {
*length= (uint) strlen(buff->field_name); *length= (uint) strlen((*buff)->field_name);
return (byte*) buff->field_name; return (byte*) (*buff)->field_name;
} }
/* /*
...@@ -479,7 +479,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, ...@@ -479,7 +479,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (outparam->timestamp_field == reg_field) if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i; outparam->timestamp_field_offset=i;
if (use_hash) if (use_hash)
(void) my_hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
} }
*field_ptr=0; // End marker *field_ptr=0; // End marker
......
...@@ -65,7 +65,8 @@ struct st_table { ...@@ -65,7 +65,8 @@ struct st_table {
handler *file; handler *file;
Field **field; /* Pointer to fields */ Field **field; /* Pointer to fields */
Field_blob **blob_field; /* Pointer to blob fields */ Field_blob **blob_field; /* Pointer to blob fields */
HASH name_hash; /* hash of field names */ /* hash of field names (contains pointers to elements of field array) */
HASH name_hash;
byte *record[2]; /* Pointer to records */ byte *record[2]; /* Pointer to records */
byte *default_values; /* Default values for INSERT */ byte *default_values; /* Default values for INSERT */
byte *insert_values; /* used by INSERT ... UPDATE */ byte *insert_values; /* used by INSERT ... UPDATE */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment