diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 610 |
1 files changed, 489 insertions, 121 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 954cf7a5a6d..781e7273e7a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -32,11 +32,19 @@ 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, + uint db_stat, uint prgflag, + uint ha_open_flags, TABLE *outparam, + TABLE_LIST *table_desc, MEM_ROOT *mem_root); +static 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); extern "C" byte *table_cache_key(const byte *record,uint *length, my_bool not_used __attribute__((unused))) @@ -277,7 +285,7 @@ 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)) found=1; @@ -328,7 +336,7 @@ 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) + for (TABLE *table=thd->open_tables; table ; table= table->next) table->version=refresh_version; } VOID(pthread_mutex_unlock(&LOCK_open)); @@ -540,6 +548,7 @@ void close_temporary_tables(THD *thd) thd->temporary_tables=0; } +#ifdef UNUSED /* Find first suitable table by alias in given list. @@ -564,9 +573,10 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table, break; return table; } +#endif /*UNUSED*/ /* - Find real table in given list. + Find real table in given global list. SYNOPSIS find_real_table_in_list() @@ -583,13 +593,40 @@ TABLE_LIST * find_real_table_in_list(TABLE_LIST *table, const char *db_name, const char *table_name) { - for (; table; table= table->next) + for (; table; table= table->next_global) if (!strcmp(table->db, db_name) && !strcmp(table->real_name, table_name)) break; return table; } + +/* + Find real table in given local list. + + SYNOPSIS + find_real_table_in_local_list() + table - pointer to table list + db_name - data base name + table_name - table name + + RETURN VALUES + NULL Table not found + # Pointer to found table. +*/ + +TABLE_LIST * find_real_table_in_local_list(TABLE_LIST *table, + const char *db_name, + const char *table_name) +{ + for (; table; table= table->next_local) + if (!strcmp(table->db, db_name) && + !strcmp(table->real_name, table_name)) + break; + return table; +} + + TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) { char key[MAX_DBKEY_LENGTH]; @@ -749,7 +786,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) 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) || + if (open_unireg_entry(thd, table, db, table_name, table_name, 0, 0) || !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key, key_length))) { @@ -787,12 +824,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,25 +838,29 @@ 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->real_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+8 && - !memcmp(table->table_cache_key,key,key_length+8)) + for (table= thd->temporary_tables; table ; table=table->next) { - if (table->query_id == thd->query_id) + if (table->key_length == key_length + 8 && + !memcmp(table->table_cache_key, key, key_length + 8)) { - 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_printf_error(ER_CANT_REOPEN_TABLE, + ER(ER_CANT_REOPEN_TABLE), MYF(0), table->table_name); + DBUG_RETURN(0); + } + table->query_id= thd->query_id; + table->clear_query_id= 1; + thd->tmp_table_used= 1; + goto reset; } - table->query_id=thd->query_id; - table->clear_query_id=1; - thd->tmp_table_used= 1; - goto reset; } } @@ -868,7 +910,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); @@ -898,15 +942,23 @@ 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->real_name, + alias, table_list, mem_root) || + (!table_list->view && + !(table->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); } + if (table_list->view) + { + my_free((gptr)table, MYF(0)); + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(0); // VIEW + } table->key_length=key_length; table->version=refresh_version; table->flush_version=flush_version; @@ -916,7 +968,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->in_use=thd; check_unused(); // Debugging call - + VOID(pthread_mutex_unlock(&LOCK_open)); if (refresh) { @@ -946,6 +998,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->used_keys= table->keys_for_keyread; if (table->timestamp_field) table->timestamp_field->set_timestamp_offsets(); + table_list->updatable= 1; // It is not derived table nor non-updatable VIEW DBUG_ASSERT(table->key_read == 0); DBUG_RETURN(table); } @@ -992,7 +1045,8 @@ bool reopen_table(TABLE *table,bool 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(current_thd, &tmp, db, table_name, + table->table_name, 0, 0)) goto end; free_io_cache(table); @@ -1309,6 +1363,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 + mem_root temporary mem_root for parsing NOTES Extra argument for open is taken from thd->open_options @@ -1317,21 +1373,32 @@ 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; + // we support new format only is have all parameters for it + uint new_frm_flag= (table_desc && mem_root) ? NO_ERR_ON_NEW_FRM : 0; uint discover_retry_count= 0; 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)) + while ((error= openfrm(path, alias, + (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | + HA_GET_INDEX | HA_TRY_READ_ONLY | + new_frm_flag), + 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, + (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->crashed) { @@ -1398,6 +1465,10 @@ 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 we are here, there was no fatal error (but error may be still unitialized). @@ -1457,12 +1528,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 @@ -1472,11 +1549,15 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter) continue; (*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 */ @@ -1486,7 +1567,7 @@ 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) @@ -1514,11 +1595,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)); DBUG_RETURN(result); } @@ -1586,9 +1671,7 @@ 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) ; + while (!(table= open_table(thd, table_list, 0, &refresh)) && refresh) ; if (table) { @@ -1670,7 +1753,6 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables) uint counter; if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter)) DBUG_RETURN(-1); /* purecov: inspected */ - fix_tables_pointers(thd->lex->all_selects_list); DBUG_RETURN(mysql_handle_derived(thd->lex)); } @@ -1706,9 +1788,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) TABLE **start,**ptr; if (!(ptr=start=(TABLE**) sql_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()) *(ptr++)= table->table; } if (!(thd->lock=mysql_lock_tables(thd,start,count))) @@ -1716,9 +1798,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,12 +1900,109 @@ bool rm_temporary_table(enum db_type base, char *path) ** return unique field ******************************************************************************/ +// Special Field pointers for find_field_in_tables returning +const Field *not_found_field= (Field*) 0x1; +const 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, + +/* + Find field in table or view + + SYNOPSIS + find_field_in_table() + thd thread handler + table_list table where to find + name name of field + 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) + + 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, uint length, Item **ref, + bool check_grants_table, bool check_grants_view, + bool allow_rowid, uint *cached_field_index_ptr) { + Field *fld; + if (table_list->field_translation) + { + DBUG_ASSERT(ref != 0 && table_list->view != 0); + uint num= table_list->view->select_lex.item_list.elements; + Item **trans= table_list->field_translation; + for (uint i= 0; i < num; i ++) + { + if (strcmp(trans[i]->name, name) == 0) + { + *ref= trans[i]; +#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)) + return WRONG_GRANT; +#endif + return (Field*) view_ref_found; + } + } + 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)) + { + return WRONG_GRANT; + } +#endif + 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 +*/ + +static 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; @@ -1869,7 +2048,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->table_cache_key, + table->real_name, name, length)) return WRONG_GRANT; #endif return field; @@ -1884,25 +2065,25 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, 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 + ref if view field is found, pointer to view item will + be returned via this parameter report_error If FALSE then do not report error if item not found and return not_found_field + 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. + view_ref_found view field is found, item passed through ref parameter found 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, bool report_error, + bool check_privileges) { Field *found=0; const char *db=item->db_name; @@ -1923,14 +2104,15 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, 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)); + 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)); if (found) { - (*where)= tables; if (found == WRONG_GRANT) return (Field*) 0; return found; @@ -1952,19 +2134,22 @@ 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) { if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && (!db || !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, length, ref, + (test(tables->table->grant. + want_privilege) && + check_privileges), + (test(tables->grant.want_privilege) && + check_privileges), + 1, &(item->cached_field_index)); if (find) { - (*where)= item->cached_table= tables; + item->cached_table= tables; if (!tables->cacheable_table) item->cached_table= 0; if (find == WRONG_GRANT) @@ -2007,8 +2192,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, 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) { @@ -2018,14 +2203,18 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, 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, length, ref, + (test(tables->table->grant. + want_privilege) && + check_privileges), + (test(tables->grant.want_privilege) && + check_privileges), + allow_rowid, &(item->cached_field_index)); if (field) { if (field == WRONG_GRANT) return (Field*) 0; - (*where)= item->cached_table= tables; + item->cached_table= tables; if (!tables->cacheable_table) item->cached_table= 0; if (found) @@ -2184,12 +2373,13 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, reg2 Item *item; List_iterator<Item> it(fields); 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) @@ -2202,7 +2392,8 @@ 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)) { if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -2270,7 +2461,9 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, SYNOPSIS setup_tables() + thd - thread handler tables - tables list + conds - condition of current SELECT (can be changed by VIEW) RETURN 0 ok; In this case *map will includes the choosed index @@ -2283,14 +2476,20 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, This has to be called for all tables that are used by items, as otherwise table->map is not set and all Item_field will be regarded as const items. + + if tables do not contain VIEWs it is OK to pass 0 as conds */ -bool setup_tables(TABLE_LIST *tables) +bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds) { DBUG_ENTER("setup_tables"); + if (!tables || tables->setup_is_done) + DBUG_RETURN(0); + tables->setup_is_done= 1; uint tablenr=0; - for (TABLE_LIST *table_list=tables ; table_list ; - table_list=table_list->next,tablenr++) + for (TABLE_LIST *table_list= tables; + table_list; + table_list= table_list->next_local, tablenr++) { TABLE *table= table_list->table; setup_table_map(table, table_list, tablenr); @@ -2312,6 +2511,8 @@ bool setup_tables(TABLE_LIST *tables) table->keys_in_use_for_query.subtract(map); } table->used_keys.intersect(table->keys_in_use_for_query); + if (table_list->ancestor) + table_list->setup_ancestor(thd, conds); } if (tablenr > MAX_TABLES) { @@ -2366,14 +2567,15 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, ****************************************************************************/ 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) { uint found; DBUG_ENTER("insert_fields"); found=0; - for (; tables ; tables=tables->next) + for (; tables; tables= tables->next_local) { TABLE *table=tables->table; if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, @@ -2382,18 +2584,41 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, { #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->grant.privilege & SELECT_ACL) && !any_privileges) + { + if (tables->view) + { + Field_iterator_view fields; + fields.set(tables); + if (check_grant_all_columns(thd, SELECT_ACL, &tables->grant, + tables->view_db.str, + tables->view_name.str, + &fields)) + DBUG_RETURN(1); + } + else + { + Field_iterator_table fields; + fields.set(tables); + if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, + table->table_cache_key, table->real_name, + &fields)) + DBUG_RETURN(1); + } + } #endif - Field **ptr=table->field,*field; - TABLE *natural_join_table= 0; + /* allocate 2 variables on stack to avoid pool alloaction */ + Field_iterator_table table_iter; + Field_iterator_view view_iter; + Field_iterator *iterator; + TABLE_LIST *natural_join_table= 0; + Field *field; thd->used_tables|=table->map; TABLE_LIST *embedded= tables; TABLE_LIST *last= embedded; TABLE_LIST *embedding; - + while ((embedding= embedded->embedding) && embedding->join_list->elements != 1) { @@ -2405,9 +2630,9 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, if (last != tables) break; embedded= embedding; - } - - if (tables == last && + } + + if (tables == last && !embedded->outer_join && embedded->natural_join && !embedded->natural_join->outer_join) @@ -2415,32 +2640,96 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, embedding= embedded->natural_join; while (embedding->nested_join) embedding= embedding->nested_join->join_list.head(); - natural_join_table= embedding->table; - } + natural_join_table= embedding; + } + if (tables->field_translation) + iterator= &view_iter; + else + iterator= &table_iter; + iterator->set(tables); - while ((field = *ptr++)) + for (; iterator->end(); 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, + !find_field_in_table(thd, natural_join_table, field_name, + strlen(field_name), ¬_used_item, 0, 0, 0, ¬_used_field_index)) { - Item_field *item= new Item_field(thd, field); + Item *item= iterator->item(thd); 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->real_name; + } + if (!(fld->have_privileges= (get_column_grant(thd, + &table->grant, + db, + tab, + fld->field_name) & + VIEW_ANY_ACL))) + { + my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, + ER(ER_COLUMNACCESS_DENIED_ERROR), + MYF(0), + "ANY", + thd->priv_user, + thd->host_or_ip, + fld->field_name, + tab); + /* TODO: should be removed to have only one send_error */ + send_error(thd); + DBUG_RETURN(1); + } + } +#endif } - /* - 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); + 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 (thd->current_arena && + thd->lex->current_select->first_execution) + { + Item_field *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 + */ + item->changed_during_fix_field= it->ref(); + } + } /* All fields are used */ table->used_fields=table->fields; @@ -2452,6 +2741,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, my_error(ER_NO_TABLES_USED,MYF(0)); else my_error(ER_BAD_TABLE_ERROR,MYF(0),table_name); + send_error(thd); } DBUG_RETURN(!found); } @@ -2473,7 +2763,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) DBUG_ENTER("setup_conds"); thd->set_query_id=1; - + select_lex->cond_count= 0; if (*conds) { @@ -2485,18 +2775,19 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) /* Check if we are using outer joins */ - for (TABLE_LIST *table=tables ; table ; table=table->next) + for (TABLE_LIST *table= tables; table; table= table->next_local) { TABLE_LIST *embedded; TABLE_LIST *embedding= table; do - { + { embedded= embedding; if (embedded->on_expr) { /* Make a join an a expression */ thd->where="on clause"; - if (embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) || + if (!embedded->on_expr->fixed && + embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) || embedded->on_expr->check_cols(1)) DBUG_RETURN(1); select_lex->cond_count++; @@ -2543,33 +2834,59 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) thd->set_n_backup_item_arena(arena, &backup); TABLE *t1=tab1->table; TABLE *t2=tab2->table; + /* allocate 2 variables on stack to avoid pool alloaction */ + Field_iterator_table table_iter; + Field_iterator_view view_iter; + Field_iterator *iterator; Item_cond_and *cond_and=new Item_cond_and(); if (!cond_and) // If not out of memory DBUG_RETURN(1); cond_and->top_level_item(); - Field **t1_field, *t2_field; - for (t1_field= t1->field; (*t1_field); t1_field++) + if (table->field_translation) { - const char *t1_field_name= (*t1_field)->field_name; + iterator= &view_iter; + view_iter.set(tab1); + } + else + { + iterator= &table_iter; + table_iter.set(tab1); + } + + Field *t1_field, *t2_field; + Item *item_t2; + for (; iterator->end(); iterator->next()) + { + const char *t1_field_name= iterator->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, + if ((t2_field= find_field_in_table(thd, tab2, t1_field_name, + strlen(t1_field_name), &item_t2, + 0, 0, 0, ¬_used_field_index))) { - Item_func_eq *tmp=new Item_func_eq(new Item_field(*t1_field), - new Item_field(t2_field)); + if (t2_field != view_ref_found) + { + if (!(item_t2= new Item_field(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; - /* 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; select_lex->cond_count+= cond_and->list.elements; // to prevent natural join processing during PS re-execution @@ -2856,3 +3173,54 @@ 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_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, uint db_stat, uint prgflag, + uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc, + MEM_ROOT *mem_root) +{ + DBUG_ENTER("open_new_frm"); + LEX_STRING pathstr; + pathstr.str= (char *)path; + pathstr.length= strlen(path); + File_parser *parser= sql_parse_prepare(&pathstr, mem_root, 1); + if (parser) + { + if (!strncmp("VIEW", parser->type()->str, parser->type()->length)) + { + if (mysql_make_view(parser, table_desc)) + { + bzero(outparam, sizeof(*outparam)); // do not run repair + DBUG_RETURN(1); + } + } + else + { + /* only VIEWs are supported now */ + my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), path, parser->type()->str); + bzero(outparam, sizeof(outparam)); // do not run repair + DBUG_RETURN(1); + } + } + else + { + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} |