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.cc1786
1 files changed, 1273 insertions, 513 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index fe1f268e277..5f9f743932d 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -19,6 +19,8 @@
#include "mysql_priv.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
@@ -31,18 +33,24 @@ TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
HASH assign_cache;
-static int open_unireg_entry(THD *thd,TABLE *entry,const char *db,
- const char *name, const char *alias);
+static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
+ const char *name, const char *alias,
+ TABLE_LIST *table_list, MEM_ROOT *mem_root);
static void free_cache_entry(TABLE *entry);
static void mysql_rm_tmp_tables(void);
-
+static my_bool open_new_frm(const char *path, const char *alias,
+ const char *db, const char *table_name,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam,
+ TABLE_LIST *table_desc, MEM_ROOT *mem_root);
+static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
{
TABLE *entry=(TABLE*) record;
- *length=entry->key_length;
- return (byte*) entry->table_cache_key;
+ *length= entry->s->key_length;
+ return (byte*) entry->s->table_cache_key;
}
bool table_cache_init(void)
@@ -140,20 +148,21 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
{
OPEN_TABLE_LIST *table;
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
+ TABLE_SHARE *share= entry->s;
- DBUG_ASSERT(entry->real_name);
- if ((!entry->real_name)) // To be removed
+ DBUG_ASSERT(share->table_name);
+ if ((!share->table_name)) // To be removed
continue; // Shouldn't happen
if (wild)
{
- strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
+ strxmov(name,share->table_cache_key,".",share->table_name,NullS);
if (wild_compare(name,wild,0))
continue;
}
/* Check if user has SELECT privilege for any column in the table */
- table_list.db= (char*) entry->table_cache_key;
- table_list.real_name= entry->real_name;
+ table_list.db= (char*) share->db;
+ table_list.table_name= (char*) share->table_name;
table_list.grant.privilege=0;
if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1))
@@ -161,8 +170,8 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
/* need to check if we haven't already listed it */
for (table= open_list ; table ; table=table->next)
{
- if (!strcmp(table->table,entry->real_name) &&
- !strcmp(table->db,entry->table_cache_key))
+ if (!strcmp(table->table,share->table_name) &&
+ !strcmp(table->db,entry->s->db))
{
if (entry->in_use)
table->in_use++;
@@ -174,15 +183,15 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
if (table)
continue;
if (!(*start_list = (OPEN_TABLE_LIST *)
- sql_alloc(sizeof(**start_list)+entry->key_length)))
+ sql_alloc(sizeof(**start_list)+share->key_length)))
{
open_list=0; // Out of memory
break;
}
strmov((*start_list)->table=
strmov(((*start_list)->db= (char*) ((*start_list)+1)),
- entry->table_cache_key)+1,
- entry->real_name);
+ entry->s->db)+1,
+ entry->s->table_name);
(*start_list)->in_use= entry->in_use ? 1 : 0;
(*start_list)->locked= entry->locked_by_name ? 1 : 0;
start_list= &(*start_list)->next;
@@ -200,6 +209,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
void intern_close_table(TABLE *table)
{ // Free all structures
free_io_cache(table);
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file
}
@@ -282,9 +292,9 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
else
{
bool found=0;
- for (TABLE_LIST *table=tables ; table ; table=table->next)
+ for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if (remove_table_from_cache(thd, table->db, table->real_name, 1))
+ if (remove_table_from_cache(thd, table->db, table->table_name, 1))
found=1;
}
if (!found)
@@ -316,7 +326,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if ((table->version) < refresh_version && table->db_stat)
+ if ((table->s->version) < refresh_version && table->db_stat)
{
found=1;
pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -333,8 +343,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
result=reopen_tables(thd,1,1);
thd->in_lock_tables=0;
/* Set version for table */
- for (TABLE *table=thd->open_tables; table ; table=table->next)
- table->version=refresh_version;
+ for (TABLE *table=thd->open_tables; table ; table= table->next)
+ table->s->version= refresh_version;
}
VOID(pthread_mutex_unlock(&LOCK_open));
if (if_wait_for_refresh)
@@ -365,7 +375,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
Put all normal tables used by thread in free list.
*/
-void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
+void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived,
+ TABLE *stopper)
{
bool found_old_table;
DBUG_ENTER("close_thread_tables");
@@ -400,10 +411,10 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&LOCK_open);
- DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables));
+ DBUG_PRINT("info", ("thd->open_tables: %p", thd->open_tables));
found_old_table= 0;
- while (thd->open_tables)
+ while (thd->open_tables != stopper)
found_old_table|=close_thread_table(thd, &thd->open_tables);
thd->some_tables_deleted=0;
@@ -431,9 +442,10 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
bool found_old_table= 0;
TABLE *table= *table_ptr;
DBUG_ASSERT(table->key_read == 0);
+ DBUG_ASSERT(table->file->inited == handler::NONE);
*table_ptr=table->next;
- if (table->version != refresh_version ||
+ if (table->s->version != refresh_version ||
thd->version != refresh_version || !table->db_stat)
{
VOID(hash_delete(&open_cache,(byte*) table));
@@ -441,9 +453,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
}
else
{
- if (table->flush_version != flush_version)
+ if (table->s->flush_version != flush_version)
{
- table->flush_version=flush_version;
+ table->s->flush_version= flush_version;
table->file->extra(HA_EXTRA_FLUSH);
}
else
@@ -471,8 +483,8 @@ void close_temporary(TABLE *table,bool delete_table)
{
DBUG_ENTER("close_temporary");
char path[FN_REFLEN];
- db_type table_type=table->db_type;
- strmov(path,table->path);
+ db_type table_type=table->s->db_type;
+ strmov(path,table->s->path);
free_io_cache(table);
closefrm(table);
my_free((char*) table,MYF(0));
@@ -500,7 +512,7 @@ void close_temporary_tables(THD *thd)
/* We'll re-use always same buffer so make it big enough for longest name */
for (table=thd->temporary_tables ; table ; table=table->next)
- greatest_key_length= max(greatest_key_length, table->key_length);
+ greatest_key_length= max(greatest_key_length, table->s->key_length);
if ((query = alloc_root(thd->mem_root, greatest_key_length+50)))
// Better add "if exists", in case a RESET MASTER has been done
@@ -512,14 +524,14 @@ void close_temporary_tables(THD *thd)
In we are OOM for 'query' this is not fatal. We skip temporary tables
not created directly by the user.
*/
- if (query && mysql_bin_log.is_open() && (table->real_name[0] != '#'))
+ if (query && mysql_bin_log.is_open() && (table->s->table_name[0] != '#'))
{
/*
Here we assume table_cache_key always starts
with \0 terminated db name
*/
- end = strxmov(name_in_query, table->table_cache_key, "`.`",
- table->real_name, "`", NullS);
+ end = strxmov(name_in_query, table->s->db, "`.`",
+ table->s->table_name, "`", NullS);
Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
/*
Imagine the thread had created a temp table, then was doing a SELECT, and
@@ -540,56 +552,119 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
+
/*
- Find first suitable table by alias in given list.
+ Find table in list.
SYNOPSIS
find_table_in_list()
- table - pointer to table list
- db_name - data base name or 0 for any
- table_name - table name or 0 for any
+ table Pointer to table list
+ offset Offset to which list in table structure to use
+ db_name Data base name
+ table_name Table name
+
+ NOTES:
+ This is called by find_table_in_local_list() and
+ find_table_in_global_list().
RETURN VALUES
NULL Table not found
# Pointer to found table.
*/
-TABLE_LIST * find_table_in_list(TABLE_LIST *table,
- const char *db_name, const char *table_name)
+TABLE_LIST *find_table_in_list(TABLE_LIST *table,
+ uint offset,
+ const char *db_name,
+ const char *table_name)
{
- for (; table; table= table->next)
- if ((!db_name || !strcmp(table->db, db_name)) &&
- (!table_name || !my_strcasecmp(table_alias_charset,
- table->alias, table_name)))
- break;
+ if (lower_case_table_names)
+ {
+ for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ {
+ if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE) &&
+ ((!strcmp(table->db, db_name) &&
+ !strcmp(table->table_name, table_name)) ||
+ (table->view &&
+ !my_strcasecmp(table_alias_charset,
+ table->db, db_name) &&
+ !my_strcasecmp(table_alias_charset,
+ table->table->alias, table_name))))
+ break;
+ }
+ }
+ else
+ {
+ for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ {
+ if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE) &&
+ ((!strcmp(table->db, db_name) &&
+ !strcmp(table->table_name, table_name)) ||
+ (table->view &&
+ !strcmp(table->table->s->db, db_name) &&
+ !strcmp(table->table->alias, table_name))))
+ break;
+ }
+ }
return table;
}
+
/*
- Find real table in given list.
+ Test that table is unique
SYNOPSIS
- find_real_table_in_list()
- table - pointer to table list
- db_name - data base name
- table_name - table name
+ unique_table()
+ table table which should be chaked
+ table_list list of tables
- RETURN VALUES
- NULL Table not found
- # Pointer to found table.
+ RETURN
+ found duplicate
+ 0 if table is unique
*/
-TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
- const char *db_name,
- const char *table_name)
+TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
{
- for (; table; table= table->next)
- if (!strcmp(table->db, db_name) &&
- !strcmp(table->real_name, table_name))
+ DBUG_ENTER("unique_table");
+ DBUG_PRINT("enter", ("table alias: %s", table->alias));
+ TABLE_LIST *res;
+ const char *d_name= table->db, *t_name= table->table_name;
+ char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
+ /* temporary table is always unique */
+ if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
+ return 0;
+ if (table->view)
+ {
+ /* it is view and table opened */
+ if (lower_case_table_names)
+ {
+ strmov(t_name_buff, table->table->alias);
+ my_casedn_str(files_charset_info, t_name_buff);
+ t_name= t_name_buff;
+ strmov(d_name_buff, table->table->s->db);
+ my_casedn_str(files_charset_info, d_name_buff);
+ d_name= d_name_buff;
+ }
+ else
+ {
+ d_name= table->table->s->db;
+ t_name= table->table->alias;
+ }
+ }
+
+ DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
+ for(;;)
+ {
+ if (!(res= find_table_in_global_list(table_list, d_name, t_name)) ||
+ !res->table || res->table != table->table)
break;
- return table;
+ /* if we found entry of this table try again. */
+ table_list= res->next_global;
+ DBUG_PRINT("info", ("found same copy of table"));
+ }
+ DBUG_RETURN(res);
}
+
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
{
char key[MAX_DBKEY_LENGTH];
@@ -604,8 +679,8 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
prev= &thd->temporary_tables;
for (table=thd->temporary_tables ; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length))
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key,key,key_length))
return prev;
prev= &table->next;
}
@@ -633,22 +708,26 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name)
Prepares a table cache key, which is the concatenation of db, table_name and
thd->slave_proxy_id, separated by '\0'.
*/
+
bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
const char *table_name)
{
char *key;
+ TABLE_SHARE *share= table->s;
+
if (!(key=(char*) alloc_root(&table->mem_root,
(uint) strlen(db)+
(uint) strlen(table_name)+6+4)))
return 1; /* purecov: inspected */
- table->key_length=(uint)
- (strmov((table->real_name=strmov(table->table_cache_key=key,
- db)+1),
- table_name) - table->table_cache_key)+1;
- int4store(key+table->key_length,thd->server_id);
- table->key_length += 4;
- int4store(key+table->key_length,thd->variables.pseudo_thread_id);
- table->key_length += 4;
+ share->key_length= (uint)
+ (strmov((char*) (share->table_name= strmov(share->table_cache_key= key,
+ db)+1),
+ table_name) - share->table_cache_key)+1;
+ share->db= share->table_cache_key;
+ int4store(key+share->key_length, thd->server_id);
+ share->key_length+= 4;
+ int4store(key+share->key_length, thd->variables.pseudo_thread_id);
+ share->key_length+= 4;
return 0;
}
@@ -679,15 +758,16 @@ static void relink_unused(TABLE *table)
TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
{
char key[MAX_DBKEY_LENGTH];
- uint key_length=find->key_length;
+ uint key_length= find->s->key_length;
TABLE *start=list,**prev,*next;
prev= &start;
- memcpy(key,find->table_cache_key,key_length);
+
+ memcpy(key, find->s->table_cache_key, key_length);
for (; list ; list=next)
{
next=list->next;
- if (list->key_length == key_length &&
- !memcmp(list->table_cache_key,key,key_length))
+ if (list->s->key_length == key_length &&
+ !memcmp(list->s->table_cache_key, key, key_length))
{
if (thd->locked_tables)
mysql_lock_remove(thd, thd->locked_tables,list);
@@ -738,29 +818,34 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
DBUG_ENTER("reopen_name_locked_table");
if (thd->killed)
DBUG_RETURN(0);
- TABLE* table;
+ TABLE *table;
+ TABLE_SHARE *share;
if (!(table = table_list->table))
DBUG_RETURN(0);
char* db = thd->db ? thd->db : table_list->db;
- char* table_name = table_list->real_name;
+ char* table_name = table_list->table_name;
char key[MAX_DBKEY_LENGTH];
uint key_length;
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
pthread_mutex_lock(&LOCK_open);
- if (open_unireg_entry(thd, table, db, table_name, table_name) ||
- !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
- key_length)))
+ if (open_unireg_entry(thd, table, db, table_name, table_name, 0,
+ thd->mem_root) ||
+ !(table->s->table_cache_key= memdup_root(&table->mem_root, (char*) key,
+ key_length)))
{
+ delete table->triggers;
closefrm(table);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(0);
}
- table->key_length=key_length;
- table->version=0;
- table->flush_version=0;
+ share= table->s;
+ share->db= share->table_cache_key;
+ share->key_length=key_length;
+ share->version=0;
+ share->flush_version=0;
table->in_use = thd;
check_unused();
pthread_mutex_unlock(&LOCK_open);
@@ -769,10 +854,10 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
- table->used_keys= table->keys_for_keyread;
+ table->keys_in_use_for_query= share->keys_in_use;
+ table->used_keys= share->keys_for_keyread;
DBUG_RETURN(table);
}
@@ -787,12 +872,13 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
******************************************************************************/
-TABLE *open_table(THD *thd,const char *db,const char *table_name,
- const char *alias,bool *refresh)
+TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+ bool *refresh)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
+ char *alias= table_list->alias;
DBUG_ENTER("open_table");
/* find a unused table in the open table cache */
@@ -800,27 +886,30 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
*refresh=0;
if (thd->killed)
DBUG_RETURN(0);
- key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
+ key_length= (uint) (strmov(strmov(key, table_list->db)+1,
+ table_list->table_name)-key)+1;
int4store(key + key_length, thd->server_id);
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
- for (table=thd->temporary_tables; table ; table=table->next)
+ if (!table_list->skip_temporary)
{
- if (table->key_length == key_length + TMP_TABLE_KEY_EXTRA &&
- !memcmp(table->table_cache_key, key,
- key_length + TMP_TABLE_KEY_EXTRA))
+ for (table= thd->temporary_tables; table ; table=table->next)
{
- if (table->query_id == thd->query_id)
+ if (table->s->key_length == key_length + TMP_TABLE_KEY_EXTRA &&
+ !memcmp(table->s->table_cache_key, key,
+ key_length + TMP_TABLE_KEY_EXTRA))
{
- my_printf_error(ER_CANT_REOPEN_TABLE,
- ER(ER_CANT_REOPEN_TABLE),MYF(0),table->table_name);
- DBUG_RETURN(0);
+ if (table->query_id == thd->query_id)
+ {
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
+ DBUG_RETURN(0);
+ }
+ table->query_id= thd->query_id;
+ table->clear_query_id= 1;
+ thd->tmp_table_used= 1;
+ DBUG_PRINT("info",("Using temporary table"));
+ goto reset;
}
- table->query_id=thd->query_id;
- table->clear_query_id=1;
- thd->tmp_table_used= 1;
- DBUG_PRINT("info",("Using temporary table"));
- goto reset;
}
}
@@ -828,9 +917,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
{ // Using table locks
for (table=thd->open_tables; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length) &&
- !my_strcasecmp(system_charset_info, table->table_name, alias) &&
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key,key,key_length) &&
+ !my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id)
{
table->query_id=thd->query_id;
@@ -838,7 +927,38 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
goto reset;
}
}
- my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
+ /*
+ is it view?
+ (it is work around to allow to open view with locked tables,
+ real fix will be made after definition cache will be made)
+ */
+ {
+ char path[FN_REFLEN];
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", table_list->db, "/",
+ table_list->table_name, reg_ext, NullS);
+ (void) unpack_filename(path, path);
+ if (mysql_frm_type(path) == FRMTYPE_VIEW)
+ {
+ TABLE tab;// will not be used (because it's VIEW) but have to be passed
+ table= &tab;
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (open_unireg_entry(thd, table, table_list->db,
+ table_list->table_name,
+ alias, table_list, mem_root))
+ {
+ table->next=table->prev=table;
+ free_cache_entry(table);
+ }
+ else
+ {
+ DBUG_ASSERT(table_list->view);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(0); // VIEW
+ }
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ }
+ my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
DBUG_RETURN(0);
}
@@ -855,13 +975,14 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
}
/* close handler tables which are marked for flush */
- mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE);
+ if (thd->handler_tables)
+ 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 ;
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
{
- if (table->version != refresh_version)
+ if (table->s->version != refresh_version)
{
/*
** There is a refresh in progress for this table
@@ -871,7 +992,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
if (table->in_use != thd)
wait_for_refresh(thd);
else
+ {
VOID(pthread_mutex_unlock(&LOCK_open));
+ }
if (refresh)
*refresh=1;
DBUG_RETURN(0);
@@ -887,10 +1010,11 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
}
table->prev->next=table->next; /* Remove from unused list */
table->next->prev=table->prev;
-
+ table->in_use= thd;
}
else
{
+ TABLE_SHARE *share;
/* Free cache if too big */
while (open_cache.records > table_cache_size && unused_tables)
VOID(hash_delete(&open_cache,(byte*) unused_tables)); /* purecov: tested */
@@ -901,25 +1025,35 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
- if (open_unireg_entry(thd, table,db,table_name,alias) ||
- !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key,
- key_length)))
+ if (open_unireg_entry(thd, table, table_list->db, table_list->table_name,
+ alias, table_list, mem_root) ||
+ (!table_list->view &&
+ !(table->s->table_cache_key= memdup_root(&table->mem_root,
+ (char*) key,
+ key_length))))
{
table->next=table->prev=table;
free_cache_entry(table);
VOID(pthread_mutex_unlock(&LOCK_open));
DBUG_RETURN(NULL);
}
- table->key_length=key_length;
- table->version=refresh_version;
- table->flush_version=flush_version;
+ if (table_list->view)
+ {
+ my_free((gptr)table, MYF(0));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(0); // VIEW
+ }
+ share= table->s;
+ share->db= share->table_cache_key;
+ share->key_length= key_length;
+ share->version= refresh_version;
+ share->flush_version= flush_version;
DBUG_PRINT("info", ("inserting table %p into the cache", table));
VOID(my_hash_insert(&open_cache,(byte*) table));
}
- table->in_use=thd;
check_unused(); // Debugging call
-
+
VOID(pthread_mutex_unlock(&LOCK_open));
if (refresh)
{
@@ -929,51 +1063,29 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->reginfo.lock_type=TL_READ; /* Assume read */
reset:
+ if (thd->lex->need_correct_ident())
+ table->alias_name_used= my_strcasecmp(table_alias_charset,
+ table->s->table_name, alias);
/* Fix alias if table name changes */
- if (strcmp(table->table_name,alias))
+ if (strcmp(table->alias, alias))
{
uint length=(uint) strlen(alias)+1;
- table->table_name= (char*) my_realloc(table->table_name,length,
- MYF(MY_WME));
- memcpy(table->table_name,alias,length);
- for (uint i=0 ; i < table->fields ; i++)
- table->field[i]->table_name=table->table_name;
+ table->alias= (char*) my_realloc((char*) table->alias, length,
+ MYF(MY_WME));
+ memcpy((char*) table->alias, alias, length);
}
-#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;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
- table->used_keys= table->keys_for_keyread;
+ table->keys_in_use_for_query= table->s->keys_in_use;
+ table->insert_values= 0;
+ table->used_keys= table->s->keys_for_keyread;
if (table->timestamp_field)
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);
}
@@ -986,8 +1098,8 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
for (TABLE *table=thd->open_tables; table ; table=table->next)
{
- if (table->key_length == key_length &&
- !memcmp(table->table_cache_key,key,key_length))
+ if (table->s->key_length == key_length &&
+ !memcmp(table->s->table_cache_key,key,key_length))
return table;
}
return(0);
@@ -1004,9 +1116,9 @@ TABLE *find_locked_table(THD *thd, const char *db,const char *table_name)
bool reopen_table(TABLE *table,bool locked)
{
TABLE tmp;
- char *db=table->table_cache_key;
- char *table_name=table->real_name;
- bool error=1;
+ char *db= table->s->table_cache_key;
+ const char *table_name= table->s->table_name;
+ bool error= 1;
Field **field;
uint key,part;
DBUG_ENTER("reopen_table");
@@ -1014,60 +1126,64 @@ bool reopen_table(TABLE *table,bool locked)
#ifdef EXTRA_DEBUG
if (table->db_stat)
sql_print_error("Table %s had a open data handler in reopen_table",
- table->table_name);
+ table->alias);
#endif
if (!locked)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&LOCK_open);
- if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name))
+ if (open_unireg_entry(table->in_use, &tmp, db, table_name,
+ table->alias, 0, table->in_use->mem_root))
goto end;
free_io_cache(table);
- if (!(tmp.table_cache_key= memdup_root(&tmp.mem_root,db,
- table->key_length)))
+ if (!(tmp.s->table_cache_key= memdup_root(&tmp.mem_root,db,
+ table->s->key_length)))
{
+ delete tmp.triggers;
closefrm(&tmp); // End of memory
goto end;
}
+ tmp.s->db= tmp.s->table_cache_key;
/* This list copies variables set by open_table */
tmp.tablenr= table->tablenr;
tmp.used_fields= table->used_fields;
tmp.const_table= table->const_table;
- tmp.outer_join= table->outer_join;
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
- tmp.keys_in_use_for_query= tmp.keys_in_use;
- tmp.used_keys= tmp.keys_for_keyread;
+ tmp.keys_in_use_for_query= tmp.s->keys_in_use;
+ tmp.used_keys= tmp.s->keys_for_keyread;
tmp.force_index= tmp.force_index;
/* Get state */
- tmp.key_length= table->key_length;
+ tmp.s->key_length= table->s->key_length;
tmp.in_use= table->in_use;
tmp.reginfo.lock_type=table->reginfo.lock_type;
- tmp.version= refresh_version;
- tmp.tmp_table= table->tmp_table;
+ tmp.s->version= refresh_version;
+ tmp.s->tmp_table= table->s->tmp_table;
tmp.grant= table->grant;
/* Replace table in open list */
tmp.next= table->next;
tmp.prev= table->prev;
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file, free everything
- *table=tmp;
+ *table= tmp;
+ table->s= &table->share_not_to_be_used;
table->file->change_table_ptr(table);
- DBUG_ASSERT(table->table_name);
+ DBUG_ASSERT(table->alias);
for (field=table->field ; *field ; field++)
{
(*field)->table= (*field)->orig_table= table;
- (*field)->table_name=table->table_name;
+ (*field)->table_name= &table->alias;
}
- for (key=0 ; key < table->keys ; key++)
+ for (key=0 ; key < table->s->keys ; key++)
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
table->key_info[key].key_part[part].field->table= table;
VOID(pthread_cond_broadcast(&COND_refresh));
@@ -1091,8 +1207,8 @@ bool close_data_tables(THD *thd,const char *db, const char *table_name)
TABLE *table;
for (table=thd->open_tables; table ; table=table->next)
{
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name, table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_remove(thd, thd->locked_tables,table);
table->file->close();
@@ -1137,7 +1253,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
next=table->next;
if (!tables || (!db_stat && reopen_table(table,1)))
{
- my_error(ER_CANT_REOPEN_TABLE,MYF(0),table->table_name);
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
VOID(hash_delete(&open_cache,(byte*) table));
error=1;
}
@@ -1149,7 +1265,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
*tables_ptr++= table; // need new lock on this
if (in_refresh)
{
- table->version=0;
+ table->s->version=0;
table->locked_by_flush=0;
}
}
@@ -1188,11 +1304,11 @@ void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
bool found=send_refresh;
for (; table ; table=table->next)
{
- if (table->version != refresh_version)
+ if (table->s->version != refresh_version)
{
found=1;
if (!abort_locks) // If not from flush tables
- table->version = refresh_version; // Let other threads use table
+ table->s->version= refresh_version; // Let other threads use table
if (table->db_stat)
{
if (abort_locks)
@@ -1222,8 +1338,8 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
do
{
- char *key= table->table_cache_key;
- uint key_length=table->key_length;
+ char *key= table->s->table_cache_key;
+ uint key_length= table->s->key_length;
for (TABLE *search=(TABLE*) hash_search(&open_cache,
(byte*) key,key_length) ;
search ;
@@ -1231,7 +1347,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
{
if (search->locked_by_flush ||
search->locked_by_name && wait_for_name_lock ||
- search->db_stat && search->version < refresh_version)
+ search->db_stat && search->s->version < refresh_version)
return 1; // Table is used
}
} while ((table=table->next));
@@ -1278,11 +1394,11 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name)
TABLE *table,*next,**prev;
bool found=0;
prev= &thd->open_tables;
- for (table=thd->open_tables; table ; table=next)
+ for (table= thd->open_tables; table ; table=next)
{
next=table->next;
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name, table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_remove(thd, thd->locked_tables,table);
VOID(hash_delete(&open_cache,(byte*) table));
@@ -1317,8 +1433,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
TABLE *table;
for (table= thd->open_tables; table ; table= table->next)
{
- if (!strcmp(table->real_name,table_name) &&
- !strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->table_name,table_name) &&
+ !strcmp(table->s->db, db))
{
mysql_lock_abort(thd,table);
break;
@@ -1337,6 +1453,8 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
db Database name
name Table name
alias Alias name
+ table_desc TABLE_LIST descriptor (used with views)
+ mem_root temporary mem_root for parsing
NOTES
Extra argument for open is taken from thd->open_options
@@ -1345,9 +1463,9 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
0 ok
# Error
*/
-
static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
- const char *name, const char *alias)
+ const char *name, const char *alias,
+ TABLE_LIST *table_desc, MEM_ROOT *mem_root)
{
char path[FN_REFLEN];
int error;
@@ -1355,19 +1473,28 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
DBUG_ENTER("open_unireg_entry");
strxmov(path, mysql_data_home, "/", db, "/", name, NullS);
- while (openfrm(path,alias,
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
- thd->open_options, entry))
- {
- if (!entry->crashed)
+ while ((error= openfrm(thd, path, alias,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY |
+ NO_ERR_ON_NEW_FRM),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ thd->open_options, entry)) &&
+ (error != 5 ||
+ (fn_format(path, path, 0, reg_ext, MY_UNPACK_FILENAME),
+ open_new_frm(path, alias, db, name,
+ (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
+ HA_GET_INDEX | HA_TRY_READ_ONLY),
+ READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ thd->open_options, entry, table_desc, mem_root))))
+
+ {
+ if (!entry->s || !entry->s->crashed)
{
/*
- Frm file could not be found on disk
- Since it does not exist, no one can be using it
- LOCK_open has been locked to protect from someone else
- trying to discover the table at the same time.
+ Frm file could not be found on disk
+ Since it does not exist, no one can be using it
+ LOCK_open has been locked to protect from someone else
+ trying to discover the table at the same time.
*/
if (discover_retry_count++ != 0)
goto err;
@@ -1382,7 +1509,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
TABLE_LIST table_list;
bzero((char*) &table_list, sizeof(table_list)); // just for safe
table_list.db=(char*) db;
- table_list.real_name=(char*) name;
+ table_list.table_name=(char*) name;
safe_mutex_assert_owner(&LOCK_open);
@@ -1401,7 +1528,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
pthread_mutex_unlock(&LOCK_open);
thd->clear_error(); // Clear error message
error= 0;
- if (openfrm(path,alias,
+ if (openfrm(thd, path, alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
@@ -1426,6 +1553,13 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
goto err;
break;
}
+
+ if (error == 5)
+ DBUG_RETURN(0); // we have just opened VIEW
+
+ if (Table_triggers_list::check_n_load(thd, db, name, entry))
+ goto err;
+
/*
If we are here, there was no fatal error (but error may be still
unitialized).
@@ -1454,6 +1588,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
*/
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)
closefrm(entry);
goto err;
@@ -1462,6 +1597,14 @@ memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name);
}
DBUG_RETURN(0);
err:
+ /* Hide "Table doesn't exist" errors if table belong to view */
+ if (thd->net.last_errno == ER_NO_SUCH_TABLE &&
+ table_desc && table_desc->belong_to_view)
+ {
+ TABLE_LIST * view= table_desc->belong_to_view;
+ thd->clear_error();
+ my_error(ER_VIEW_INVALID, MYF(0), view->view_db.str, view->view_name.str);
+ }
DBUG_RETURN(1);
}
@@ -1485,12 +1628,18 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
bool refresh;
int result=0;
DBUG_ENTER("open_tables");
+ MEM_ROOT new_frm_mem;
+ /*
+ temporary mem_root for new .frm parsing.
+ TODO: variables for size
+ */
+ init_alloc_root(&new_frm_mem, 8024, 8024);
thd->current_tablenr= 0;
restart:
*counter= 0;
thd->proc_info="Opening tables";
- for (tables=start ; tables ; tables=tables->next)
+ for (tables= start; tables ;tables= tables->next_global)
{
/*
Ignore placeholders for derived tables. After derived tables
@@ -1498,13 +1647,23 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
*/
if (tables->derived)
continue;
+ if (tables->schema_table)
+ {
+ if (!mysql_schema_table(thd, thd->lex, tables))
+ continue;
+ DBUG_RETURN(-1);
+ }
(*counter)++;
if (!tables->table &&
- !(tables->table= open_table(thd,
- tables->db,
- tables->real_name,
- tables->alias, &refresh)))
+ !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh)))
{
+ free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+ if (tables->view)
+ {
+ (*counter)--;
+ continue; //VIEW placeholder
+ }
+
if (refresh) // Refresh in progress
{
/* close all 'old' tables used by this thread */
@@ -1514,12 +1673,12 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
thd->version=refresh_version;
TABLE **prev_table= &thd->open_tables;
bool found=0;
- for (TABLE_LIST *tmp=start ; tmp ; tmp=tmp->next)
+ for (TABLE_LIST *tmp= start; tmp; tmp= tmp->next_global)
{
/* Close normal (not temporary) changed tables */
- if (tmp->table && ! tmp->table->tmp_table)
+ if (tmp->table && ! tmp->table->s->tmp_table)
{
- if (tmp->table->version != refresh_version ||
+ if (tmp->table->s->version != refresh_version ||
! tmp->table->db_stat)
{
VOID(hash_delete(&open_cache,(byte*) tmp->table));
@@ -1542,11 +1701,15 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
result= -1; // Fatal error
break;
}
+ else
+ free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
tables->table->reginfo.lock_type=tables->lock_type;
tables->table->grant= tables->grant;
}
thd->proc_info=0;
+ free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
DBUG_RETURN(result);
}
@@ -1574,9 +1737,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
(int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
{
- my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
- ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
- MYF(0),table->table_name);
+ my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias);
DBUG_RETURN(1);
}
if ((error=table->file->start_stmt(thd)))
@@ -1614,9 +1775,11 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->proc_info="Opening table";
thd->current_tablenr= 0;
- while (!(table=open_table(thd,table_list->db,
- table_list->real_name,table_list->alias,
- &refresh)) && refresh) ;
+ /* open_ltable can be used only for BASIC TABLEs */
+ table_list->required_type= FRMTYPE_TABLE;
+ while (!(table= open_table(thd, table_list, thd->mem_root, &refresh)) &&
+ refresh)
+ ;
if (table)
{
@@ -1685,21 +1848,25 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
tables - list of tables for open&locking
RETURN
- 0 - ok
- -1 - error
+ FALSE - ok
+ TRUE - error
NOTE
The lock will automaticly be freed by close_thread_tables()
*/
-int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+bool 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))
- DBUG_RETURN(-1); /* purecov: inspected */
- relink_tables_for_derived(thd);
- DBUG_RETURN(mysql_handle_derived(thd->lex));
+ DBUG_ENTER("open_and_lock_tables");
+ if (open_tables(thd, tables, &counter) ||
+ lock_tables(thd, tables, counter) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(thd->lex, &mysql_derived_filling)))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ relink_tables_for_multidelete(thd);
+ DBUG_RETURN(0);
}
@@ -1720,35 +1887,40 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
data from the tables.
*/
-int open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
+bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables)
{
uint counter;
DBUG_ENTER("open_normal_and_derived_tables");
- if (open_tables(thd, tables, &counter))
- DBUG_RETURN(-1); /* purecov: inspected */
- relink_tables_for_derived(thd);
- DBUG_RETURN(mysql_handle_derived(thd->lex));
+ DBUG_ASSERT(!thd->fill_derived_tables());
+ if (open_tables(thd, tables, &counter) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ relink_tables_for_multidelete(thd); // Not really needed, but
+ DBUG_RETURN(0);
}
/*
Let us propagate pointers to open tables from global table list
- to table lists in particular selects if needed.
+ to table lists for multi-delete
*/
-void relink_tables_for_derived(THD *thd)
+static void relink_tables_for_multidelete(THD *thd)
{
- if (thd->lex->all_selects_list->next_select_in_list() ||
- thd->lex->time_zone_tables_used)
+ if (thd->lex->all_selects_list->next_select_in_list())
{
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;
+ cursor=cursor->next_local)
+ {
+ if (cursor->correspondent_table)
+ cursor->table= cursor->correspondent_table->table;
+ }
+ }
}
}
@@ -1782,11 +1954,11 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
TABLE **start,**ptr;
- if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*)*count)))
+ if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
return -1;
- for (table = tables ; table ; table=table->next)
+ for (table= tables; table; table= table->next_global)
{
- if (!table->derived)
+ if (!table->placeholder() && !table->schema_table)
*(ptr++)= table->table;
}
if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
@@ -1794,9 +1966,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
}
else
{
- for (table = tables ; table ; table=table->next)
+ for (table= tables; table; table= table->next_global)
{
- if (!table->derived &&
+ if (!table->placeholder() &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
@@ -1818,6 +1990,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list)
{
TABLE *tmp_table;
+ TABLE_SHARE *share;
DBUG_ENTER("open_temporary_table");
/*
@@ -1832,7 +2005,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
MYF(MY_WME))))
DBUG_RETURN(0); /* purecov: inspected */
- if (openfrm(path, table_name,
+ if (openfrm(thd, path, table_name,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX),
READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
ha_open_options,
@@ -1842,21 +2015,22 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
DBUG_RETURN(0);
}
+ share= tmp_table->s;
tmp_table->reginfo.lock_type=TL_WRITE; // Simulate locked
- tmp_table->in_use= thd;
- tmp_table->tmp_table = (tmp_table->file->has_transactions() ?
- TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
- tmp_table->table_cache_key=(char*) (tmp_table+1);
- tmp_table->key_length= (uint) (strmov((tmp_table->real_name=
- strmov(tmp_table->table_cache_key,db)
- +1), table_name)
- - tmp_table->table_cache_key)+1;
- int4store(tmp_table->table_cache_key + tmp_table->key_length,
- thd->server_id);
- tmp_table->key_length += 4;
- int4store(tmp_table->table_cache_key + tmp_table->key_length,
+ share->tmp_table= (tmp_table->file->has_transactions() ?
+ TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
+ share->table_cache_key= (char*) (tmp_table+1);
+ share->db= share->table_cache_key;
+ share->key_length= (uint) (strmov(((char*) (share->table_name=
+ strmov(share->table_cache_key,
+ db)+1)),
+ table_name) -
+ share->table_cache_key) +1;
+ int4store(share->table_cache_key + share->key_length, thd->server_id);
+ share->key_length+= 4;
+ int4store(share->table_cache_key + share->key_length,
thd->variables.pseudo_thread_id);
- tmp_table->key_length += 4;
+ share->key_length+= 4;
if (link_in_list)
{
@@ -1896,23 +2070,147 @@ bool rm_temporary_table(enum db_type base, char *path)
** return unique field
******************************************************************************/
+/* Special Field pointers for find_field_in_tables returning */
+Field *not_found_field= (Field*) 0x1;
+Field *view_ref_found= (Field*) 0x2;
+
#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,
- uint *cached_field_index_ptr)
+
+/*
+ Find field in table or view
+
+ SYNOPSIS
+ find_field_in_table()
+ thd thread handler
+ table_list table where to find
+ name name of field
+ item_name name of item if it will be created (VIEW)
+ length length of name
+ ref expression substituted in VIEW should be
+ passed using this reference (return
+ view_ref_found)
+ check_grants_table do check columns grants for table?
+ check_grants_view do check columns grants for view?
+ allow_rowid do allow finding of "_rowid" field?
+ cached_field_index_ptr cached position in field list (used to
+ speedup prepared tables field finding)
+ register_tree_change TRUE if ref is not stack variable and we
+ need register changes in item tree
+
+ RETURN
+ 0 field is not found
+ view_ref_found found value in VIEW (real result is in *ref)
+ # pointer to field
+*/
+
+Field *
+find_field_in_table(THD *thd, TABLE_LIST *table_list,
+ const char *name, const char *item_name,
+ uint length, Item **ref,
+ bool check_grants_table, bool check_grants_view,
+ bool allow_rowid,
+ uint *cached_field_index_ptr,
+ bool register_tree_change)
+{
+ Field *fld;
+ DBUG_ENTER("find_field_in_table");
+ DBUG_PRINT("enter", ("table: '%s' name: '%s' item name: '%s' ref 0x%lx",
+ table_list->alias, name, item_name, (ulong) ref));
+ if (table_list->field_translation)
+ {
+ DBUG_ASSERT(ref != 0 && table_list->view != 0);
+ uint num= table_list->view->select_lex.item_list.elements;
+ Field_translator *trans= table_list->field_translation;
+ for (uint i= 0; i < num; i ++)
+ {
+ if (!my_strcasecmp(system_charset_info, trans[i].name, name))
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_grants_view &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ DBUG_RETURN(WRONG_GRANT);
+#endif
+ if (thd->lex->current_select->no_wrap_view_item)
+ {
+ if (register_tree_change)
+ thd->change_item_tree(ref, trans[i].item);
+ else
+ *ref= trans[i].item;
+ }
+ else
+ {
+ Item_ref *item_ref= new Item_ref(&trans[i].item,
+ table_list->view_name.str,
+ item_name);
+ /* as far as Item_ref have defined reference it do not need tables */
+ if (register_tree_change && item_ref)
+ thd->change_item_tree(ref, item_ref);
+ else if (item_ref)
+ *ref= item_ref;
+ }
+ DBUG_RETURN((Field*) view_ref_found);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ fld= find_field_in_real_table(thd, table_list->table, name, length,
+ check_grants_table, allow_rowid,
+ cached_field_index_ptr);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* check for views with temporary table algorithm */
+ if (check_grants_view && table_list->view &&
+ fld && fld != WRONG_GRANT &&
+ check_grant_column(thd, &table_list->grant,
+ table_list->view_db.str,
+ table_list->view_name.str,
+ name, length))
+ {
+ DBUG_RETURN(WRONG_GRANT);
+ }
+#endif
+ DBUG_RETURN(fld);
+}
+
+
+/*
+ Find field in table
+
+ SYNOPSIS
+ find_field_in_real_table()
+ thd thread handler
+ table_list table where to find
+ name name of field
+ length length of name
+ check_grants do check columns grants?
+ allow_rowid do allow finding of "_rowid" field?
+ cached_field_index_ptr cached position in field list (used to
+ speedup prepared tables field finding)
+
+ RETURN
+ 0 field is not found
+ # pointer to field
+*/
+
+Field *find_field_in_real_table(THD *thd, TABLE *table,
+ const char *name, uint length,
+ bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr)
{
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 &&
+ if (cached_field_index < table->s->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 (table->s->name_hash.records)
+ field_ptr= (Field**) hash_search(&table->s->name_hash, (byte*) name,
+ length);
else
{
if (!(field_ptr= table->field))
@@ -1947,7 +2245,9 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
thd->dupp_field=field;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_grants && check_grant_column(thd,table,name,length))
+ if (check_grants && check_grant_column(thd, &table->grant,
+ table->s->db,
+ table->s->table_name, name, length))
return WRONG_GRANT;
#endif
return field;
@@ -1961,26 +2261,33 @@ 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 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
- and return not_found_field
+ tables Tables to be searched for item
+ ref If 'item' is resolved to a view field, ref is set to
+ point to the found view field
+ report_error Degree of error reporting:
+ - IGNORE_ERRORS then do not report any error
+ - IGNORE_EXCEPT_NON_UNIQUE report only non-unique
+ fields, suppress all other errors
+ - REPORT_EXCEPT_NON_UNIQUE report all other errors
+ except when non-unique fields were found
+ - REPORT_ALL_ERRORS
+ check_privileges need to check privileges
RETURN VALUES
- 0 Field is not found or field is not unique- error
- message is reported
- not_found_field Function was called with report_error == FALSE and
- field was not found. no error message reported.
- found field
+ 0 If error: the found field is not unique, or there are
+ no sufficient access priviliges for the found field,
+ or the field is qualified with non-existing table.
+ not_found_field The function was called with report_error ==
+ (IGNORE_ERRORS || IGNORE_EXCEPT_NON_UNIQUE) and a
+ field was not found.
+ view_ref_found View field is found, item passed through ref parameter
+ found field If a item was resolved to some field
*/
-// Special Field pointer for find_field_in_tables returning
-const Field *not_found_field= (Field*) 0x1;
-
Field *
find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- TABLE_LIST **where, bool report_error)
+ Item **ref, find_item_error_report_type report_error,
+ bool check_privileges)
{
Field *found=0;
const char *db=item->db_name;
@@ -1993,24 +2300,42 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
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
+ 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
+ With this optimization we also miss case when addition of one more
+ field makes some prepared query ambiguous and so erroneous, 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 (item->cached_table->table && !item->cached_table->view)
+ {
+ found= find_field_in_real_table(thd, item->cached_table->table,
+ name, length,
+ test(item->cached_table->
+ table->grant.want_privilege) &&
+ check_privileges,
+ 1, &(item->cached_field_index));
+ }
+ else
+ {
+ TABLE_LIST *table= item->cached_table;
+ found= find_field_in_table(thd, table, name, item->name, length,
+ ref,
+ (table->table &&
+ test(table->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(table->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index),
+ TRUE);
+ }
if (found)
{
- (*where)= tables;
if (found == WRONG_GRANT)
- return (Field*) 0;
+ return (Field*) 0;
return found;
}
}
@@ -2018,7 +2343,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (db && lower_case_table_names)
{
/*
- convert database to lower case for comparision.
+ 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
*/
@@ -2030,19 +2355,27 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
if (table_name && table_name[0])
{ /* Qualified field */
bool found_table=0;
- for (; tables ; tables=tables->next)
+ for (; tables; tables= tables->next_local)
{
+ /* TODO; Ensure that db and tables->db always points to something ! */
if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
- (!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
+ (!db || !db[0] || !tables->db || !tables->db[0] ||
+ !strcmp(db,tables->db)))
{
found_table=1;
- Field *find=find_field_in_table(thd,tables->table,name,length,
- test(tables->table->grant.
- want_privilege),
- 1, &(item->cached_field_index));
+ Field *find= find_field_in_table(thd, tables, name, item->name,
+ length, ref,
+ (tables->table &&
+ test(tables->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(tables->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index),
+ TRUE);
if (find)
{
- (*where)= item->cached_table= tables;
+ item->cached_table= tables;
if (!tables->cacheable_table)
item->cached_table= 0;
if (find == WRONG_GRANT)
@@ -2051,8 +2384,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return find;
if (found)
{
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == IGNORE_EXCEPT_NON_UNIQUE)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ item->full_name(),thd->where);
return (Field*) 0;
}
found=find;
@@ -2061,7 +2396,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
}
if (found)
return found;
- if (!found_table && report_error)
+ if (!found_table && (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE))
{
char buff[NAME_LEN*2+1];
if (db && db[0])
@@ -2069,44 +2405,51 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
table_name=buff;
}
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- table_name, thd->where);
+ my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
}
else
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
}
- bool allow_rowid= tables && !tables->next; // Only one table
- for (; tables ; tables=tables->next)
+
+ bool allow_rowid= tables && !tables->next_local; // Only one table
+ for (; tables ; tables= tables->next_local)
{
- if (!tables->table)
+ if (!tables->table && !tables->ancestor)
{
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(),thd->where);
return (Field*) not_found_field;
}
- Field *field=find_field_in_table(thd,tables->table,name,length,
- test(tables->table->grant.want_privilege),
- allow_rowid, &(item->cached_field_index));
+ Field *field= find_field_in_table(thd, tables, name, item->name,
+ length, ref,
+ (tables->table &&
+ test(tables->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(tables->grant.want_privilege) &&
+ check_privileges),
+ allow_rowid,
+ &(item->cached_field_index),
+ TRUE);
if (field)
{
if (field == WRONG_GRANT)
return (Field*) 0;
- (*where)= item->cached_table= tables;
- if (!tables->cacheable_table)
- item->cached_table= 0;
+ item->cached_table= (!tables->cacheable_table || found) ? 0 : tables;
if (found)
{
if (!thd->where) // Returns first found
break;
- my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
- name,thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == IGNORE_EXCEPT_NON_UNIQUE)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
return (Field*) 0;
}
found=field;
@@ -2114,9 +2457,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
}
if (found)
return found;
- if (report_error)
- my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
- MYF(0), item->full_name(), thd->where);
+ if (report_error == REPORT_ALL_ERRORS ||
+ report_error == REPORT_EXCEPT_NON_UNIQUE)
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
else
return (Field*) not_found_field;
return (Field*) 0;
@@ -2153,8 +2496,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
found field
*/
-// Special Item pointer for find_item_in_list returning
-const Item **not_found_item= (const Item**) 0x1;
+/* Special Item pointer to serve as a return value from find_item_in_list(). */
+Item **not_found_item= (Item**) 0x1;
Item **
@@ -2169,6 +2512,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
bool found_unaliased_non_uniq= 0;
uint unaliased_counter;
+ LINT_INIT(unaliased_counter); // Dependent on found_unaliased
+
*unaliased= FALSE;
if (find->type() == Item::FIELD_ITEM || find->type() == Item::REF_ITEM)
@@ -2228,8 +2573,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
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);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item**) 0;
}
found_unaliased= li.ref();
@@ -2253,8 +2598,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
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);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item**) 0;
}
found= li.ref();
@@ -2297,8 +2642,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
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);
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item **) 0;
}
if (found_unaliased)
@@ -2313,8 +2658,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
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),
- find->full_name(), current_thd->where);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
return (Item **) 0;
}
else
@@ -2329,27 +2674,29 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
- DBUG_ENTER("setup_wild");
if (!wild_num)
- DBUG_RETURN(0);
+ return(0);
- reg2 Item *item;
+ Item *item;
List_iterator<Item> it(fields);
Item_arena *arena, backup;
+ DBUG_ENTER("setup_wild");
+
/*
- 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
+ Don't use arena if we are not in prepared statements or stored procedures
+ For PS/SP we have to use arena to remember the changes
*/
arena= thd->change_arena_if_needed(&backup);
while (wild_num && (item= it++))
- {
+ {
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*' &&
!((Item_field*) item)->field)
{
uint elem= fields.elements;
+ bool any_privileges= ((Item_field *) item)->any_privileges;
Item_subselect *subsel= thd->lex->current_select->master_unit()->item;
if (subsel &&
subsel->substype() == Item_subselect::EXISTS_SUBS)
@@ -2362,9 +2709,10 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
it.replace(new Item_int("Not_used", (longlong) 1, 21));
}
else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name, &it))
+ ((Item_field*) item)->table_name, &it,
+ any_privileges, arena != 0))
{
- if (arena)
+ if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(-1);
}
@@ -2381,7 +2729,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
}
if (arena)
+ {
+ /* make * substituting permanent */
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ select_lex->with_wild= 0;
+ select_lex->item_list= fields;
+
thd->restore_backup_item_arena(arena, &backup);
+ }
DBUG_RETURN(0);
}
@@ -2389,12 +2744,13 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
** Check that all given fields exists and fill struct with current data
****************************************************************************/
-int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, bool set_query_id,
- List<Item> *sum_func_list, bool allow_sum_func)
+bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, bool set_query_id,
+ List<Item> *sum_func_list, bool allow_sum_func)
{
reg2 Item *item;
List_iterator<Item> it(fields);
+ SELECT_LEX *select_lex= thd->lex->current_select;
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
@@ -2420,7 +2776,9 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
- DBUG_RETURN(-1); /* purecov: inspected */
+ {
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ }
if (ref)
*(ref++)= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
@@ -2433,36 +2791,91 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
/*
+ make list of leaves of join table tree
+
+ SYNOPSIS
+ make_leaves_list()
+ list pointer to pointer on list first element
+ tables table list
+
+ RETURN pointer on pointer to next_leaf of last element
+*/
+
+TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
+{
+ for (TABLE_LIST *table= tables; table; table= table->next_local)
+ {
+ if (table->view && !table->table)
+ {
+ /* it is for multi table views only, check it */
+ DBUG_ASSERT(table->ancestor->next_local);
+ list= make_leaves_list(list, table->ancestor);
+ }
+ else
+ {
+ *list= table;
+ list= &table->next_leaf;
+ }
+ }
+ return list;
+}
+
+/*
prepare tables
SYNOPSIS
setup_tables()
- tables table list
-
+ thd Thread handler
+ tables Table list
+ conds Condition of current SELECT (can be changed by VIEW)
+ leaves List of join table leaves list
+ refresh It is onle refresh for subquery
+ select_insert It is SELECT ... INSERT command
- 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
+ Check also that the 'used keys' and 'ignored keys' exists and set up the
+ table structure accordingly
+ Create leaf tables list
- 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.
- RETURN
- 0 ok; In this case *map will includes the choosed index
- 1 error
+ RETURN
+ FALSE ok; In this case *map will includes the choosed index
+ TRUE error
*/
-bool setup_tables(TABLE_LIST *tables)
+bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
+ TABLE_LIST **leaves, bool refresh, bool select_insert)
{
+ uint tablenr= 0;
DBUG_ENTER("setup_tables");
- uint tablenr=0;
- for (TABLE_LIST *table_list=tables ; table_list ;
- table_list=table_list->next,tablenr++)
+ /*
+ this is used for INSERT ... SELECT.
+ For select we setup tables except first (and its underlying tables)
+ */
+ TABLE_LIST *first_select_table= (select_insert ?
+ tables->next_local:
+ 0);
+ if (!(*leaves))
+ make_leaves_list(leaves, tables);
+
+ for (TABLE_LIST *table_list= *leaves;
+ table_list;
+ table_list= table_list->next_leaf, tablenr++)
{
TABLE *table= table_list->table;
+ if (first_select_table &&
+ (table_list->belong_to_view ?
+ table_list->belong_to_view :
+ table_list) == first_select_table)
+ {
+ /* new counting for SELECT of INSERT ... SELECT command */
+ first_select_table= 0;
+ tablenr= 0;
+ }
setup_table_map(table, table_list, tablenr);
- table->used_keys= table->keys_for_keyread;
+ table->used_keys= table->s->keys_for_keyread;
if (table_list->use_index)
{
key_map map;
@@ -2486,6 +2899,18 @@ bool setup_tables(TABLE_LIST *tables)
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
DBUG_RETURN(1);
}
+ if (!refresh)
+ {
+ for (TABLE_LIST *table_list= tables;
+ table_list;
+ table_list= table_list->next_local)
+ {
+ if (table_list->ancestor &&
+ table_list->setup_ancestor(thd, conds,
+ table_list->effective_with_check))
+ DBUG_RETURN(1);
+ }
+ }
DBUG_RETURN(0);
}
@@ -2514,11 +2939,13 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
map->clear_all();
while ((name=it++))
{
- if ((pos= find_type(&table->keynames, name->ptr(), name->length(), 1)) <=
- 0)
+ if (table->s->keynames.type_names == 0 ||
+ (pos= find_type(&table->s->keynames, name->ptr(),
+ name->length(), 1)) <=
+ 0)
{
- my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
- table->real_name);
+ my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0),
+ name->c_ptr(), table->s->table_name);
map->set_all();
return 1;
}
@@ -2528,17 +2955,37 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
}
-/****************************************************************************
- This just drops in all fields instead of current '*' field
- Returns pointer to last inserted field if ok
-****************************************************************************/
+/*
+ Drops in all fields instead of current '*' field
+
+ SYNOPSIS
+ insert_fields()
+ thd Thread handler
+ tables List of tables
+ db_name Database name in case of 'database_name.table_name.*'
+ table_name Table name in case of 'table_name.*'
+ it Pointer to '*'
+ any_privileges 0 If we should ensure that we have SELECT privileges
+ for all columns
+ 1 If any privilege is ok
+ allocate_view_names if true view names will be copied to current Item_arena
+ memory (made for SP/PS)
+ RETURN
+ 0 ok
+ 'it' is updated to point at last inserted
+ 1 error. Error message is generated but not sent to client
+*/
bool
-insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
- const char *table_name, List_iterator<Item> *it)
+insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
+ const char *table_name, List_iterator<Item> *it,
+ bool any_privileges, bool allocate_view_names)
{
- char name_buff[NAME_LEN+1];
+ /* allocate variables on stack to avoid pool alloaction */
+ 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)
@@ -2553,216 +3000,432 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
db_name= name_buff;
}
-
- found=0;
- for (; tables ; tables=tables->next)
+ found= 0;
+ for (; tables; tables= tables->next_local)
{
- TABLE *table=tables->table;
+ Field_iterator *iterator;
+ TABLE_LIST *natural_join_table;
+ Field *field;
+ TABLE_LIST *embedded;
+ TABLE_LIST *last;
+ TABLE_LIST *embedding;
+ TABLE *table= tables->table;
+ bool alias_used= 0;
+
if (!table_name || (!my_strcasecmp(table_alias_charset, table_name,
tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
{
+ bool view;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access right to all columns */
- if (!(table->grant.privilege & SELECT_ACL) &&
- check_grant_all_columns(thd,SELECT_ACL,table))
- DBUG_RETURN(-1);
+ if (!((table && (table->grant.privilege & SELECT_ACL) ||
+ tables->view && (tables->grant.privilege & SELECT_ACL))) &&
+ !any_privileges)
+ {
+ if (tables->view)
+ {
+ view_iter.set(tables);
+ if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant,
+ tables->view_db.str,
+ tables->view_name.str,
+ &view_iter))
+ goto err;
+ }
+ else if (!tables->schema_table)
+ {
+ DBUG_ASSERT(table != 0);
+ table_iter.set(tables);
+ if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
+ table->s->db,
+ table->s->table_name,
+ &table_iter))
+ goto err;
+ }
+ }
#endif
- Field **ptr=table->field,*field;
- TABLE *natural_join_table= 0;
+ if (table)
+ thd->used_tables|= table->map;
+ else
+ {
+ view_iter.set(tables);
+ for (; !view_iter.end_of_fields(); view_iter.next())
+ {
+ thd->used_tables|= view_iter.item(thd)->used_tables();
+ }
+ }
+ natural_join_table= 0;
+ last= embedded= tables;
- 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 ((embedding= embedded->embedding) &&
+ embedding->join_list->elements != 1)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(embedding->nested_join->join_list);
+ last= it++;
+ while ((next= it++))
+ last= next;
+ if (last != tables)
+ break;
+ embedded= embedding;
+ }
- while ((field = *ptr++))
+ if (tables == last &&
+ !embedded->outer_join &&
+ embedded->natural_join &&
+ !embedded->natural_join->outer_join)
+ {
+ embedding= embedded->natural_join;
+ while (embedding->nested_join)
+ embedding= embedding->nested_join->join_list.head();
+ natural_join_table= embedding;
+ }
+ if (tables->field_translation)
+ {
+ iterator= &view_iter;
+ view= 1;
+ alias_used= my_strcasecmp(table_alias_charset,
+ tables->table_name, tables->alias);
+ }
+ else
{
+ iterator= &table_iter;
+ view= 0;
+ }
+ iterator->set(tables);
+
+ for (; !iterator->end_of_fields(); iterator->next())
+ {
+ Item *not_used_item;
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
+ const char *field_name= iterator->name();
/* 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,
- &not_used_field_index))
+ !find_field_in_table(thd, natural_join_table, field_name,
+ field_name,
+ strlen(field_name), &not_used_item, 0, 0, 0,
+ &not_used_field_index, TRUE))
{
- Item_field *item= new Item_field(thd, field);
+ Item *item= iterator->item(thd);
+ if (view && !thd->lex->current_select->no_wrap_view_item)
+ {
+ /*
+ as far as we have view, then item point to view_iter, so we
+ can use it directly for this view specific operation
+ */
+ item= new Item_ref(view_iter.item_ptr(), tables->view_name.str,
+ field_name);
+ }
if (!found++)
(void) it->replace(item); // Replace '*'
else
it->after(item);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (any_privileges)
+ {
+ /*
+ In time of view creation MEGRGE algorithm for underlying
+ VIEWs can't be used => it should be Item_field
+ */
+ DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
+ Item_field *fld= (Item_field*)item;
+ char *db, *tab;
+ if (tables->view)
+ {
+ db= tables->view_db.str;
+ tab= tables->view_name.str;
+ }
+ else
+ {
+ db= tables->db;
+ tab= tables->table_name;
+ }
+ if (!tables->schema_table &&
+ !(fld->have_privileges= (get_column_grant(thd,
+ &table->grant,
+ db,
+ tab,
+ fld->field_name) &
+ VIEW_ANY_ACL)))
+ {
+ my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
+ "ANY",
+ thd->priv_user,
+ thd->host_or_ip,
+ fld->field_name,
+ tab);
+ goto err;
+ }
+ }
+#endif
+ }
+ if ((field= iterator->field()))
+ {
+ /*
+ Mark if field used before in this select.
+ Used by 'insert' to verify if a field name is used twice
+ */
+ if (field->query_id == thd->query_id)
+ thd->dupp_field=field;
+ field->query_id=thd->query_id;
+ table->used_keys.intersect(field->part_of_key);
+ }
+ else if (allocate_view_names &&
+ thd->lex->current_select->first_execution)
+ {
+ Item_field *item;
+ if (alias_used)
+ item= new Item_field(0,
+ thd->strdup(tables->alias),
+ thd->strdup(field_name));
+ else
+ item= new Item_field(thd->strdup(tables->view_db.str),
+ thd->strdup(tables->view_name.str),
+ thd->strdup(field_name));
+ /*
+ during cleunup() this item will be put in list to replace
+ expression from VIEW
+ */
+ thd->nocheck_register_item_tree_change(it->ref(), item,
+ thd->mem_root);
}
- /*
- Mark if field used before in this select.
- Used by 'insert' to verify if a field name is used twice
- */
- if (field->query_id == thd->query_id)
- thd->dupp_field=field;
- field->query_id=thd->query_id;
- table->used_keys.intersect(field->part_of_key);
}
- /* All fields are used */
- table->used_fields=table->fields;
+ /*
+ All fields are used in case if usual tables (in case of view used
+ fields marked in setup_tables during fix_fields of view columns
+ */
+ if (table)
+ table->used_fields= table->s->fields;
}
}
- if (!found)
- {
- if (!table_name)
- my_error(ER_NO_TABLES_USED,MYF(0));
- else
- my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name);
- }
- DBUG_RETURN(!found);
+ if (found)
+ DBUG_RETURN(0);
+
+ if (!table_name)
+ my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+err:
+#endif
+ DBUG_RETURN(1);
}
/*
-** Fix all conditions and outer join expressions
+ Fix all conditions and outer join expressions
+
+ SYNOPSIS
+ setup_conds()
+ thd thread handler
+ tables list of tables for name resolving
+ leaves list of leaves of join table tree
*/
-int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
+int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{
table_map not_null_tables= 0;
- Item_arena *arena= 0, backup;
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ Item_arena *arena= thd->current_arena, backup;
+ bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
+ TABLE_LIST *table= NULL; // For HP compilers
DBUG_ENTER("setup_conds");
+ if (select_lex->conds_processed_with_permanent_arena ||
+ arena->is_conventional())
+ arena= 0; // For easier test
+
thd->set_query_id=1;
- thd->lex->current_select->cond_count= 0;
+
+ thd->lex->current_select->no_wrap_view_item= 1;
+ select_lex->cond_count= 0;
if (*conds)
{
thd->where="where clause";
if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) ||
(*conds)->check_cols(1))
- DBUG_RETURN(1);
- not_null_tables= (*conds)->not_null_tables();
+ goto err_no_arena;
}
-
/* Check if we are using outer joins */
- for (TABLE_LIST *table=tables ; table ; table=table->next)
+ for (table= leaves; table; table= table->next_leaf)
{
- if (table->on_expr)
+ TABLE_LIST *embedded;
+ TABLE_LIST *embedding= table;
+ do
{
- /* Make a join an a expression */
- thd->where="on clause";
-
- 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++;
-
- /*
- If it's a normal join or a LEFT JOIN which can be optimized away
- add the ON/USING expression to the WHERE
- */
- if (!table->outer_join ||
- ((table->table->map & not_null_tables) &&
- !(specialflag & SPECIAL_NO_NEW_FUNC)))
+ embedded= embedding;
+ if (embedded->on_expr)
{
- table->outer_join= 0;
- arena= thd->change_arena_if_needed(&backup);
- *conds= and_conds(*conds, table->on_expr);
- table->on_expr=0;
- if (arena)
- {
- thd->restore_backup_item_arena(arena, &backup);
- arena= 0; // Safety if goto err
- }
- if ((*conds) && !(*conds)->fixed &&
- (*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
+ /* Make a join an a expression */
+ thd->where="on clause";
+ if (!embedded->on_expr->fixed &&
+ embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) ||
+ embedded->on_expr->check_cols(1))
+ goto err_no_arena;
+ select_lex->cond_count++;
}
- }
- if (table->natural_join)
- {
- arena= thd->change_arena_if_needed(&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();
- if (!cond_and) // If not out of memory
- goto err;
- cond_and->top_level_item();
-
- Field **t1_field, *t2_field;
- for (t1_field= t1->field; (*t1_field); t1_field++)
+ if (embedded->natural_join)
{
- 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,
- &not_used_field_index)))
+ /* Make a join of all fields wich have the same name */
+ TABLE_LIST *tab1= embedded;
+ TABLE_LIST *tab2= embedded->natural_join;
+ if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
{
- Item_func_eq *tmp=new Item_func_eq(new Item_field(thd, *t1_field),
- new Item_field(thd, 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);
+ while (tab1->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
+ tab1= it++;
+ while ((next= it++))
+ tab1= next;
+ }
+ }
+ else
+ {
+ while (tab1->nested_join)
+ tab1= tab1->nested_join->join_list.head();
+ }
+ if (embedded->outer_join & JOIN_TYPE_RIGHT)
+ {
+ while (tab2->nested_join)
+ {
+ TABLE_LIST *next;
+ List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
+ tab2= it++;
+ while ((next= it++))
+ tab2= next;
+ }
+ }
+ else
+ {
+ while (tab2->nested_join)
+ tab2= tab2->nested_join->join_list.head();
}
- }
- thd->lex->current_select->cond_count+= cond_and->list.elements;
- // to prevent natural join processing during PS re-execution
- table->natural_join= 0;
+ if (arena)
+ arena= thd->change_arena_if_needed(&backup);
+
+ TABLE *t1=tab1->table;
+ TABLE *t2=tab2->table;
+ Field_iterator_table table_iter;
+ Field_iterator_view view_iter;
+ Field_iterator *iterator;
+ Field *t1_field, *t2_field;
+ Item *item_t2= 0;
+ Item_cond_and *cond_and= new Item_cond_and();
+
+ if (!cond_and) // If not out of memory
+ goto err_no_arena;
+ cond_and->top_level_item();
+
+ if (table->field_translation)
+ {
+ iterator= &view_iter;
+ view_iter.set(tab1);
+ }
+ else
+ {
+ iterator= &table_iter;
+ table_iter.set(tab1);
+ }
- if (cond_and->list.elements)
- {
- if (!table->outer_join) // Not left join
+ for (; !iterator->end_of_fields(); iterator->next())
{
- *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)
+ const char *t1_field_name= iterator->name();
+ uint not_used_field_index= NO_CACHED_FIELD_INDEX;
+
+ if ((t2_field= find_field_in_table(thd, tab2, t1_field_name,
+ t1_field_name,
+ strlen(t1_field_name), &item_t2,
+ 0, 0, 0,
+ &not_used_field_index,
+ FALSE)))
{
- if (!(*conds)->fixed &&
- (*conds)->fix_fields(thd, tables, conds))
- DBUG_RETURN(1);
+ if (t2_field != view_ref_found)
+ {
+ if (!(item_t2= new Item_field(thd, t2_field)))
+ goto err;
+ /* Mark field used for table cache */
+ t2_field->query_id= thd->query_id;
+ t2->used_keys.intersect(t2_field->part_of_key);
+ }
+ if ((t1_field= iterator->field()))
+ {
+ /* Mark field used for table cache */
+ t1_field->query_id= thd->query_id;
+ t1->used_keys.intersect(t1_field->part_of_key);
+ }
+ Item_func_eq *tmp= new Item_func_eq(iterator->item(thd),
+ item_t2);
+ if (!tmp)
+ goto err;
+ cond_and->list.push_back(tmp);
}
}
- else
+ select_lex->cond_count+= cond_and->list.elements;
+
+ // to prevent natural join processing during PS re-execution
+ embedding->natural_join= 0;
+
+ if (cond_and->list.elements)
{
- table->on_expr= and_conds(table->on_expr, cond_and);
- // fix_fields() should be made with temporary memory pool
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
- if (table->on_expr && !table->on_expr->fixed)
+ COND *on_expr= cond_and;
+ on_expr->fix_fields(thd, 0, &on_expr);
+ if (!embedded->outer_join) // Not left join
{
- if (!table->on_expr->fixed &&
- table->on_expr->fix_fields(thd, tables, &table->on_expr))
- DBUG_RETURN(1);
+ *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))
+ goto err_no_arena;
+ }
+ }
+ 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,
+ &embedded->on_expr))
+ goto err_no_arena;
+ }
}
}
+ else if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
}
- else if (arena)
- {
- thd->restore_backup_item_arena(arena, &backup);
- arena= 0; // Safety if goto err
- }
+ embedding= embedded->embedding;
}
+ while (embedding &&
+ embedding->nested_join->join_list.head() == embedded);
}
- if (thd->current_arena->is_stmt_prepare())
+ if (!thd->current_arena->is_conventional())
{
/*
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.
+ We do this ON -> WHERE transformation only once per PS/SP statement.
*/
- thd->lex->current_select->where= *conds;
+ select_lex->where= *conds;
+ select_lex->conds_processed_with_permanent_arena= 1;
}
+ thd->lex->current_select->no_wrap_view_item= save_wrapper;
DBUG_RETURN(test(thd->net.report_error));
err:
if (arena)
thd->restore_backup_item_arena(arena, &backup);
+err_no_arena:
+ thd->lex->current_select->no_wrap_view_item= save_wrapper;
DBUG_RETURN(1);
}
@@ -2772,8 +3435,25 @@ err:
** Returns : 1 if some field has wrong type
******************************************************************************/
-int
-fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
+
+/*
+ Fill fields with given items.
+
+ SYNOPSIS
+ fill_record()
+ thd thread handler
+ fields Item_fields list to be filled
+ values values to fill with
+ ignore_errors TRUE if we should ignore errors
+
+ RETURN
+ FALSE OK
+ TRUE error occured
+*/
+
+bool
+fill_record(THD * thd, List<Item> &fields, List<Item> &values,
+ bool ignore_errors)
{
List_iterator_fast<Item> f(fields),v(values);
Item *value;
@@ -2788,14 +3468,32 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
if (rfield == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
- DBUG_RETURN(1);
+ {
+ my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
+ DBUG_RETURN(TRUE);
+ }
}
- DBUG_RETURN(0);
+ DBUG_RETURN(thd->net.report_error);
}
-int
-fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
+/*
+ Fill field buffer with values from Field list
+
+ SYNOPSIS
+ fill_record()
+ thd thread handler
+ ptr pointer on pointer to record
+ values list of fields
+ ignore_errors TRUE if we should ignore errors
+
+ RETURN
+ FALSE OK
+ TRUE error occured
+*/
+
+bool
+fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
{
List_iterator_fast<Item> v(values);
Item *value;
@@ -2809,9 +3507,12 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if ((value->save_in_field(field, 0) < 0) && !ignore_errors)
- DBUG_RETURN(1);
+ {
+ my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
+ DBUG_RETURN(TRUE);
+ }
}
- DBUG_RETURN(0);
+ DBUG_RETURN(thd->net.report_error);
}
@@ -2869,14 +3570,14 @@ void remove_db_from_cache(const my_string db)
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
- if (!strcmp(table->table_cache_key,db))
+ if (!strcmp(table->s->db, db))
{
- table->version=0L; /* Free when thread is ready */
+ table->s->version= 0L; /* Free when thread is ready */
if (!table->in_use)
relink_unused(table);
}
}
- while (unused_tables && !unused_tables->version)
+ while (unused_tables && !unused_tables->s->version)
VOID(hash_delete(&open_cache,(byte*) unused_tables));
}
@@ -2921,7 +3622,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
{
THD *in_use;
- table->version=0L; /* Free when thread is ready */
+ table->s->version= 0L; /* Free when thread is ready */
if (!(in_use=table->in_use))
{
DBUG_PRINT("info",("Table was not in use"));
@@ -2936,7 +3637,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed)
{
- in_use->killed=1;
+ in_use->killed= THD::KILL_CONNECTION;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
@@ -2961,7 +3662,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
else
result= result || return_if_owned_by_thd;
}
- while (unused_tables && !unused_tables->version)
+ while (unused_tables && !unused_tables->s->version)
VOID(hash_delete(&open_cache,(byte*) unused_tables));
DBUG_RETURN(result);
}
@@ -3002,3 +3703,62 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
}
return 0;
}
+
+
+/*
+ open new .frm format table
+
+ SYNOPSIS
+ open_new_frm()
+ path path to .frm
+ alias alias for table
+ db database
+ table_name name of table
+ db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
+ can be 0 (example in ha_example_table)
+ prgflag READ_ALL etc..
+ ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
+ outparam result table
+ table_desc TABLE_LIST descriptor
+ mem_root temporary MEM_ROOT for parsing
+*/
+
+static my_bool
+open_new_frm(const char *path, const char *alias,
+ const char *db, const char *table_name,
+ uint db_stat, uint prgflag,
+ uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
+ MEM_ROOT *mem_root)
+{
+ LEX_STRING pathstr;
+ File_parser *parser;
+ DBUG_ENTER("open_new_frm");
+
+ pathstr.str= (char*) path;
+ pathstr.length= strlen(path);
+
+ if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
+ {
+ if (!strncmp("VIEW", parser->type()->str, parser->type()->length))
+ {
+ if (table_desc == 0 || table_desc->required_type == FRMTYPE_TABLE)
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0), db, table_name, "BASE TABLE");
+ goto err;
+ }
+ if (mysql_make_view(parser, table_desc))
+ goto err;
+ }
+ else
+ {
+ /* only VIEWs are supported now */
+ my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str);
+ goto err;
+ }
+ DBUG_RETURN(0);
+ }
+
+err:
+ bzero(outparam, sizeof(TABLE)); // do not run repair
+ DBUG_RETURN(1);
+}