summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorkostja@bodhi.(none) <>2007-07-16 23:31:36 +0400
committerkostja@bodhi.(none) <>2007-07-16 23:31:36 +0400
commit88fc7cab26425a5dc43aff02cb84e1363ce0129d (patch)
tree53d9d30f94c45fc9b3f51662dd10574784b16e0a /sql
parent06d656b808c26841007d00512ad91ec0dcbae19f (diff)
parent5466b0df1407b0412a5845e4fd43c4ae0d1ba5b5 (diff)
downloadmariadb-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.h45
-rw-r--r--sql/item.cc2
-rw-r--r--sql/item.h10
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/sp.cc63
-rw-r--r--sql/sp_head.cc53
-rw-r--r--sql/sp_head.h6
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_db.cc8
-rw-r--r--sql/sql_lex.cc60
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sql_prepare.cc59
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_show.cc14
-rw-r--r--sql/sql_trigger.cc40
-rw-r--r--sql/sql_trigger.h8
-rw-r--r--sql/sql_udf.h1
-rw-r--r--sql/sql_view.cc13
-rw-r--r--sql/sql_yacc.yy25
-rw-r--r--sql/table.cc221
-rw-r--r--sql/table.h77
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;