summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <dlenev@brandersnatch.localdomain>2004-03-31 22:17:10 +0400
committerunknown <dlenev@brandersnatch.localdomain>2004-03-31 22:17:10 +0400
commite6d766154709c920c010a96fb8d10295cd694dbc (patch)
tree955a27f6963da17e12ea042cedc8a8ced053e0e6 /sql
parent0dd6f77d47a9fbb857cf906ed025ebbc44137116 (diff)
parentd2906f0ed07bc06161d749d03ffa8acb7c09c785 (diff)
downloadmariadb-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.cc26
-rw-r--r--sql/item.h27
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_base.cc84
-rw-r--r--sql/table.cc8
-rw-r--r--sql/table.h3
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 */