summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc241
1 files changed, 175 insertions, 66 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 61cbe432909..0aee91af0da 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1719,6 +1719,26 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
uint counter;
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(thd->net.report_error ? -1 : 1); /* purecov: inspected */
+ /*
+ Let us propagate pointers to open tables from global table list
+ to table lists in particular selects if needed.
+ */
+ if (thd->lex->all_selects_list->next_select_in_list() ||
+ thd->lex->time_zone_tables_used)
+ {
+ for (SELECT_LEX *sl= thd->lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= (TABLE_LIST *) sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ {
+ if (cursor->table_list)
+ cursor->table= cursor->table_list->table;
+ }
+ }
+ }
DBUG_RETURN(mysql_handle_derived(thd->lex));
}
@@ -1929,7 +1949,9 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
else
{
Item_arena *arena= thd->current_arena, backup;
- if (arena)
+ if (!arena->is_stmt_prepare())
+ arena= 0;
+ else
thd->set_n_backup_item_arena(arena, &backup);
*ref= new Item_ref(trans + i, 0, table_list->view_name.str,
item_name);
@@ -2261,10 +2283,12 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
- Item **found=0,*item;
+ Item **found=0, **found_unaliased= 0, *item;
const char *db_name=0;
const char *field_name=0;
const char *table_name=0;
+ bool found_unaliased_non_uniq= 0;
+ uint unaliased_counter;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
{
field_name= ((Item_ident*) find)->field_name;
@@ -2277,42 +2301,93 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (field_name && item->type() == Item::FIELD_ITEM)
{
Item_field *item_field= (Item_field*) item;
+
/*
In case of group_concat() with ORDER BY condition in the QUERY
item_field can be field of temporary table without item name
(if this field created from expression argument of group_concat()),
=> we have to check presence of name before compare
*/
- if (item_field->name &&
- (!my_strcasecmp(system_charset_info, item_field->name, field_name) ||
- !my_strcasecmp(system_charset_info,
- item_field->field_name, field_name)))
+ if (!item_field->name)
+ continue;
+
+ if (table_name)
{
- if (!table_name)
- {
- if (found)
- {
- if ((*found)->eq(item,0))
- continue; // Same field twice (Access?)
- if (report_error != IGNORE_ERRORS)
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- find->full_name(), current_thd->where);
- return (Item**) 0;
- }
- found= li.ref();
- *counter= i;
- }
- else
- {
- if (!strcmp(item_field->table_name,table_name) &&
- (!db_name || (db_name && item_field->db_name &&
- !strcmp(item_field->db_name, db_name))))
- {
- found= li.ref();
- *counter= i;
- break;
- }
- }
+ /*
+ If table name is specified we should find field 'field_name' in
+ table 'table_name'. According to SQL-standard we should ignore
+ aliases in this case. Note that we should prefer fields from the
+ select list over other fields from the tables participating in
+ this select in case of ambiguity.
+
+ We use strcmp for table names and database names as these may be
+ case sensitive.
+ In cases where they are not case sensitive, they are always in lower
+ case.
+ */
+ if (!my_strcasecmp(system_charset_info, item_field->field_name,
+ field_name) &&
+ !strcmp(item_field->table_name, table_name) &&
+ (!db_name || (item_field->db_name &&
+ !strcmp(item_field->db_name, db_name))))
+ {
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
+ MYF(0), find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ if (db_name)
+ break; // Perfect match
+ }
+ }
+ else if (!my_strcasecmp(system_charset_info, item_field->name,
+ field_name))
+ {
+ /*
+ If table name was not given we should scan through aliases
+ (or non-aliased fields) first. We are also checking unaliased
+ name of the field in then next else-if, to be able to find
+ instantly field (hidden by alias) if no suitable alias (or
+ non-aliased field) was found.
+ */
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
+ MYF(0), find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ }
+ else if (!my_strcasecmp(system_charset_info, item_field->field_name,
+ field_name))
+ {
+ /*
+ We will use un-aliased field or react on such ambiguities only if
+ we won't be able to find aliased field.
+ Again if we have ambiguity with field outside of select list
+ we should prefer fields from select list.
+ */
+ if (found_unaliased)
+ {
+ if ((*found_unaliased)->eq(item, 0))
+ continue; // Same field twice
+ found_unaliased_non_uniq= 1;
+ }
+ else
+ {
+ found_unaliased= li.ref();
+ unaliased_counter= i;
+ }
}
}
else if (!table_name && (item->eq(find,0) ||
@@ -2325,9 +2400,24 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
break;
}
}
+ if (!found)
+ {
+ if (found_unaliased_non_uniq)
+ {
+ if (report_error != IGNORE_ERRORS)
+ my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR), MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item **) 0;
+ }
+ if (found_unaliased)
+ {
+ found= found_unaliased;
+ *counter= unaliased_counter;
+ }
+ }
if (found)
return found;
- else if (report_error != REPORT_EXCEPT_NOT_FOUND)
+ if (report_error != REPORT_EXCEPT_NOT_FOUND)
{
if (report_error == REPORT_ALL_ERRORS)
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
@@ -2346,9 +2436,12 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
+ Item *item;
if (!wild_num)
return 0;
Item_arena *arena= thd->current_arena, backup;
+ if (!arena->is_stmt_prepare())
+ arena= 0; // For easier test
/*
If we are in preparing prepared statement phase then we have change
@@ -2356,9 +2449,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
- reg2 Item *item;
+
List_iterator<Item> it(fields);
- while ( wild_num && (item= it++))
+ while (wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*' &&
@@ -2580,8 +2673,21 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
Field_iterator_table table_iter;
Field_iterator_view view_iter;
uint found;
+ char name_buff[NAME_LEN+1];
DBUG_ENTER("insert_fields");
+ if (db_name && lower_case_table_names)
+ {
+ /*
+ convert database to lower case for comparison
+ We can't do this in Item_field as this would change the
+ 'name' of the item which may be used in the select list
+ */
+ strmake(name_buff, db_name, sizeof(name_buff)-1);
+ my_casedn_str(files_charset_info, name_buff);
+ db_name= name_buff;
+ }
+
found= 0;
for (; tables; tables= tables->next_local)
{
@@ -2721,7 +2827,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
field->query_id=thd->query_id;
table->used_keys.intersect(field->part_of_key);
}
- else if (thd->current_arena &&
+ else if (thd->current_arena->is_stmt_prepare() &&
thd->lex->current_select->first_execution)
{
Item_field *item= new Item_field(thd->strdup(tables->view_db.str),
@@ -2761,13 +2867,14 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table_map not_null_tables= 0;
SELECT_LEX *select_lex= thd->lex->current_select;
- Item_arena *arena= ((thd->current_arena &&
- !select_lex->conds_processed_with_permanent_arena) ?
- thd->current_arena :
- 0);
+ Item_arena *arena= thd->current_arena;
Item_arena backup;
DBUG_ENTER("setup_conds");
+ if (select_lex->conds_processed_with_permanent_arena ||
+ !arena->is_stmt_prepare())
+ arena= 0; // For easier test
+
thd->set_query_id=1;
select_lex->cond_count= 0;
@@ -2779,7 +2886,6 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(1);
}
-
/* Check if we are using outer joins */
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
@@ -2900,31 +3006,34 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// to prevent natural join processing during PS re-execution
embedding->natural_join= 0;
- COND *on_expr= cond_and;
- on_expr->fix_fields(thd, 0, &on_expr);
- if (!embedded->outer_join) // Not left join
- {
- *conds= and_conds(*conds, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (*conds && !(*conds)->fixed)
- {
- if ((*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
- }
- }
- else
+ if (cond_and->list.elements)
{
- embedded->on_expr= and_conds(embedded->on_expr, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (embedded->on_expr && !embedded->on_expr->fixed)
- {
- if (embedded->on_expr->fix_fields(thd, tables, &table->on_expr))
- DBUG_RETURN(1);
- }
+ COND *on_expr= cond_and;
+ on_expr->fix_fields(thd, 0, &on_expr);
+ if (!embedded->outer_join) // Not left join
+ {
+ *conds= and_conds(*conds, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (*conds && !(*conds)->fixed)
+ {
+ if ((*conds)->fix_fields(thd, tables, conds))
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ embedded->on_expr= and_conds(embedded->on_expr, cond_and);
+ // fix_fields() should be made with temporary memory pool
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
+ if (embedded->on_expr && !embedded->on_expr->fixed)
+ {
+ if (embedded->on_expr->fix_fields(thd, tables, &table->on_expr))
+ DBUG_RETURN(1);
+ }
+ }
}
}
embedding= embedded->embedding;
@@ -2972,7 +3081,7 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
Field *rfield= field->field;
TABLE *table= rfield->table;
if (rfield == table->next_number_field)
- table->auto_increment_field_not_null= true;
+ table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
DBUG_RETURN(1);
}
@@ -2993,7 +3102,7 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
value=v++;
TABLE *table= field->table;
if (field == table->next_number_field)
- table->auto_increment_field_not_null= true;
+ table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(field, 0) < 0) && !ignore_errors)
DBUG_RETURN(1);
}