WL#1218 "Triggers"
After review and after merge fixes.
This commit is contained in:
parent
9b1bc6a4d5
commit
6dc933b730
@ -151,15 +151,15 @@ drop table t1;
|
|||||||
#
|
#
|
||||||
create table t1 (i int);
|
create table t1 (i int);
|
||||||
|
|
||||||
--error 1358
|
--error 1362
|
||||||
create trigger trg before insert on t1 for each row set @a:= old.i;
|
create trigger trg before insert on t1 for each row set @a:= old.i;
|
||||||
--error 1358
|
--error 1362
|
||||||
create trigger trg before delete on t1 for each row set @a:= new.i;
|
create trigger trg before delete on t1 for each row set @a:= new.i;
|
||||||
--error 1357
|
--error 1361
|
||||||
create trigger trg before update on t1 for each row set old.i:=1;
|
create trigger trg before update on t1 for each row set old.i:=1;
|
||||||
--error 1358
|
--error 1362
|
||||||
create trigger trg before delete on t1 for each row set new.i:=1;
|
create trigger trg before delete on t1 for each row set new.i:=1;
|
||||||
--error 1357
|
--error 1361
|
||||||
create trigger trg after update on t1 for each row set new.i:=1;
|
create trigger trg after update on t1 for each row set new.i:=1;
|
||||||
# TODO: We should also test wrong field names here, we don't do it now
|
# TODO: We should also test wrong field names here, we don't do it now
|
||||||
# because proper error handling is not in place yet.
|
# because proper error handling is not in place yet.
|
||||||
@ -173,23 +173,23 @@ create trigger trg after update on t1 for each row set new.i:=1;
|
|||||||
create trigger trg before insert on t2 for each row set @a:=1;
|
create trigger trg before insert on t2 for each row set @a:=1;
|
||||||
|
|
||||||
create trigger trg before insert on t1 for each row set @a:=1;
|
create trigger trg before insert on t1 for each row set @a:=1;
|
||||||
--error 1354
|
--error 1358
|
||||||
create trigger trg after insert on t1 for each row set @a:=1;
|
create trigger trg after insert on t1 for each row set @a:=1;
|
||||||
--error 1354
|
--error 1358
|
||||||
create trigger trg2 before insert on t1 for each row set @a:=1;
|
create trigger trg2 before insert on t1 for each row set @a:=1;
|
||||||
drop trigger t1.trg;
|
drop trigger t1.trg;
|
||||||
|
|
||||||
--error 1355
|
--error 1359
|
||||||
drop trigger t1.trg;
|
drop trigger t1.trg;
|
||||||
|
|
||||||
create view v1 as select * from t1;
|
create view v1 as select * from t1;
|
||||||
--error 1356
|
--error 1360
|
||||||
create trigger trg before insert on v1 for each row set @a:=1;
|
create trigger trg before insert on v1 for each row set @a:=1;
|
||||||
drop view v1;
|
drop view v1;
|
||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
create temporary table t1 (i int);
|
create temporary table t1 (i int);
|
||||||
--error 1356
|
--error 1360
|
||||||
create trigger trg before insert on t1 for each row set @a:=1;
|
create trigger trg before insert on t1 for each row set @a:=1;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -1230,7 +1230,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
|
|||||||
thd->spcont->set_item(m_offset, it);
|
thd->spcont->set_item(m_offset, it);
|
||||||
}
|
}
|
||||||
*nextp = m_ip+1;
|
*nextp = m_ip+1;
|
||||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
@ -1387,7 +1387,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
|
|||||||
else
|
else
|
||||||
*nextp = m_ip+1;
|
*nextp = m_ip+1;
|
||||||
}
|
}
|
||||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
@ -1444,7 +1444,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
|
|||||||
else
|
else
|
||||||
*nextp = m_ip+1;
|
*nextp = m_ip+1;
|
||||||
}
|
}
|
||||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
@ -392,8 +392,8 @@ class sp_instr_set_user_var : public sp_instr
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sp_instr_set_user_var(uint ip, LEX_STRING var, Item *val)
|
sp_instr_set_user_var(uint ip, sp_pcontext *ctx, LEX_STRING var, Item *val)
|
||||||
: sp_instr(ip), m_set_var_item(var, val)
|
: sp_instr(ip, ctx), m_set_var_item(var, val)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~sp_instr_set_user_var()
|
virtual ~sp_instr_set_user_var()
|
||||||
@ -419,8 +419,9 @@ class sp_instr_set_trigger_field : public sp_instr
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sp_instr_set_trigger_field(uint ip, LEX_STRING field_name, Item *val)
|
sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
|
||||||
: sp_instr(ip),
|
LEX_STRING field_name, Item *val)
|
||||||
|
: sp_instr(ip, ctx),
|
||||||
trigger_field(Item_trigger_field::NEW_ROW, field_name.str),
|
trigger_field(Item_trigger_field::NEW_ROW, field_name.str),
|
||||||
value(val)
|
value(val)
|
||||||
{}
|
{}
|
||||||
|
@ -319,18 +319,18 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
if (!strncmp(triggers_file_type.str, parser->type()->str,
|
if (!strncmp(triggers_file_type.str, parser->type()->str,
|
||||||
parser->type()->length))
|
parser->type()->length))
|
||||||
{
|
{
|
||||||
int i;
|
Field **fld, **old_fld;
|
||||||
Table_triggers_list *triggers_info=
|
Table_triggers_list *triggers=
|
||||||
new (&table->mem_root) Table_triggers_list();
|
new (&table->mem_root) Table_triggers_list();
|
||||||
|
|
||||||
if (!triggers_info)
|
if (!triggers)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
if (parser->parse((gptr)triggers_info, &table->mem_root,
|
if (parser->parse((gptr)triggers, &table->mem_root,
|
||||||
triggers_file_parameters, 1))
|
triggers_file_parameters, 1))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
table->triggers= triggers_info;
|
table->triggers= triggers;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We have to prepare array of Field objects which will represent OLD.*
|
We have to prepare array of Field objects which will represent OLD.*
|
||||||
@ -338,27 +338,26 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
|
|
||||||
TODO: This could be avoided if there is no ON UPDATE trigger.
|
TODO: This could be avoided if there is no ON UPDATE trigger.
|
||||||
*/
|
*/
|
||||||
if (!(triggers_info->old_field=
|
if (!(triggers->old_field=
|
||||||
(Field **)alloc_root(&table->mem_root, (table->fields + 1) *
|
(Field **)alloc_root(&table->mem_root, (table->fields + 1) *
|
||||||
sizeof(Field*))))
|
sizeof(Field*))))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
for (i= 0; i < table->fields; i++)
|
for (fld= table->field, old_fld= triggers->old_field; *fld;
|
||||||
|
fld++, old_fld++)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
QQ: it is supposed that it is ok to use this function for field
|
QQ: it is supposed that it is ok to use this function for field
|
||||||
cloning...
|
cloning...
|
||||||
*/
|
*/
|
||||||
if (!(triggers_info->old_field[i]=
|
if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
|
||||||
table->field[i]->new_field(&table->mem_root, table)))
|
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
triggers_info->old_field[i]->move_field((my_ptrdiff_t)
|
(*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
|
||||||
(table->record[1] -
|
table->record[0]));
|
||||||
table->record[0]));
|
|
||||||
}
|
}
|
||||||
triggers_info->old_field[i]= 0;
|
*old_fld= 0;
|
||||||
|
|
||||||
List_iterator_fast<LEX_STRING> it(triggers_info->definitions_list);
|
List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
|
||||||
LEX_STRING *trg_create_str, *trg_name_str;
|
LEX_STRING *trg_create_str, *trg_name_str;
|
||||||
char *trg_name_buff;
|
char *trg_name_buff;
|
||||||
LEX *old_lex= thd->lex, lex;
|
LEX *old_lex= thd->lex, lex;
|
||||||
@ -367,8 +366,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
|
|
||||||
while ((trg_create_str= it++))
|
while ((trg_create_str= it++))
|
||||||
{
|
{
|
||||||
lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);
|
mysql_init_query(thd, (uchar*)trg_create_str->str,
|
||||||
mysql_init_query(thd, true);
|
trg_create_str->length, true);
|
||||||
lex.trg_table= table;
|
lex.trg_table= table;
|
||||||
if (yyparse((void *)thd) || thd->is_fatal_error)
|
if (yyparse((void *)thd) || thd->is_fatal_error)
|
||||||
{
|
{
|
||||||
@ -385,7 +384,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
goto err_with_lex_cleanup;
|
goto err_with_lex_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggers_info->bodies[lex.trg_chistics.event]
|
triggers->bodies[lex.trg_chistics.event]
|
||||||
[lex.trg_chistics.action_time]= lex.sphead;
|
[lex.trg_chistics.action_time]= lex.sphead;
|
||||||
lex.sphead= 0;
|
lex.sphead= 0;
|
||||||
|
|
||||||
@ -404,7 +403,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
|||||||
old_global_mem_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
|
old_global_mem_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
|
||||||
my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
|
my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
|
||||||
|
|
||||||
if (triggers_info->names_list.push_back(trg_name_str))
|
if (triggers->names_list.push_back(trg_name_str))
|
||||||
goto err_with_lex_cleanup;
|
goto err_with_lex_cleanup;
|
||||||
|
|
||||||
my_pthread_setspecific_ptr(THR_MALLOC, old_global_mem_root);
|
my_pthread_setspecific_ptr(THR_MALLOC, old_global_mem_root);
|
||||||
|
@ -1212,15 +1212,6 @@ create:
|
|||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
|
|
||||||
lex->name_and_length= $3;
|
|
||||||
|
|
||||||
/* QQ: Could we loosen lock type in certain cases ? */
|
|
||||||
if (!lex->select_lex.add_table_to_list(YYTHD, $7,
|
|
||||||
(LEX_STRING*) 0,
|
|
||||||
TL_OPTION_UPDATING,
|
|
||||||
TL_WRITE))
|
|
||||||
YYABORT;
|
|
||||||
|
|
||||||
if (lex->sphead)
|
if (lex->sphead)
|
||||||
{
|
{
|
||||||
net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "TRIGGER");
|
net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "TRIGGER");
|
||||||
@ -1256,6 +1247,23 @@ create:
|
|||||||
if (sp->m_old_cmq)
|
if (sp->m_old_cmq)
|
||||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||||
sp->restore_thd_mem_root(YYTHD);
|
sp->restore_thd_mem_root(YYTHD);
|
||||||
|
|
||||||
|
lex->name_and_length= $3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We have to do it after parsing trigger body, because some of
|
||||||
|
sp_proc_stmt alternatives are not saving/restoring LEX, so
|
||||||
|
lex->query_tables can be wiped out.
|
||||||
|
|
||||||
|
QQ: What are other consequences of this?
|
||||||
|
|
||||||
|
QQ: Could we loosen lock type in certain cases ?
|
||||||
|
*/
|
||||||
|
if (!lex->select_lex.add_table_to_list(YYTHD, $7,
|
||||||
|
(LEX_STRING*) 0,
|
||||||
|
TL_OPTION_UPDATING,
|
||||||
|
TL_WRITE))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -6922,10 +6930,18 @@ option_value:
|
|||||||
We have to use special instruction in functions and triggers
|
We have to use special instruction in functions and triggers
|
||||||
because sp_instr_stmt will close all tables and thus ruin
|
because sp_instr_stmt will close all tables and thus ruin
|
||||||
execution of statement invoking function or trigger.
|
execution of statement invoking function or trigger.
|
||||||
|
|
||||||
|
We also do not want to allow expression with subselects in
|
||||||
|
this case.
|
||||||
*/
|
*/
|
||||||
|
if (lex->query_tables)
|
||||||
|
{
|
||||||
|
send_error(YYTHD, ER_SP_SUBSELECT_NYI);
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
sp_instr_set_user_var *i=
|
sp_instr_set_user_var *i=
|
||||||
new sp_instr_set_user_var(lex->sphead->instructions(),
|
new sp_instr_set_user_var(lex->sphead->instructions(),
|
||||||
$2, $4);
|
lex->spcont, $2, $4);
|
||||||
lex->sphead->add_instr(i);
|
lex->sphead->add_instr(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -6941,12 +6957,8 @@ option_value:
|
|||||||
/* We are in trigger and assigning value to field of new row */
|
/* We are in trigger and assigning value to field of new row */
|
||||||
Item *it;
|
Item *it;
|
||||||
sp_instr_set_trigger_field *i;
|
sp_instr_set_trigger_field *i;
|
||||||
if ($3 && $3->type() == Item::SUBSELECT_ITEM)
|
if (lex->query_tables)
|
||||||
{ /*
|
{
|
||||||
QQ For now, just disallow subselects as values
|
|
||||||
Unfortunately this doesn't helps in case when we have
|
|
||||||
subselect deeper in expression.
|
|
||||||
*/
|
|
||||||
send_error(YYTHD, ER_SP_SUBSELECT_NYI);
|
send_error(YYTHD, ER_SP_SUBSELECT_NYI);
|
||||||
YYABORT;
|
YYABORT;
|
||||||
}
|
}
|
||||||
@ -6958,7 +6970,7 @@ option_value:
|
|||||||
it= new Item_null();
|
it= new Item_null();
|
||||||
}
|
}
|
||||||
i= new sp_instr_set_trigger_field(lex->sphead->instructions(),
|
i= new sp_instr_set_trigger_field(lex->sphead->instructions(),
|
||||||
$1.base_name, it);
|
lex->spcont, $1.base_name, it);
|
||||||
if (lex->trg_table && i->setup_field(YYTHD, lex->trg_table,
|
if (lex->trg_table && i->setup_field(YYTHD, lex->trg_table,
|
||||||
lex->trg_chistics.event))
|
lex->trg_chistics.event))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user