diff options
author | kostja@bodhi.(none) <> | 2007-07-16 23:31:36 +0400 |
---|---|---|
committer | kostja@bodhi.(none) <> | 2007-07-16 23:31:36 +0400 |
commit | 88fc7cab26425a5dc43aff02cb84e1363ce0129d (patch) | |
tree | 53d9d30f94c45fc9b3f51662dd10574784b16e0a /sql | |
parent | 06d656b808c26841007d00512ad91ec0dcbae19f (diff) | |
parent | 5466b0df1407b0412a5845e4fd43c4ae0d1ba5b5 (diff) | |
download | mariadb-git-88fc7cab26425a5dc43aff02cb84e1363ce0129d.tar.gz |
Merge bodhi.(none):/opt/local/work/mysql-5.0-runtime
into bodhi.(none):/opt/local/work/mysql-5.1-runtime
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.h | 45 | ||||
-rw-r--r-- | sql/item.cc | 2 | ||||
-rw-r--r-- | sql/item.h | 10 | ||||
-rw-r--r-- | sql/mysql_priv.h | 6 | ||||
-rw-r--r-- | sql/sp.cc | 63 | ||||
-rw-r--r-- | sql/sp_head.cc | 53 | ||||
-rw-r--r-- | sql/sp_head.h | 6 | ||||
-rw-r--r-- | sql/sql_base.cc | 2 | ||||
-rw-r--r-- | sql/sql_db.cc | 8 | ||||
-rw-r--r-- | sql/sql_lex.cc | 60 | ||||
-rw-r--r-- | sql/sql_lex.h | 6 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 59 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 14 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 40 | ||||
-rw-r--r-- | sql/sql_trigger.h | 8 | ||||
-rw-r--r-- | sql/sql_udf.h | 1 | ||||
-rw-r--r-- | sql/sql_view.cc | 13 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 25 | ||||
-rw-r--r-- | sql/table.cc | 221 | ||||
-rw-r--r-- | sql/table.h | 77 |
22 files changed, 528 insertions, 202 deletions
diff --git a/sql/handler.h b/sql/handler.h index 09de9a3873a..c4e45e5b8f1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1639,16 +1639,49 @@ public: /* Type of table for caching query */ virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } - /* ask handler about permission to cache table when query is to be cached */ + + + /** + @brief Register a named table with a call back function to the query cache. + + @param thd The thread handle + @param table_key A pointer to the table name in the table cache + @param key_length The length of the table name + @param[out] engine_callback The pointer to the storage engine call back + function + @param[out] engine_data Storage engine specific data which could be + anything + + This method offers the storage engine, the possibility to store a reference + to a table name which is going to be used with query cache. + The method is called each time a statement is written to the cache and can + be used to verify if a specific statement is cachable. It also offers + the possibility to register a generic (but static) call back function which + is called each time a statement is matched against the query cache. + + @note If engine_data supplied with this function is different from + engine_data supplied with the callback function, and the callback returns + FALSE, a table invalidation on the current table will occur. + + @return Upon success the engine_callback will point to the storage engine + call back function, if any, and engine_data will point to any storage + engine data used in the specific implementation. + @retval TRUE Success + @retval FALSE The specified table or current statement should not be + cached + */ + virtual my_bool register_query_cache_table(THD *thd, char *table_key, - uint key_length, - qc_engine_callback - *engine_callback, - ulonglong *engine_data) + uint key_length, + qc_engine_callback + *engine_callback, + ulonglong *engine_data) { *engine_callback= 0; - return 1; + return TRUE; } + + /* RETURN true Primary key (if there is one) is clustered key covering all fields diff --git a/sql/item.cc b/sql/item.cc index d7743c491eb..711a21ecbec 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5899,7 +5899,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) if (!arg->fixed) { bool res; - st_table_list *orig_next_table= context->last_name_resolution_table; + TABLE_LIST *orig_next_table= context->last_name_resolution_table; context->last_name_resolution_table= context->first_name_resolution_table; res= arg->fix_fields(thd, &arg); context->last_name_resolution_table= orig_next_table; diff --git a/sql/item.h b/sql/item.h index 6d993d72821..432da6c3a1c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -19,7 +19,7 @@ #endif class Protocol; -struct st_table_list; +struct TABLE_LIST; void item_init(void); /* Init item functions */ class Item_field; @@ -2442,14 +2442,6 @@ enum trg_action_time_type TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX }; -/* - Event on which trigger is invoked. -*/ -enum trg_event_type -{ - TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX -}; - class Table_triggers_list; /* diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f3a987ea744..40bb2f9509d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -531,9 +531,9 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define SHOW_LOG_STATUS_FREE "FREE" #define SHOW_LOG_STATUS_INUSE "IN USE" -struct st_table_list; +struct TABLE_LIST; class String; -void view_store_options(THD *thd, st_table_list *table, String *buff); +void view_store_options(THD *thd, TABLE_LIST *table, String *buff); /* Options to add_table_to_list() */ #define TL_OPTION_UPDATING 1 @@ -1372,7 +1372,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr); void close_temporary_tables(THD *thd); void close_tables_for_reopen(THD *thd, TABLE_LIST **tables); TABLE_LIST *find_table_in_list(TABLE_LIST *table, - st_table_list *TABLE_LIST::*link, + TABLE_LIST *TABLE_LIST::*link, const char *db_name, const char *table_name); TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, diff --git a/sql/sp.cc b/sql/sp.cc index 66c6c05c930..d806673c6f3 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -602,6 +602,15 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, (*sphp)->set_info(created, modified, &chistics, sql_mode); (*sphp)->set_creation_ctx(creation_ctx); (*sphp)->optimize(); + /* + Not strictly necessary to invoke this method here, since we know + that we've parsed CREATE PROCEDURE/FUNCTION and not an + UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to + maintain the invariant that this method is called for each + distinct statement, in case its logic is extended with other + types of analyses in future. + */ + newlex.set_trg_event_type_for_tables(); } } @@ -1912,32 +1921,40 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, TABLE_LIST *table) { int ret= 0; - Table_triggers_list *triggers= table->table->triggers; - if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key, - table->belong_to_view)) + + Sroutine_hash_entry **last_cached_routine_ptr= + (Sroutine_hash_entry **)lex->sroutines_list.next; + + if (static_cast<int>(table->lock_type) >= + static_cast<int>(TL_WRITE_ALLOW_WRITE)) { - Sroutine_hash_entry **last_cached_routine_ptr= - (Sroutine_hash_entry **)lex->sroutines_list.next; for (int i= 0; i < (int)TRG_EVENT_MAX; i++) { - for (int j= 0; j < (int)TRG_ACTION_MAX; j++) + if (table->trg_event_map & + static_cast<uint8>(1 << static_cast<int>(i))) { - sp_head *trigger_body= triggers->bodies[i][j]; - if (trigger_body) + for (int j= 0; j < (int)TRG_ACTION_MAX; j++) { - (void)trigger_body-> - add_used_tables_to_table_list(thd, &lex->query_tables_last, - table->belong_to_view); - sp_update_stmt_used_routines(thd, lex, - &trigger_body->m_sroutines, - table->belong_to_view); - trigger_body->propagate_attributes(lex); + /* We can have only one trigger per action type currently */ + sp_head *trigger= table->table->triggers->bodies[i][j]; + if (trigger && + add_used_routine(lex, thd->stmt_arena, &trigger->m_sroutines_key, + table->belong_to_view)) + { + trigger->add_used_tables_to_table_list(thd, &lex->query_tables_last, + table->belong_to_view); + trigger->propagate_attributes(lex); + sp_update_stmt_used_routines(thd, lex, + &trigger->m_sroutines, + table->belong_to_view); + } } } } - ret= sp_cache_routines_and_add_tables_aux(thd, lex, - *last_cached_routine_ptr, FALSE); } + ret= sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr, + FALSE, NULL); return ret; } @@ -2044,15 +2061,11 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db, DBUG_PRINT("enter", ("newdb: %s", new_db.str)); /* - Set new_db to an empty string if it's NULL, because mysql_change_db - requires a non-NULL argument. - new_db.str can be NULL only if we're restoring the old database after - execution of a stored procedure and there were no current database - selected. The stored procedure itself must always have its database - initialized. + A stored routine always belongs to some database. The + old database (old_db) might be NULL, but to restore the + old database we will use mysql_change_db. */ - if (new_db.str == NULL) - new_db.str= empty_c_string; + DBUG_ASSERT(new_db.str && new_db.length); if (thd->db) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d3a9787ee2b..a11c3c666c8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -512,12 +512,35 @@ sp_head::init(LEX *lex) */ lex->trg_table_fields.empty(); my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); - m_param_begin= m_param_end= m_body_begin= 0; - m_qname.str= m_db.str= m_name.str= m_params.str= - m_body.str= m_defstr.str= 0; - m_qname.length= m_db.length= m_name.length= m_params.length= - m_body.length= m_defstr.length= 0; + + m_param_begin= NULL; + m_param_end= NULL; + + m_body_begin= NULL ; + + m_qname.str= NULL; + m_qname.length= 0; + + m_db.str= NULL; + m_db.length= 0; + + m_name.str= NULL; + m_name.length= 0; + + m_params.str= NULL; + m_params.length= 0; + + m_body.str= NULL; + m_body.length= 0; + + m_defstr.str= NULL; + m_defstr.length= 0; + + m_sroutines_key.str= NULL; + m_sroutines_key.length= 0; + m_return_field_def.charset= NULL; + DBUG_VOID_RETURN; } @@ -543,9 +566,14 @@ sp_head::init_sp_name(THD *thd, sp_name *spname) if (spname->m_qname.length == 0) spname->init_qname(thd); - m_qname.length= spname->m_qname.length; - m_qname.str= strmake_root(thd->mem_root, spname->m_qname.str, - m_qname.length); + m_sroutines_key.length= spname->m_sroutines_key.length; + m_sroutines_key.str= memdup_root(thd->mem_root, + spname->m_sroutines_key.str, + spname->m_sroutines_key.length + 1); + m_sroutines_key.str[0]= static_cast<char>(m_type); + + m_qname.length= m_sroutines_key.length - 1; + m_qname.str= m_sroutines_key.str + 1; DBUG_VOID_RETURN; } @@ -1924,8 +1952,11 @@ sp_head::restore_lex(THD *thd) { DBUG_ENTER("sp_head::restore_lex"); LEX *sublex= thd->lex; - LEX *oldlex= (LEX *)m_lex.pop(); + LEX *oldlex; + + sublex->set_trg_event_type_for_tables(); + oldlex= (LEX *)m_lex.pop(); if (! oldlex) return; // Nothing to restore @@ -3545,6 +3576,7 @@ typedef struct st_sp_table thr_lock_type lock_type; /* lock type used for prelocking */ uint lock_count; uint query_lock_count; + uint8 trg_event_map; } SP_TABLE; uchar * @@ -3631,6 +3663,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->query_lock_count++; if (tab->query_lock_count > tab->lock_count) tab->lock_count++; + tab->trg_event_map|= table->trg_event_map; } else { @@ -3652,6 +3685,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->db_length= table->db_length; tab->lock_type= table->lock_type; tab->lock_count= tab->query_lock_count= 1; + tab->trg_event_map= table->trg_event_map; my_hash_insert(&m_sptabs, (uchar *)tab); } } @@ -3729,6 +3763,7 @@ sp_head::add_used_tables_to_table_list(THD *thd, table->cacheable_table= 1; table->prelocking_placeholder= 1; table->belong_to_view= belong_to_view; + table->trg_event_map= stab->trg_event_map; /* Everyting else should be zeroed */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 490fda67bfe..f6764fbc90e 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -184,6 +184,12 @@ public: st_sp_chistics *m_chistics; ulong m_sql_mode; // For SHOW CREATE and execution LEX_STRING m_qname; // db.name + /** + Key representing routine in the set of stored routines used by statement. + [routine_type]db.name\0 + @sa sp_name::m_sroutines_key + */ + LEX_STRING m_sroutines_key; LEX_STRING m_db; LEX_STRING m_name; LEX_STRING m_params; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fb5fd2ec627..6fd57c5a428 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1476,7 +1476,7 @@ void close_temporary_tables(THD *thd) */ TABLE_LIST *find_table_in_list(TABLE_LIST *table, - st_table_list *TABLE_LIST::*link, + TABLE_LIST *TABLE_LIST::*link, const char *db_name, const char *table_name) { diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 8b0e371be43..575db5b80f7 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1397,10 +1397,10 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) { if (force_switch) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR)); - - /* Change db to NULL. */ + /* + This can only happen when we restore the old db in THD after + execution of a routine is complete. Change db to NULL. + */ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 639f0d2325d..5e91f147033 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2297,7 +2297,7 @@ bool st_lex::need_correct_ident() VIEW_CHECK_CASCADED CHECK OPTION CASCADED */ -uint8 st_lex::get_effective_with_check(st_table_list *view) +uint8 st_lex::get_effective_with_check(TABLE_LIST *view) { if (view->select_lex->master_unit() == &unit && which_check_option_applicable()) @@ -2306,6 +2306,43 @@ uint8 st_lex::get_effective_with_check(st_table_list *view) } +/** + This method should be called only during parsing. + It is aware of compound statements (stored routine bodies) + and will initialize the destination with the default + database of the stored routine, rather than the default + database of the connection it is parsed in. + E.g. if one has no current database selected, or current database + set to 'bar' and then issues: + + CREATE PROCEDURE foo.p1() BEGIN SELECT * FROM t1 END// + + t1 is meant to refer to foo.t1, not to bar.t1. + + This method is needed to support this rule. + + @return TRUE in case of error (parsing should be aborted, FALSE in + case of success +*/ + +bool +st_lex::copy_db_to(char **p_db, uint *p_db_length) const +{ + if (sphead) + { + DBUG_ASSERT(sphead->m_db.str && sphead->m_db.length); + /* + It is safe to assign the string by-pointer, both sphead and + its statements reside in the same memory root. + */ + *p_db= sphead->m_db.str; + if (p_db_length) + *p_db_length= sphead->m_db.length; + return FALSE; + } + return thd->copy_db_to(p_db, p_db_length); +} + /* initialize limit counters @@ -2329,6 +2366,27 @@ void st_select_lex_unit::set_limit(SELECT_LEX *sl) } +/** + Update the parsed tree with information about triggers that + may be fired when executing this statement. +*/ + +void st_lex::set_trg_event_type_for_tables() +{ + /* + Do not iterate over sub-selects, only the tables in the outermost + SELECT_LEX can be modified, if any. + */ + TABLE_LIST *tables= select_lex.get_table_list(); + + while (tables) + { + tables->set_trg_event_type(this); + tables= tables->next_local; + } +} + + /* Unlink the first table from the global table list and the first table from outer select (lex->select_lex) local list diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 254403fe736..09ace624559 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1732,6 +1732,8 @@ typedef struct st_lex : public Query_tables_list un->uncacheable|= cause; } } + void set_trg_event_type_for_tables(); + TABLE_LIST *unlink_first_table(bool *link_to_local); void link_first_table_back(TABLE_LIST *first, bool link_to_local); void first_lists_tables_same(); @@ -1741,7 +1743,7 @@ typedef struct st_lex : public Query_tables_list bool can_not_use_merged(); bool only_view_structure(); bool need_correct_ident(); - uint8 get_effective_with_check(st_table_list *view); + uint8 get_effective_with_check(TABLE_LIST *view); /* Is this update command where 'WHITH CHECK OPTION' clause is important @@ -1780,6 +1782,8 @@ typedef struct st_lex : public Query_tables_list context_stack.pop(); } + bool copy_db_to(char **p_db, uint *p_db_length) const; + Name_resolution_context *current_context() { return context_stack.head(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 48177a5f350..10ecb086730 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5392,8 +5392,9 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, (thd->query_length= (ulong)(*found_semicolon - thd->query))) thd->query_length--; /* Actually execute the query */ - mysql_execute_command(thd); - query_cache_end_of_result(thd); + lex->set_trg_event_type_for_tables(); + mysql_execute_command(thd); + query_cache_end_of_result(thd); } } } @@ -5680,7 +5681,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->db= table->db.str; ptr->db_length= table->db.length; } - else if (thd->copy_db_to(&ptr->db, &ptr->db_length)) + else if (lex->copy_db_to(&ptr->db, &ptr->db_length)) DBUG_RETURN(0); ptr->alias= alias_str; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 406e242cada..a97bd908468 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1941,13 +1941,6 @@ void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length) /* Statement map deletes statement on erase */ thd->stmt_map.erase(stmt); } - else - { - const char *format= "[%lu] %.*b"; - general_log_print(thd, COM_STMT_PREPARE, format, stmt->id, - stmt->query_length, stmt->query); - - } /* check_prepared_statemnt sends the metadata packet in case of success */ DBUG_VOID_RETURN; } @@ -2330,12 +2323,6 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) test(flags & (ulong) CURSOR_TYPE_READ_ONLY)); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - if (error == 0) - { - const char *format= "[%lu] %.*b"; - general_log_print(thd, COM_STMT_EXECUTE, format, stmt->id, - thd->query_length, thd->query); - } DBUG_VOID_RETURN; set_params_data_err: @@ -2880,6 +2867,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) error= parse_sql(thd, &lip, NULL) || thd->net.report_error || init_param_array(this); + lex->set_trg_event_type_for_tables(); /* While doing context analysis of the query (in check_prepared_statement) @@ -2929,6 +2917,29 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) init_stmt_after_parse(lex); state= Query_arena::PREPARED; flags&= ~ (uint) IS_IN_USE; + + /* + Log COM_EXECUTE to the general log. Note, that in case of SQL + prepared statements this causes two records to be output: + + Query PREPARE stmt from @user_variable + Prepare <statement SQL text> + + This is considered user-friendly, since in the + second log entry we output the actual statement text. + + Do not print anything if this is an SQL prepared statement and + we're inside a stored procedure (also called Dynamic SQL) -- + sub-statements inside stored procedures are not logged into + the general log. + */ + if (thd->spcont == NULL) + { + const char *format= "[%lu] %.*b"; + general_log_print(thd, COM_STMT_PREPARE, format, id, + query_length, query); + + } } DBUG_RETURN(error); } @@ -3075,6 +3086,28 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) if (state == Query_arena::PREPARED) state= Query_arena::EXECUTED; + /* + Log COM_EXECUTE to the general log. Note, that in case of SQL + prepared statements this causes two records to be output: + + Query EXECUTE <statement name> + Execute <statement SQL text> + + This is considered user-friendly, since in the + second log entry we output values of parameter markers. + + Do not print anything if this is an SQL prepared statement and + we're inside a stored procedure (also called Dynamic SQL) -- + sub-statements inside stored procedures are not logged into + the general log. + */ + if (error == 0 && thd->spcont == NULL) + { + const char *format= "[%lu] %.*b"; + general_log_print(thd, COM_STMT_EXECUTE, format, id, + thd->query_length, thd->query); + } + error: flags&= ~ (uint) IS_IN_USE; return error; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3cda4029161..dc8a10a013f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15752,11 +15752,11 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables) Print table as it should be in join list SYNOPSIS - st_table_list::print(); + TABLE_LIST::print(); str string where table should bbe printed */ -void st_table_list::print(THD *thd, String *str) +void TABLE_LIST::print(THD *thd, String *str) { if (nested_join) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b65515c9e01..e503d0acd84 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2824,7 +2824,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) } -static int get_schema_tables_record(THD *thd, struct st_table_list *tables, +static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3016,7 +3016,7 @@ static int get_schema_tables_record(THD *thd, struct st_table_list *tables, } -static int get_schema_column_record(THD *thd, struct st_table_list *tables, +static int get_schema_column_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3523,7 +3523,7 @@ err: } -static int get_schema_stat_record(THD *thd, struct st_table_list *tables, +static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3613,7 +3613,7 @@ static int get_schema_stat_record(THD *thd, struct st_table_list *tables, } -static int get_schema_views_record(THD *thd, struct st_table_list *tables, +static int get_schema_views_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3731,7 +3731,7 @@ bool store_constraints(THD *thd, TABLE *table, const char *db, } -static int get_schema_constraints_record(THD *thd, struct st_table_list *tables, +static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3832,7 +3832,7 @@ static bool store_trigger(THD *thd, TABLE *table, const char *db, } -static int get_schema_triggers_record(THD *thd, struct st_table_list *tables, +static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) @@ -3909,7 +3909,7 @@ void store_key_column_usage(TABLE *table, const char*db, const char *tname, static int get_schema_key_column_usage_record(THD *thd, - struct st_table_list *tables, + TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 55eae2f5ea5..fa0154dc39e 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1212,17 +1212,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, table->triggers= triggers; /* - Construct key that will represent triggers for this table in the set - of routines used by statement. - */ - triggers->sroutines_key.length= 1+strlen(db)+1+strlen(table_name)+1; - if (!(triggers->sroutines_key.str= (char*) - alloc_root(&table->mem_root, triggers->sroutines_key.length))) - DBUG_RETURN(1); - triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER; - strxmov(triggers->sroutines_key.str+1, db, ".", table_name, NullS); - - /* TODO: This could be avoided if there is no triggers for UPDATE and DELETE. */ @@ -1270,6 +1259,15 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_ASSERT(lex.sphead == 0); goto err_with_lex_cleanup; } + /* + Not strictly necessary to invoke this method here, since we know + that we've parsed CREATE TRIGGER and not an + UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to + maintain the invariant that this method is called for each + distinct statement, in case its logic is extended with other + types of analyses in future. + */ + lex.set_trg_event_type_for_tables(); lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); @@ -1899,8 +1897,9 @@ bool Table_triggers_list::process_triggers(THD *thd, { bool err_status; Sub_statement_state statement_state; + sp_head *sp_trigger= bodies[event][time_type]; - if (!bodies[event][time_type]) + if (sp_trigger == NULL) return FALSE; if (old_row_is_record1) @@ -1913,15 +1912,20 @@ bool Table_triggers_list::process_triggers(THD *thd, new_field= record1_field; old_field= trigger_table->field; } + /* + This trigger must have been processed by the pre-locking + algorithm. + */ + DBUG_ASSERT(trigger_table->pos_in_table_list->trg_event_map & + static_cast<uint>(1 << static_cast<int>(event))); thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); err_status= - bodies[event][time_type]->execute_trigger( - thd, - &trigger_table->s->db, - &trigger_table->s->table_name, - &subject_table_grants[event][time_type]); + sp_trigger->execute_trigger(thd, + &trigger_table->s->db, + &trigger_table->s->table_name, + &subject_table_grants[event][time_type]); thd->restore_sub_statement_state(&statement_state); @@ -1935,7 +1939,7 @@ bool Table_triggers_list::process_triggers(THD *thd, SYNOPSIS mark_fields_used() thd Current thread context - event Type of event triggers for which we are going to inspect + event Type of event triggers for which we are going to ins DESCRIPTION This method marks fields of subject table which are read/set in its diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index bfdbae12bdc..8f6b08c927f 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -56,14 +56,6 @@ class Table_triggers_list: public Sql_alloc updating trigger definitions during RENAME TABLE. */ List<LEX_STRING> on_table_names_list; - /* - Key representing triggers for this table in set of all stored - routines used by statement. - TODO: We won't need this member once triggers namespace will be - database-wide instead of table-wide because then we will be able - to use key based on sp_name as for other stored routines. - */ - LEX_STRING sroutines_key; /* Grant information for each trigger (pair: subject table, trigger definer). diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 3cd9343610c..4b8b492698e 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -47,7 +47,6 @@ typedef struct st_udf_func } udf_func; class Item_result_field; -struct st_table_list; class udf_handler :public Sql_alloc { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index ce311f5d4a2..9a46bbc39e4 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1199,7 +1199,20 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, */ for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local) tbl->lock_type= table->lock_type; + /* + If the view is mergeable, we might want to + INSERT/UPDATE/DELETE into tables of this view. Preserve the + original sql command and 'duplicates' of the outer lex. + This is used later in set_trg_event_type_for_command. + */ + lex->sql_command= old_lex->sql_command; + lex->duplicates= old_lex->duplicates; } + /* + This method has a dependency on the proper lock type being set, + so in case of views should be called here. + */ + lex->set_trg_event_type_for_tables(); /* If we are opening this view as part of implicit LOCK TABLES, then diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index df83e1d2e25..08ce421ef86 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1940,13 +1940,13 @@ sp_name: } | ident { - THD *thd= YYTHD; + LEX *lex= Lex; LEX_STRING db; if (check_routine_name(&$1)) { MYSQL_YYABORT; } - if (thd->copy_db_to(&db.str, &db.length)) + if (lex->copy_db_to(&db.str, &db.length)) MYSQL_YYABORT; $$= new sp_name(db, $1, false); if ($$) @@ -5130,14 +5130,13 @@ alter: Lex->create_info.default_table_charset= NULL; Lex->create_info.used_fields= 0; } - opt_create_database_options + create_database_options { - THD *thd= YYTHD; - LEX *lex= thd->lex; + LEX *lex=Lex; lex->sql_command=SQLCOM_ALTER_DB; lex->name= $3; if (lex->name.str == NULL && - thd->copy_db_to(&lex->name.str, &lex->name.length)) + lex->copy_db_to(&lex->name.str, &lex->name.length)) MYSQL_YYABORT; } | ALTER PROCEDURE sp_name @@ -5591,12 +5590,11 @@ alter_list_item: } | RENAME opt_to table_ident { - THD *thd= YYTHD; - LEX *lex= thd->lex; + LEX *lex=Lex; size_t dummy; lex->select_lex.db=$3->db.str; if (lex->select_lex.db == NULL && - thd->copy_db_to(&lex->select_lex.db, &dummy)) + lex->copy_db_to(&lex->select_lex.db, &dummy)) { MYSQL_YYABORT; } @@ -10881,10 +10879,9 @@ require_list_element: grant_ident: '*' { - THD *thd= YYTHD; - LEX *lex= thd->lex; + LEX *lex= Lex; size_t dummy; - if (thd->copy_db_to(&lex->current_select->db, &dummy)) + if (lex->copy_db_to(&lex->current_select->db, &dummy)) MYSQL_YYABORT; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; @@ -11530,12 +11527,12 @@ trigger_tail: MYSQL_YYABORT; sp->reset_thd_mem_root(thd); sp->init(lex); + sp->m_type= TYPE_ENUM_TRIGGER; sp->init_sp_name(thd, $3); lex->stmt_definition_begin= $2; lex->ident.str= $7; lex->ident.length= $11 - $7; - sp->m_type= TYPE_ENUM_TRIGGER; lex->sphead= sp; lex->spname= $3; /* @@ -11611,9 +11608,9 @@ sp_tail: sp= new sp_head(); sp->reset_thd_mem_root(YYTHD); sp->init(lex); + sp->m_type= TYPE_ENUM_PROCEDURE; sp->init_sp_name(YYTHD, $3); - sp->m_type= TYPE_ENUM_PROCEDURE; lex->sphead= sp; /* * We have to turn of CLIENT_MULTI_QUERIES while parsing a diff --git a/sql/table.cc b/sql/table.cc index 27a93b85fb5..6678073e145 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2849,15 +2849,144 @@ void st_table::reset_item_list(List<Item> *item_list) const } } + +/** + Set the initial purpose of this TABLE_LIST object in the list of + used tables. We need to track this information on table-by- + table basis, since when this table becomes an element of the + pre-locked list, it's impossible to identify which SQL + sub-statement it has been originally used in. + + E.g.: + + User request: SELECT * FROM t1 WHERE f1(); + FUNCTION f1(): DELETE FROM t2; RETURN 1; + BEFORE DELETE trigger on t2: INSERT INTO t3 VALUES (old.a); + + For this user request, the pre-locked list will contain t1, t2, t3 + table elements, each needed for different DML. + + This method is called immediately after parsing for tables + of the table list of the top-level select lex. + + The trigger event map is updated to reflect INSERT, UPDATE, DELETE, + REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE .. + REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE + clause. +*/ + +void +TABLE_LIST::set_trg_event_type(const st_lex *lex) +{ + enum trg_event_type trg_event; + + /* + Some auxiliary operations + (e.g. GRANT processing) create TABLE_LIST instances outside + the parser. Additionally, some commands (e.g. OPTIMIZE) change + the lock type for a table only after parsing is done. Luckily, + these do not fire triggers and do not need to pre-load them. + For these TABLE_LISTs set_trg_event_type is never called, and + trg_event_map is always empty. That means that the pre-locking + algorithm will ignore triggers defined on these tables, if + any, and the execution will either fail with an assert in + sql_trigger.cc or with an error that a used table was not + pre-locked, in case of a production build. + + TODO: this usage pattern creates unnecessary module dependencies + and should be rewritten to go through the parser. + Table list instances created outside the parser in most cases + refer to mysql.* system tables. It is not allowed to have + a trigger on a system table, but keeping track of + initialization provides extra safety in case this limitation + is circumvented. + */ + + /* + This is a fast check to filter out statements that do + not change data, or tables on the right side, in case of + INSERT .. SELECT, CREATE TABLE .. SELECT and so on. + Here we also filter out OPTIMIZE statement and non-updateable + views, for which lock_type is TL_UNLOCK or TL_READ after + parsing. + */ + if (static_cast<int>(lock_type) < static_cast<int>(TL_WRITE_ALLOW_WRITE)) + return; + + switch (lex->sql_command) { + /* + Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE + clause, it will be handled later in this method. + */ + case SQLCOM_INSERT: /* fall through */ + case SQLCOM_INSERT_SELECT: + /* + LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT + triggers. + If the statement also has REPLACE clause, it will be + handled later in this method. + */ + case SQLCOM_LOAD: /* fall through */ + /* + REPLACE is semantically equivalent to INSERT. In case + of a primary or unique key conflict, it deletes the old + record and inserts a new one. So we also may need to + fire ON DELETE triggers. This functionality is handled + later in this method. + */ + case SQLCOM_REPLACE: /* fall through */ + case SQLCOM_REPLACE_SELECT: + /* + CREATE TABLE ... SELECT defaults to INSERT if the table or + view already exists. REPLACE option of CREATE TABLE ... + REPLACE SELECT is handled later in this method. + */ + case SQLCOM_CREATE_TABLE: + trg_event= TRG_EVENT_INSERT; + break; + /* Basic update and multi-update */ + case SQLCOM_UPDATE: /* fall through */ + case SQLCOM_UPDATE_MULTI: + trg_event= TRG_EVENT_UPDATE; + break; + /* Basic delete and multi-delete */ + case SQLCOM_DELETE: /* fall through */ + case SQLCOM_DELETE_MULTI: + trg_event= TRG_EVENT_DELETE; + break; + default: + /* + OK to return, since value of 'duplicates' is irrelevant + for non-updating commands. + */ + return; + } + trg_event_map|= static_cast<uint8>(1 << static_cast<int>(trg_event)); + + switch (lex->duplicates) { + case DUP_UPDATE: + trg_event= TRG_EVENT_UPDATE; + break; + case DUP_REPLACE: + trg_event= TRG_EVENT_DELETE; + break; + case DUP_ERROR: + default: + return; + } + trg_event_map|= static_cast<uint8>(1 << static_cast<int>(trg_event)); +} + + /* calculate md5 of query SYNOPSIS - st_table_list::calc_md5() + TABLE_LIST::calc_md5() buffer buffer for md5 writing */ -void st_table_list::calc_md5(char *buffer) +void TABLE_LIST::calc_md5(char *buffer) { my_MD5_CTX context; uchar digest[16]; @@ -2882,10 +3011,10 @@ void st_table_list::calc_md5(char *buffer) it (it is a kind of optimisation) SYNOPSIS - st_table_list::set_underlying_merge() + TABLE_LIST::set_underlying_merge() */ -void st_table_list::set_underlying_merge() +void TABLE_LIST::set_underlying_merge() { TABLE_LIST *tbl; @@ -2920,7 +3049,7 @@ void st_table_list::set_underlying_merge() setup fields of placeholder of merged VIEW SYNOPSIS - st_table_list::setup_underlying() + TABLE_LIST::setup_underlying() thd - thread handler DESCRIPTION @@ -2933,9 +3062,9 @@ void st_table_list::set_underlying_merge() TRUE - error */ -bool st_table_list::setup_underlying(THD *thd) +bool TABLE_LIST::setup_underlying(THD *thd) { - DBUG_ENTER("st_table_list::setup_underlying"); + DBUG_ENTER("TABLE_LIST::setup_underlying"); if (!field_translation && merge_underlying_list) { @@ -2998,7 +3127,7 @@ bool st_table_list::setup_underlying(THD *thd) Prepare where expression of view SYNOPSIS - st_table_list::prep_where() + TABLE_LIST::prep_where() thd - thread handler conds - condition of this JOIN no_where_clause - do not build WHERE or ON outer qwery do not need it @@ -3012,10 +3141,10 @@ bool st_table_list::setup_underlying(THD *thd) TRUE - error */ -bool st_table_list::prep_where(THD *thd, Item **conds, +bool TABLE_LIST::prep_where(THD *thd, Item **conds, bool no_where_clause) { - DBUG_ENTER("st_table_list::prep_where"); + DBUG_ENTER("TABLE_LIST::prep_where"); for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { @@ -3115,7 +3244,7 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded) Prepare check option expression of table SYNOPSIS - st_table_list::prep_check_option() + TABLE_LIST::prep_check_option() thd - thread handler check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE, VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) @@ -3130,16 +3259,16 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded) This method builds check option condition to use it later on every call (usual execution or every SP/PS call). This method have to be called after WHERE preparation - (st_table_list::prep_where) + (TABLE_LIST::prep_where) RETURN FALSE - OK TRUE - error */ -bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) +bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) { - DBUG_ENTER("st_table_list::prep_check_option"); + DBUG_ENTER("TABLE_LIST::prep_check_option"); bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED; for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) @@ -3198,12 +3327,12 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) Hide errors which show view underlying table information SYNOPSIS - st_table_list::hide_view_error() + TABLE_LIST::hide_view_error() thd thread handler */ -void st_table_list::hide_view_error(THD *thd) +void TABLE_LIST::hide_view_error(THD *thd) { /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || @@ -3234,7 +3363,7 @@ void st_table_list::hide_view_error(THD *thd) table_to_find (TABLE) SYNOPSIS - st_table_list::find_underlying_table() + TABLE_LIST::find_underlying_table() table_to_find table to find RETURN @@ -3242,7 +3371,7 @@ void st_table_list::hide_view_error(THD *thd) found table reference */ -st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find) +TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find) { /* is this real table and table which we are looking for? */ if (table == table_to_find && merge_underlying_list == 0) @@ -3261,10 +3390,10 @@ st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find) cleunup items belonged to view fields translation table SYNOPSIS - st_table_list::cleanup_items() + TABLE_LIST::cleanup_items() */ -void st_table_list::cleanup_items() +void TABLE_LIST::cleanup_items() { if (!field_translation) return; @@ -3280,7 +3409,7 @@ void st_table_list::cleanup_items() check CHECK OPTION condition SYNOPSIS - st_table_list::view_check_option() + TABLE_LIST::view_check_option() ignore_failure ignore check option fail RETURN @@ -3289,7 +3418,7 @@ void st_table_list::cleanup_items() VIEW_CHECK_SKIP FAILED, but continue */ -int st_table_list::view_check_option(THD *thd, bool ignore_failure) +int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) { if (check_option && check_option->val_int() == 0) { @@ -3314,7 +3443,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) table belong to given mask SYNOPSIS - st_table_list::check_single_table() + TABLE_LIST::check_single_table() table_arg reference on variable where to store found table (should be 0 on call, to find table, or point to table for unique test) @@ -3326,9 +3455,9 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) TRUE found several tables */ -bool st_table_list::check_single_table(st_table_list **table_arg, +bool TABLE_LIST::check_single_table(TABLE_LIST **table_arg, table_map map, - st_table_list *view_arg) + TABLE_LIST *view_arg) { for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { @@ -3361,7 +3490,7 @@ bool st_table_list::check_single_table(st_table_list **table_arg, TRUE - out of memory */ -bool st_table_list::set_insert_values(MEM_ROOT *mem_root) +bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root) { if (table) { @@ -3385,7 +3514,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) Test if this is a leaf with respect to name resolution. SYNOPSIS - st_table_list::is_leaf_for_name_resolution() + TABLE_LIST::is_leaf_for_name_resolution() DESCRIPTION A table reference is a leaf with respect to name resolution if @@ -3397,7 +3526,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) RETURN TRUE if a leaf, FALSE otherwise. */ -bool st_table_list::is_leaf_for_name_resolution() +bool TABLE_LIST::is_leaf_for_name_resolution() { return (view || is_natural_join || is_join_columns_complete || !nested_join); @@ -3409,7 +3538,7 @@ bool st_table_list::is_leaf_for_name_resolution() respect to name resolution. SYNOPSIS - st_table_list::first_leaf_for_name_resolution() + TABLE_LIST::first_leaf_for_name_resolution() DESCRIPTION Given that 'this' is a nested table reference, recursively walk @@ -3427,7 +3556,7 @@ bool st_table_list::is_leaf_for_name_resolution() else return 'this' */ -TABLE_LIST *st_table_list::first_leaf_for_name_resolution() +TABLE_LIST *TABLE_LIST::first_leaf_for_name_resolution() { TABLE_LIST *cur_table_ref; NESTED_JOIN *cur_nested_join; @@ -3467,7 +3596,7 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() respect to name resolution. SYNOPSIS - st_table_list::last_leaf_for_name_resolution() + TABLE_LIST::last_leaf_for_name_resolution() DESCRIPTION Given that 'this' is a nested table reference, recursively walk @@ -3485,7 +3614,7 @@ TABLE_LIST *st_table_list::first_leaf_for_name_resolution() - else - 'this' */ -TABLE_LIST *st_table_list::last_leaf_for_name_resolution() +TABLE_LIST *TABLE_LIST::last_leaf_for_name_resolution() { TABLE_LIST *cur_table_ref= this; NESTED_JOIN *cur_nested_join; @@ -3527,7 +3656,7 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution() want_access Acess which we require */ -void st_table_list::register_want_access(ulong want_access) +void TABLE_LIST::register_want_access(ulong want_access) { /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ want_access&= ~SHOW_VIEW_ACL; @@ -3546,7 +3675,7 @@ void st_table_list::register_want_access(ulong want_access) Load security context information for this view SYNOPSIS - st_table_list::prepare_view_securety_context() + TABLE_LIST::prepare_view_securety_context() thd [in] thread handler RETURN @@ -3555,9 +3684,9 @@ void st_table_list::register_want_access(ulong want_access) */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -bool st_table_list::prepare_view_securety_context(THD *thd) +bool TABLE_LIST::prepare_view_securety_context(THD *thd) { - DBUG_ENTER("st_table_list::prepare_view_securety_context"); + DBUG_ENTER("TABLE_LIST::prepare_view_securety_context"); DBUG_PRINT("enter", ("table: %s", alias)); DBUG_ASSERT(!prelocking_placeholder && view); @@ -3606,17 +3735,17 @@ bool st_table_list::prepare_view_securety_context(THD *thd) Find security context of current view SYNOPSIS - st_table_list::find_view_security_context() + TABLE_LIST::find_view_security_context() thd [in] thread handler */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -Security_context *st_table_list::find_view_security_context(THD *thd) +Security_context *TABLE_LIST::find_view_security_context(THD *thd) { Security_context *sctx; TABLE_LIST *upper_view= this; - DBUG_ENTER("st_table_list::find_view_security_context"); + DBUG_ENTER("TABLE_LIST::find_view_security_context"); DBUG_ASSERT(view); while (upper_view && !upper_view->view_suid) @@ -3645,7 +3774,7 @@ Security_context *st_table_list::find_view_security_context(THD *thd) Prepare security context and load underlying tables priveleges for view SYNOPSIS - st_table_list::prepare_security() + TABLE_LIST::prepare_security() thd [in] thread handler RETURN @@ -3653,11 +3782,11 @@ Security_context *st_table_list::find_view_security_context(THD *thd) TRUE Error */ -bool st_table_list::prepare_security(THD *thd) +bool TABLE_LIST::prepare_security(THD *thd) { List_iterator_fast<TABLE_LIST> tb(*view_tables); TABLE_LIST *tbl; - DBUG_ENTER("st_table_list::prepare_security"); + DBUG_ENTER("TABLE_LIST::prepare_security"); #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_security_ctx= thd->security_ctx; @@ -4406,10 +4535,10 @@ void st_table::mark_columns_needed_for_insert() Cleanup this table for re-execution. SYNOPSIS - st_table_list::reinit_before_use() + TABLE_LIST::reinit_before_use() */ -void st_table_list::reinit_before_use(THD *thd) +void TABLE_LIST::reinit_before_use(THD *thd) { /* Reset old pointers to TABLEs: they are not valid since the tables @@ -4436,7 +4565,7 @@ void st_table_list::reinit_before_use(THD *thd) Return subselect that contains the FROM list this table is taken from SYNOPSIS - st_table_list::containing_subselect() + TABLE_LIST::containing_subselect() RETURN Subselect item for the subquery that contains the FROM list @@ -4445,7 +4574,7 @@ void st_table_list::reinit_before_use(THD *thd) */ -Item_subselect *st_table_list::containing_subselect() +Item_subselect *TABLE_LIST::containing_subselect() { return (select_lex ? select_lex->master_unit()->item : 0); } diff --git a/sql/table.h b/sql/table.h index 4c98f5146ab..b70517d5067 100644 --- a/sql/table.h +++ b/sql/table.h @@ -85,6 +85,15 @@ enum tmp_table_type INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE }; +/** Event on which trigger is invoked. */ +enum trg_event_type +{ + TRG_EVENT_INSERT= 0, + TRG_EVENT_UPDATE= 1, + TRG_EVENT_DELETE= 2, + TRG_EVENT_MAX +}; + enum frm_type_enum { FRMTYPE_ERROR= 0, @@ -386,7 +395,7 @@ struct st_table { /* Table's triggers, 0 if there are no of them */ Table_triggers_list *triggers; - struct st_table_list *pos_in_table_list;/* Element referring to this table */ + TABLE_LIST *pos_in_table_list;/* Element referring to this table */ ORDER *group; const char *alias; /* alias or table name */ uchar *null_flags; @@ -625,7 +634,7 @@ typedef struct st_field_info } ST_FIELD_INFO; -struct st_table_list; +struct TABLE_LIST; typedef class Item COND; typedef struct st_schema_table @@ -633,12 +642,12 @@ typedef struct st_schema_table const char* table_name; ST_FIELD_INFO *fields_info; /* Create information_schema table */ - TABLE *(*create_table) (THD *thd, struct st_table_list *table_list); + TABLE *(*create_table) (THD *thd, TABLE_LIST *table_list); /* Fill table with data */ - int (*fill_table) (THD *thd, struct st_table_list *tables, COND *cond); + int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond); /* Handle fileds for old SHOW */ int (*old_format) (THD *thd, struct st_schema_table *schema_table); - int (*process_table) (THD *thd, struct st_table_list *tables, + int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table, bool res, const char *base_name, const char *file_name); int idx_field1, idx_field2; @@ -671,7 +680,7 @@ struct st_lex; class select_union; class TMP_TABLE_PARAM; -Item *create_view_field(THD *thd, st_table_list *view, Item **field_ref, +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, const char *name); struct Field_translator @@ -692,7 +701,7 @@ class Natural_join_column: public Sql_alloc public: Field_translator *view_field; /* Column reference of merge view. */ Field *table_field; /* Column reference of table or temp view. */ - st_table_list *table_ref; /* Original base table/view reference. */ + TABLE_LIST *table_ref; /* Original base table/view reference. */ /* True if a common join column of two NATURAL/USING join operands. Notice that when we have a hierarchy of nested NATURAL/USING joins, a column can @@ -702,8 +711,8 @@ public: */ bool is_common; public: - Natural_join_column(Field_translator *field_param, st_table_list *tab); - Natural_join_column(Field *field_param, st_table_list *tab); + Natural_join_column(Field_translator *field_param, TABLE_LIST *tab); + Natural_join_column(Field *field_param, TABLE_LIST *tab); const char *name(); Item *create_item(THD *thd); Field *field(); @@ -746,9 +755,9 @@ public: */ class index_hint; -typedef struct st_table_list +struct TABLE_LIST { - st_table_list() {} /* Remove gcc warning */ + TABLE_LIST() {} /* Remove gcc warning */ /** Prepare TABLE_LIST that consists of one table instance to use in @@ -769,9 +778,9 @@ typedef struct st_table_list views as leaves (unlike 'next_leaf' below). Created at parse time in st_select_lex::add_table_to_list() -> table_list.link_in_list(). */ - struct st_table_list *next_local; + TABLE_LIST *next_local; /* link in a global list of all queries tables */ - struct st_table_list *next_global, **prev_global; + TABLE_LIST *next_global, **prev_global; char *db, *alias, *table_name, *schema_table_name; char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ @@ -791,7 +800,7 @@ typedef struct st_table_list 'this' represents a NATURAL or USING join operation. Thus after parsing 'this' is a NATURAL/USING join iff (natural_join != NULL). */ - struct st_table_list *natural_join; + TABLE_LIST *natural_join; /* True if 'this' represents a nested join that is a NATURAL JOIN. For one of the operands of 'this', the member 'natural_join' points @@ -815,7 +824,7 @@ typedef struct st_table_list base tables. All of these TABLE_LIST instances contain a materialized list of columns. The list is local to a subquery. */ - struct st_table_list *next_name_resolution_table; + TABLE_LIST *next_name_resolution_table; /* Index names in a "... JOIN ... USE/IGNORE INDEX ..." clause. */ List<index_hint> *index_hints; TABLE *table; /* opened table */ @@ -832,7 +841,7 @@ typedef struct st_table_list here it will be reference of first occurrence of t1 to second (as you can see this lists can't be merged) */ - st_table_list *correspondent_table; + TABLE_LIST *correspondent_table; st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ st_select_lex *schema_select_lex; @@ -853,20 +862,20 @@ typedef struct st_table_list does not include the tables of subqueries used in the view. Is set only for merged views. */ - st_table_list *merge_underlying_list; + TABLE_LIST *merge_underlying_list; /* - 0 for base tables - in case of the view it is the list of all (not only underlying tables but also used in subquery ones) tables of the view. */ - List<st_table_list> *view_tables; + List<TABLE_LIST> *view_tables; /* most upper view this table belongs to */ - st_table_list *belong_to_view; + TABLE_LIST *belong_to_view; /* The view directly referencing this table (non-zero only for merged underlying tables of a view). */ - st_table_list *referencing_view; + TABLE_LIST *referencing_view; /* Security context (non-zero only for tables which belong to view with SQL SECURITY DEFINER) @@ -883,7 +892,7 @@ typedef struct st_table_list leaves. Created in setup_tables() -> make_leaves_list(). */ bool allowed_show; - st_table_list *next_leaf; + TABLE_LIST *next_leaf; Item *where; /* VIEW WHERE clause condition */ Item *check_option; /* WITH CHECK OPTION condition */ LEX_STRING select_stmt; /* text of (CREATE/SELECT) statement */ @@ -923,8 +932,8 @@ typedef struct st_table_list table_map dep_tables; /* tables the table depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */ struct st_nested_join *nested_join; /* if the element is a nested join */ - st_table_list *embedding; /* nested join containing the table */ - List<struct st_table_list> *join_list;/* join list the table belongs to */ + TABLE_LIST *embedding; /* nested join containing the table */ + List<TABLE_LIST> *join_list;/* join list the table belongs to */ bool cacheable_table; /* stop PS caching */ /* used in multi-upd/views privilege check */ bool table_in_first_from_clause; @@ -979,6 +988,13 @@ typedef struct st_table_list /* End of view definition context. */ + /** + Indicates what triggers we need to pre-load for this TABLE_LIST + when opening an associated TABLE. This is filled after + the parsed tree is created. + */ + uint8 trg_event_map; + enum enum_schema_table_state schema_table_state; void calc_md5(char *buffer); void set_underlying_merge(); @@ -991,15 +1007,15 @@ typedef struct st_table_list !table; } void print(THD *thd, String *str); - bool check_single_table(st_table_list **table, table_map map, - st_table_list *view); + bool check_single_table(TABLE_LIST **table, table_map map, + TABLE_LIST *view); bool set_insert_values(MEM_ROOT *mem_root); void hide_view_error(THD *thd); - st_table_list *find_underlying_table(TABLE *table); - st_table_list *first_leaf_for_name_resolution(); - st_table_list *last_leaf_for_name_resolution(); + TABLE_LIST *find_underlying_table(TABLE *table); + TABLE_LIST *first_leaf_for_name_resolution(); + TABLE_LIST *last_leaf_for_name_resolution(); bool is_leaf_for_name_resolution(); - inline st_table_list *top_table() + inline TABLE_LIST *top_table() { return belong_to_view ? belong_to_view : this; } inline bool prepare_check_option(THD *thd) { @@ -1036,6 +1052,7 @@ typedef struct st_table_list */ bool process_index_hints(TABLE *table); + void set_trg_event_type(const st_lex *lex); private: bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_where(THD *thd, Item **conds, bool no_where_clause); @@ -1043,7 +1060,7 @@ private: Cleanup for re-execution in a prepared statement or a stored procedure. */ -} TABLE_LIST; +}; class Item; |