diff options
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r-- | sql/sp_head.cc | 289 |
1 files changed, 248 insertions, 41 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d52474998a8..260e5aacd67 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -23,6 +23,7 @@ #include "sp.h" #include "sp_pcontext.h" #include "sp_rcontext.h" +#include "sp_cache.h" Item_result sp_map_result_type(enum enum_field_types type) @@ -259,11 +260,14 @@ sp_head::sp_head() :Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE) { + extern byte * + sp_table_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); state= INITIALIZED; m_backpatch.empty(); m_lex.empty(); + hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); DBUG_VOID_RETURN; } @@ -439,6 +443,8 @@ sp_head::destroy() if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left delete lex; } + if (m_sptabs.array.buffer) + hash_free(&m_sptabs); DBUG_VOID_RETURN; } @@ -799,48 +805,10 @@ sp_head::restore_lex(THD *thd) oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); // Collect some data from the sub statement lex. - sp_merge_funs(oldlex, sublex); -#ifdef NOT_USED_NOW - // QQ We're not using this at the moment. - if (sublex.sql_command == SQLCOM_CALL) - { - // It would be slightly faster to keep the list sorted, but we need - // an "insert before" method to do that. - char *proc= sublex.udf.name.str; - - List_iterator_fast<char *> li(m_calls); - char **it; - - while ((it= li++)) - if (my_strcasecmp(system_charset_info, proc, *it) == 0) - break; - if (! it) - m_calls.push_back(&proc); - - } + sp_merge_hash(&oldlex->spfuns, &sublex->spfuns); + sp_merge_hash(&oldlex->spprocs, &sublex->spprocs); // Merge used tables - // QQ ...or just open tables in thd->open_tables? - // This is not entirerly clear at the moment, but for now, we collect - // tables here. - for (sl= sublex.all_selects_list ; - sl ; - sl= sl->next_select()) - { - for (TABLE_LIST *tables= sl->get_table_list() ; - tables ; - tables= tables->next) - { - List_iterator_fast<char *> li(m_tables); - char **tb; - - while ((tb= li++)) - if (my_strcasecmp(system_charset_info, tables->table_name, *tb) == 0) - break; - if (! tb) - m_tables.push_back(&tables->table_name); - } - } -#endif + sp_merge_table_list(thd, &m_sptabs, sublex->query_tables, sublex); if (! sublex->sp_lex_in_use) delete sublex; thd->lex= oldlex; @@ -1864,3 +1832,242 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ + +/* + * Table merge hash table + * + */ +typedef struct st_sp_table +{ + LEX_STRING qname; + bool temp; + TABLE_LIST *table; +} SP_TABLE; + +byte * +sp_table_key(const byte *ptr, uint *plen, my_bool first) +{ + SP_TABLE *tab= (SP_TABLE *)ptr; + *plen= tab->qname.length; + return (byte *)tab->qname.str; +} + +/* + * Merge the table list into the hash table. + * If the optional lex is provided, it's used to check and set + * the flag for creation of a temporary table. + */ +bool +sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table, + LEX *lex_for_tmp_check) +{ + for (; table ; table= table->next_global) + if (!table->derived && + (!table->select_lex || + !(table->select_lex->options & OPTION_SCHEMA_TABLE))) + { + char tname[64+1+64+1+64+1]; // db.table.alias\0 + uint tlen, alen; + SP_TABLE *tab; + + tlen= table->db_length; + memcpy(tname, table->db, tlen); + tname[tlen++]= '.'; + memcpy(tname+tlen, table->table_name, table->table_name_length); + tlen+= table->table_name_length; + tname[tlen++]= '.'; + alen= strlen(table->alias); + memcpy(tname+tlen, table->alias, alen); + tlen+= alen; + tname[tlen]= '\0'; + + if ((tab= (SP_TABLE *)hash_search(h, (byte *)tname, tlen))) + { + if (tab->table->lock_type < table->lock_type) + tab->table= table; // Use the table with the highest lock type + } + else + { + if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) + return FALSE; + tab->qname.length= tlen; + tab->qname.str= (char *)thd->strmake(tname, tab->qname.length); + if (!tab->qname.str) + return FALSE; + if (lex_for_tmp_check && + lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && + lex_for_tmp_check->query_tables == table && + lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) + tab->temp= TRUE; + tab->table= table; + my_hash_insert(h, (byte *)tab); + } + } + return TRUE; +} + +void +sp_merge_routine_tables(THD *thd, LEX *lex) +{ + uint i; + + for (i= 0 ; i < lex->spfuns.records ; i++) + { + sp_head *sp; + LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spfuns, i); + sp_name name(*ls); + + name.m_qname= *ls; + if ((sp= sp_cache_lookup(&thd->sp_func_cache, &name))) + sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs); + } + for (i= 0 ; i < lex->spprocs.records ; i++) + { + sp_head *sp; + LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spprocs, i); + sp_name name(*ls); + + name.m_qname= *ls; + if ((sp= sp_cache_lookup(&thd->sp_proc_cache, &name))) + sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs); + } +} + +void +sp_merge_table_hash(HASH *hdst, HASH *hsrc) +{ + for (uint i=0 ; i < hsrc->records ; i++) + { + SP_TABLE *tabdst; + SP_TABLE *tabsrc= (SP_TABLE *)hash_element(hsrc, i); + + if (! (tabdst= (SP_TABLE *)hash_search(hdst, + tabsrc->qname.str, + tabsrc->qname.length))) + { + my_hash_insert(hdst, (byte *)tabsrc); + } + else + { + if (tabdst->table->lock_type < tabsrc->table->lock_type) + tabdst->table= tabsrc->table; // Use the highest lock type + } + } +} + +TABLE_LIST * +sp_hash_to_table_list(THD *thd, HASH *h) +{ + uint i; + TABLE_LIST *tables= NULL; + DBUG_ENTER("sp_hash_to_table_list"); + + for (i=0 ; i < h->records ; i++) + { + SP_TABLE *stab= (SP_TABLE *)hash_element(h, i); + if (stab->temp) + continue; + TABLE_LIST *table, *otable= stab->table; + + if (! (table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) + return NULL; + table->db= otable->db; + table->db_length= otable->db_length; + table->alias= otable->alias; + table->table_name= otable->table_name; + table->table_name_length= otable->table_name_length; + table->lock_type= otable->lock_type; + table->updating= otable->updating; + table->force_index= otable->force_index; + table->ignore_leaves= otable->ignore_leaves; + table->derived= otable->derived; + table->schema_table= otable->schema_table; + table->select_lex= otable->select_lex; + table->cacheable_table= otable->cacheable_table; + table->use_index= otable->use_index; + table->ignore_index= otable->ignore_index; + table->option= otable->option; + + table->next_global= tables; + tables= table; + } + DBUG_RETURN(tables); +} + +bool +sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables) +{ + DBUG_ENTER("sp_open_and_lock_tables"); + bool ret; + + thd->in_lock_tables= 1; + thd->options|= OPTION_TABLE_LOCK; + if (simple_open_n_lock_tables(thd, tables)) + { + thd->options&= ~(ulong)(OPTION_TABLE_LOCK); + ret= FALSE; + } + else + { +#if 0 + // QQ What about this? +#ifdef HAVE_QUERY_CACHE + if (thd->variables.query_cache_wlock_invalidate) + query_cache.invalidate_locked_for_write(first_table); // QQ first_table? +#endif /* HAVE_QUERY_CACHE */ +#endif + thd->locked_tables= thd->lock; + thd->lock= 0; + ret= TRUE; + } + thd->in_lock_tables= 0; + DBUG_RETURN(ret); +} + +void +sp_unlock_tables(THD *thd) +{ + thd->lock= thd->locked_tables; + thd->locked_tables= 0; + close_thread_tables(thd); // Free tables + if (thd->options & OPTION_TABLE_LOCK) + { +#if 0 + // QQ What about this? + end_active_trans(thd); +#endif + thd->options&= ~(ulong)(OPTION_TABLE_LOCK); + } + if (thd->global_read_lock) + unlock_global_read_lock(thd); +} + +/* + * Simple function for adding an explicetly named (systems) table to + * the global table list, e.g. "mysql", "proc". + * + */ +TABLE_LIST * +sp_add_to_query_tables(THD *thd, LEX *lex, + const char *db, const char *name, + thr_lock_type locktype) +{ + TABLE_LIST *table; + + if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) + { + my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST)); + return NULL; + } + table->db_length= strlen(db); + table->db= thd->strmake(db, table->db_length); + table->table_name_length= strlen(name); + table->table_name= thd->strmake(name, table->table_name_length); + table->alias= thd->strdup(name); + table->lock_type= locktype; + table->select_lex= lex->current_select; // QQ? + table->cacheable_table= 1; + + lex->add_to_query_tables(table); + return table; +} |