diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 184 |
1 files changed, 124 insertions, 60 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4f273fbd0c4..af6c4740e93 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -308,7 +308,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_close_list(thd, tables); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -371,7 +371,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) { - bool found_old_table=0; + bool found_old_table; DBUG_ENTER("close_thread_tables"); if (thd->derived_tables && !skip_derived) @@ -406,6 +406,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables)); + found_old_table= 0; while (thd->open_tables) found_old_table|=close_thread_table(thd, &thd->open_tables); thd->some_tables_deleted=0; @@ -876,8 +877,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { for (table= thd->temporary_tables; table ; table=table->next) { - if (table->key_length == key_length + 8 && - !memcmp(table->table_cache_key, key, key_length + 8)) + if (table->key_length == key_length + TMP_TABLE_KEY_EXTRA && + !memcmp(table->table_cache_key, key, + key_length + TMP_TABLE_KEY_EXTRA)) { if (table->query_id == thd->query_id) { @@ -888,7 +890,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->query_id= thd->query_id; table->clear_query_id= 1; thd->tmp_table_used= 1; - goto reset; + DBUG_PRINT("info",("Using temporary table")); + goto reset; } } } @@ -903,6 +906,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->query_id != thd->query_id) { table->query_id=thd->query_id; + DBUG_PRINT("info",("Using locked table")); goto reset; } } @@ -954,7 +958,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, } /* close handler tables which are marked for flush */ - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -1047,6 +1051,31 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, for (uint i=0 ; i < table->fields ; i++) table->field[i]->table_name=table->table_name; } +#if MYSQL_VERSION_ID < 40100 + /* + If per-connection "new" variable (represented by variables.new_mode) + is set then we should pretend that the length of TIMESTAMP field is 19. + The cheapest (from perfomance viewpoint) way to achieve that is to set + field_length of all Field_timestamp objects in a table after opening + it (to 19 if new_mode is true or to original field length otherwise). + We save value of new_mode variable in TABLE::timestamp_mode to + not perform this setup if new_mode value is the same between sequential + table opens. + */ + my_bool new_mode= thd->variables.new_mode; + if (table->timestamp_mode != new_mode) + { + for (uint i=0 ; i < table->fields ; i++) + { + Field *field= table->field[i]; + + if (field->type() == FIELD_TYPE_TIMESTAMP) + field->field_length= new_mode ? 19 : + ((Field_timestamp *)(field))->orig_field_length; + } + table->timestamp_mode= new_mode; + } +#endif /* These variables are also set in reopen_table() */ table->tablenr=thd->current_tablenr++; table->used_fields=0; @@ -1056,7 +1085,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->keys_in_use_for_query= table->keys_in_use; table->used_keys= table->keys_for_keyread; if (table->timestamp_field) - table->timestamp_field->set_timestamp_offsets(); + table->timestamp_field_type= table->timestamp_field->get_auto_set_type(); table_list->updatable= 1; // It is not derived table nor non-updatable VIEW DBUG_ASSERT(table->key_read == 0); DBUG_RETURN(table); @@ -1339,7 +1368,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); @@ -1469,7 +1498,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, */ if (discover_retry_count++ != 0) goto err; - if (create_table_from_handler(db, name, true) != 0) + if (ha_create_table_from_engine(thd, db, name, TRUE) != 0) goto err; thd->clear_error(); // Clear error message @@ -1510,7 +1539,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, /* Give right error message */ thd->clear_error(); my_error(ER_NOT_KEYFILE, MYF(0), name, my_errno); - sql_print_error("Error: Couldn't repair table: %s.%s",db,name); + sql_print_error("Couldn't repair table: %s.%s",db,name); if (entry->file) closefrm(entry); error=1; @@ -1557,7 +1586,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, DBA on top of warning the client (which will automatically be done because of MYF(MY_WME) in my_malloc() above). */ - sql_print_error("Error: when opening HEAP table, could not allocate \ + sql_print_error("When opening HEAP table, could not allocate \ memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name); delete entry->triggers; if (entry->file) @@ -1827,13 +1856,22 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("open_and_lock_tables"); uint counter; - if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter) - || mysql_handle_derived(thd->lex)) + if (open_tables(thd, tables, &counter) || + lock_tables(thd, tables, counter) || + mysql_handle_derived(thd->lex)) 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. - */ + relink_tables_for_derived(thd); + DBUG_RETURN(0); +} + + +/* + Let us propagate pointers to open tables from global table list + to table lists in particular selects if needed. +*/ + +void relink_tables_for_derived(THD *thd) +{ if (thd->lex->all_selects_list->next_select_in_list() || thd->lex->time_zone_tables_used) { @@ -1850,7 +1888,6 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables) } } } - DBUG_RETURN(0); } @@ -1890,7 +1927,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) if (!table->placeholder()) *(ptr++)= table->table; } - if (!(thd->lock=mysql_lock_tables(thd,start,count))) + if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start)))) return -1; /* purecov: inspected */ } else @@ -1983,8 +2020,8 @@ bool rm_temporary_table(enum db_type base, char *path) if (file && file->delete_table(path)) { error=1; - sql_print_error("Warning: Could not remove tmp table: '%s', error: %d", - path, my_errno); + sql_print_warning("Could not remove tmp table: '%s', error: %d", + path, my_errno); } delete file; DBUG_RETURN(error); @@ -2367,14 +2404,17 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return not_found_item, report other errors, return 0 IGNORE_ERRORS Do not report errors, return 0 if error - + unaliased Set to true if item is field which was found + by original field name and not by its alias + in item list. Set to false otherwise. + RETURN VALUES 0 Item is not found or item is not unique, error message is reported not_found_item Function was called with report_error == REPORT_EXCEPT_NOT_FOUND and item was not found. No error message was reported - found field + found field */ // Special Item pointer for find_item_in_list returning @@ -2383,7 +2423,7 @@ const Item **not_found_item= (const Item**) 0x1; Item ** find_item_in_list(Item *find, List<Item> &items, uint *counter, - find_item_error_report_type report_error) + find_item_error_report_type report_error, bool *unaliased) { List_iterator<Item> li(items); Item **found=0, **found_unaliased= 0, *item; @@ -2392,6 +2432,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, const char *table_name=0; bool found_unaliased_non_uniq= 0; uint unaliased_counter; + + *unaliased= FALSE; + if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM) { field_name= ((Item_ident*) find)->field_name; @@ -2419,32 +2462,42 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, /* 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. + aliases in this case. + + Since we should NOT prefer fields from the select list over + other fields from the tables participating in this select in + case of ambiguity we have to do extra check outside this function. 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. + case sensitive. In cases where they are not case sensitive, they + are always in lower case. + + item_field->field_name and item_field->table_name can be 0x0 if + item is not fix_field()'ed yet. */ - if (!my_strcasecmp(system_charset_info, item_field->field_name, + if (item_field->field_name && item_field->table_name && + !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_unaliased) { - if ((*found)->eq(item, 0)) - continue; // Same field twice + if ((*found_unaliased)->eq(item, 0)) + continue; + /* + Two matching fields in select list. + We already can bail out because we are searching through + unaliased names only and will have duplicate error anyway. + */ 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; + found_unaliased= li.ref(); + unaliased_counter= i; if (db_name) break; // Perfect match } @@ -2516,6 +2569,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, { found= found_unaliased; *counter= unaliased_counter; + *unaliased= TRUE; } } if (found) @@ -2540,8 +2594,11 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, uint wild_num) { Item *item; + DBUG_ENTER("setup_wild"); + if (!wild_num) - return 0; + DBUG_RETURN(0); + Item_arena *arena= thd->current_arena, backup; /* @@ -2556,7 +2613,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List_iterator<Item> it(fields); while (wild_num && (item= it++)) { - if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name && + if (item->type() == Item::FIELD_ITEM && + ((Item_field*) item)->field_name && ((Item_field*) item)->field_name[0] == '*' && !((Item_field*) item)->field) { @@ -2579,7 +2637,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, { if (arena) thd->restore_backup_item_arena(arena, &backup); - return (-1); + DBUG_RETURN(-1); } if (sum_func_list) { @@ -2602,7 +2660,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, thd->restore_backup_item_arena(arena, &backup); } - return 0; + DBUG_RETURN(0); } /**************************************************************************** @@ -2635,7 +2693,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, *(ref++)= item; if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && sum_func_list) - item->split_sum_func(ref_pointer_array, *sum_func_list); + item->split_sum_func(thd, ref_pointer_array, *sum_func_list); thd->used_tables|=item->used_tables(); } DBUG_RETURN(test(thd->net.report_error)); @@ -2647,23 +2705,21 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, SYNOPSIS setup_tables() - thd - thread handler - tables - tables list - conds - condition of current SELECT (can be changed by VIEW) + thd Thread handler + tables Table list + conds Condition of current SELECT (can be changed by VIEW) - RETURN - 0 ok; In this case *map will includes the choosed index - 1 error - - NOTE - Remap table numbers if INSERT ... SELECT - Check also that the 'used keys' and 'ignored keys' exists and set up the - table structure accordingly + NOTE + Remap table numbers if INSERT ... SELECT + Check also that the 'used keys' and 'ignored keys' exists and set up the + table structure accordingly - This has to be called for all tables that are used by items, as otherwise - table->map is not set and all Item_field will be regarded as const items. + This has to be called for all tables that are used by items, as otherwise + table->map is not set and all Item_field will be regarded as const items. - if tables do not contain VIEWs it is OK to pass 0 as conds + RETURN + 0 ok; In this case *map will includes the choosed index + 1 error */ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds) @@ -2973,8 +3029,7 @@ 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; - Item_arena backup; + Item_arena *arena= thd->current_arena, backup; bool save_wrapper= thd->lex->current_select->no_wrap_view_item; DBUG_ENTER("setup_conds"); @@ -3090,7 +3145,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { if (t2_field != view_ref_found) { - if (!(item_t2= new Item_field(t2_field))) + if (!(item_t2= new Item_field(thd, t2_field))) goto err; /* Mark field used for table cache */ t2_field->query_id= thd->query_id; @@ -3143,6 +3198,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } } } + else if (arena) + thd->restore_backup_item_arena(arena, &backup); } embedding= embedded->embedding; } @@ -3301,8 +3358,15 @@ void flush_tables() /* -** Mark all entries with the table as deleted to force an reopen of the table -** Returns true if the table is in use by another thread + Mark all entries with the table as deleted to force an reopen of the table + + The table will be closed (not stored in cache) by the current thread when + close_thread_tables() is called. + + RETURN + 0 This thread now have exclusive access to this table and no other thread + can access the table until close_thread_tables() is called. + 1 Table is in use by another thread */ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, |