diff options
author | unknown <dlenev@brandersnatch.localdomain> | 2004-03-31 22:17:10 +0400 |
---|---|---|
committer | unknown <dlenev@brandersnatch.localdomain> | 2004-03-31 22:17:10 +0400 |
commit | e6d766154709c920c010a96fb8d10295cd694dbc (patch) | |
tree | 955a27f6963da17e12ea042cedc8a8ced053e0e6 /sql | |
parent | 0dd6f77d47a9fbb857cf906ed025ebbc44137116 (diff) | |
parent | d2906f0ed07bc06161d749d03ffa8acb7c09c785 (diff) | |
download | mariadb-git-e6d766154709c920c010a96fb8d10295cd694dbc.tar.gz |
Merge of fix for bug #2050 and bug #3307
BitKeeper/etc/logging_ok:
auto-union
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_base.cc:
Manual merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 26 | ||||
-rw-r--r-- | sql/item.h | 27 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_acl.cc | 4 | ||||
-rw-r--r-- | sql/sql_base.cc | 84 | ||||
-rw-r--r-- | sql/table.cc | 8 | ||||
-rw-r--r-- | sql/table.h | 3 |
7 files changed, 120 insertions, 35 deletions
diff --git a/sql/item.cc b/sql/item.cc index 48e35f06ec3..9cad60b8197 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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), diff --git a/sql/item.h b/sql/item.h index dffa93eaac8..902f42dd07c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -257,15 +257,37 @@ public: 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 @@ public: { 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; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index bd919d12348..4fd41b7bd66 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -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 diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ef5036bb9f1..3add540f9a9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -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); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 60c2938ba4e..2b60a3b3e04 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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 diff --git a/sql/table.cc b/sql/table.cc index 526810de74a..dcd0d39d855 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -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 diff --git a/sql/table.h b/sql/table.h index c027e2ccc44..039e3ded9f3 100644 --- a/sql/table.h +++ b/sql/table.h @@ -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 */ |