summaryrefslogtreecommitdiff
path: root/sql/sql_yacc.yy
diff options
context:
space:
mode:
authorunknown <sanja@askmonty.org>2010-02-01 08:14:12 +0200
committerunknown <sanja@askmonty.org>2010-02-01 08:14:12 +0200
commite5099a2c85468d01d084b1071f724bc20766271d (patch)
tree50e180dfcaa058cefb382d2ab931592cddbd007d /sql/sql_yacc.yy
parentf83113df07d6ef8e8a6d1db8f6dc3bb90fb0652a (diff)
parente9bce6c9d4bde35306b845e22e9b5ada69c4512f (diff)
downloadmariadb-git-e5099a2c85468d01d084b1071f724bc20766271d.tar.gz
merge 5.1->5.2
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r--sql/sql_yacc.yy320
1 files changed, 202 insertions, 118 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 976d130b26b..d423575cf06 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
lex->sphead->do_cont_backpatch();
}
+
+static bool
+find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp)
+{
+ tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);
+
+ if (tmp->var == NULL)
+ my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str);
+ else
+ tmp->base_name= null_lex_str;
+
+ return thd->is_error();
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to push a system variable into the assignment list.
+
+ @param thd the current thread
+ @param tmp the system variable with base name
+ @param var_type the scope of the variable
+ @param val the value being assigned to the variable
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+static bool
+set_system_variable(THD *thd, struct sys_var_with_base *tmp,
+ enum enum_var_type var_type, Item *val)
+{
+ set_var *var;
+ LEX *lex= thd->lex;
+
+ /* No AUTOCOMMIT from a stored function or trigger. */
+ if (lex->spcont && tmp->var == &sys_autocommit)
+ lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+
+ if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val)))
+ return TRUE;
+
+ return lex->var_list.push_back(var);
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to push a SP local variable into the assignment list.
+
+ @param thd the current thread
+ @param var_type the SP local variable
+ @param val the value being assigned to the variable
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+static bool
+set_local_variable(THD *thd, sp_variable_t *spv, Item *val)
+{
+ Item *it;
+ LEX *lex= thd->lex;
+ sp_instr_set *sp_set;
+
+ if (val)
+ it= val;
+ else if (spv->dflt)
+ it= spv->dflt;
+ else
+ {
+ it= new (thd->mem_root) Item_null();
+ if (it == NULL)
+ return TRUE;
+ }
+
+ sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont,
+ spv->offset, it, spv->type, lex, TRUE);
+
+ return (sp_set == NULL || lex->sphead->add_instr(sp_set));
+}
+
+
+/**
+ Helper action for a SET statement.
+ Used to SET a field of NEW row.
+
+ @param thd the current thread
+ @param name the field name
+ @param val the value being assigned to the row
+
+ @return TRUE if error, FALSE otherwise.
+*/
+
+static bool
+set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val)
+{
+ LEX *lex= thd->lex;
+ Item_trigger_field *trg_fld;
+ sp_instr_set_trigger_field *sp_fld;
+
+ /* QQ: Shouldn't this be field's default value ? */
+ if (! val)
+ val= new Item_null();
+
+ DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
+ (lex->trg_chistics.event == TRG_EVENT_INSERT ||
+ lex->trg_chistics.event == TRG_EVENT_UPDATE));
+
+ trg_fld= new (thd->mem_root)
+ Item_trigger_field(lex->current_context(),
+ Item_trigger_field::NEW_ROW,
+ name->str, UPDATE_ACL, FALSE);
+
+ if (trg_fld == NULL)
+ return TRUE;
+
+ sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(),
+ lex->spcont, trg_fld, val, lex);
+
+ if (sp_fld == NULL)
+ return TRUE;
+
+ /*
+ Let us add this item to list of all Item_trigger_field
+ objects in trigger.
+ */
+ lex->trg_table_fields.link_in_list((uchar *) trg_fld,
+ (uchar **) &trg_fld->next_trg_field);
+
+ return lex->sphead->add_instr(sp_fld);
+}
+
+
/**
Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
@@ -2348,8 +2480,8 @@ sp_decl:
}
pctx->declare_var_boundary(0);
- lex->sphead->restore_lex(YYTHD);
-
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
$$.vars= $2;
$$.conds= $$.hndlrs= $$.curs= 0;
}
@@ -2459,7 +2591,8 @@ sp_cursor_stmt:
}
lex->sp_lex_in_use= TRUE;
$$= lex;
- lex->sphead->restore_lex(YYTHD);
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
;
@@ -2678,7 +2811,8 @@ sp_proc_stmt_statement:
sp->add_instr(i))
MYSQL_YYABORT;
}
- sp->restore_lex(thd);
+ if (sp->restore_lex(thd))
+ MYSQL_YYABORT;
}
;
@@ -2706,7 +2840,8 @@ sp_proc_stmt_return:
MYSQL_YYABORT;
sp->m_flags|= sp_head::HAS_RETURN;
}
- sp->restore_lex(YYTHD);
+ if (sp->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
;
@@ -2946,7 +3081,8 @@ sp_if:
sp->add_cont_backpatch(i) ||
sp->add_instr(i))
MYSQL_YYABORT;
- sp->restore_lex(YYTHD);
+ if (sp->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
sp_proc_stmts1
{
@@ -2992,7 +3128,9 @@ simple_case_stmt:
if (case_stmt_action_expr(lex, $3))
MYSQL_YYABORT;
- lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ /* For expr $3 */
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
simple_when_clause_list
else_clause_opt
@@ -3042,7 +3180,9 @@ simple_when_clause:
LEX *lex= Lex;
if (case_stmt_action_when(lex, $3, true))
MYSQL_YYABORT;
- lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ /* For expr $3 */
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
THEN_SYM
sp_proc_stmts1
@@ -3063,7 +3203,9 @@ searched_when_clause:
LEX *lex= Lex;
if (case_stmt_action_when(lex, $3, false))
MYSQL_YYABORT;
- lex->sphead->restore_lex(YYTHD); /* For expr $3 */
+ /* For expr $3 */
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
THEN_SYM
sp_proc_stmts1
@@ -3240,7 +3382,8 @@ sp_unlabeled_control:
sp->new_cont_backpatch(i) ||
sp->add_instr(i))
MYSQL_YYABORT;
- sp->restore_lex(YYTHD);
+ if (sp->restore_lex(YYTHD))
+ MYSQL_YYABORT;
}
sp_proc_stmts1 END WHILE_SYM
{
@@ -3266,7 +3409,8 @@ sp_unlabeled_control:
if (i == NULL ||
lex->sphead->add_instr(i))
MYSQL_YYABORT;
- lex->sphead->restore_lex(YYTHD);
+ if (lex->sphead->restore_lex(YYTHD))
+ MYSQL_YYABORT;
/* We can shortcut the cont_backpatch here */
i->m_cont_dest= ip+1;
}
@@ -7645,6 +7789,14 @@ function_call_nonkeyword:
}
| SYSDATE optional_braces
{
+ /*
+ Unlike other time-related functions, SYSDATE() is
+ replication-unsafe because it is not affected by the
+ TIMESTAMP variable. It is unsafe even if
+ sysdate_is_now=1, because the slave may have
+ sysdate_is_now=0.
+ */
+ Lex->set_stmt_unsafe();
if (global_system_variables.sysdate_is_now == 0)
$$= new (YYTHD->mem_root) Item_func_sysdate_local();
else
@@ -9589,16 +9741,12 @@ replace:
insert_lock_option:
/* empty */
{
-#ifdef HAVE_QUERY_CACHE
/*
- If it is SP we do not allow insert optimisation whan result of
+ If it is SP we do not allow insert optimisation when result of
insert visible only after the table unlocking but everyone can
read table.
*/
$$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
-#else
- $$= TL_WRITE_CONCURRENT_INSERT;
-#endif
}
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
| DELAYED_SYM { $$= TL_WRITE_DELAYED; }
@@ -10659,15 +10807,11 @@ load_data_lock:
/* empty */ { $$= TL_WRITE_DEFAULT; }
| CONCURRENT
{
-#ifdef HAVE_QUERY_CACHE
/*
- Ignore this option in SP to avoid problem with query cache
+ Ignore this option in SP to avoid problem with query cache and
+ triggers with non default priority locks
*/
- if (Lex->sphead != 0)
- $$= TL_WRITE_DEFAULT;
- else
-#endif
- $$= TL_WRITE_CONCURRENT_INSERT;
+ $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
}
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
;
@@ -11944,7 +12088,8 @@ option_type_value:
if (sp->add_instr(i))
MYSQL_YYABORT;
}
- lex->sphead->restore_lex(thd);
+ if (lex->sphead->restore_lex(thd))
+ MYSQL_YYABORT;
}
}
;
@@ -11984,98 +12129,42 @@ sys_option_value:
option_type internal_variable_name equal set_expr_or_default
{
THD *thd= YYTHD;
- LEX *lex=Lex;
+ LEX *lex= Lex;
+ LEX_STRING *name= &$2.base_name;
if ($2.var == trg_new_row_fake_var)
{
/* We are in trigger and assigning value to field of new row */
- Item *it;
- Item_trigger_field *trg_fld;
- sp_instr_set_trigger_field *sp_fld;
- LINT_INIT(sp_fld);
if ($1)
{
my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT;
}
- if ($4)
- it= $4;
- else
- {
- /* QQ: Shouldn't this be field's default value ? */
- it= new Item_null();
- }
-
- DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
- (lex->trg_chistics.event == TRG_EVENT_INSERT ||
- lex->trg_chistics.event == TRG_EVENT_UPDATE));
-
- trg_fld= new (thd->mem_root)
- Item_trigger_field(Lex->current_context(),
- Item_trigger_field::NEW_ROW,
- $2.base_name.str,
- UPDATE_ACL, FALSE);
- if (trg_fld == NULL)
- MYSQL_YYABORT;
-
- sp_fld= new sp_instr_set_trigger_field(lex->sphead->
- instructions(),
- lex->spcont,
- trg_fld,
- it, lex);
- if (sp_fld == NULL)
- MYSQL_YYABORT;
-
- /*
- Let us add this item to list of all Item_trigger_field
- objects in trigger.
- */
- lex->trg_table_fields.link_in_list((uchar *)trg_fld,
- (uchar **) &trg_fld->
- next_trg_field);
-
- if (lex->sphead->add_instr(sp_fld))
+ if (set_trigger_new_row(YYTHD, name, $4))
MYSQL_YYABORT;
}
else if ($2.var)
- { /* System variable */
+ {
if ($1)
lex->option_type= $1;
- set_var *var= new set_var(lex->option_type, $2.var,
- &$2.base_name, $4);
- if (var == NULL)
+
+ /* It is a system variable. */
+ if (set_system_variable(thd, &$2, lex->option_type, $4))
MYSQL_YYABORT;
- lex->var_list.push_back(var);
}
else
{
- /* An SP local variable */
- sp_pcontext *ctx= lex->spcont;
- sp_variable_t *spv;
- sp_instr_set *sp_set;
- Item *it;
+ sp_pcontext *spc= lex->spcont;
+ sp_variable_t *spv= spc->find_variable(name);
+
if ($1)
{
my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT;
}
- spv= ctx->find_variable(&$2.base_name);
-
- if ($4)
- it= $4;
- else if (spv->dflt)
- it= spv->dflt;
- else
- {
- it= new (thd->mem_root) Item_null();
- if (it == NULL)
- MYSQL_YYABORT;
- }
- sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
- spv->offset, it, spv->type, lex, TRUE);
- if (sp_set == NULL ||
- lex->sphead->add_instr(sp_set))
+ /* It is a local variable. */
+ if (set_local_variable(thd, spv, $4))
MYSQL_YYABORT;
}
}
@@ -12111,11 +12200,16 @@ option_value:
}
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
- LEX *lex=Lex;
- set_var *var= new set_var($3, $4.var, &$4.base_name, $6);
- if (var == NULL)
+ THD *thd= YYTHD;
+ struct sys_var_with_base tmp= $4;
+ /* Lookup if necessary: must be a system variable. */
+ if (tmp.var == NULL)
+ {
+ if (find_sys_var_null_base(thd, &tmp))
+ MYSQL_YYABORT;
+ }
+ if (set_system_variable(thd, &tmp, $3, $6))
MYSQL_YYABORT;
- lex->var_list.push_back(var);
}
| charset old_or_new_charset_name_or_default
{
@@ -12208,31 +12302,26 @@ internal_variable_name:
ident
{
THD *thd= YYTHD;
- LEX *lex= thd->lex;
- sp_pcontext *spc= lex->spcont;
+ sp_pcontext *spc= thd->lex->spcont;
sp_variable_t *spv;
- /* We have to lookup here since local vars can shadow sysvars */
+ /* Best effort lookup for system variable. */
if (!spc || !(spv = spc->find_variable(&$1)))
{
+ struct sys_var_with_base tmp= {NULL, $1};
+
/* Not an SP local variable */
- sys_var *tmp=find_sys_var(thd, $1.str, $1.length);
- if (!tmp)
+ if (find_sys_var_null_base(thd, &tmp))
MYSQL_YYABORT;
- $$.var= tmp;
- $$.base_name= null_lex_str;
- if (spc && tmp == &sys_autocommit)
- {
- /*
- We don't allow setting AUTOCOMMIT from a stored function
- or trigger.
- */
- lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
- }
+
+ $$= tmp;
}
else
{
- /* An SP local variable */
+ /*
+ Possibly an SP local variable (or a shadowed sysvar).
+ Will depend on the context of the SET statement.
+ */
$$.var= NULL;
$$.base_name= $1;
}
@@ -12390,12 +12479,7 @@ lock_option:
| WRITE_SYM { $$= TL_WRITE_DEFAULT; }
| WRITE_SYM CONCURRENT
{
-#ifdef HAVE_QUERY_CACHE
- if (Lex->sphead != 0)
- $$= TL_WRITE_DEFAULT;
- else
-#endif
- $$= TL_WRITE_CONCURRENT_INSERT;
+ $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT);
}
| LOW_PRIORITY WRITE_SYM { $$= TL_WRITE_LOW_PRIORITY; }