mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge 4.1 -> 5.0.
This commit is contained in:
357
sql/sql_base.cc
357
sql/sql_base.cc
@ -46,12 +46,12 @@ extern "C" byte *table_cache_key(const byte *record,uint *length,
|
||||
return (byte*) entry->table_cache_key;
|
||||
}
|
||||
|
||||
void table_cache_init(void)
|
||||
bool table_cache_init(void)
|
||||
{
|
||||
VOID(hash_init(&open_cache,&my_charset_bin,
|
||||
table_cache_size+16,0,0,table_cache_key,
|
||||
(hash_free_key) free_cache_entry,0));
|
||||
mysql_rm_tmp_tables();
|
||||
return hash_init(&open_cache, &my_charset_bin, table_cache_size+16,
|
||||
0, 0,table_cache_key,
|
||||
(hash_free_key) free_cache_entry, 0) != 0;
|
||||
}
|
||||
|
||||
void table_cache_free(void)
|
||||
@ -156,6 +156,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
|
||||
table_list.db= (char*) entry->table_cache_key;
|
||||
table_list.real_name= entry->real_name;
|
||||
table_list.grant.privilege=0;
|
||||
|
||||
if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1))
|
||||
continue;
|
||||
/* need to check if we haven't already listed it */
|
||||
@ -284,8 +285,10 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
|
||||
if (!found)
|
||||
if_wait_for_refresh=0; // Nothing to wait for
|
||||
}
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (!tables)
|
||||
kill_delayed_threads();
|
||||
#endif
|
||||
if (if_wait_for_refresh)
|
||||
{
|
||||
/*
|
||||
@ -485,13 +488,19 @@ void close_temporary_tables(THD *thd)
|
||||
return;
|
||||
|
||||
LINT_INIT(end);
|
||||
query_buf_size= 50; // Enough for DROP ... TABLE
|
||||
query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS
|
||||
|
||||
for (table=thd->temporary_tables ; table ; table=table->next)
|
||||
/*
|
||||
We are going to add 4 ` around the db/table names, so 1 does not look
|
||||
enough; indeed it is enough, because table->key_length is greater (by 8,
|
||||
because of server_id and thread_id) than db||table.
|
||||
*/
|
||||
query_buf_size+= table->key_length+1;
|
||||
|
||||
if ((query = alloc_root(&thd->mem_root, query_buf_size)))
|
||||
end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE ");
|
||||
// Better add "if exists", in case a RESET MASTER has been done
|
||||
end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
|
||||
|
||||
for (table=thd->temporary_tables ; table ; table=next)
|
||||
{
|
||||
@ -504,8 +513,8 @@ void close_temporary_tables(THD *thd)
|
||||
Here we assume table_cache_key always starts
|
||||
with \0 terminated db name
|
||||
*/
|
||||
end = strxmov(end,"`",table->table_cache_key,"`",
|
||||
".`",table->real_name,"`,", NullS);
|
||||
end = strxmov(end,"`",table->table_cache_key,"`.`",
|
||||
table->real_name,"`,", NullS);
|
||||
}
|
||||
next=table->next;
|
||||
close_temporary(table);
|
||||
@ -515,6 +524,16 @@ void close_temporary_tables(THD *thd)
|
||||
/* The -1 is to remove last ',' */
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0);
|
||||
/*
|
||||
Imagine the thread had created a temp table, then was doing a SELECT, and
|
||||
the SELECT was killed. Then it's not clever to mark the statement above as
|
||||
"killed", because it's not really a statement updating data, and there
|
||||
are 99.99% chances it will succeed on slave.
|
||||
If a real update (one updating a persistent table) was killed on the
|
||||
master, then this real update will be logged with error_code=killed,
|
||||
rightfully causing the slave to stop.
|
||||
*/
|
||||
qinfo.error_code= 0;
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
thd->temporary_tables=0;
|
||||
@ -549,7 +568,7 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table,
|
||||
Find real table in given list.
|
||||
|
||||
SYNOPSIS
|
||||
find_table_in_list()
|
||||
find_real_table_in_list()
|
||||
table - pointer to table list
|
||||
db_name - data base name
|
||||
table_name - table name
|
||||
@ -808,8 +827,12 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
|
||||
{
|
||||
if (table->key_length == key_length &&
|
||||
!memcmp(table->table_cache_key,key,key_length) &&
|
||||
!my_strcasecmp(system_charset_info,table->table_name,alias))
|
||||
!my_strcasecmp(system_charset_info, table->table_name, alias) &&
|
||||
table->query_id != thd->query_id)
|
||||
{
|
||||
table->query_id=thd->query_id;
|
||||
goto reset;
|
||||
}
|
||||
}
|
||||
my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
|
||||
DBUG_RETURN(0);
|
||||
@ -917,6 +940,8 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
|
||||
table->status=STATUS_NO_RECORD;
|
||||
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();
|
||||
DBUG_ASSERT(table->key_read == 0);
|
||||
DBUG_RETURN(table);
|
||||
}
|
||||
@ -1308,6 +1333,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
||||
bzero((char*) &table_list, sizeof(table_list)); // just for safe
|
||||
table_list.db=(char*) db;
|
||||
table_list.real_name=(char*) name;
|
||||
|
||||
safe_mutex_assert_owner(&LOCK_open);
|
||||
|
||||
if ((error=lock_table_name(thd,&table_list)))
|
||||
@ -1342,15 +1368,47 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
|
||||
error=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
thd->clear_error(); // Clear error message
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlock_table_name(thd,&table_list);
|
||||
|
||||
if (error)
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
If we are here, there was no fatal error (but error may be still
|
||||
unitialized).
|
||||
*/
|
||||
if (unlikely(entry->file->implicit_emptied))
|
||||
{
|
||||
entry->file->implicit_emptied= 0;
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
char *query, *end;
|
||||
uint query_buf_size= 20 + 2*NAME_LEN + 1;
|
||||
if ((query= (char*)my_malloc(query_buf_size,MYF(MY_WME))))
|
||||
{
|
||||
end = strxmov(strmov(query, "DELETE FROM `"),
|
||||
db,"`.`",name,"`", NullS);
|
||||
Query_log_event qinfo(thd, query, (ulong)(end-query), 0);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
my_free(query, MYF(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
As replication is maybe going to be corrupted, we need to warn the
|
||||
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 \
|
||||
memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name);
|
||||
if (entry->file)
|
||||
closefrm(entry);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
err:
|
||||
DBUG_RETURN(1);
|
||||
@ -1376,10 +1434,10 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
|
||||
bool refresh;
|
||||
int result=0;
|
||||
DBUG_ENTER("open_tables");
|
||||
*counter= 0;
|
||||
|
||||
thd->current_tablenr= 0;
|
||||
restart:
|
||||
*counter= 0;
|
||||
thd->proc_info="Opening tables";
|
||||
for (tables=start ; tables ; tables=tables->next)
|
||||
{
|
||||
@ -1721,7 +1779,11 @@ bool rm_temporary_table(enum db_type base, char *path)
|
||||
*fn_ext(path)='\0'; // remove extension
|
||||
handler *file=get_new_handler((TABLE*) 0, base);
|
||||
if (file && file->delete_table(path))
|
||||
{
|
||||
error=1;
|
||||
sql_print_error("Warning: Could not remove tmp table: '%s', error: %d",
|
||||
path, my_errno);
|
||||
}
|
||||
delete file;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@ -1735,33 +1797,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=(Field*) hash_search(&table->name_hash,(byte*) name,
|
||||
length)))
|
||||
goto found;
|
||||
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)
|
||||
{
|
||||
*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)
|
||||
@ -1788,7 +1859,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
|
||||
find_field_in_tables()
|
||||
thd Pointer to current thread structure
|
||||
item Field item that should be found
|
||||
tables Tables for scaning
|
||||
tables Tables for scanning
|
||||
where Table where field found will be returned via
|
||||
this parameter
|
||||
report_error If FALSE then do not report error if item not found
|
||||
@ -1816,6 +1887,32 @@ 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, item->cached_table->table, name, length,
|
||||
test(item->cached_table->
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@ -1840,10 +1937,12 @@ 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 (!tables->cacheable_table)
|
||||
item->cached_table= 0;
|
||||
if (find == WRONG_GRANT)
|
||||
return (Field*) 0;
|
||||
if (db || !thd->where)
|
||||
@ -1897,12 +1996,14 @@ 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 (!tables->cacheable_table)
|
||||
item->cached_table= 0;
|
||||
if (found)
|
||||
{
|
||||
if (!thd->where) // Returns first found
|
||||
@ -1997,7 +2098,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
|
||||
{
|
||||
if (!strcmp(item_field->table_name,table_name) &&
|
||||
(!db_name || (db_name && item_field->db_name &&
|
||||
!strcmp(item_field->table_name,table_name))))
|
||||
!strcmp(item_field->db_name, db_name))))
|
||||
{
|
||||
found= li.ref();
|
||||
*counter= i;
|
||||
@ -2039,6 +2140,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
{
|
||||
if (!wild_num)
|
||||
return 0;
|
||||
Statement *stmt= thd->current_statement, backup;
|
||||
|
||||
/*
|
||||
If we are in preparing prepared statement phase then we have change
|
||||
temporary mem_root to statement mem root to save changes of SELECT list
|
||||
*/
|
||||
if (stmt)
|
||||
thd->set_n_backup_item_arena(stmt, &backup);
|
||||
reg2 Item *item;
|
||||
List_iterator<Item> it(fields);
|
||||
while ( wild_num && (item= it++))
|
||||
@ -2050,7 +2159,11 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
uint elem= fields.elements;
|
||||
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
|
||||
((Item_field*) item)->table_name, &it))
|
||||
{
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
return (-1);
|
||||
}
|
||||
if (sum_func_list)
|
||||
{
|
||||
/*
|
||||
@ -2063,6 +2176,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
wild_num--;
|
||||
}
|
||||
}
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2085,10 +2200,9 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
Item **ref= ref_pointer_array;
|
||||
while ((item= it++))
|
||||
{
|
||||
if (item->fix_fields(thd, tables, it.ref()) ||
|
||||
item->check_cols(1))
|
||||
if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
|
||||
(item= *(it.ref()))->check_cols(1))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
item= *(it.ref()); //Item can be changed in fix fields
|
||||
if (ref)
|
||||
*(ref++)= item;
|
||||
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
|
||||
@ -2106,8 +2220,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
SYNOPSIS
|
||||
setup_tables()
|
||||
tables - tables list
|
||||
reinit - true if called for table reinitialization before
|
||||
subquery reexecuting
|
||||
|
||||
RETURN
|
||||
0 ok; In this case *map will includes the choosed index
|
||||
@ -2122,7 +2234,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
table->map is not set and all Item_field will be regarded as const items.
|
||||
*/
|
||||
|
||||
bool setup_tables(TABLE_LIST *tables, my_bool reinit)
|
||||
bool setup_tables(TABLE_LIST *tables)
|
||||
{
|
||||
DBUG_ENTER("setup_tables");
|
||||
uint tablenr=0;
|
||||
@ -2149,13 +2261,6 @@ bool setup_tables(TABLE_LIST *tables, my_bool reinit)
|
||||
table->keys_in_use_for_query.subtract(map);
|
||||
}
|
||||
table->used_keys.intersect(table->keys_in_use_for_query);
|
||||
if ((table_list->shared || table->clear_query_id) && !reinit)
|
||||
{
|
||||
table->clear_query_id= 0;
|
||||
/* Clear query_id that may have been set by previous select */
|
||||
for (Field **ptr=table->field ; *ptr ; ptr++)
|
||||
(*ptr)->query_id=0;
|
||||
}
|
||||
}
|
||||
if (tablenr > MAX_TABLES)
|
||||
{
|
||||
@ -2231,14 +2336,29 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
|
||||
DBUG_RETURN(-1);
|
||||
#endif
|
||||
Field **ptr=table->field,*field;
|
||||
TABLE *natural_join_table= 0;
|
||||
|
||||
thd->used_tables|=table->map;
|
||||
if (!table->outer_join &&
|
||||
tables->natural_join &&
|
||||
!tables->natural_join->table->outer_join)
|
||||
natural_join_table= tables->natural_join->table;
|
||||
|
||||
while ((field = *ptr++))
|
||||
{
|
||||
Item_field *item= new Item_field(field);
|
||||
if (!found++)
|
||||
(void) it->replace(item); // Replace '*'
|
||||
else
|
||||
it->after(item);
|
||||
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
|
||||
/* Skip duplicate field names if NATURAL JOIN is used */
|
||||
if (!natural_join_table ||
|
||||
!find_field_in_table(thd, natural_join_table, field->field_name,
|
||||
strlen(field->field_name), 0, 0,
|
||||
¬_used_field_index))
|
||||
{
|
||||
Item_field *item= new Item_field(thd, field);
|
||||
if (!found++)
|
||||
(void) it->replace(item); // Replace '*'
|
||||
else
|
||||
it->after(item);
|
||||
}
|
||||
/*
|
||||
Mark if field used before in this select.
|
||||
Used by 'insert' to verify if a field name is used twice
|
||||
@ -2270,6 +2390,8 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
|
||||
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
{
|
||||
table_map not_null_tables= 0;
|
||||
Statement *stmt= thd->current_statement, backup;
|
||||
|
||||
DBUG_ENTER("setup_conds");
|
||||
thd->set_query_id=1;
|
||||
|
||||
@ -2277,11 +2399,13 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
if (*conds)
|
||||
{
|
||||
thd->where="where clause";
|
||||
if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1))
|
||||
if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) ||
|
||||
(*conds)->check_cols(1))
|
||||
DBUG_RETURN(1);
|
||||
not_null_tables= (*conds)->not_null_tables();
|
||||
}
|
||||
|
||||
|
||||
/* Check if we are using outer joins */
|
||||
for (TABLE_LIST *table=tables ; table ; table=table->next)
|
||||
{
|
||||
@ -2289,7 +2413,9 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
{
|
||||
/* Make a join an a expression */
|
||||
thd->where="on clause";
|
||||
if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
|
||||
|
||||
if (!table->on_expr->fixed &&
|
||||
table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
|
||||
table->on_expr->check_cols(1))
|
||||
DBUG_RETURN(1);
|
||||
thd->lex->current_select->cond_count++;
|
||||
@ -2303,58 +2429,98 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
!(specialflag & SPECIAL_NO_NEW_FUNC)))
|
||||
{
|
||||
table->outer_join= 0;
|
||||
if (!(*conds=and_conds(*conds, table->on_expr)))
|
||||
DBUG_RETURN(1);
|
||||
if (stmt)
|
||||
thd->set_n_backup_item_arena(stmt, &backup);
|
||||
*conds= and_conds(*conds, table->on_expr);
|
||||
table->on_expr=0;
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
if ((*conds) && !(*conds)->fixed &&
|
||||
(*conds)->fix_fields(thd, tables, conds))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if (table->natural_join)
|
||||
{
|
||||
if (stmt)
|
||||
thd->set_n_backup_item_arena(stmt, &backup);
|
||||
/* Make a join of all fields with have the same name */
|
||||
TABLE *t1=table->table;
|
||||
TABLE *t2=table->natural_join->table;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
TABLE *t1= table->table;
|
||||
TABLE *t2= table->natural_join->table;
|
||||
Item_cond_and *cond_and= new Item_cond_and();
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
goto err;
|
||||
cond_and->top_level_item();
|
||||
|
||||
uint i,j;
|
||||
for (i=0 ; i < t1->fields ; i++)
|
||||
Field **t1_field, *t2_field;
|
||||
for (t1_field= t1->field; (*t1_field); t1_field++)
|
||||
{
|
||||
// TODO: This could be optimized to use hashed names if t2 had a hash
|
||||
for (j=0 ; j < t2->fields ; j++)
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info,
|
||||
t1->field[i]->field_name,
|
||||
t2->field[j]->field_name))
|
||||
{
|
||||
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
|
||||
new Item_field(t2->field[j]));
|
||||
if (!tmp)
|
||||
DBUG_RETURN(1);
|
||||
tmp->fix_length_and_dec(); // Update cmp_type
|
||||
tmp->const_item_cache=0;
|
||||
/* Mark field used for table cache */
|
||||
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
|
||||
cond_and->list.push_back(tmp);
|
||||
t1->used_keys.intersect(t1->field[i]->part_of_key);
|
||||
t2->used_keys.intersect(t2->field[j]->part_of_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char *t1_field_name= (*t1_field)->field_name;
|
||||
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
|
||||
|
||||
if ((t2_field= find_field_in_table(thd, t2, t1_field_name,
|
||||
strlen(t1_field_name), 0, 0,
|
||||
¬_used_field_index)))
|
||||
{
|
||||
Item_func_eq *tmp=new Item_func_eq(new Item_field(*t1_field),
|
||||
new Item_field(t2_field));
|
||||
if (!tmp)
|
||||
goto err;
|
||||
/* Mark field used for table cache */
|
||||
(*t1_field)->query_id= t2_field->query_id= thd->query_id;
|
||||
cond_and->list.push_back(tmp);
|
||||
t1->used_keys.intersect((*t1_field)->part_of_key);
|
||||
t2->used_keys.intersect(t2_field->part_of_key);
|
||||
}
|
||||
}
|
||||
cond_and->used_tables_cache= t1->map | t2->map;
|
||||
thd->lex->current_select->cond_count+= cond_and->list.elements;
|
||||
|
||||
// to prevent natural join processing during PS re-execution
|
||||
table->natural_join= 0;
|
||||
|
||||
if (!table->outer_join) // Not left join
|
||||
{
|
||||
if (!(*conds=and_conds(*conds, cond_and)))
|
||||
DBUG_RETURN(1);
|
||||
*conds= and_conds(*conds, cond_and);
|
||||
// fix_fields() should be made with temporary memory pool
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
if (*conds && !(*conds)->fixed)
|
||||
{
|
||||
if ((*conds)->fix_fields(thd, tables, conds))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
table->on_expr=and_conds(table->on_expr,cond_and);
|
||||
{
|
||||
table->on_expr= and_conds(table->on_expr, cond_and);
|
||||
// fix_fields() should be made with temporary memory pool
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
if (table->on_expr && !table->on_expr->fixed)
|
||||
{
|
||||
if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stmt)
|
||||
{
|
||||
/*
|
||||
We are in prepared statement preparation code => we should store
|
||||
WHERE clause changing for next executions.
|
||||
|
||||
We do this ON -> WHERE transformation only once per PS statement.
|
||||
*/
|
||||
thd->lex->current_select->where= *conds;
|
||||
}
|
||||
DBUG_RETURN(test(thd->net.report_error));
|
||||
|
||||
err:
|
||||
if (stmt)
|
||||
thd->restore_backup_item_arena(stmt, &backup);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
@ -2378,7 +2544,7 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
|
||||
TABLE *table= rfield->table;
|
||||
if (rfield == table->next_number_field)
|
||||
table->auto_increment_field_not_null= true;
|
||||
if (value->save_in_field(rfield, 0) > 0 && !ignore_errors)
|
||||
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
@ -2399,7 +2565,7 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
|
||||
TABLE *table= field->table;
|
||||
if (field == table->next_number_field)
|
||||
table->auto_increment_field_not_null= true;
|
||||
if (value->save_in_field(field, 0) == 1 && !ignore_errors)
|
||||
if ((value->save_in_field(field, 0) < 0) && !ignore_errors)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
@ -2550,7 +2716,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
|
||||
if (table->db_stat)
|
||||
result=1;
|
||||
/* Kill delayed insert threads */
|
||||
if (in_use->system_thread && ! in_use->killed)
|
||||
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
|
||||
! in_use->killed)
|
||||
{
|
||||
in_use->killed= THD::KILL_CONNECTION;
|
||||
pthread_mutex_lock(&in_use->mysys_var->mutex);
|
||||
|
Reference in New Issue
Block a user