WL#1218 "Triggers"

After review and after merge fixes.
parent 9b1bc6a4
...@@ -151,15 +151,15 @@ drop table t1; ...@@ -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; ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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))
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment