summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_yacc.yy252
1 files changed, 164 insertions, 88 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 86bef83cf1a..b0f45fe845a 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.
@@ -11809,98 +11941,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;
}
}
@@ -11936,11 +12012,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
{
@@ -12033,31 +12114,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;
}