@ -2035,12 +2035,131 @@ 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 .
@ brief 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 .
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 st_lex : : set_trg_event_type_for_tables ( )
{
enum trg_event_type trg_event ;
uint8 new_trg_event_map = 0 ;
/*
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 .
*/
switch ( sql_command ) {
case SQLCOM_LOCK_TABLES :
/*
On a LOCK TABLE , all triggers must be pre - loaded for this TABLE_LIST
when opening an associated TABLE .
*/
new_trg_event_map = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_INSERT ) ) |
static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_UPDATE ) ) |
static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_DELETE ) ) ;
break ;
/*
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 :
new_trg_event_map | = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_INSERT ) ) ;
break ;
/* Basic update and multi-update */
case SQLCOM_UPDATE : /* fall through */
case SQLCOM_UPDATE_MULTI :
new_trg_event_map | = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_UPDATE ) ) ;
break ;
/* Basic delete and multi-delete */
case SQLCOM_DELETE : /* fall through */
case SQLCOM_DELETE_MULTI :
new_trg_event_map | = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_DELETE ) ) ;
break ;
default :
break ;
}
switch ( duplicates ) {
case DUP_UPDATE :
new_trg_event_map | = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_UPDATE ) ) ;
break ;
case DUP_REPLACE :
new_trg_event_map | = static_cast < uint8 >
( 1 < < static_cast < int > ( TRG_EVENT_DELETE ) ) ;
break ;
case DUP_ERROR :
default :
break ;
}
/*
Do not iterate over sub - selects , only the tables in the outermost
SELECT_LEX can be modified , if any .
@ -2049,7 +2168,17 @@ void st_lex::set_trg_event_type_for_tables()
while ( tables )
{
tables - > set_trg_event_type ( this ) ;
/*
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 > ( tables - > lock_type ) > =
static_cast < int > ( TL_WRITE_ALLOW_WRITE ) )
tables - > trg_event_map = new_trg_event_map ;
tables = tables - > next_local ;
}
}