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.cc184
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,