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
bk@mysql.r18.ru
carsten@tsort.bitbybit.dk
davida@isil.mysql.com
dlenev@brandersnatch.localdomain
dlenev@build.mysql.com
dlenev@mysql.com
gerberb@ou800.zenez.com
......
......@@ -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,
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),
depended_from(0)
:
orig_db_name(db_name_par), orig_table_name(table_name_par),
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;
}
......@@ -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)
Item_ident::Item_ident(THD *thd, Item_ident *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),
db_name(item->db_name),
table_name(item->table_name),
field_name(item->field_name),
cached_field_index(item->cached_field_index),
cached_table(item->cached_table),
depended_from(item->depended_from)
{}
......@@ -128,6 +136,9 @@ void Item_ident::cleanup()
*changed_during_fix_field= this;
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)
......@@ -309,6 +320,15 @@ Item_field::Item_field(Field *f)
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)
Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
......
......@@ -257,15 +257,37 @@ class Item_num: public Item
virtual Item_num *neg()= 0;
};
#define NO_CACHED_FIELD_INDEX ((uint)(-1))
class st_select_lex;
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;
public:
const char *db_name;
const char *table_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;
Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par);
......@@ -297,6 +319,11 @@ class Item_field :public Item_ident
{ collation.set(DERIVATION_IMPLICIT); }
// Constructor need 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.)
*/
Item_field(THD *thd, Field *field);
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
......
......@@ -552,7 +552,8 @@ extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
TABLE_LIST **where, bool report_error);
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
#include <openssl/des.h>
struct st_des_keyblock
......
......@@ -2194,8 +2194,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1);
while ((column = column_iter++))
{
uint unused_field_idx= NO_CACHED_FIELD_INDEX;
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),
column->column.c_ptr(), table_list->alias);
......
......@@ -1793,33 +1793,42 @@ bool rm_temporary_table(enum db_type base, char *path)
#define WRONG_GRANT (Field*) -1
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;
if (table->name_hash.records)
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
if (cached_field_index < table->fields &&
!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
{
if (!(field_ptr= table->field))
return (Field *)0;
for (; *field_ptr; ++field_ptr)
if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
break;
}
if (field_ptr && *field_ptr)
{
if ((field=(Field*) hash_search(&table->name_hash,(byte*) name,
length)))
goto found;
*cached_field_index_ptr= field_ptr - table->field;
field= *field_ptr;
}
else
{
Field **ptr;
if (!(ptr=table->field))
return (Field *)0;
while ((field = *ptr++))
{
if (!my_strcasecmp(system_charset_info, field->field_name, name))
goto found;
}
if (!allow_rowid ||
my_strcasecmp(system_charset_info, name, "_rowid") ||
!(field=table->rowid_field))
return (Field*) 0;
}
if (allow_rowid &&
!my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
return (Field*) 0;
found:
if (thd->set_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,
uint length=(uint) strlen(name);
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)
{
/*
......@@ -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,
test(tables->table->grant.
want_privilege),
1);
1, &(item->cached_field_index));
if (find)
{
(*where)= tables;
(*where)= item->cached_table= tables;
if (find == WRONG_GRANT)
return (Field*) 0;
if (db || !thd->where)
......@@ -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,
test(tables->table->grant.want_privilege),
allow_rowid);
allow_rowid, &(item->cached_field_index));
if (field)
{
if (field == WRONG_GRANT)
return (Field*) 0;
(*where)= tables;
(*where)= item->cached_table= tables;
if (found)
{
if (!thd->where) // Returns first found
......@@ -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,
strlen(field->field_name), 0, 0))
{
Item_field *item= new Item_field(field);
Item_field *item= new Item_field(thd, field);
if (!found++)
(void) it->replace(item); // Replace '*'
else
......
......@@ -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 byte* get_field_name(Field *buff,uint *length,
static byte* get_field_name(Field **buff,uint *length,
my_bool not_used __attribute__((unused)))
{
*length= (uint) strlen(buff->field_name);
return (byte*) buff->field_name;
*length= (uint) strlen((*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,
if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i;
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
......
......@@ -65,7 +65,8 @@ struct st_table {
handler *file;
Field **field; /* Pointer to 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 *default_values; /* Default values for INSERT */
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