diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 241 |
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); } |