Commit 892af780 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10411 Providing compatibility for basic PL/SQL constructs

Part6: assignment operator

  var:= 10;
parent 7e10e388
......@@ -80,3 +80,175 @@ SELECT @p1, @p2;
@p1 @p2
p1 p2new
DROP PROCEDURE p1;
# Testing Oracle-style assigment
CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
BEGIN
p1:= 'p1new';
END;
/
SET @p1='p1';
CALL p1(@p1);
SELECT @p1;
@p1
p1new
DROP PROCEDURE p1;
# Testing that (some) keyword_sp are allowed in Oracle-style assignments
CREATE PROCEDURE p1 (action OUT INT) action:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (clob OUT INT) clob:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (enum OUT INT) enum:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (via OUT INT) via:=10;
DROP PROCEDURE p1;
# Testing keyword_directly_assignable
CREATE PROCEDURE p1 (ascii OUT INT) ascii:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (backup OUT INT) backup:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (binlog OUT INT) binlog:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (byte OUT INT) byte:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (cache OUT INT) cache:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (checksum OUT INT) checksum:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (checkpoint OUT INT) checkpoint:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_add OUT INT) column_add:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_check OUT INT) column_check:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_create OUT INT) column_create:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_delete OUT INT) column_delete:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_get OUT INT) column_get:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (commit OUT INT) commit:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (deallocate OUT INT) deallocate:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (examined OUT INT) examined:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (execute OUT INT) execute:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (flush OUT INT) flush:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (format OUT INT) format:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (get OUT INT) get:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (help OUT INT) help:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (host OUT INT) host:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (install OUT INT) install:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (option OUT INT) option:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (options OUT INT) options:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (owner OUT INT) owner:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (parser OUT INT) parser:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (port OUT INT) port:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (prepare OUT INT) prepare:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (remove OUT INT) remove:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (reset OUT INT) reset:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (restore OUT INT) restore:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (rollback OUT INT) rollback:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (security OUT INT) security:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (server OUT INT) server:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (shutdown OUT INT) shutdown:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (signed OUT INT) signed:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (socket OUT INT) socket:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (slave OUT INT) slave:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (slaves OUT INT) slaves:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (soname OUT INT) soname:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (start OUT INT) start:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (stop OUT INT) stop:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (stored OUT INT) stored:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (unicode OUT INT) unicode:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (uninstall OUT INT) uninstall:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (upgrade OUT INT) upgrade:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (wrapper OUT INT) wrapper:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (xa OUT INT) xa:=10;
DROP PROCEDURE p1;
# Testing that keyword_directly_not_assignable works in SET statements.
CREATE PROCEDURE p1 (contains OUT INT) SET contains=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (language OUT INT) SET language=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (no OUT INT) SET no=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (charset OUT INT) SET charset=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (do OUT INT) SET do=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (repair OUT INT) SET repair=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (handler OUT INT) SET handler=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (open OUT INT) SET open=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (close OUT INT) SET close=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (savepoint OUT INT) SET savepoint=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (truncate OUT INT) SET truncate=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (begin OUT INT) SET begin=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (end OUT INT) SET end=10;
DROP PROCEDURE p1;
# Testing that keyword_directly_not_assignable works in table/column names
CREATE TABLE contains (contains INT);
DROP TABLE contains;
CREATE TABLE language (language INT);
DROP TABLE language;
CREATE TABLE no (no INT);
DROP TABLE no;
CREATE TABLE charset (charset INT);
DROP TABLE charset;
CREATE TABLE do (do INT);
DROP TABLE do;
CREATE TABLE repair (repair INT);
DROP TABLE repair;
CREATE TABLE handler (handler INT);
DROP TABLE handler;
CREATE TABLE open (open INT);
DROP TABLE open;
CREATE TABLE close (close INT);
DROP TABLE close;
CREATE TABLE savepoint (savepoint INT);
DROP TABLE savepoint;
CREATE TABLE truncate (truncate INT);
DROP TABLE truncate;
CREATE TABLE begin (begin INT);
DROP TABLE begin;
CREATE TABLE end (end INT);
DROP TABLE end;
......@@ -88,3 +88,181 @@ SET @p1='p1', @p2='p2';
CALL p1(@p1, @p2);
SELECT @p1, @p2;
DROP PROCEDURE p1;
--echo # Testing Oracle-style assigment
DELIMITER /;
CREATE PROCEDURE p1 (p1 OUT VARCHAR2(10))
BEGIN
p1:= 'p1new';
END;
/
DELIMITER ;/
SET @p1='p1';
CALL p1(@p1);
SELECT @p1;
DROP PROCEDURE p1;
--echo # Testing that (some) keyword_sp are allowed in Oracle-style assignments
CREATE PROCEDURE p1 (action OUT INT) action:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (clob OUT INT) clob:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (enum OUT INT) enum:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (via OUT INT) via:=10;
DROP PROCEDURE p1;
--echo # Testing keyword_directly_assignable
CREATE PROCEDURE p1 (ascii OUT INT) ascii:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (backup OUT INT) backup:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (binlog OUT INT) binlog:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (byte OUT INT) byte:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (cache OUT INT) cache:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (checksum OUT INT) checksum:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (checkpoint OUT INT) checkpoint:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_add OUT INT) column_add:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_check OUT INT) column_check:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_create OUT INT) column_create:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_delete OUT INT) column_delete:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (column_get OUT INT) column_get:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (commit OUT INT) commit:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (deallocate OUT INT) deallocate:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (examined OUT INT) examined:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (execute OUT INT) execute:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (flush OUT INT) flush:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (format OUT INT) format:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (get OUT INT) get:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (help OUT INT) help:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (host OUT INT) host:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (install OUT INT) install:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (option OUT INT) option:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (options OUT INT) options:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (owner OUT INT) owner:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (parser OUT INT) parser:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (port OUT INT) port:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (prepare OUT INT) prepare:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (remove OUT INT) remove:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (reset OUT INT) reset:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (restore OUT INT) restore:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (rollback OUT INT) rollback:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (security OUT INT) security:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (server OUT INT) server:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (shutdown OUT INT) shutdown:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (signed OUT INT) signed:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (socket OUT INT) socket:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (slave OUT INT) slave:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (slaves OUT INT) slaves:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (soname OUT INT) soname:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (start OUT INT) start:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (stop OUT INT) stop:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (stored OUT INT) stored:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (unicode OUT INT) unicode:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (uninstall OUT INT) uninstall:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (upgrade OUT INT) upgrade:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (wrapper OUT INT) wrapper:=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (xa OUT INT) xa:=10;
DROP PROCEDURE p1;
--echo # Testing that keyword_directly_not_assignable works in SET statements.
CREATE PROCEDURE p1 (contains OUT INT) SET contains=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (language OUT INT) SET language=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (no OUT INT) SET no=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (charset OUT INT) SET charset=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (do OUT INT) SET do=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (repair OUT INT) SET repair=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (handler OUT INT) SET handler=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (open OUT INT) SET open=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (close OUT INT) SET close=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (savepoint OUT INT) SET savepoint=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (truncate OUT INT) SET truncate=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (begin OUT INT) SET begin=10;
DROP PROCEDURE p1;
CREATE PROCEDURE p1 (end OUT INT) SET end=10;
DROP PROCEDURE p1;
--echo # Testing that keyword_directly_not_assignable works in table/column names
CREATE TABLE contains (contains INT);
DROP TABLE contains;
CREATE TABLE language (language INT);
DROP TABLE language;
CREATE TABLE no (no INT);
DROP TABLE no;
CREATE TABLE charset (charset INT);
DROP TABLE charset;
CREATE TABLE do (do INT);
DROP TABLE do;
CREATE TABLE repair (repair INT);
DROP TABLE repair;
CREATE TABLE handler (handler INT);
DROP TABLE handler;
CREATE TABLE open (open INT);
DROP TABLE open;
CREATE TABLE close (close INT);
DROP TABLE close;
CREATE TABLE savepoint (savepoint INT);
DROP TABLE savepoint;
CREATE TABLE truncate (truncate INT);
DROP TABLE truncate;
CREATE TABLE begin (begin INT);
DROP TABLE begin;
CREATE TABLE end (end INT);
DROP TABLE end;
......@@ -686,6 +686,17 @@ sys_var *intern_find_sys_var(const char *str, uint length)
}
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)
tmp->base_name= null_lex_str;
return thd->is_error();
}
/**
Execute update of all variables.
......
......@@ -391,6 +391,7 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);
sys_var *find_sys_var(THD *thd, const char *str, size_t length=0);
bool find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);
#define SYSVAR_AUTOSIZE(VAR,VAL) \
......
......@@ -5090,6 +5090,102 @@ bool LEX::sp_param_fill_definition(sp_variable *spvar)
}
void LEX::set_stmt_init()
{
sql_command= SQLCOM_SET_OPTION;
mysql_init_select(this);
option_type= OPT_SESSION;
autocommit= 0;
};
bool LEX::init_internal_variable(struct sys_var_with_base *variable,
LEX_STRING name)
{
sp_variable *spv;
/* Best effort lookup for system variable. */
if (!spcont || !(spv = spcont->find_variable(name, false)))
{
struct sys_var_with_base tmp= {NULL, name};
/* Not an SP local variable */
if (find_sys_var_null_base(thd, &tmp))
return true;
*variable= tmp;
return false;
}
/*
Possibly an SP local variable (or a shadowed sysvar).
Will depend on the context of the SET statement.
*/
variable->var= NULL;
variable->base_name= name;
return false;
}
bool LEX::init_internal_variable(struct sys_var_with_base *variable,
LEX_STRING dbname, LEX_STRING name)
{
if (check_reserved_words(&dbname))
{
thd->parse_error();
return true;
}
if (sphead && sphead->m_type == TYPE_ENUM_TRIGGER &&
(!my_strcasecmp(system_charset_info, dbname.str, "NEW") ||
!my_strcasecmp(system_charset_info, dbname.str, "OLD")))
{
if (dbname.str[0]=='O' || dbname.str[0]=='o')
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
return true;
}
if (trg_chistics.event == TRG_EVENT_DELETE)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
return true;
}
if (trg_chistics.action_time == TRG_ACTION_AFTER)
{
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
return true;
}
/* This special combination will denote field of NEW row */
variable->var= trg_new_row_fake_var;
variable->base_name= name;
return false;
}
sys_var *tmp= find_sys_var(thd, name.str, name.length);
if (!tmp)
return true;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name.str);
variable->var= tmp;
variable->base_name= dbname;
return false;
}
bool LEX::init_default_internal_variable(struct sys_var_with_base *variable,
LEX_STRING name)
{
sys_var *tmp= find_sys_var(thd, name.str, name.length);
if (!tmp)
return true;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), name.str);
variable->var= tmp;
variable->base_name.str= (char*) "default";
variable->base_name.length= 7;
return false;
}
#ifdef MYSQL_SERVER
uint binlog_unsafe_map[256];
......
......@@ -3064,6 +3064,13 @@ struct LEX: public Query_tables_list
bool set_trigger_new_row(LEX_STRING *name, Item *val);
bool set_system_variable(struct sys_var_with_base *tmp,
enum enum_var_type var_type, Item *val);
void set_stmt_init();
bool init_internal_variable(struct sys_var_with_base *variable,
LEX_STRING name);
bool init_internal_variable(struct sys_var_with_base *variable,
LEX_STRING dbname, LEX_STRING name);
bool init_default_internal_variable(struct sys_var_with_base *variable,
LEX_STRING name);
bool set_local_variable(sp_variable *spv, Item *val);
Item_splocal *create_item_for_sp_var(LEX_STRING name, sp_variable *spvar,
const char *start_in_q,
......
......@@ -335,17 +335,6 @@ int LEX::case_stmt_action_then()
return sphead->push_backpatch(thd, i, spcont->last_label());
}
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)
tmp->base_name= null_lex_str;
return thd->is_error();
}
/**
Helper action for a SET statement.
......@@ -14880,22 +14869,15 @@ set:
SET
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SET_OPTION;
mysql_init_select(lex);
lex->option_type=OPT_SESSION;
lex->set_stmt_init();
lex->var_list.empty();
lex->autocommit= 0;
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
start_option_value_list
{}
| SET STATEMENT_SYM
{
LEX *lex= Lex;
mysql_init_select(lex);
lex->option_type= OPT_SESSION;
lex->sql_command= SQLCOM_SET_OPTION;
lex->autocommit= 0;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
{
......@@ -15193,77 +15175,18 @@ option_value_no_option_type:
internal_variable_name:
ident
{
sp_pcontext *spc= thd->lex->spcont;
sp_variable *spv;
/* Best effort lookup for system variable. */
if (!spc || !(spv = spc->find_variable($1, false)))
{
struct sys_var_with_base tmp= {NULL, $1};
/* Not an SP local variable */
if (find_sys_var_null_base(thd, &tmp))
MYSQL_YYABORT;
$$= tmp;
}
else
{
/*
Possibly an SP local variable (or a shadowed sysvar).
Will depend on the context of the SET statement.
*/
$$.var= NULL;
$$.base_name= $1;
}
if (Lex->init_internal_variable(&$$, $1))
MYSQL_YYABORT;
}
| ident '.' ident
{
LEX *lex= Lex;
if (check_reserved_words(&$1))
{
thd->parse_error();
if (Lex->init_internal_variable(&$$, $1, $3))
MYSQL_YYABORT;
}
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
{
if ($1.str[0]=='O' || $1.str[0]=='o')
my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", ""));
if (lex->trg_chistics.event == TRG_EVENT_DELETE)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
"NEW", "on DELETE");
MYSQL_YYABORT;
}
if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after "));
/* This special combination will denote field of NEW row */
$$.var= trg_new_row_fake_var;
$$.base_name= $3;
}
else
{
sys_var *tmp=find_sys_var(thd, $3.str, $3.length);
if (!tmp)
MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
$$.base_name= $1;
}
}
| DEFAULT '.' ident
{
sys_var *tmp=find_sys_var(thd, $3.str, $3.length);
if (!tmp)
if (Lex->init_default_internal_variable(&$$, $3))
MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
$$.base_name.str= (char*) "default";
$$.base_name.length= 7;
}
;
......
......@@ -215,18 +215,6 @@ static bool push_sp_empty_label(THD *thd)
}
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)
tmp->base_name= null_lex_str;
return thd->is_error();
}
#define bincmp_collation(X,Y) \
do \
{ \
......@@ -335,10 +323,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
Currently there are 102 shift/reduce conflicts.
Currently there are 104 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
%expect 102
%expect 104
/*
Comments for TOKENS.
......@@ -1059,7 +1047,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_component key_cache_name
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident
label_declaration_oracle
label_declaration_oracle ident_directly_assignable
%type <lex_string_with_metadata>
TEXT_STRING
......@@ -1217,6 +1205,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <Lex_length_and_dec> precision opt_precision float_options
%type <symbol> keyword keyword_sp
keyword_directly_assignable
keyword_directly_not_assignable
%type <lex_user> user grant_user grant_role user_or_role current_role
admin_option_for_role user_maybe_role
......@@ -1234,6 +1224,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
UNDERSCORE_CHARSET
%type <variable> internal_variable_name
internal_variable_name_directly_assignable
%type <select_lex> subselect
get_select_lex get_select_lex_derived
......@@ -1320,6 +1311,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
vcol_opt_attribute_list vcol_attribute
opt_serial_attribute opt_serial_attribute_list serial_attribute
explainable_command
set_assign
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
......@@ -1507,6 +1499,7 @@ statement:
| savepoint
| select
| set
| set_assign
| signal_stmt
| show
| shutdown
......@@ -13788,6 +13781,26 @@ ident:
}
;
ident_directly_assignable:
IDENT_sys { $$=$1; }
| keyword_directly_assignable
{
$$.str= thd->strmake($1.str, $1.length);
if ($$.str == NULL)
MYSQL_YYABORT;
$$.length= $1.length;
}
| keyword_sp
{
$$.str= thd->strmake($1.str, $1.length);
if ($$.str == NULL)
MYSQL_YYABORT;
$$.length= $1.length;
}
;
label_ident:
IDENT_sys { $$=$1; }
| keyword_sp
......@@ -13876,27 +13889,30 @@ user: user_maybe_role
/* Keyword that we allow for identifiers (except SP labels) */
keyword:
keyword_sp {}
| ASCII_SYM {}
| keyword_directly_assignable {}
| keyword_directly_not_assignable {}
;
/*
Keywords that we allow in Oracle-style direct assignments:
xxx := 10;
*/
keyword_directly_assignable:
ASCII_SYM {}
| BACKUP_SYM {}
| BEGIN_SYM {}
| BINLOG_SYM {}
| BYTE_SYM {}
| CACHE_SYM {}
| CHARSET {}
| CHECKSUM_SYM {}
| CHECKPOINT_SYM {}
| CLOSE_SYM {}
| COLUMN_ADD_SYM {}
| COLUMN_CHECK_SYM {}
| COLUMN_CREATE_SYM {}
| COLUMN_DELETE_SYM {}
| COLUMN_GET_SYM {}
| COMMENT_SYM {}
| COMMIT_SYM {}
| CONTAINS_SYM {}
| DEALLOCATE_SYM {}
| DO_SYM {}
| END {}
| EXAMINED_SYM {}
| EXCLUDE_SYM {}
| EXECUTE_SYM {}
......@@ -13905,13 +13921,9 @@ keyword:
| FOLLOWING_SYM {}
| FORMAT_SYM {}
| GET_SYM {}
| HANDLER_SYM {}
| HELP_SYM {}
| HOST_SYM {}
| INSTALL_SYM {}
| LANGUAGE_SYM {}
| NO_SYM {}
| OPEN_SYM {}
| OPTION {}
| OPTIONS_SYM {}
| OTHERS_SYM {}
......@@ -13922,11 +13934,9 @@ keyword:
| PRECEDING_SYM {}
| PREPARE_SYM {}
| REMOVE_SYM {}
| REPAIR {}
| RESET_SYM {}
| RESTORE_SYM {}
| ROLLBACK_SYM {}
| SAVEPOINT_SYM {}
| SECURITY_SYM {}
| SERVER_SYM {}
| SHUTDOWN {}
......@@ -13939,7 +13949,6 @@ keyword:
| STOP_SYM {}
| STORED_SYM {}
| TIES_SYM {}
| TRUNCATE_SYM {}
| UNICODE_SYM {}
| UNINSTALL_SYM {}
| UNBOUNDED_SYM {}
......@@ -13948,6 +13957,51 @@ keyword:
| UPGRADE_SYM {}
;
/*
Keywords that are allowed as identifiers (e.g. table, column names),
but:
- not allowed as SP label names
- not allowed as variable names in Oracle-style assignments:
xxx := 10;
If we allowed these variables in assignments, there would be conflicts
with SP characteristics, or verb clauses, or compound statements, e.g.:
CREATE PROCEDURE p1 LANGUAGE ...
would be either:
CREATE PROCEDURE p1 LANGUAGE SQL BEGIN END;
or
CREATE PROCEDURE p1 LANGUAGE:=10;
Note, these variables can still be assigned using quoted identifiers:
`do`:= 10;
"do":= 10; (when ANSI_QUOTES)
or using a SET statement:
SET do= 10;
Note, some of these keywords are reserved keywords in Oracle.
In case if heavy grammar conflicts are found in the future,
we'll possibly need to make them reserved for sql_mode=ORACLE.
TODO: Allow these variables as SP lables when sql_mode=ORACLE.
TODO: Allow assigning of "SP characteristics" marked variables
inside compound blocks.
*/
keyword_directly_not_assignable:
CONTAINS_SYM { /* SP characteristic */ }
| LANGUAGE_SYM { /* SP characteristic */ }
| NO_SYM { /* SP characteristic */ }
| CHARSET { /* SET CHARSET utf8; */ }
| DO_SYM { /* Verb clause */ }
| REPAIR { /* Verb clause */ }
| HANDLER_SYM { /* Verb clause */ }
| CLOSE_SYM { /* Verb clause. Reserved in Oracle */ }
| OPEN_SYM { /* Verb clause. Reserved in Oracle */ }
| SAVEPOINT_SYM { /* Verb clause. Reserved in Oracle */ }
| TRUNCATE_SYM { /* Verb clause. Reserved in Oracle */ }
| BEGIN_SYM { /* Compound. Reserved in Oracle */ }
| END { /* Compound. Reserved in Oracle */ }
;
/*
* Keywords that we allow for labels in SPs.
* Anything that's the beginning of a statement or characteristics
......@@ -14271,7 +14325,7 @@ keyword_sp:
| X509_SYM {}
| XML_SYM {}
| YEAR_SYM {}
| VIA_SYM {}
| VIA_SYM {}
;
/*
......@@ -14285,22 +14339,15 @@ set:
SET
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_SET_OPTION;
mysql_init_select(lex);
lex->option_type=OPT_SESSION;
lex->set_stmt_init();
lex->var_list.empty();
lex->autocommit= 0;
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
start_option_value_list
{}
| SET STATEMENT_SYM
{
LEX *lex= Lex;
mysql_init_select(lex);
lex->option_type= OPT_SESSION;
lex->sql_command= SQLCOM_SET_OPTION;
lex->autocommit= 0;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
{
......@@ -14314,6 +14361,28 @@ set:
{}
;
set_assign:
internal_variable_name_directly_assignable SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
set_expr_or_default
{
sp_pcontext *spc= Lex->spcont;
sp_variable *spv= spc->find_variable($1.base_name, false);
/* It is a local variable. */
if (Lex->set_local_variable(spv, $4))
MYSQL_YYABORT;
if (sp_create_assignment_instr(thd, yychar == YYEMPTY))
MYSQL_YYABORT;
}
;
set_stmt_option_value_following_option_type_list:
/*
Only system variables can be used here. If this condition is changed
......@@ -14598,77 +14667,37 @@ option_value_no_option_type:
internal_variable_name:
ident
{
sp_pcontext *spc= thd->lex->spcont;
sp_variable *spv;
/* Best effort lookup for system variable. */
if (!spc || !(spv = spc->find_variable($1, false)))
{
struct sys_var_with_base tmp= {NULL, $1};
if (Lex->init_internal_variable(&$$, $1))
MYSQL_YYABORT;
}
| ident '.' ident
{
if (Lex->init_internal_variable(&$$, $1, $3))
MYSQL_YYABORT;
}
| DEFAULT '.' ident
{
if (Lex->init_default_internal_variable(&$$, $3))
MYSQL_YYABORT;
}
;
/* Not an SP local variable */
if (find_sys_var_null_base(thd, &tmp))
MYSQL_YYABORT;
$$= tmp;
}
else
{
/*
Possibly an SP local variable (or a shadowed sysvar).
Will depend on the context of the SET statement.
*/
$$.var= NULL;
$$.base_name= $1;
}
internal_variable_name_directly_assignable:
ident_directly_assignable
{
if (Lex->init_internal_variable(&$$, $1))
MYSQL_YYABORT;
}
| ident '.' ident
| ident_directly_assignable '.' ident
{
LEX *lex= Lex;
if (check_reserved_words(&$1))
{
thd->parse_error();
if (Lex->init_internal_variable(&$$, $1, $3))
MYSQL_YYABORT;
}
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
{
if ($1.str[0]=='O' || $1.str[0]=='o')
my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", ""));
if (lex->trg_chistics.event == TRG_EVENT_DELETE)
{
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
"NEW", "on DELETE");
MYSQL_YYABORT;
}
if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
my_yyabort_error((ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after "));
/* This special combination will denote field of NEW row */
$$.var= trg_new_row_fake_var;
$$.base_name= $3;
}
else
{
sys_var *tmp=find_sys_var(thd, $3.str, $3.length);
if (!tmp)
MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
$$.base_name= $1;
}
}
| DEFAULT '.' ident
{
sys_var *tmp=find_sys_var(thd, $3.str, $3.length);
if (!tmp)
if (Lex->init_default_internal_variable(&$$, $3))
MYSQL_YYABORT;
if (!tmp->is_struct())
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
$$.var= tmp;
$$.base_name.str= (char*) "default";
$$.base_name.length= 7;
}
;
......@@ -15485,11 +15514,6 @@ opt_release:
| NO_SYM RELEASE_SYM { $$= TVL_NO; }
;
opt_savepoint:
/* empty */ {}
| SAVEPOINT_SYM {}
;
commit:
COMMIT_SYM opt_work opt_chain opt_release
{
......@@ -15512,13 +15536,18 @@ rollback:
lex->tx_chain= $3;
lex->tx_release= $4;
}
| ROLLBACK_SYM opt_work
TO_SYM opt_savepoint ident
| ROLLBACK_SYM opt_work TO_SYM SAVEPOINT_SYM ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
lex->ident= $5;
}
| ROLLBACK_SYM opt_work TO_SYM ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
lex->ident= $4;
}
;
savepoint:
......
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