diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:00:34 +0000 |
commit | 3f619478f796eddbba6e39502fe941b285dd97b1 (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /sql/sql_yacc.yy | |
parent | Initial commit. (diff) | |
download | mariadb-3f619478f796eddbba6e39502fe941b285dd97b1.tar.xz mariadb-3f619478f796eddbba6e39502fe941b285dd97b1.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r-- | sql/sql_yacc.yy | 19510 |
1 files changed, 19510 insertions, 0 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy new file mode 100644 index 00000000..ffa70dea --- /dev/null +++ b/sql/sql_yacc.yy @@ -0,0 +1,19510 @@ +/* + Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2023, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* sql_yacc.yy */ + +/** + @defgroup Parser Parser + @{ +*/ + +%{ +#define YYLIP (& thd->m_parser_state->m_lip) +#define YYPS (& thd->m_parser_state->m_yacc) +#define YYCSCL (thd->variables.character_set_client) + +#define MYSQL_YACC +#define YYINITDEPTH 100 +#define YYMAXDEPTH 3200 /* Because of 64K stack */ +#define Lex (thd->lex) + +#define Select Lex->current_select +#include "mariadb.h" +#include "sql_priv.h" +#include "sql_parse.h" /* comp_*_creator */ +#include "sql_table.h" /* primary_key_name */ +#include "sql_partition.h" /* partition_info, HASH_PARTITION */ +#include "sql_class.h" /* Key_part_spec, enum_filetype, Diag_condition_item_name */ +#include "slave.h" +#include "lex_symbol.h" +#include "item_create.h" +#include "sp_head.h" +#include "sp_rcontext.h" +#include "sp.h" +#include "sql_show.h" +#include "sql_alter.h" // Sql_cmd_alter_table* +#include "sql_truncate.h" // Sql_cmd_truncate_table +#include "sql_admin.h" // Sql_cmd_analyze/Check..._table +#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part. +#include "sql_handler.h" // Sql_cmd_handler_* +#include "sql_signal.h" +#include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics +#include "sql_cte.h" +#include "sql_window.h" +#include "item_windowfunc.h" +#include "event_parse_data.h" +#include "create_options.h" +#include <myisam.h> +#include <myisammrg.h> +#include "keycaches.h" +#include "set_var.h" +#include "rpl_mi.h" +#include "lex_token.h" +#include "sql_lex.h" +#include "sql_sequence.h" +#include "my_base.h" +#include "sql_type_json.h" +#include "json_table.h" + +/* this is to get the bison compilation windows warnings out */ +#ifdef _MSC_VER +/* warning C4065: switch statement contains 'default' but no 'case' labels */ +/* warning C4102: 'yyexhaustedlab': unreferenced label */ +#pragma warning (disable : 4065 4102) +#endif +#if defined (__GNUC__) || defined (__clang__) +#pragma GCC diagnostic ignored "-Wunused-label" /* yyexhaustedlab: */ +#endif + +int yylex(void *yylval, void *yythd); + +#define yyoverflow(A,B,C,D,E,F) \ + { \ + size_t val= *(F); \ + if (unlikely(my_yyoverflow((B), (D), &val))) \ + { \ + yyerror(thd, (char*) (A)); \ + return 2; \ + } \ + else \ + { \ + *(F)= (YYSIZE_T)val; \ + } \ + } + +#define MYSQL_YYABORT \ + do \ + { \ + YYABORT; \ + } while (0) + +#define MYSQL_YYABORT_UNLESS(A) \ + if (unlikely(!(A))) \ + { \ + thd->parse_error(); \ + MYSQL_YYABORT; \ + } + +#define my_yyabort_error(A) \ + do { my_error A; MYSQL_YYABORT; } while(0) + +#ifndef DBUG_OFF +#define YYDEBUG 1 +#else +#define YYDEBUG 0 +#endif + + +static Item* escape(THD *thd) +{ + thd->lex->escape_used= false; + const char *esc= thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES ? "" : "\\"; + return new (thd->mem_root) Item_string_ascii(thd, esc, MY_TEST(esc[0])); +} + + +/** + @brief Bison callback to report a syntax/OOM error + + This function is invoked by the bison-generated parser + when a syntax error, a parse error or an out-of-memory + condition occurs. This function is not invoked when the + parser is requested to abort by semantic action code + by means of YYABORT or YYACCEPT macros. This is why these + macros should not be used (use MYSQL_YYABORT/MYSQL_YYACCEPT + instead). + + The parser will abort immediately after invoking this callback. + + This function is not for use in semantic actions and is internal to + the parser, as it performs some pre-return cleanup. + In semantic actions, please use thd->parse_error() or my_error to + push an error into the error stack and MYSQL_YYABORT + to abort from the parser. +*/ + +static void yyerror(THD *thd, const char *s) +{ + /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */ + if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0) + s= ER_THD(thd, ER_SYNTAX_ERROR); + thd->parse_error(s, 0); +} + + +#ifndef DBUG_OFF +#define __CONCAT_UNDERSCORED(x,y) x ## _ ## y +#define _CONCAT_UNDERSCORED(x,y) __CONCAT_UNDERSCORED(x,y) +void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)() +{ + /* + MYSQLdebug is in sql/yy_*.cc, in bison generated code. + Turning this option on is **VERY** verbose, and should be + used when investigating a syntax error problem only. + + The syntax to run with bison traces is as follows : + - Starting a server manually : + mysqld --debug-dbug="d,parser_debug" ... + - Running a test : + mysql-test-run.pl --mysqld="--debug-dbug=d,parser_debug" ... + + The result will be in the process stderr (var/log/master.err) + */ + +#ifndef _AIX + extern int yydebug; +#else + static int yydebug; +#endif + yydebug= 1; +} +#endif + + +%} +%union { + int num; + ulong ulong_num; + ulonglong ulonglong_number; + longlong longlong_number; + uint sp_instr_addr; + + /* structs */ + LEX_CSTRING lex_str; + Lex_ident_cli_st kwd; + Lex_ident_cli_st ident_cli; + Lex_ident_sys_st ident_sys; + Lex_column_list_privilege_st column_list_privilege; + Lex_string_with_metadata_st lex_string_with_metadata; + Lex_spblock_st spblock; + Lex_spblock_handlers_st spblock_handlers; + Lex_length_and_dec_st Lex_length_and_dec; + Lex_cast_type_st Lex_cast_type; + Lex_field_type_st Lex_field_type; + Lex_exact_charset_extended_collation_attrs_st + Lex_exact_charset_extended_collation_attrs; + Lex_extended_collation_st Lex_extended_collation; + Lex_dyncol_type_st Lex_dyncol_type; + Lex_for_loop_st for_loop; + Lex_for_loop_bounds_st for_loop_bounds; + Lex_trim_st trim; + Json_table_column::On_response json_on_response; + Lex_substring_spec_st substring_spec; + vers_history_point_t vers_history_point; + struct + { + enum sub_select_type unit_type; + bool distinct; + } unit_operation; + struct + { + SELECT_LEX *first; + SELECT_LEX *prev_last; + } select_list; + SQL_I_List<ORDER> *select_order; + Lex_select_lock select_lock; + Lex_select_limit select_limit; + Lex_order_limit_lock *order_limit_lock; + + /* pointers */ + Lex_ident_sys *ident_sys_ptr; + Create_field *create_field; + Spvar_definition *spvar_definition; + Row_definition_list *spvar_definition_list; + const Type_handler *type_handler; + const class Sp_handler *sp_handler; + CHARSET_INFO *charset; + Condition_information_item *cond_info_item; + DYNCALL_CREATE_DEF *dyncol_def; + Diagnostics_information *diag_info; + Item *item; + Item_num *item_num; + Item_param *item_param; + Item_basic_constant *item_basic_constant; + Key_part_spec *key_part; + LEX *lex; + sp_expr_lex *expr_lex; + sp_assignment_lex *assignment_lex; + class sp_lex_cursor *sp_cursor_stmt; + LEX_CSTRING *lex_str_ptr; + LEX_USER *lex_user; + USER_AUTH *user_auth; + List<Condition_information_item> *cond_info_list; + List<DYNCALL_CREATE_DEF> *dyncol_def_list; + List<Item> *item_list; + List<sp_assignment_lex> *sp_assignment_lex_list; + List<Statement_information_item> *stmt_info_list; + List<String> *string_list; + List<Lex_ident_sys> *ident_sys_list; + Statement_information_item *stmt_info_item; + String *string; + TABLE_LIST *table_list; + Table_ident *table; + Qualified_column_ident *qualified_column_ident; + char *simple_string; + const char *const_simple_string; + chooser_compare_func_creator boolfunc2creator; + class Lex_grant_privilege *lex_grant; + class Lex_grant_object_name *lex_grant_ident; + class my_var *myvar; + class sp_condition_value *spcondvalue; + class sp_head *sphead; + class sp_name *spname; + class sp_variable *spvar; + class With_element_head *with_element_head; + class With_clause *with_clause; + class Virtual_column_info *virtual_column; + engine_option_value *engine_option_value_ptr; + + handlerton *db_type; + st_select_lex *select_lex; + st_select_lex_unit *select_lex_unit; + struct p_elem_val *p_elem_value; + class Window_frame *window_frame; + class Window_frame_bound *window_frame_bound; + udf_func *udf; + st_trg_execution_order trg_execution_order; + + /* enums */ + enum enum_sp_suid_behaviour sp_suid; + enum enum_sp_aggregate_type sp_aggregate_type; + enum enum_view_suid view_suid; + enum Condition_information_item::Name cond_info_item_name; + enum enum_diag_condition_item_name diag_condition_item_name; + enum Diagnostics_information::Which_area diag_area; + enum enum_fk_option m_fk_option; + enum Item_udftype udf_type; + enum Key::Keytype key_type; + enum Statement_information_item::Name stmt_info_item_name; + enum enum_filetype filetype; + enum enum_tx_isolation tx_isolation; + enum enum_var_type var_type; + enum enum_yes_no_unknown m_yes_no_unk; + enum ha_choice choice; + enum ha_key_alg key_alg; + enum ha_rkey_function ha_rkey_mode; + enum index_hint_type index_hint; + enum interval_type interval, interval_time_st; + enum row_type row_type; + enum sp_variable::enum_mode spvar_mode; + enum thr_lock_type lock_type; + enum enum_mysql_timestamp_type date_time_type; + enum Window_frame_bound::Bound_precedence_type bound_precedence_type; + enum Window_frame::Frame_units frame_units; + enum Window_frame::Frame_exclusion frame_exclusion; + enum trigger_order_type trigger_action_order_type; + DDL_options_st object_ddl_options; + enum vers_kind_t vers_range_unit; + enum Column_definition::enum_column_versioning vers_column_versioning; + enum plsql_cursor_attr_t plsql_cursor_attr; + privilege_t privilege; +} + +%{ +/* avoid unintentional %union size increases, it's what a parser stack made of */ +static_assert(sizeof(YYSTYPE) == sizeof(void*)*2+8, "%union size check"); +bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); +%} + +%define api.pure /* We have threads */ +%parse-param { THD *thd } +%lex-param { THD *thd } +/* + We should not introduce any further shift/reduce conflicts. +*/ + +%ifdef MARIADB +%expect 64 +%else +%expect 65 +%endif + +/* + Comments for TOKENS. + For each token, please include in the same line a comment that contains + the following tags: + SQL-2011-R : Reserved keyword as per SQL-2011 + SQL-2011-N : Non Reserved keyword as per SQL-2011 + SQL-2003-R : Reserved keyword as per SQL-2003 + SQL-2003-N : Non Reserved keyword as per SQL-2003 + SQL-1999-R : Reserved keyword as per SQL-1999 + SQL-1999-N : Non Reserved keyword as per SQL-1999 + MYSQL : MySQL extention (unspecified) + MYSQL-FUNC : MySQL extention, function + INTERNAL : Not a real token, lex optimization + OPERATOR : SQL operator + FUTURE-USE : Reserved for future use + + This makes the code grep-able, and helps maintenance. +*/ + + +%token <lex_str> '@' + +/* + Special purpose tokens +*/ +%token <NONE> ABORT_SYM /* INTERNAL (used in lex) */ +%token <NONE> IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */ +%token <NONE> FORCE_LOOKAHEAD /* INTERNAL never returned by the lexer */ +%token <NONE> END_OF_INPUT /* INTERNAL */ +%token <kwd> COLON_ORACLE_SYM /* INTERNAL */ +%token <kwd> PARAM_MARKER /* INTERNAL */ +%token <NONE> FOR_SYSTEM_TIME_SYM /* INTERNAL */ +%token <NONE> LEFT_PAREN_ALT /* INTERNAL */ +%token <NONE> LEFT_PAREN_WITH /* INTERNAL */ +%token <NONE> LEFT_PAREN_LIKE /* INTERNAL */ +%token <NONE> ORACLE_CONCAT_SYM /* INTERNAL */ +%token <NONE> PERCENT_ORACLE_SYM /* INTERNAL */ +%token <NONE> WITH_CUBE_SYM /* INTERNAL */ +%token <NONE> WITH_ROLLUP_SYM /* INTERNAL */ +%token <NONE> WITH_SYSTEM_SYM /* INTERNAL */ + +/* + Identifiers +*/ +%token IDENT +%token IDENT_QUOTED +%token LEX_HOSTNAME +%token UNDERSCORE_CHARSET /* _latin1 */ + + +/* + Literals +*/ +%token BIN_NUM /* LITERAL */ +%token DECIMAL_NUM /* LITERAL */ +%token FLOAT_NUM /* LITERAL */ +%token HEX_NUM /* LITERAL */ +%token HEX_STRING /* LITERAL */ +%token LONG_NUM /* LITERAL */ +%token NCHAR_STRING /* LITERAL */ +%token NUM /* LITERAL */ +%token TEXT_STRING /* LITERAL */ +%token ULONGLONG_NUM /* LITERAL */ + + +/* + Operators +*/ +%token <NONE> AND_AND_SYM /* OPERATOR */ +%token <NONE> DOT_DOT_SYM /* OPERATOR */ +%token <NONE> EQUAL_SYM /* OPERATOR */ +%token <NONE> GE /* OPERATOR */ +%token <NONE> LE /* OPERATOR */ +%token <NONE> MYSQL_CONCAT_SYM /* OPERATOR */ +%token <NONE> NE /* OPERATOR */ +%token <NONE> NOT2_SYM /* OPERATOR */ +%token <NONE> OR2_SYM /* OPERATOR */ +%token <NONE> SET_VAR /* OPERATOR */ +%token <NONE> SHIFT_LEFT /* OPERATOR */ +%token <NONE> SHIFT_RIGHT /* OPERATOR */ + + +/* + Reserved keywords +*/ +%token <kwd> ACCESSIBLE_SYM +%token <kwd> ADD /* SQL-2003-R */ +%token <kwd> ALL /* SQL-2003-R */ +%token <kwd> ALTER /* SQL-2003-R */ +%token <kwd> ANALYZE_SYM +%token <kwd> AND_SYM /* SQL-2003-R */ +%token <kwd> ASC /* SQL-2003-N */ +%token <kwd> ASENSITIVE_SYM /* FUTURE-USE */ +%token <kwd> AS /* SQL-2003-R */ +%token <kwd> BEFORE_SYM /* SQL-2003-N */ +%token <kwd> BETWEEN_SYM /* SQL-2003-R */ +%token <kwd> BIGINT /* SQL-2003-R */ +%token <kwd> BINARY /* SQL-2003-R */ +%token <kwd> BIT_AND /* MYSQL-FUNC */ +%token <kwd> BIT_OR /* MYSQL-FUNC */ +%token <kwd> BIT_XOR /* MYSQL-FUNC */ +%token <kwd> BLOB_MARIADB_SYM /* SQL-2003-R */ +%token <kwd> BLOB_ORACLE_SYM /* Oracle-R */ +%token <kwd> BODY_ORACLE_SYM /* Oracle-R */ +%token <kwd> BOTH /* SQL-2003-R */ +%token <kwd> BY /* SQL-2003-R */ +%token <kwd> CALL_SYM /* SQL-2003-R */ +%token <kwd> CASCADE /* SQL-2003-N */ +%token <kwd> CASE_SYM /* SQL-2003-R */ +%token <kwd> CAST_SYM /* SQL-2003-R */ +%token <kwd> CHANGE +%token <kwd> CHAR_SYM /* SQL-2003-R */ +%token <kwd> CHECK_SYM /* SQL-2003-R */ +%token <kwd> COLLATE_SYM /* SQL-2003-R */ +%token <kwd> CONDITION_SYM /* SQL-2003-R, SQL-2008-R */ +%token <kwd> CONSTRAINT /* SQL-2003-R */ +%token <kwd> CONTINUE_MARIADB_SYM /* SQL-2003-R, Oracle-R */ +%token <kwd> CONTINUE_ORACLE_SYM /* SQL-2003-R, Oracle-R */ +%token <kwd> CONVERT_SYM /* SQL-2003-N */ +%token <kwd> COUNT_SYM /* SQL-2003-N */ +%token <kwd> CREATE /* SQL-2003-R */ +%token <kwd> CROSS /* SQL-2003-R */ +%token <kwd> CUME_DIST_SYM +%token <kwd> CURDATE /* MYSQL-FUNC */ +%token <kwd> CURRENT_ROLE /* SQL-2003-R */ +%token <kwd> CURRENT_USER /* SQL-2003-R */ +%token <kwd> CURSOR_SYM /* SQL-2003-R */ +%token <kwd> CURTIME /* MYSQL-FUNC */ +%token <kwd> DATABASE +%token <kwd> DATABASES +%token <kwd> DATE_ADD_INTERVAL /* MYSQL-FUNC */ +%token <kwd> DATE_SUB_INTERVAL /* MYSQL-FUNC */ +%token <kwd> DAY_HOUR_SYM +%token <kwd> DAY_MICROSECOND_SYM +%token <kwd> DAY_MINUTE_SYM +%token <kwd> DAY_SECOND_SYM +%token <kwd> DECIMAL_SYM /* SQL-2003-R */ +%token <kwd> DECLARE_MARIADB_SYM /* SQL-2003-R */ +%token <kwd> DECLARE_ORACLE_SYM /* Oracle-R */ +%token <kwd> DEFAULT /* SQL-2003-R */ +%token <kwd> DELETE_DOMAIN_ID_SYM +%token <kwd> DELETE_SYM /* SQL-2003-R */ +%token <kwd> DENSE_RANK_SYM +%token <kwd> DESCRIBE /* SQL-2003-R */ +%token <kwd> DESC /* SQL-2003-N */ +%token <kwd> DETERMINISTIC_SYM /* SQL-2003-R */ +%token <kwd> DISTINCT /* SQL-2003-R */ +%token <kwd> DIV_SYM +%token <kwd> DO_DOMAIN_IDS_SYM +%token <kwd> DOUBLE_SYM /* SQL-2003-R */ +%token <kwd> DROP /* SQL-2003-R */ +%token <kwd> DUAL_SYM +%token <kwd> EACH_SYM /* SQL-2003-R */ +%token <kwd> ELSEIF_MARIADB_SYM +%token <kwd> ELSE /* SQL-2003-R */ +%token <kwd> ELSIF_ORACLE_SYM /* PLSQL-R */ +%token <kwd> EMPTY_SYM /* SQL-2016-R */ +%token <kwd> ENCLOSED +%token <kwd> ESCAPED +%token <kwd> EXCEPT_SYM /* SQL-2003-R */ +%token <kwd> EXISTS /* SQL-2003-R */ +%token <kwd> EXTRACT_SYM /* SQL-2003-N */ +%token <kwd> FALSE_SYM /* SQL-2003-R */ +%token <kwd> FETCH_SYM /* SQL-2003-R */ +%token <kwd> FIRST_VALUE_SYM /* SQL-2011 */ +%token <kwd> FLOAT_SYM /* SQL-2003-R */ +%token <kwd> FOREIGN /* SQL-2003-R */ +%token <kwd> FOR_SYM /* SQL-2003-R */ +%token <kwd> FROM +%token <kwd> FULLTEXT_SYM +%token <kwd> GOTO_ORACLE_SYM /* Oracle-R */ +%token <kwd> GRANT /* SQL-2003-R */ +%token <kwd> GROUP_CONCAT_SYM +%token <rwd> JSON_ARRAYAGG_SYM +%token <rwd> JSON_OBJECTAGG_SYM +%token <kwd> JSON_TABLE_SYM +%token <kwd> GROUP_SYM /* SQL-2003-R */ +%token <kwd> HAVING /* SQL-2003-R */ +%token <kwd> HOUR_MICROSECOND_SYM +%token <kwd> HOUR_MINUTE_SYM +%token <kwd> HOUR_SECOND_SYM +%token <kwd> IF_SYM +%token <kwd> IGNORE_DOMAIN_IDS_SYM +%token <kwd> IGNORE_SYM +%token <kwd> IGNORED_SYM +%token <kwd> INDEX_SYM +%token <kwd> INFILE +%token <kwd> INNER_SYM /* SQL-2003-R */ +%token <kwd> INOUT_SYM /* SQL-2003-R */ +%token <kwd> INSENSITIVE_SYM /* SQL-2003-R */ +%token <kwd> INSERT /* SQL-2003-R */ +%token <kwd> IN_SYM /* SQL-2003-R */ +%token <kwd> INTERSECT_SYM /* SQL-2003-R */ +%token <kwd> INTERVAL_SYM /* SQL-2003-R */ +%token <kwd> INTO /* SQL-2003-R */ +%token <kwd> INT_SYM /* SQL-2003-R */ +%token <kwd> IS /* SQL-2003-R */ +%token <kwd> ITERATE_SYM +%token <kwd> JOIN_SYM /* SQL-2003-R */ +%token <kwd> KEYS +%token <kwd> KEY_SYM /* SQL-2003-N */ +%token <kwd> KILL_SYM +%token <kwd> LAG_SYM /* SQL-2011 */ +%token <kwd> LEADING /* SQL-2003-R */ +%token <kwd> LEAD_SYM /* SQL-2011 */ +%token <kwd> LEAVE_SYM +%token <kwd> LEFT /* SQL-2003-R */ +%token <kwd> LIKE /* SQL-2003-R */ +%token <kwd> LIMIT +%token <kwd> LINEAR_SYM +%token <kwd> LINES +%token <kwd> LOAD +%token <kwd> LOCATOR_SYM /* SQL-2003-N */ +%token <kwd> LOCK_SYM +%token <kwd> LONGBLOB +%token <kwd> LONG_SYM +%token <kwd> LONGTEXT +%token <kwd> LOOP_SYM +%token <kwd> LOW_PRIORITY +%token <kwd> MASTER_SSL_VERIFY_SERVER_CERT_SYM +%token <kwd> MATCH /* SQL-2003-R */ +%token <kwd> MAX_SYM /* SQL-2003-N */ +%token <kwd> MAXVALUE_SYM /* SQL-2003-N */ +%token <kwd> MEDIAN_SYM +%token <kwd> MEDIUMBLOB +%token <kwd> MEDIUMINT +%token <kwd> MEDIUMTEXT +%token <kwd> MIN_SYM /* SQL-2003-N */ +%token <kwd> MINUS_ORACLE_SYM /* Oracle-R */ +%token <kwd> MINUTE_MICROSECOND_SYM +%token <kwd> MINUTE_SECOND_SYM +%token <kwd> MODIFIES_SYM /* SQL-2003-R */ +%token <kwd> MOD_SYM /* SQL-2003-N */ +%token <kwd> NATURAL /* SQL-2003-R */ +%token <kwd> NEG +%token <kwd> NESTED_SYM /* SQL-2003-N */ +%token <kwd> NOT_SYM /* SQL-2003-R */ +%token <kwd> NO_WRITE_TO_BINLOG +%token <kwd> NOW_SYM +%token <kwd> NTH_VALUE_SYM /* SQL-2011 */ +%token <kwd> NTILE_SYM +%token <kwd> NULL_SYM /* SQL-2003-R */ +%token <kwd> NUMERIC_SYM /* SQL-2003-R */ +%token <kwd> ON /* SQL-2003-R */ +%token <kwd> OPTIMIZE +%token <kwd> OPTIONALLY +%token <kwd> ORDER_SYM /* SQL-2003-R */ +%token <kwd> ORDINALITY_SYM /* SQL-2003-N */ +%token <kwd> OR_SYM /* SQL-2003-R */ +%token <kwd> OTHERS_ORACLE_SYM /* SQL-2011-N, PLSQL-R */ +%token <kwd> OUTER +%token <kwd> OUTFILE +%token <kwd> OUT_SYM /* SQL-2003-R */ +%token <kwd> OVER_SYM +%token <kwd> PACKAGE_ORACLE_SYM /* Oracle-R */ +%token <kwd> PAGE_CHECKSUM_SYM +%token <kwd> PARSE_VCOL_EXPR_SYM +%token <kwd> PARTITION_SYM /* SQL-2003-R */ +%token <kwd> PATH_SYM /* SQL-2003-N */ +%token <kwd> PERCENTILE_CONT_SYM +%token <kwd> PERCENTILE_DISC_SYM +%token <kwd> PERCENT_RANK_SYM +%token <kwd> PORTION_SYM /* SQL-2016-R */ +%token <kwd> POSITION_SYM /* SQL-2003-N */ +%token <kwd> PRECISION /* SQL-2003-R */ +%token <kwd> PRIMARY_SYM /* SQL-2003-R */ +%token <kwd> PROCEDURE_SYM /* SQL-2003-R */ +%token <kwd> PURGE +%token <kwd> RAISE_ORACLE_SYM /* PLSQL-R */ +%token <kwd> RANGE_SYM /* SQL-2003-R */ +%token <kwd> RANK_SYM +%token <kwd> READS_SYM /* SQL-2003-R */ +%token <kwd> READ_SYM /* SQL-2003-N */ +%token <kwd> READ_WRITE_SYM +%token <kwd> REAL /* SQL-2003-R */ +%token <kwd> RECURSIVE_SYM +%token <kwd> REFERENCES /* SQL-2003-R */ +%token <kwd> REF_SYSTEM_ID_SYM +%token <kwd> REGEXP +%token <kwd> RELEASE_SYM /* SQL-2003-R */ +%token <kwd> RENAME +%token <kwd> REPEAT_SYM /* MYSQL-FUNC */ +%token <kwd> REQUIRE_SYM +%token <kwd> RESIGNAL_SYM /* SQL-2003-R */ +%token <kwd> RESTRICT +%token <kwd> RETURNING_SYM +%token <kwd> RETURN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */ +%token <kwd> RETURN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */ +%token <kwd> REVOKE /* SQL-2003-R */ +%token <kwd> RIGHT /* SQL-2003-R */ +%token <kwd> ROW_NUMBER_SYM +%token <kwd> ROWS_SYM /* SQL-2003-R */ +%token <kwd> ROWTYPE_ORACLE_SYM /* PLSQL-R */ +%token <kwd> SECOND_MICROSECOND_SYM +%token <kwd> SELECT_SYM /* SQL-2003-R */ +%token <kwd> SENSITIVE_SYM /* FUTURE-USE */ +%token <kwd> SEPARATOR_SYM +%token <kwd> SERVER_OPTIONS +%token <kwd> SET /* SQL-2003-R */ +%token <kwd> SHOW +%token <kwd> SIGNAL_SYM /* SQL-2003-R */ +%token <kwd> SMALLINT /* SQL-2003-R */ +%token <kwd> SPATIAL_SYM +%token <kwd> SPECIFIC_SYM /* SQL-2003-R */ +%token <kwd> SQL_BIG_RESULT +%token <kwd> SQLEXCEPTION_SYM /* SQL-2003-R */ +%token <kwd> SQL_SMALL_RESULT +%token <kwd> SQLSTATE_SYM /* SQL-2003-R */ +%token <kwd> SQL_SYM /* SQL-2003-R */ +%token <kwd> SQLWARNING_SYM /* SQL-2003-R */ +%token <kwd> SSL_SYM +%token <kwd> STARTING +%token <kwd> STATS_AUTO_RECALC_SYM +%token <kwd> STATS_PERSISTENT_SYM +%token <kwd> STATS_SAMPLE_PAGES_SYM +%token <kwd> STDDEV_SAMP_SYM /* SQL-2003-N */ +%token <kwd> STD_SYM +%token <kwd> STRAIGHT_JOIN +%token <kwd> SUM_SYM /* SQL-2003-N */ +%token <kwd> SYSDATE +%token <kwd> TABLE_REF_PRIORITY +%token <kwd> TABLE_SYM /* SQL-2003-R */ +%token <kwd> TERMINATED +%token <kwd> THEN_SYM /* SQL-2003-R */ +%token <kwd> TINYBLOB +%token <kwd> TINYINT +%token <kwd> TINYTEXT +%token <kwd> TO_SYM /* SQL-2003-R */ +%token <kwd> TRAILING /* SQL-2003-R */ +%token <kwd> TRIGGER_SYM /* SQL-2003-R */ +%token <kwd> TRUE_SYM /* SQL-2003-R */ +%token <kwd> UNDO_SYM /* FUTURE-USE */ +%token <kwd> UNION_SYM /* SQL-2003-R */ +%token <kwd> UNIQUE_SYM +%token <kwd> UNLOCK_SYM +%token <kwd> UNSIGNED +%token <kwd> UPDATE_SYM /* SQL-2003-R */ +%token <kwd> USAGE /* SQL-2003-N */ +%token <kwd> USE_SYM +%token <kwd> USING /* SQL-2003-R */ +%token <kwd> UTC_DATE_SYM +%token <kwd> UTC_TIMESTAMP_SYM +%token <kwd> UTC_TIME_SYM +%token <kwd> VALUES_IN_SYM +%token <kwd> VALUES_LESS_SYM +%token <kwd> VALUES /* SQL-2003-R */ +%token <kwd> VARBINARY +%token <kwd> VARCHAR /* SQL-2003-R */ +%token <kwd> VARIANCE_SYM +%token <kwd> VAR_SAMP_SYM +%token <kwd> VARYING /* SQL-2003-R */ +%token <kwd> WHEN_SYM /* SQL-2003-R */ +%token <kwd> WHERE /* SQL-2003-R */ +%token <kwd> WHILE_SYM +%token <kwd> WITH /* SQL-2003-R */ +%token <kwd> XOR +%token <kwd> YEAR_MONTH_SYM +%token <kwd> ZEROFILL + + +/* + Keywords that have different reserved status in std/oracle modes. +*/ +%token <kwd> BODY_MARIADB_SYM // Oracle-R +%token <kwd> ELSEIF_ORACLE_SYM +%token <kwd> ELSIF_MARIADB_SYM // PLSQL-R +%token <kwd> EXCEPTION_ORACLE_SYM // SQL-2003-N, PLSQL-R +%token <kwd> GOTO_MARIADB_SYM // Oracle-R +%token <kwd> OTHERS_MARIADB_SYM // SQL-2011-N, PLSQL-R +%token <kwd> PACKAGE_MARIADB_SYM // Oracle-R +%token <kwd> RAISE_MARIADB_SYM // PLSQL-R +%token <kwd> ROWTYPE_MARIADB_SYM // PLSQL-R +%token <kwd> ROWNUM_SYM /* Oracle-R */ + +/* + SQL functions with a special syntax +*/ +%token <kwd> REPLACE /* MYSQL-FUNC */ +%token <kwd> SUBSTRING /* SQL-2003-N */ +%token <kwd> TRIM /* SQL-2003-N */ + + +/* + Non-reserved keywords +*/ + +%token <kwd> ACCOUNT_SYM /* MYSQL */ +%token <kwd> ACTION /* SQL-2003-N */ +%token <kwd> ADMIN_SYM /* SQL-2003-N */ +%token <kwd> ADDDATE_SYM /* MYSQL-FUNC */ +%token <kwd> ADD_MONTHS_SYM /* Oracle FUNC*/ +%token <kwd> AFTER_SYM /* SQL-2003-N */ +%token <kwd> AGAINST +%token <kwd> AGGREGATE_SYM +%token <kwd> ALGORITHM_SYM +%token <kwd> ALWAYS_SYM +%token <kwd> ANY_SYM /* SQL-2003-R */ +%token <kwd> ASCII_SYM /* MYSQL-FUNC */ +%token <kwd> AT_SYM /* SQL-2003-R */ +%token <kwd> ATOMIC_SYM /* SQL-2003-R */ +%token <kwd> AUTHORS_SYM +%token <kwd> AUTOEXTEND_SIZE_SYM +%token <kwd> AUTO_INC +%token <kwd> AUTO_SYM +%token <kwd> AVG_ROW_LENGTH +%token <kwd> AVG_SYM /* SQL-2003-N */ +%token <kwd> BACKUP_SYM +%token <kwd> BEGIN_MARIADB_SYM /* SQL-2003-R, PLSQL-R */ +%token <kwd> BEGIN_ORACLE_SYM /* SQL-2003-R, PLSQL-R */ +%token <kwd> BINLOG_SYM +%token <kwd> BIT_SYM /* MYSQL-FUNC */ +%token <kwd> BLOCK_SYM +%token <kwd> BOOL_SYM +%token <kwd> BOOLEAN_SYM /* SQL-2003-R, PLSQL-R */ +%token <kwd> BTREE_SYM +%token <kwd> BYTE_SYM +%token <kwd> CACHE_SYM +%token <kwd> CASCADED /* SQL-2003-R */ +%token <kwd> CATALOG_NAME_SYM /* SQL-2003-N */ +%token <kwd> CHAIN_SYM /* SQL-2003-N */ +%token <kwd> CHANGED +%token <kwd> CHANNEL_SYM +%token <kwd> CHARSET +%token <kwd> CHECKPOINT_SYM +%token <kwd> CHECKSUM_SYM +%token <kwd> CIPHER_SYM +%token <kwd> CLASS_ORIGIN_SYM /* SQL-2003-N */ +%token <kwd> CLIENT_SYM +%token <kwd> CLOB_MARIADB_SYM /* SQL-2003-R */ +%token <kwd> CLOB_ORACLE_SYM /* Oracle-R */ +%token <kwd> CLOSE_SYM /* SQL-2003-R */ +%token <kwd> COALESCE /* SQL-2003-N */ +%token <kwd> CODE_SYM +%token <kwd> COLLATION_SYM /* SQL-2003-N */ +%token <kwd> COLUMNS +%token <kwd> COLUMN_ADD_SYM +%token <kwd> COLUMN_CHECK_SYM +%token <kwd> COLUMN_CREATE_SYM +%token <kwd> COLUMN_DELETE_SYM +%token <kwd> COLUMN_GET_SYM +%token <kwd> COLUMN_SYM /* SQL-2003-R */ +%token <kwd> COLUMN_NAME_SYM /* SQL-2003-N */ +%token <kwd> COMMENT_SYM /* Oracle-R */ +%token <kwd> COMMITTED_SYM /* SQL-2003-N */ +%token <kwd> COMMIT_SYM /* SQL-2003-R */ +%token <kwd> COMPACT_SYM +%token <kwd> COMPLETION_SYM +%token <kwd> COMPRESSED_SYM +%token <kwd> CONCURRENT +%token <kwd> CONNECTION_SYM +%token <kwd> CONSISTENT_SYM +%token <kwd> CONSTRAINT_CATALOG_SYM /* SQL-2003-N */ +%token <kwd> CONSTRAINT_NAME_SYM /* SQL-2003-N */ +%token <kwd> CONSTRAINT_SCHEMA_SYM /* SQL-2003-N */ +%token <kwd> CONTAINS_SYM /* SQL-2003-N */ +%token <kwd> CONTEXT_SYM +%token <kwd> CONTRIBUTORS_SYM +%token <kwd> CPU_SYM +%token <kwd> CUBE_SYM /* SQL-2003-R */ +%token <kwd> CURRENT_SYM /* SQL-2003-R */ +%token <kwd> CURRENT_POS_SYM +%token <kwd> CURSOR_NAME_SYM /* SQL-2003-N */ +%token <kwd> CYCLE_SYM +%token <kwd> DATAFILE_SYM +%token <kwd> DATA_SYM /* SQL-2003-N */ +%token <kwd> DATETIME +%token <kwd> DATE_FORMAT_SYM /* MYSQL-FUNC */ +%token <kwd> DATE_SYM /* SQL-2003-R, Oracle-R, PLSQL-R */ +%token <kwd> DAY_SYM /* SQL-2003-R */ +%token <kwd> DEALLOCATE_SYM /* SQL-2003-R */ +%token <kwd> DEFINER_SYM +%token <kwd> DELAYED_SYM +%token <kwd> DELAY_KEY_WRITE_SYM +%token <kwd> DES_KEY_FILE +%token <kwd> DIAGNOSTICS_SYM /* SQL-2003-N */ +%token <kwd> DIRECTORY_SYM +%token <kwd> DISABLE_SYM +%token <kwd> DISCARD +%token <kwd> DISK_SYM +%token <kwd> DO_SYM +%token <kwd> DUMPFILE +%token <kwd> DUPLICATE_SYM +%token <kwd> DYNAMIC_SYM /* SQL-2003-R */ +%token <kwd> ENABLE_SYM +%token <kwd> END /* SQL-2003-R, PLSQL-R */ +%token <kwd> ENDS_SYM +%token <kwd> ENGINES_SYM +%token <kwd> ENGINE_SYM +%token <kwd> ENUM +%token <kwd> ERROR_SYM +%token <kwd> ERRORS +%token <kwd> ESCAPE_SYM /* SQL-2003-R */ +%token <kwd> EVENTS_SYM +%token <kwd> EVENT_SYM +%token <kwd> EVERY_SYM /* SQL-2003-N */ +%token <kwd> EXCHANGE_SYM +%token <kwd> EXAMINED_SYM +%token <kwd> EXCLUDE_SYM /* SQL-2011-N */ +%token <kwd> EXECUTE_SYM /* SQL-2003-R */ +%token <kwd> EXCEPTION_MARIADB_SYM /* SQL-2003-N, PLSQL-R */ +%token <kwd> EXIT_MARIADB_SYM /* PLSQL-R */ +%token <kwd> EXIT_ORACLE_SYM /* PLSQL-R */ +%token <kwd> EXPANSION_SYM +%token <kwd> EXPIRE_SYM /* MySQL */ +%token <kwd> EXPORT_SYM +%token <kwd> EXTENDED_SYM +%token <kwd> EXTENT_SIZE_SYM +%token <kwd> FAST_SYM +%token <kwd> FAULTS_SYM +%token <kwd> FEDERATED_SYM /* MariaDB privilege */ +%token <kwd> FILE_SYM +%token <kwd> FIRST_SYM /* SQL-2003-N */ +%token <kwd> FIXED_SYM +%token <kwd> FLUSH_SYM +%token <kwd> FOLLOWS_SYM /* MYSQL trigger*/ +%token <kwd> FOLLOWING_SYM /* SQL-2011-N */ +%token <kwd> FORCE_SYM +%token <kwd> FORMAT_SYM +%token <kwd> FOUND_SYM /* SQL-2003-R */ +%token <kwd> FULL /* SQL-2003-R */ +%token <kwd> FUNCTION_SYM /* SQL-2003-R, Oracle-R */ +%token <kwd> GENERAL +%token <kwd> GENERATED_SYM +%token <kwd> GET_FORMAT /* MYSQL-FUNC */ +%token <kwd> GET_SYM /* SQL-2003-R */ +%token <kwd> GLOBAL_SYM /* SQL-2003-R */ +%token <kwd> GRANTS +%token <kwd> HANDLER_SYM +%token <kwd> HARD_SYM +%token <kwd> HASH_SYM +%token <kwd> HELP_SYM +%token <kwd> HIGH_PRIORITY +%token <kwd> HISTORY_SYM /* MYSQL */ +%token <kwd> HOST_SYM +%token <kwd> HOSTS_SYM +%token <kwd> HOUR_SYM /* SQL-2003-R */ +%token <kwd> ID_SYM /* MYSQL */ +%token <kwd> IDENTIFIED_SYM +%token <kwd> IGNORE_SERVER_IDS_SYM +%token <kwd> IMMEDIATE_SYM /* SQL-2003-R */ +%token <kwd> IMPORT +%token <kwd> INCREMENT_SYM +%token <kwd> INDEXES +%token <kwd> INITIAL_SIZE_SYM +%token <kwd> INSERT_METHOD +%token <kwd> INSTALL_SYM +%token <kwd> INVOKER_SYM +%token <kwd> IO_SYM +%token <kwd> IPC_SYM +%token <kwd> ISOLATION /* SQL-2003-R */ +%token <kwd> ISOPEN_SYM /* Oracle-N */ +%token <kwd> ISSUER_SYM +%token <kwd> INVISIBLE_SYM +%token <kwd> JSON_SYM +%token <kwd> KEY_BLOCK_SIZE +%token <kwd> LANGUAGE_SYM /* SQL-2003-R */ +%token <kwd> LAST_SYM /* SQL-2003-N */ +%token <kwd> LAST_VALUE +%token <kwd> LASTVAL_SYM /* PostgreSQL sequence function */ +%token <kwd> LEAVES +%token <kwd> LESS_SYM +%token <kwd> LEVEL_SYM +%token <kwd> LIST_SYM +%token <kwd> LOCAL_SYM /* SQL-2003-R */ +%token <kwd> LOCKED_SYM +%token <kwd> LOCKS_SYM +%token <kwd> LOGFILE_SYM +%token <kwd> LOGS_SYM +%token <kwd> MASTER_CONNECT_RETRY_SYM +%token <kwd> MASTER_DELAY_SYM +%token <kwd> MASTER_GTID_POS_SYM +%token <kwd> MASTER_HOST_SYM +%token <kwd> MASTER_LOG_FILE_SYM +%token <kwd> MASTER_LOG_POS_SYM +%token <kwd> MASTER_PASSWORD_SYM +%token <kwd> MASTER_PORT_SYM +%token <kwd> MASTER_SERVER_ID_SYM +%token <kwd> MASTER_SSL_CAPATH_SYM +%token <kwd> MASTER_SSL_CA_SYM +%token <kwd> MASTER_SSL_CERT_SYM +%token <kwd> MASTER_SSL_CIPHER_SYM +%token <kwd> MASTER_SSL_CRL_SYM +%token <kwd> MASTER_SSL_CRLPATH_SYM +%token <kwd> MASTER_SSL_KEY_SYM +%token <kwd> MASTER_SSL_SYM +%token <kwd> MASTER_SYM +%token <kwd> MASTER_USER_SYM +%token <kwd> MASTER_USE_GTID_SYM +%token <kwd> MASTER_HEARTBEAT_PERIOD_SYM +%token <kwd> MASTER_DEMOTE_TO_SLAVE_SYM +%token <kwd> MAX_CONNECTIONS_PER_HOUR +%token <kwd> MAX_QUERIES_PER_HOUR +%token <kwd> MAX_ROWS +%token <kwd> MAX_SIZE_SYM +%token <kwd> MAX_UPDATES_PER_HOUR +%token <kwd> MAX_STATEMENT_TIME_SYM +%token <kwd> MAX_USER_CONNECTIONS_SYM +%token <kwd> MEDIUM_SYM +%token <kwd> MEMORY_SYM +%token <kwd> MERGE_SYM /* SQL-2003-R */ +%token <kwd> MESSAGE_TEXT_SYM /* SQL-2003-N */ +%token <kwd> MICROSECOND_SYM /* MYSQL-FUNC */ +%token <kwd> MIGRATE_SYM +%token <kwd> MINUTE_SYM /* SQL-2003-R */ +%token <kwd> MINVALUE_SYM +%token <kwd> MIN_ROWS +%token <kwd> MODE_SYM +%token <kwd> MODIFY_SYM +%token <kwd> MONITOR_SYM /* MariaDB privilege */ +%token <kwd> MONTH_SYM /* SQL-2003-R */ +%token <kwd> MUTEX_SYM +%token <kwd> MYSQL_SYM +%token <kwd> MYSQL_ERRNO_SYM +%token <kwd> NAMES_SYM /* SQL-2003-N */ +%token <kwd> NAME_SYM /* SQL-2003-N */ +%token <kwd> NATIONAL_SYM /* SQL-2003-R */ +%token <kwd> NCHAR_SYM /* SQL-2003-R */ +%token <kwd> NEVER_SYM /* MySQL */ +%token <kwd> NEW_SYM /* SQL-2003-R */ +%token <kwd> NEXT_SYM /* SQL-2003-N */ +%token <kwd> NEXTVAL_SYM /* PostgreSQL sequence function */ +%token <kwd> NOCACHE_SYM +%token <kwd> NOCYCLE_SYM +%token <kwd> NODEGROUP_SYM +%token <kwd> NONE_SYM /* SQL-2003-R */ +%token <kwd> NOTFOUND_SYM /* Oracle-R */ +%token <kwd> NO_SYM /* SQL-2003-R */ +%token <kwd> NOMAXVALUE_SYM +%token <kwd> NOMINVALUE_SYM +%token <kwd> NO_WAIT_SYM +%token <kwd> NOWAIT_SYM +%token <kwd> NUMBER_MARIADB_SYM /* SQL-2003-N */ +%token <kwd> NUMBER_ORACLE_SYM /* Oracle-R, PLSQL-R */ +%token <kwd> NVARCHAR_SYM +%token <kwd> OF_SYM /* SQL-1992-R, Oracle-R */ +%token <kwd> OFFSET_SYM +%token <kwd> OLD_PASSWORD_SYM +%token <kwd> ONE_SYM +%token <kwd> ONLY_SYM /* SQL-2003-R */ +%token <kwd> ONLINE_SYM +%token <kwd> OPEN_SYM /* SQL-2003-R */ +%token <kwd> OPTIONS_SYM +%token <kwd> OPTION /* SQL-2003-N */ +%token <kwd> OVERLAPS_SYM +%token <kwd> OWNER_SYM +%token <kwd> PACK_KEYS_SYM +%token <kwd> PAGE_SYM +%token <kwd> PARSER_SYM +%token <kwd> PARTIAL /* SQL-2003-N */ +%token <kwd> PARTITIONS_SYM +%token <kwd> PARTITIONING_SYM +%token <kwd> PASSWORD_SYM +%token <kwd> PERIOD_SYM /* SQL-2011-R */ +%token <kwd> PERSISTENT_SYM +%token <kwd> PHASE_SYM +%token <kwd> PLUGINS_SYM +%token <kwd> PLUGIN_SYM +%token <kwd> PORT_SYM +%token <kwd> PRECEDES_SYM /* MYSQL */ +%token <kwd> PRECEDING_SYM /* SQL-2011-N */ +%token <kwd> PREPARE_SYM /* SQL-2003-R */ +%token <kwd> PRESERVE_SYM +%token <kwd> PREV_SYM +%token <kwd> PREVIOUS_SYM +%token <kwd> PRIVILEGES /* SQL-2003-N */ +%token <kwd> PROCESS +%token <kwd> PROCESSLIST_SYM +%token <kwd> PROFILE_SYM +%token <kwd> PROFILES_SYM +%token <kwd> PROXY_SYM +%token <kwd> QUARTER_SYM +%token <kwd> QUERY_SYM +%token <kwd> QUICK +%token <kwd> RAW_MARIADB_SYM +%token <kwd> RAW_ORACLE_SYM /* Oracle-R */ +%token <kwd> READ_ONLY_SYM +%token <kwd> REBUILD_SYM +%token <kwd> RECOVER_SYM +%token <kwd> REDOFILE_SYM +%token <kwd> REDO_BUFFER_SIZE_SYM +%token <kwd> REDUNDANT_SYM +%token <kwd> RELAY +%token <kwd> RELAYLOG_SYM +%token <kwd> RELAY_LOG_FILE_SYM +%token <kwd> RELAY_LOG_POS_SYM +%token <kwd> RELAY_THREAD +%token <kwd> RELOAD +%token <kwd> REMOVE_SYM +%token <kwd> REORGANIZE_SYM +%token <kwd> REPAIR +%token <kwd> REPEATABLE_SYM /* SQL-2003-N */ +%token <kwd> REPLAY_SYM /* MariaDB privilege */ +%token <kwd> REPLICATION +%token <kwd> RESET_SYM +%token <kwd> RESTART_SYM +%token <kwd> RESOURCES +%token <kwd> RESTORE_SYM +%token <kwd> RESUME_SYM +%token <kwd> RETURNED_SQLSTATE_SYM /* SQL-2003-N */ +%token <kwd> RETURNS_SYM /* SQL-2003-R */ +%token <kwd> REUSE_SYM /* Oracle-R */ +%token <kwd> REVERSE_SYM +%token <kwd> ROLE_SYM +%token <kwd> ROLLBACK_SYM /* SQL-2003-R */ +%token <kwd> ROLLUP_SYM /* SQL-2003-R */ +%token <kwd> ROUTINE_SYM /* SQL-2003-N */ +%token <kwd> ROWCOUNT_SYM /* Oracle-N */ +%token <kwd> ROW_SYM /* SQL-2003-R */ +%token <kwd> ROW_COUNT_SYM /* SQL-2003-N */ +%token <kwd> ROW_FORMAT_SYM +%token <kwd> RTREE_SYM +%token <kwd> SAVEPOINT_SYM /* SQL-2003-R */ +%token <kwd> SCHEDULE_SYM +%token <kwd> SCHEMA_NAME_SYM /* SQL-2003-N */ +%token <kwd> SECOND_SYM /* SQL-2003-R */ +%token <kwd> SECURITY_SYM /* SQL-2003-N */ +%token <kwd> SEQUENCE_SYM +%token <kwd> SERIALIZABLE_SYM /* SQL-2003-N */ +%token <kwd> SERIAL_SYM +%token <kwd> SESSION_SYM /* SQL-2003-N */ +%token <kwd> SERVER_SYM +%token <kwd> SETVAL_SYM /* PostgreSQL sequence function */ +%token <kwd> SHARE_SYM +%token <kwd> SHUTDOWN +%token <kwd> SIGNED_SYM +%token <kwd> SIMPLE_SYM /* SQL-2003-N */ +%token <kwd> SKIP_SYM +%token <kwd> SLAVE +%token <kwd> SLAVES +%token <kwd> SLAVE_POS_SYM +%token <kwd> SLOW +%token <kwd> SNAPSHOT_SYM +%token <kwd> SOCKET_SYM +%token <kwd> SOFT_SYM +%token <kwd> SONAME_SYM +%token <kwd> SOUNDS_SYM +%token <kwd> SOURCE_SYM +%token <kwd> SQL_BUFFER_RESULT +%token <kwd> SQL_CACHE_SYM +%token <kwd> SQL_CALC_FOUND_ROWS +%token <kwd> SQL_NO_CACHE_SYM +%token <kwd> SQL_THREAD +%token <kwd> STAGE_SYM +%token <kwd> STARTS_SYM +%token <kwd> START_SYM /* SQL-2003-R */ +%token <kwd> STATEMENT_SYM +%token <kwd> STATUS_SYM +%token <kwd> STOP_SYM +%token <kwd> STORAGE_SYM +%token <kwd> STORED_SYM +%token <kwd> STRING_SYM +%token <kwd> SUBCLASS_ORIGIN_SYM /* SQL-2003-N */ +%token <kwd> SUBDATE_SYM +%token <kwd> SUBJECT_SYM +%token <kwd> SUBPARTITIONS_SYM +%token <kwd> SUBPARTITION_SYM +%token <kwd> SUPER_SYM +%token <kwd> SUSPEND_SYM +%token <kwd> SWAPS_SYM +%token <kwd> SWITCHES_SYM +%token <kwd> SYSTEM /* SQL-2011-R */ +%token <kwd> SYSTEM_TIME_SYM /* SQL-2011-R */ +%token <kwd> TABLES +%token <kwd> TABLESPACE +%token <kwd> TABLE_CHECKSUM_SYM +%token <kwd> TABLE_NAME_SYM /* SQL-2003-N */ +%token <kwd> TEMPORARY /* SQL-2003-N */ +%token <kwd> TEMPTABLE_SYM +%token <kwd> TEXT_SYM +%token <kwd> THAN_SYM +%token <kwd> TIES_SYM /* SQL-2011-N */ +%token <kwd> TIMESTAMP /* SQL-2003-R */ +%token <kwd> TIMESTAMP_ADD +%token <kwd> TIMESTAMP_DIFF +%token <kwd> TIME_SYM /* SQL-2003-R, Oracle-R */ +%token <kwd> TRANSACTION_SYM +%token <kwd> TRANSACTIONAL_SYM +%token <kwd> THREADS_SYM +%token <kwd> TRIGGERS_SYM +%token <kwd> TRIM_ORACLE +%token <kwd> TRUNCATE_SYM +%token <kwd> TYPES_SYM +%token <kwd> TYPE_SYM /* SQL-2003-N */ +%token <kwd> UDF_RETURNS_SYM +%token <kwd> UNBOUNDED_SYM /* SQL-2011-N */ +%token <kwd> UNCOMMITTED_SYM /* SQL-2003-N */ +%token <kwd> UNDEFINED_SYM +%token <kwd> UNDOFILE_SYM +%token <kwd> UNDO_BUFFER_SIZE_SYM +%token <kwd> UNICODE_SYM +%token <kwd> UNINSTALL_SYM +%token <kwd> UNKNOWN_SYM /* SQL-2003-R */ +%token <kwd> UNTIL_SYM +%token <kwd> UPGRADE_SYM +%token <kwd> USER_SYM /* SQL-2003-R */ +%token <kwd> USE_FRM +%token <kwd> VALUE_SYM /* SQL-2003-R */ +%token <kwd> VARCHAR2_MARIADB_SYM +%token <kwd> VARCHAR2_ORACLE_SYM /* Oracle-R, PLSQL-R */ +%token <kwd> VARIABLES +%token <kwd> VERSIONING_SYM /* SQL-2011-R */ +%token <kwd> VIA_SYM +%token <kwd> VIEW_SYM /* SQL-2003-N */ +%token <kwd> VISIBLE_SYM /* MySQL 8.0 */ +%token <kwd> VIRTUAL_SYM +%token <kwd> WAIT_SYM +%token <kwd> WARNINGS +%token <kwd> WEEK_SYM +%token <kwd> WEIGHT_STRING_SYM +%token <kwd> WINDOW_SYM /* SQL-2003-R */ +%token <kwd> WITHIN +%token <kwd> WITHOUT /* SQL-2003-R */ +%token <kwd> WORK_SYM /* SQL-2003-N */ +%token <kwd> WRAPPER_SYM +%token <kwd> WRITE_SYM /* SQL-2003-N */ +%token <kwd> X509_SYM +%token <kwd> XA_SYM +%token <kwd> XML_SYM +%token <kwd> YEAR_SYM /* SQL-2003-R */ + +/* A dummy token to force the priority of table_ref production in a join. */ +%left CONDITIONLESS_JOIN +%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING + +%left SET_VAR +%left OR_SYM OR2_SYM +%left XOR +%left AND_SYM AND_AND_SYM + +%left PREC_BELOW_NOT + +/* The precendence of boolean NOT is in fact here. See the comment below. */ + +%left '=' EQUAL_SYM GE '>' LE '<' NE +%nonassoc IS +%right BETWEEN_SYM +%left LIKE SOUNDS_SYM REGEXP IN_SYM +%left '|' +%left '&' +%left SHIFT_LEFT SHIFT_RIGHT +%left '-' '+' ORACLE_CONCAT_SYM +%left '*' '/' '%' DIV_SYM MOD_SYM +%left '^' +%left MYSQL_CONCAT_SYM +/* + Boolean negation has a special branch in "expr" starting with NOT_SYM. + The precedence of logical negation is determined by the grammar itself + (without using Bison terminal symbol precedence) in this order + - Boolean factor (i.e. logical AND) + - Boolean NOT + - Boolean test (such as '=', IS NULL, IS TRUE) + + But we also need a precedence for NOT_SYM in other contexts, + to shift (without reduce) in these cases: + predicate <here> NOT IN ... + predicate <here> NOT BETWEEN ... + predicate <here> NOT LIKE ... + predicate <here> NOT REGEXP ... + If the precedence of NOT_SYM was low, it would reduce immediately + after scanning "predicate" and then produce a syntax error on "NOT". +*/ +%nonassoc NOT_SYM +%nonassoc NEG '~' NOT2_SYM BINARY +%nonassoc COLLATE_SYM +%nonassoc SUBQUERY_AS_EXPR + +/* + Tokens that can change their meaning from identifier to something else + in certain context. + + - TRANSACTION: identifier, history unit: + SELECT transaction FROM t1; + SELECT * FROM t1 FOR SYSTEM_TIME AS OF TRANSACTION @var; + + - TIMESTAMP: identifier, literal, history unit: + SELECT timestamp FROM t1; + SELECT TIMESTAMP '2001-01-01 10:20:30'; + SELECT * FROM t1 FOR SYSTEM_TIME AS OF TIMESTAMP CONCAT(@date,' ',@time); + + - PERIOD: identifier, period for system time: + SELECT period FROM t1; + ALTER TABLE DROP PERIOD FOR SYSTEM TIME; + + - SYSTEM: identifier, system versioning: + SELECT system FROM t1; + ALTER TABLE DROP SYSTEM VERSIONIONG; + + - USER: identifier, user: + SELECT user FROM t1; + KILL USER foo; + + Note, we need here only tokens that cause shift/reduce conflicts + with keyword identifiers. For example: + opt_clause1: %empty | KEYWORD ... ; + clause2: opt_clause1 ident; + KEYWORD can appear both in opt_clause1 and in "ident" through the "keyword" + rule. So the parser reports a conflict on how to interpret KEYWORD: + - as a start of non-empty branch in opt_clause1, or + - as an identifier which follows the empty branch in opt_clause1. + + Example#1: + alter_list_item: + DROP opt_column opt_if_exists_table_element field_ident + | DROP SYSTEM VERSIONING_SYM + SYSTEM can be a keyword in field_ident, or can be a start of + SYSTEM VERSIONING. + + Example#2: + system_time_expr: AS OF_SYM history_point + history_point: opt_history_unit bit_expr + opt_history_unit: | TRANSACTION_SYM + TRANSACTION can be a non-empty history unit, or can be an identifier + in bit_expr. + + In the grammar below we use %prec to explicitly tell Bison to go + through the empty branch in the optional rule only when the lookahead + token does not belong to a small set of selected tokens. + + Tokens NEXT_SYM and PREVIOUS_SYM also change their meaning from + identifiers to sequence operations when followed by VALUE_SYM: + SELECT NEXT VALUE FOR s1, PREVIOUS VALUE FOR s1; + but we don't need to list them here as they do not seem to cause + conflicts (according to bison -v), as both meanings + (as identifier, and as a sequence operation) are parts of the same target + column_default_non_parenthesized_expr, and there are no any optional + clauses between the start of column_default_non_parenthesized_expr + and until NEXT_SYM / PREVIOUS_SYM. +*/ +%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE +%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER COMMENT_SYM + + +/* + Tokens that can appear in a token contraction on the second place + and change the meaning of the previous token. + + - TEXT_STRING: changes the meaning of TIMESTAMP/TIME/DATE + from identifier to literal: + SELECT timestamp FROM t1; + SELECT TIMESTAMP'2001-01-01 00:00:00' FROM t1; + + - Parenthesis: changes the meaning of TIMESTAMP/TIME/DATE + from identifiers to CAST-alike functions: + SELECT timestamp FROM t1; + SELECT timestamp(1) FROM t1; + + - VALUE: changes NEXT and PREVIOUS from identifier to sequence operation: + SELECT next, previous FROM t1; + SELECT NEXT VALUE FOR s1, PREVIOUS VALUE FOR s1; + + - VERSIONING: changes SYSTEM from identifier to SYSTEM VERSIONING + SELECT system FROM t1; + ALTER TABLE t1 ADD SYSTEM VERSIONING; +*/ +%left PREC_BELOW_CONTRACTION_TOKEN2 +%left TEXT_STRING '(' ')' VALUE_SYM VERSIONING_SYM +%left EMPTY_FROM_CLAUSE +%right INTO + +%type <lex_str> + DECIMAL_NUM FLOAT_NUM NUM LONG_NUM + HEX_NUM HEX_STRING + LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident_or_text + TEXT_STRING_sys TEXT_STRING_literal + key_cache_name + sp_opt_label BIN_NUM TEXT_STRING_filesystem + opt_constraint constraint opt_ident + sp_block_label sp_control_label opt_place opt_db + udt_name + +%type <ident_sys> + IDENT_sys + ident + label_ident + sp_decl_ident + ident_or_empty + ident_table_alias + ident_sysvar_name + ident_for_loop_index + +%type <lex_string_with_metadata> + TEXT_STRING + NCHAR_STRING + json_text_literal + json_text_literal_or_num + +%type <lex_str_ptr> + opt_table_alias_clause + table_alias_clause + +%type <ident_cli> + IDENT + IDENT_QUOTED + IDENT_cli + ident_cli + ident_cli_set_usual_case + +%type <ident_sys_ptr> + ident_sys_alloc + +%type <kwd> + keyword_data_type + keyword_cast_type + keyword_ident + keyword_label + keyword_set_special_case + keyword_set_usual_case + keyword_sp_block_section + keyword_sp_decl + keyword_sp_head + keyword_sp_var_and_label + keyword_sp_var_not_label + keyword_sysvar_name + keyword_sysvar_type + keyword_table_alias + keyword_verb_clause + charset + reserved_keyword_udt + reserved_keyword_udt_not_param_type + non_reserved_keyword_udt + +%type <table> + table_ident table_ident_nodb references xid + table_ident_opt_wild create_like + +%type <qualified_column_ident> + optionally_qualified_column_ident + +%type <simple_string> + remember_name remember_end + remember_tok_start + wild_and_where + +%type <const_simple_string> + field_length_str + opt_compression_method + +%type <string> + text_string hex_or_bin_String opt_gconcat_separator + +%type <type_handler> int_type real_type + +%type <sp_handler> sp_handler + +%type <json_on_response> json_on_response + +%type <Lex_field_type> field_type field_type_all + qualified_field_type + field_type_numeric + field_type_string + field_type_lob + field_type_temporal + field_type_misc + json_table_field_type + +%type <Lex_exact_charset_extended_collation_attrs> + binary + opt_binary + opt_binary_and_compression + attribute + attribute_list + field_def + +%type <Lex_extended_collation> + collation_name + collation_name_or_default + + +%type <Lex_dyncol_type> opt_dyncol_type dyncol_type + numeric_dyncol_type temporal_dyncol_type string_dyncol_type + +%type <column_list_privilege> + column_list_privilege + +%type <create_field> field_spec column_def + +%type <num> + order_dir lock_option + udf_type opt_local opt_no_write_to_binlog + opt_temporary all_or_any opt_distinct opt_glimit_clause + opt_ignore_leaves fulltext_options union_option + opt_not + transaction_access_mode_types + opt_natural_language_mode opt_query_expansion + opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment + ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt + optional_flush_tables_arguments + opt_time_precision kill_type kill_option int_num + opt_default_time_precision + case_stmt_body opt_bin_mod opt_for_system_time_clause + opt_if_exists_table_element opt_if_not_exists_table_element + opt_recursive opt_format_xid opt_for_portion_of_time_clause + ignorability + +%type <object_ddl_options> + create_or_replace + opt_if_not_exists + opt_if_exists + +/* + Bit field of MYSQL_START_TRANS_OPT_* flags. +*/ +%type <num> opt_start_transaction_option_list +%type <num> start_transaction_option_list +%type <num> start_transaction_option + +%type <m_yes_no_unk> + opt_chain opt_release + +%type <m_fk_option> + delete_option + +%type <privilege> + column_privilege + object_privilege + opt_grant_options + opt_grant_option + grant_option_list + grant_option + +%type <lex_grant> + object_privilege_list + grant_privileges + +%type <lex_grant_ident> + grant_ident + +%type <ulong_num> + ulong_num real_ulong_num merge_insert_types + ws_nweights + ws_level_flag_desc ws_level_flag_reverse ws_level_flags + opt_ws_levels ws_level_list ws_level_list_item ws_level_number + ws_level_range ws_level_list_or_range bool + field_options last_field_options + +%type <ulonglong_number> + ulonglong_num real_ulonglong_num + +%type <longlong_number> + longlong_num + +%type <choice> choice + +%type <lock_type> + replace_lock_option opt_low_priority insert_lock_option load_data_lock + insert_replace_option + +%type <item> + literal insert_ident order_ident temporal_literal + simple_ident expr sum_expr in_sum_expr + variable variable_aux + boolean_test + predicate bit_expr parenthesized_expr + table_wild simple_expr column_default_non_parenthesized_expr udf_expr + primary_expr string_factor_expr mysql_concatenation_expr + select_sublist_qualified_asterisk + expr_or_ignore expr_or_ignore_or_default set_expr_or_default + signed_literal expr_or_literal + sp_opt_default + simple_ident_nospvar + field_or_var limit_option + part_func_expr + window_func_expr + window_func + simple_window_func + inverse_distribution_function + percentile_function + inverse_distribution_function_def + explicit_cursor_attr + function_call_keyword + function_call_keyword_timestamp + function_call_nonkeyword + function_call_generic + function_call_conflict kill_expr + signal_allowed_expr + simple_target_specification + condition_number + opt_versioning_interval_start + +%type <num> opt_vers_auto_part + +%type <item_param> param_marker + +%type <item_num> + NUM_literal + +%type <item_basic_constant> text_literal + +%type <item_list> + expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else + ident_list ident_list_arg opt_expr_list + execute_using + execute_params + +%type <sp_cursor_stmt> + sp_cursor_stmt_lex + sp_cursor_stmt + +%type <expr_lex> + expr_lex + +%destructor +{ + /* + In case of a syntax/oom error let's free the sp_expr_lex + instance, but only if it has not been linked to any structures + such as sp_instr_jump_if_not::m_lex_keeper yet, e.g.: + IF f1() THEN1 + i.e. THEN1 came instead of the expected THEN causing a syntax error. + */ + if (!$$->sp_lex_in_use) + delete $$; +} <expr_lex> + + +/* + +// COMMENT_FOR_DESCTRUCTOR: +// +// %destructor is only invoked if the rule parsing fails in the middle. +// If we call YYABORT from the last code block %destructor is not called, +// because Bison's stack already contains the reduced upper level rule. +// If we need to invoke the %destructor after the YYABORT in the last code +// block, we have to add another dummy empty end-of-rule action {} at the end. + +// So to have a %destructor work properly with YYABORT, +// make sure to turn a grammar like this: + +rule: + KEYWORD expr_lex + { + if (condition) // End-of-rule action + YYABORT; + } + ; + +// into: + +rule: + KEYWORD expr_lex + { + if (condition) // This is now a mid-rule action + YYABORT; + } + { + // A dummy empty end-of-rule action. + } + ; +*/ + + +%type <assignment_lex> + assignment_source_lex + assignment_source_expr + for_loop_bound_expr + +%type <sp_assignment_lex_list> + cursor_actual_parameters + opt_parenthesized_cursor_actual_parameters + +%destructor +{ + if ($$) + { + sp_assignment_lex *elem; + List_iterator<sp_assignment_lex> li(*$$); + while ((elem= li++)) + { + if (!elem->sp_lex_in_use) + delete elem; + } + } +} <sp_assignment_lex_list> + + +%type <var_type> + option_type opt_var_type opt_var_ident_type + +%type <key_type> + constraint_key_type fulltext spatial + +%type <key_alg> + btree_or_rtree opt_key_algorithm_clause opt_USING_key_algorithm + +%type <string_list> + using_list opt_use_partition use_partition + +%type <key_part> + key_part + +%type <table_list> + join_table_list join_table + table_factor table_ref esc_table_ref + table_primary_ident table_primary_ident_opt_parens + table_primary_derived table_primary_derived_opt_parens + derived_table_list table_reference_list_parens + nested_table_reference_list join_table_parens + update_table_list table_function +%type <date_time_type> date_time_type; +%type <interval> interval + +%type <interval_time_st> interval_time_stamp + +%type <db_type> storage_engines known_storage_engines + +%type <row_type> row_types + +%type <tx_isolation> isolation_types + +%type <ha_rkey_mode> handler_rkey_mode + +%type <Lex_cast_type> cast_type cast_type_numeric cast_type_temporal + +%type <Lex_length_and_dec> precision opt_precision float_options + field_length opt_field_length + field_scale opt_field_scale + +%type <lex_user> user grant_user grant_role user_or_role current_role + admin_option_for_role user_maybe_role role_name + +%type <user_auth> opt_auth_str auth_expression auth_token + text_or_password + +%type <charset> + charset_name + charset_or_alias + charset_name_or_default + old_or_new_charset_name + old_or_new_charset_name_or_default + opt_load_data_charset + UNDERSCORE_CHARSET + +%type <select_lex> subselect + query_specification + table_value_constructor + simple_table + query_simple + query_primary + subquery + select_into_query_specification + +%type <select_lex_unit> + query_expression + query_expression_no_with_clause + query_expression_body_ext + query_expression_body_ext_parens + query_expression_body + query_specification_start + +%type <boolfunc2creator> comp_op + +%type <dyncol_def> dyncall_create_element + +%type <dyncol_def_list> dyncall_create_list + +%type <myvar> select_outvar + +%type <virtual_column> opt_check_constraint check_constraint virtual_column_func + column_default_expr + +%type <unit_operation> unit_type_decl + +%type <select_lock> + opt_procedure_or_into + opt_select_lock_type + select_lock_type + opt_lock_wait_timeout_new + +%type <select_limit> opt_limit_clause limit_clause limit_options + fetch_first_clause + +%type <order_limit_lock> + query_expression_tail + opt_query_expression_tail + order_or_limit + order_limit_lock + opt_order_limit_lock + +%type <select_order> opt_order_clause order_clause order_list + +%type <NONE> + directly_executable_statement + analyze_stmt_command backup backup_statements + query verb_clause create create_routine change select select_into + do drop drop_routine insert replace insert_start stmt_end + insert_values update delete truncate rename compound_statement + show describe load alter optimize keycache preload flush + reset purge begin_stmt_mariadb commit rollback savepoint release + slave master_def master_defs master_file_def slave_until_opts + repair analyze opt_with_admin opt_with_admin_option + analyze_table_list analyze_table_elem_spec + opt_persistent_stat_clause persistent_stat_spec + persistent_column_stat_spec persistent_index_stat_spec + table_column_list table_index_list table_index_name + check start checksum opt_returning + field_list field_list_item kill key_def constraint_def + keycache_list keycache_list_or_parts assign_to_keycache + assign_to_keycache_parts + preload_list preload_list_or_parts preload_keys preload_keys_parts + select_item_list select_item values_list no_braces + delete_limit_clause fields opt_values values + no_braces_with_names opt_values_with_names values_with_names + procedure_list procedure_list2 procedure_item + handler opt_generated_always + opt_ignore opt_column opt_restrict + grant revoke set lock unlock string_list + table_lock_list table_lock + ref_list opt_match_clause opt_on_update_delete use + opt_delete_options opt_delete_option varchar nchar nvarchar + opt_outer table_list table_name table_alias_ref_list table_alias_ref + compressed_deprecated_data_type_attribute + compressed_deprecated_column_attribute + grant_list + user_list user_and_role_list + rename_list table_or_tables + clear_privileges flush_options flush_option + opt_flush_lock flush_lock flush_options_list + equal optional_braces + opt_mi_check_type opt_to mi_check_types + table_to_table_list table_to_table opt_table_list opt_as + handler_rkey_function handler_read_or_scan + single_multi table_wild_list table_wild_one opt_wild + opt_and + select_var_list select_var_list_init help + opt_extended_describe shutdown + opt_format_json + prepare execute deallocate + statement + sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa + opt_field_or_var_spec fields_or_vars opt_load_data_set_spec + view_list_opt view_list view_select + trigger_tail event_tail + install uninstall partition_entry binlog_base64_event + normal_key_options normal_key_opts all_key_opt + spatial_key_options fulltext_key_options normal_key_opt + fulltext_key_opt spatial_key_opt fulltext_key_opts spatial_key_opts + explain_for_connection + keep_gcc_happy + key_using_alg + part_column_list + period_for_system_time + period_for_application_time + server_def server_options_list server_option + definer_opt no_definer definer get_diagnostics + parse_vcol_expr vcol_opt_specifier vcol_opt_attribute + vcol_opt_attribute_list vcol_attribute + opt_serial_attribute opt_serial_attribute_list serial_attribute + explainable_command + opt_lock_wait_timeout + opt_delete_gtid_domain + asrow_attribute + opt_constraint_no_id + json_table_columns_clause json_table_columns_list json_table_column + json_table_column_type json_opt_on_empty_or_error + json_on_error_response json_on_empty_response + +%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt +%type <NONE> sp_if_then_statements sp_case_then_statements +%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return +%type <NONE> sp_proc_stmt_compound_ok +%type <NONE> sp_proc_stmt_if +%type <NONE> sp_labeled_control sp_unlabeled_control +%type <NONE> sp_labeled_block sp_unlabeled_block +%type <NONE> sp_proc_stmt_continue_oracle +%type <NONE> sp_proc_stmt_exit_oracle +%type <NONE> sp_proc_stmt_leave +%type <NONE> sp_proc_stmt_iterate +%type <NONE> sp_proc_stmt_goto_oracle +%type <NONE> sp_proc_stmt_with_cursor +%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close +%type <NONE> case_stmt_specification +%type <NONE> loop_body while_body repeat_body +%type <NONE> for_loop_statements + +%type <num> view_algorithm view_check_option +%type <view_suid> view_suid opt_view_suid +%type <num> only_or_with_ties + +%type <plsql_cursor_attr> plsql_cursor_attr +%type <sp_suid> sp_suid +%type <sp_aggregate_type> opt_aggregate + +%type <num> sp_decl_idents sp_decl_idents_init_vars +%type <num> sp_handler_type sp_hcond_list +%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value +%type <spname> sp_name +%type <spvar> sp_param_name sp_param_name_and_mode sp_param +%type <spvar> sp_param_anchored +%type <for_loop> sp_for_loop_index_and_bounds +%type <for_loop_bounds> sp_for_loop_bounds +%type <trim> trim_operands +%type <substring_spec> substring_operands +%type <num> opt_sp_for_loop_direction +%type <spvar_mode> sp_parameter_type +%type <index_hint> index_hint_type +%type <num> index_hint_clause normal_join inner_join +%type <filetype> data_or_xml + +%type <NONE> signal_stmt resignal_stmt raise_stmt_oracle +%type <diag_condition_item_name> signal_condition_information_item_name + +%type <trg_execution_order> trigger_follows_precedes_clause; +%type <trigger_action_order_type> trigger_action_order; + +%type <diag_area> which_area; +%type <diag_info> diagnostics_information; +%type <stmt_info_item> statement_information_item; +%type <stmt_info_item_name> statement_information_item_name; +%type <stmt_info_list> statement_information; +%type <cond_info_item> condition_information_item; +%type <cond_info_item_name> condition_information_item_name; +%type <cond_info_list> condition_information; + +%type <spvar_definition> row_field_name row_field_definition +%type <spvar_definition_list> row_field_definition_list row_type_body + +%type <NONE> opt_window_clause window_def_list window_def window_spec +%type <lex_str_ptr> window_name +%type <NONE> opt_window_ref opt_window_frame_clause +%type <frame_units> window_frame_units; +%type <NONE> window_frame_extent; +%type <frame_exclusion> opt_window_frame_exclusion; +%type <window_frame_bound> window_frame_start window_frame_bound; + +%type <kwd> + '-' '+' '*' '/' '%' '(' ')' + ',' '!' '{' '}' '&' '|' + +%type <with_clause> with_clause + +%type <with_element_head> with_element_head + +%type <ident_sys_list> + comma_separated_ident_list + opt_with_column_list + with_column_list + opt_cycle + +%type <vers_range_unit> opt_history_unit +%type <vers_history_point> history_point +%type <vers_column_versioning> with_or_without_system +%type <engine_option_value_ptr> engine_defined_option; + +%ifdef MARIADB +%type <NONE> sp_tail_standalone +%type <NONE> sp_unlabeled_block_not_atomic +%type <NONE> sp_proc_stmt_in_returns_clause +%type <lex_str> sp_label +%type <spblock> sp_decl_handler +%type <spblock> sp_decls +%type <spblock> sp_decl +%type <spblock> sp_decl_body +%type <spblock> sp_decl_variable_list +%type <spblock> sp_decl_variable_list_anchored +%type <kwd> reserved_keyword_udt_param_type +%else +%type <NONE> set_assign +%type <spvar_mode> sp_opt_inout +%type <NONE> sp_tail_standalone +%type <NONE> sp_labelable_stmt +%type <simple_string> remember_end_opt +%type <lex_str> opt_package_routine_end_name +%type <lex_str> label_declaration_oracle +%type <lex_str> labels_declaration_oracle +%type <kwd> keyword_directly_assignable +%type <ident_sys> ident_directly_assignable +%type <ident_cli> ident_cli_directly_assignable +%type <spname> opt_sp_name +%type <spblock> sp_decl_body_list +%type <spblock> opt_sp_decl_body_list +%type <spblock> sp_decl_variable_list +%type <spblock> sp_decl_variable_list_anchored +%type <spblock> sp_decl_non_handler +%type <spblock> sp_decl_non_handler_list +%type <spblock> sp_decl_handler +%type <spblock> sp_decl_handler_list +%type <spblock> opt_sp_decl_handler_list +%type <spblock> package_implementation_routine_definition +%type <spblock> package_implementation_item_declaration +%type <spblock> package_implementation_declare_section +%type <spblock> package_implementation_declare_section_list1 +%type <spblock> package_implementation_declare_section_list2 +%type <spblock_handlers> sp_block_statements_and_exceptions +%type <spblock_handlers> package_implementation_executable_section +%type <sp_instr_addr> sp_instr_addr +%type <num> opt_exception_clause exception_handlers +%type <lex> remember_lex +%type <lex> package_routine_lex +%type <lex> package_specification_function +%type <lex> package_specification_procedure +%endif ORACLE + +%% + + +/* + Indentation of grammar rules: + +rule: <-- starts at col 1 + rule1a rule1b rule1c <-- starts at col 11 + { <-- starts at col 11 + code <-- starts at col 13, indentation is 2 spaces + } + | rule2a rule2b + { + code + } + ; <-- on a line by itself, starts at col 9 + + Also, please do not use any <TAB>, but spaces. + Having a uniform indentation in this file helps + code reviews, patches, merges, and make maintenance easier. + Tip: grep [[:cntrl:]] sql_yacc.yy + Thanks. +*/ + +query: + END_OF_INPUT + { + if (!thd->bootstrap && + (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT))) + my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); + + thd->lex->sql_command= SQLCOM_EMPTY_QUERY; + YYLIP->found_semicolon= NULL; + } + | directly_executable_statement + { + Lex_input_stream *lip = YYLIP; + + if ((thd->client_capabilities & CLIENT_MULTI_QUERIES) && + lip->multi_statements && + ! lip->eof()) + { + /* + We found a well formed query, and multi queries are allowed: + - force the parser to stop after the ';' + - mark the start of the next query for the next invocation + of the parser. + */ + lip->next_state= MY_LEX_END; + lip->found_semicolon= lip->get_ptr(); + } + else + { + /* Single query, terminated. */ + lip->found_semicolon= NULL; + } + } + ';' + opt_end_of_input + | directly_executable_statement END_OF_INPUT + { + /* Single query, not terminated. */ + YYLIP->found_semicolon= NULL; + } + ; + +opt_end_of_input: + /* empty */ + | END_OF_INPUT + ; + +directly_executable_statement: + statement + | begin_stmt_mariadb + | compound_statement + ; + +/* Verb clauses, except begin and compound_statement */ +verb_clause: + alter + | analyze + | analyze_stmt_command + | backup + | binlog_base64_event + | call + | change + | check + | checksum + | commit + | create + | deallocate + | delete + | describe + | do + | drop + | execute + | explain_for_connection + | flush + | get_diagnostics + | grant + | handler + | help + | insert + | install + | keep_gcc_happy + | keycache + | kill + | load + | lock + | optimize + | parse_vcol_expr + | partition_entry + | preload + | prepare + | purge + | raise_stmt_oracle + | release + | rename + | repair + | replace + | reset + | resignal_stmt + | revoke + | rollback + | savepoint + | select + | select_into + | set + | signal_stmt + | show + | shutdown + | slave + | start + | truncate + | uninstall + | unlock + | update + | use + | xa + ; + +deallocate: + deallocate_or_drop PREPARE_SYM ident + { + Lex->stmt_deallocate_prepare($3); + } + ; + +deallocate_or_drop: + DEALLOCATE_SYM + | DROP + ; + +prepare: + PREPARE_SYM ident FROM + { Lex->clause_that_disallows_subselect= "PREPARE..FROM"; } + expr + { + Lex->clause_that_disallows_subselect= NULL; + if (Lex->stmt_prepare($2, $5)) + MYSQL_YYABORT; + } + ; + +execute: + EXECUTE_SYM ident execute_using + { + if (Lex->stmt_execute($2, $3)) + MYSQL_YYABORT; + } + | EXECUTE_SYM IMMEDIATE_SYM + { Lex->clause_that_disallows_subselect= "EXECUTE IMMEDIATE"; } + expr + { Lex->clause_that_disallows_subselect= NULL; } + execute_using + { + if (Lex->stmt_execute_immediate($4, $6)) + MYSQL_YYABORT; + } + ; + +execute_using: + /* nothing */ { $$= NULL; } + | USING + { Lex->clause_that_disallows_subselect= "EXECUTE..USING"; } + execute_params + { + $$= $3; + Lex->clause_that_disallows_subselect= NULL; + } + ; + +execute_params: + expr_or_ignore_or_default + { + if (unlikely(!($$= List<Item>::make(thd->mem_root, $1)))) + MYSQL_YYABORT; + } + | execute_params ',' expr_or_ignore_or_default + { + if (($$= $1)->push_back($3, thd->mem_root)) + MYSQL_YYABORT; + } + ; + + +/* help */ + +help: + HELP_SYM + { + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HELP")); + } + ident_or_text + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_HELP; + lex->help_arg= $3.str; + } + ; + +/* change master */ + +change: + CHANGE MASTER_SYM optional_connection_name TO_SYM + { + Lex->sql_command = SQLCOM_CHANGE_MASTER; + } + master_defs + optional_for_channel + {} + ; + +master_defs: + master_def + | master_defs ',' master_def + ; + +master_def: + MASTER_HOST_SYM '=' TEXT_STRING_sys + { + Lex->mi.host = $3.str; + } + | MASTER_USER_SYM '=' TEXT_STRING_sys + { + Lex->mi.user = $3.str; + } + | MASTER_PASSWORD_SYM '=' TEXT_STRING_sys + { + Lex->mi.password = $3.str; + } + | MASTER_PORT_SYM '=' ulong_num + { + Lex->mi.port = $3; + } + | MASTER_CONNECT_RETRY_SYM '=' ulong_num + { + Lex->mi.connect_retry = $3; + } + | MASTER_DELAY_SYM '=' ulong_num + { + if ($3 > MASTER_DELAY_MAX) + { + my_error(ER_MASTER_DELAY_VALUE_OUT_OF_RANGE, MYF(0), + (ulong) $3, (ulong) MASTER_DELAY_MAX); + } + else + Lex->mi.sql_delay = $3; + } + | MASTER_SSL_SYM '=' ulong_num + { + Lex->mi.ssl= $3 ? + LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; + } + | MASTER_SSL_CA_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_ca= $3.str; + } + | MASTER_SSL_CAPATH_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_capath= $3.str; + } + | MASTER_SSL_CERT_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_cert= $3.str; + } + | MASTER_SSL_CIPHER_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_cipher= $3.str; + } + | MASTER_SSL_KEY_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_key= $3.str; + } + | MASTER_SSL_VERIFY_SERVER_CERT_SYM '=' ulong_num + { + Lex->mi.ssl_verify_server_cert= $3 ? + LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; + } + | MASTER_SSL_CRL_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_crl= $3.str; + } + | MASTER_SSL_CRLPATH_SYM '=' TEXT_STRING_sys + { + Lex->mi.ssl_crlpath= $3.str; + } + + | MASTER_HEARTBEAT_PERIOD_SYM '=' NUM_literal + { + Lex->mi.heartbeat_period= (float) $3->val_real(); + if (unlikely(Lex->mi.heartbeat_period > + SLAVE_MAX_HEARTBEAT_PERIOD) || + unlikely(Lex->mi.heartbeat_period < 0.0)) + my_yyabort_error((ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0), + SLAVE_MAX_HEARTBEAT_PERIOD)); + + if (unlikely(Lex->mi.heartbeat_period > slave_net_timeout)) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX, + ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX)); + } + if (unlikely(Lex->mi.heartbeat_period < 0.001)) + { + if (unlikely(Lex->mi.heartbeat_period != 0.0)) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN, + ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN)); + Lex->mi.heartbeat_period= 0.0; + } + Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE; + } + Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | IGNORE_SERVER_IDS_SYM '=' '(' ignore_server_id_list ')' + { + Lex->mi.repl_ignore_server_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | DO_DOMAIN_IDS_SYM '=' '(' do_domain_id_list ')' + { + Lex->mi.repl_do_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | IGNORE_DOMAIN_IDS_SYM '=' '(' ignore_domain_id_list ')' + { + Lex->mi.repl_ignore_domain_ids_opt= LEX_MASTER_INFO::LEX_MI_ENABLE; + } + | + master_file_def + ; + +ignore_server_id_list: + /* Empty */ + | ignore_server_id + | ignore_server_id_list ',' ignore_server_id + ; + +ignore_server_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_ignore_server_ids, (uchar*) &($1)); + } + ; + +do_domain_id_list: + /* Empty */ + | do_domain_id + | do_domain_id_list ',' do_domain_id + ; + +do_domain_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_do_domain_ids, (uchar*) &($1)); + } + ; + +ignore_domain_id_list: + /* Empty */ + | ignore_domain_id + | ignore_domain_id_list ',' ignore_domain_id + ; + +ignore_domain_id: + ulong_num + { + insert_dynamic(&Lex->mi.repl_ignore_domain_ids, (uchar*) &($1)); + } + ; + +master_file_def: + MASTER_LOG_FILE_SYM '=' TEXT_STRING_sys + { + Lex->mi.log_file_name = $3.str; + } + | MASTER_LOG_POS_SYM '=' ulonglong_num + { + /* + If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it + instead of causing subsequent errors. + We need to do it in this file, because only there we know that + MASTER_LOG_POS has been explicitly specified. On the contrary + in change_master() (sql_repl.cc) we cannot distinguish between 0 + (MASTER_LOG_POS explicitly specified as 0) and 0 (unspecified), + whereas we want to distinguish (specified 0 means "read the binlog + from 0" (4 in fact), unspecified means "don't change the position + (keep the preceding value)"). + */ + Lex->mi.pos= MY_MAX(BIN_LOG_HEADER_SIZE, $3); + } + | RELAY_LOG_FILE_SYM '=' TEXT_STRING_sys + { + Lex->mi.relay_log_name = $3.str; + } + | RELAY_LOG_POS_SYM '=' ulong_num + { + Lex->mi.relay_log_pos = $3; + /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ + Lex->mi.relay_log_pos= MY_MAX(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); + } + | MASTER_USE_GTID_SYM '=' CURRENT_POS_SYM + { + if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS; + } + | MASTER_USE_GTID_SYM '=' SLAVE_POS_SYM + { + if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS; + } + | MASTER_USE_GTID_SYM '=' NO_SYM + { + if (unlikely(Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid")); + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO; + } + | MASTER_DEMOTE_TO_SLAVE_SYM '=' bool + { + Lex->mi.is_demotion_opt= (bool) $3; + } + ; + +optional_connection_name: + /* empty */ + { + LEX *lex= thd->lex; + lex->mi.connection_name= null_clex_str; + } + | connection_name + ; + +connection_name: + TEXT_STRING_sys + { + Lex->mi.connection_name= $1; +#ifdef HAVE_REPLICATION + if (unlikely(check_master_connection_name(&$1))) + my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME")); +#endif + } + ; + +optional_for_channel: + /* empty */ + { + /*do nothing */ + } + | for_channel + + ; + +for_channel: + FOR_SYM CHANNEL_SYM TEXT_STRING_sys + { + if (Lex->mi.connection_name.str != NULL) + { + my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "CONNECTION_NAME AND FOR CHANNEL CAN NOT BE SPECIFIED AT THE SAME TIME)")); + } + else + { + Lex->mi.connection_name= $3; +#ifdef HAVE_REPLICATION + if (unlikely(check_master_connection_name(&$3))) + my_yyabort_error((ER_WRONG_ARGUMENTS, MYF(0), "MASTER_CONNECTION_NAME")); +#endif + } + + } + ; + +/* create a table */ + +create: + create_or_replace opt_temporary TABLE_SYM opt_if_not_exists + { + LEX *lex= thd->lex; + if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_table())) + MYSQL_YYABORT; + lex->create_info.init(); + if (lex->main_select_push()) + MYSQL_YYABORT; + lex->current_select->parsing_place= BEFORE_OPT_LIST; + if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4)) + MYSQL_YYABORT; + } + table_ident + { + LEX *lex= thd->lex; + if (!lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_SHARED_UPGRADABLE)) + MYSQL_YYABORT; + lex->alter_info.reset(); + /* + For CREATE TABLE we should not open the table even if it exists. + If the table exists, we should either not create it or replace it + */ + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + lex->name= null_clex_str; + lex->create_last_non_select_table= lex->last_table(); + lex->inc_select_stack_outer_barrier(); + } + create_body + { + LEX *lex= thd->lex; + create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select + } + | create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident + { + LEX *lex= thd->lex; + if (lex->main_select_push()) + MYSQL_YYABORT; + if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_create_sequence())) + MYSQL_YYABORT; + lex->create_info.init(); + if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2, + $1 | $4))) + MYSQL_YYABORT; + + if (!lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) + MYSQL_YYABORT; + + /* + For CREATE TABLE, an non-existing table is not an error. + Instruct open_tables() to just take an MDL lock if the + table does not exist. + */ + lex->alter_info.reset(); + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + lex->name= null_clex_str; + lex->create_last_non_select_table= lex->last_table(); + if (unlikely(!(lex->create_info.seq_create_info= + new (thd->mem_root) sequence_definition()))) + MYSQL_YYABORT; + } + opt_sequence opt_create_table_options + { + LEX *lex= thd->lex; + + if (unlikely(lex->create_info.seq_create_info->check_and_adjust(1))) + { + my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), + lex->first_select_lex()->table_list.first->db.str, + lex->first_select_lex()->table_list.first-> + table_name.str); + MYSQL_YYABORT; + } + + /* No fields specified, generate them */ + if (unlikely(prepare_sequence_fields(thd, + &lex->alter_info.create_list))) + MYSQL_YYABORT; + + /* CREATE SEQUENCE always creates a sequence */ + Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; + Lex->create_info.sequence= 1; + + create_table_set_open_action_and_adjust_tables(lex); + Lex->pop_select(); //main select + } + | create_or_replace INDEX_SYM opt_if_not_exists + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + ident + opt_key_algorithm_clause + ON table_ident + { + if (Lex->add_create_index_prepare($8)) + MYSQL_YYABORT; + if (Lex->add_create_index(Key::MULTIPLE, &$5, $6, $1 | $3)) + MYSQL_YYABORT; + } + '(' key_list ')' opt_lock_wait_timeout normal_key_options + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace UNIQUE_SYM INDEX_SYM opt_if_not_exists + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + ident + opt_key_algorithm_clause + ON table_ident + { + if (Lex->add_create_index_prepare($9)) + MYSQL_YYABORT; + if (Lex->add_create_index(Key::UNIQUE, &$6, $7, $1 | $4)) + MYSQL_YYABORT; + } + '(' key_list opt_without_overlaps ')' + opt_lock_wait_timeout normal_key_options + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace fulltext INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident + ON table_ident + { + if (Lex->add_create_index_prepare($8)) + MYSQL_YYABORT; + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) + MYSQL_YYABORT; + } + '(' key_list ')' opt_lock_wait_timeout fulltext_key_options + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace spatial INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_not_exists ident + ON table_ident + { + if (Lex->add_create_index_prepare($8)) + MYSQL_YYABORT; + if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5)) + MYSQL_YYABORT; + } + '(' key_list ')' opt_lock_wait_timeout spatial_key_options + opt_index_lock_algorithm + { + Lex->pop_select(); //main select + } + | create_or_replace DATABASE opt_if_not_exists ident + { + Lex->create_info.init(); + } + opt_create_database_options + { + LEX *lex=Lex; + if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_DB, 0, + $1 | $3))) + MYSQL_YYABORT; + lex->name= $4; + } + | create_or_replace definer_opt opt_view_suid VIEW_SYM + opt_if_not_exists table_ident + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->inc_select_stack_outer_barrier(); + if (Lex->add_create_view(thd, $1 | $5, + DTYPE_ALGORITHM_UNDEFINED, $3, $6)) + MYSQL_YYABORT; + } + view_list_opt AS view_select + { + Lex->pop_select(); //main select + } + | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM + opt_if_not_exists table_ident + { + if (unlikely(Lex->add_create_view(thd, $1 | $6, $2, $4, $7))) + MYSQL_YYABORT; + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->inc_select_stack_outer_barrier(); + } + view_list_opt AS view_select + { + Lex->pop_select(); //main select + } + | create_or_replace definer_opt TRIGGER_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } + trigger_tail + { + Lex->pop_select(); //main select + } + | create_or_replace definer_opt EVENT_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } + event_tail + { + Lex->pop_select(); //main select + } + | create_or_replace USER_SYM opt_if_not_exists clear_privileges + grant_list opt_require_clause opt_resource_options opt_account_locking_and_opt_password_expiration + { + if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER, + $1 | $3))) + MYSQL_YYABORT; + } + | create_or_replace ROLE_SYM opt_if_not_exists + clear_privileges role_list opt_with_admin + { + if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_ROLE, + $1 | $3))) + MYSQL_YYABORT; + } + | create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); } + server_def + { } + | create_routine + ; + +opt_sequence: + /* empty */ { } + | sequence_defs + ; + +sequence_defs: + sequence_def + | sequence_defs sequence_def + ; + +sequence_def: + MINVALUE_SYM opt_equal longlong_num + { + Lex->create_info.seq_create_info->min_value= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; + } + | NO_SYM MINVALUE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE")); + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; + } + | NOMINVALUE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_min_value)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MINVALUE")); + Lex->create_info.seq_create_info->used_fields|= seq_field_used_min_value; + } + | MAXVALUE_SYM opt_equal longlong_num + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_max_value)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE")); + Lex->create_info.seq_create_info->max_value= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; + } + | NO_SYM MAXVALUE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE")); + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; + } + | NOMAXVALUE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & seq_field_used_max_value)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "MAXVALUE")); + Lex->create_info.seq_create_info->used_fields|= seq_field_used_max_value; + } + | START_SYM opt_with longlong_num + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_start)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "START")); + Lex->create_info.seq_create_info->start= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_start; + } + | INCREMENT_SYM opt_by longlong_num + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_increment)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "INCREMENT")); + Lex->create_info.seq_create_info->increment= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_increment; + } + | CACHE_SYM opt_equal longlong_num + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_cache)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CACHE")); + Lex->create_info.seq_create_info->cache= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; + } + | NOCACHE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_cache)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CACHE")); + Lex->create_info.seq_create_info->cache= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cache; + } + | CYCLE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_cycle)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CYCLE")); + Lex->create_info.seq_create_info->cycle= 1; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; + } + | NOCYCLE_SYM + { + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_cycle)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CYCLE")); + Lex->create_info.seq_create_info->cycle= 0; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_cycle; + } + | RESTART_SYM + { + if (unlikely(Lex->sql_command != SQLCOM_ALTER_SEQUENCE)) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + MYSQL_YYABORT; + } + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_restart)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "RESTART")); + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart; + } + | RESTART_SYM opt_with longlong_num + { + if (unlikely(Lex->sql_command != SQLCOM_ALTER_SEQUENCE)) + { + thd->parse_error(ER_SYNTAX_ERROR, "RESTART"); + MYSQL_YYABORT; + } + if (unlikely(Lex->create_info.seq_create_info->used_fields & + seq_field_used_restart)) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "RESTART")); + Lex->create_info.seq_create_info->restart= $3; + Lex->create_info.seq_create_info->used_fields|= seq_field_used_restart | seq_field_used_restart_value; + } + ; + +/* this rule is used to force look-ahead in the parser */ +force_lookahead: {} | FORCE_LOOKAHEAD {} ; + +server_def: + SERVER_SYM opt_if_not_exists ident_or_text + { + if (unlikely(Lex->add_create_options_with_check($2))) + MYSQL_YYABORT; + Lex->server_options.reset($3); + } + FOREIGN DATA_SYM WRAPPER_SYM ident_or_text + OPTIONS_SYM '(' server_options_list ')' + { Lex->server_options.scheme= $8; } + ; + +server_options_list: + server_option + | server_options_list ',' server_option + ; + +server_option: + USER_SYM TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.username.str == 0); + Lex->server_options.username= $2; + } + | HOST_SYM TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.host.str == 0); + Lex->server_options.host= $2; + } + | DATABASE TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.db.str == 0); + Lex->server_options.db= $2; + } + | OWNER_SYM TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.owner.str == 0); + Lex->server_options.owner= $2; + } + | PASSWORD_SYM TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.password.str == 0); + Lex->server_options.password= $2; + } + | SOCKET_SYM TEXT_STRING_sys + { + MYSQL_YYABORT_UNLESS(Lex->server_options.socket.str == 0); + Lex->server_options.socket= $2; + } + | PORT_SYM ulong_num + { + Lex->server_options.port= $2; + } + ; + +event_tail: + remember_name opt_if_not_exists sp_name + { + LEX *lex=Lex; + + lex->stmt_definition_begin= $1; + if (unlikely(lex->add_create_options_with_check($2))) + MYSQL_YYABORT; + if (unlikely(!(lex->event_parse_data= + Event_parse_data::new_instance(thd)))) + MYSQL_YYABORT; + lex->event_parse_data->identifier= $3; + lex->event_parse_data->on_completion= + Event_parse_data::ON_COMPLETION_DROP; + + lex->sql_command= SQLCOM_CREATE_EVENT; + /* We need that for disallowing subqueries */ + } + ON SCHEDULE_SYM ev_schedule_time + opt_ev_on_completion + opt_ev_status + opt_ev_comment + DO_SYM ev_sql_stmt + { + /* + sql_command is set here because some rules in ev_sql_stmt + can overwrite it + */ + Lex->sql_command= SQLCOM_CREATE_EVENT; + } + ; + +ev_schedule_time: + EVERY_SYM expr interval + { + Lex->event_parse_data->item_expression= $2; + Lex->event_parse_data->interval= $3; + } + ev_starts + ev_ends + | AT_SYM expr + { + Lex->event_parse_data->item_execute_at= $2; + } + ; + +opt_ev_status: + /* empty */ { $$= 0; } + | ENABLE_SYM + { + Lex->event_parse_data->status= Event_parse_data::ENABLED; + Lex->event_parse_data->status_changed= true; + $$= 1; + } + | DISABLE_SYM ON SLAVE + { + Lex->event_parse_data->status= Event_parse_data::SLAVESIDE_DISABLED; + Lex->event_parse_data->status_changed= true; + $$= 1; + } + | DISABLE_SYM + { + Lex->event_parse_data->status= Event_parse_data::DISABLED; + Lex->event_parse_data->status_changed= true; + $$= 1; + } + ; + +ev_starts: + /* empty */ + { + Item *item= new (thd->mem_root) Item_func_now_local(thd, 0); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + Lex->event_parse_data->item_starts= item; + } + | STARTS_SYM expr + { + Lex->event_parse_data->item_starts= $2; + } + ; + +ev_ends: + /* empty */ + | ENDS_SYM expr + { + Lex->event_parse_data->item_ends= $2; + } + ; + +opt_ev_on_completion: + /* empty */ { $$= 0; } + | ev_on_completion + ; + +ev_on_completion: + ON COMPLETION_SYM opt_not PRESERVE_SYM + { + Lex->event_parse_data->on_completion= $3 + ? Event_parse_data::ON_COMPLETION_DROP + : Event_parse_data::ON_COMPLETION_PRESERVE; + $$= 1; + } + ; + +opt_ev_comment: + /* empty */ { $$= 0; } + | COMMENT_SYM TEXT_STRING_sys + { + Lex->comment= Lex->event_parse_data->comment= $2; + $$= 1; + } + ; + +ev_sql_stmt: + { + LEX *lex= thd->lex; + Lex_input_stream *lip= YYLIP; + + /* + This stops the following : + - CREATE EVENT ... DO CREATE EVENT ...; + - ALTER EVENT ... DO CREATE EVENT ...; + - CREATE EVENT ... DO ALTER EVENT DO ....; + - CREATE PROCEDURE ... BEGIN CREATE EVENT ... END| + This allows: + - CREATE EVENT ... DO DROP EVENT yyy; + - CREATE EVENT ... DO ALTER EVENT yyy; + (the nested ALTER EVENT can have anything but DO clause) + - ALTER EVENT ... DO ALTER EVENT yyy; + (the nested ALTER EVENT can have anything but DO clause) + - ALTER EVENT ... DO DROP EVENT yyy; + - CREATE PROCEDURE ... BEGIN ALTER EVENT ... END| + (the nested ALTER EVENT can have anything but DO clause) + - CREATE PROCEDURE ... BEGIN DROP EVENT ... END| + */ + if (unlikely(lex->sphead)) + my_yyabort_error((ER_EVENT_RECURSION_FORBIDDEN, MYF(0))); + + if (unlikely(!lex->make_sp_head(thd, + lex->event_parse_data->identifier, + &sp_handler_procedure, + DEFAULT_AGGREGATE))) + MYSQL_YYABORT; + + lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); + } + sp_proc_stmt force_lookahead + { + /* return back to the original memory root ASAP */ + if (Lex->sp_body_finalize_event(thd)) + MYSQL_YYABORT; + } + ; + +clear_privileges: + /* Nothing */ + { + LEX *lex=Lex; + lex->users_list.empty(); + lex->first_select_lex()->db= null_clex_str; + lex->account_options.reset(); + } + ; + +opt_aggregate: + /* Empty */ { $$= NOT_AGGREGATE; } + | AGGREGATE_SYM { $$= GROUP_AGGREGATE; } + ; + + +sp_handler: + FUNCTION_SYM { $$= &sp_handler_function; } + | PROCEDURE_SYM { $$= &sp_handler_procedure; } + | PACKAGE_ORACLE_SYM { $$= &sp_handler_package_spec; } + | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM { $$= &sp_handler_package_body; } + ; + + +sp_name: + ident '.' ident + { + if (unlikely(!($$= Lex->make_sp_name(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + | ident + { + if (unlikely(!($$= Lex->make_sp_name(thd, &$1)))) + MYSQL_YYABORT; + } + ; + +sp_a_chistics: + /* Empty */ {} + | sp_a_chistics sp_chistic {} + ; + +sp_c_chistics: + /* Empty */ {} + | sp_c_chistics sp_c_chistic {} + ; + +/* Characteristics for both create and alter */ +sp_chistic: + COMMENT_SYM TEXT_STRING_sys + { Lex->sp_chistics.comment= $2; } + | LANGUAGE_SYM SQL_SYM + { /* Just parse it, we only have one language for now. */ } + | NO_SYM SQL_SYM + { Lex->sp_chistics.daccess= SP_NO_SQL; } + | CONTAINS_SYM SQL_SYM + { Lex->sp_chistics.daccess= SP_CONTAINS_SQL; } + | READS_SYM SQL_SYM DATA_SYM + { Lex->sp_chistics.daccess= SP_READS_SQL_DATA; } + | MODIFIES_SYM SQL_SYM DATA_SYM + { Lex->sp_chistics.daccess= SP_MODIFIES_SQL_DATA; } + | sp_suid + { Lex->sp_chistics.suid= $1; } + ; + +/* Create characteristics */ +sp_c_chistic: + sp_chistic { } + | opt_not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= ! $1; } + ; + +sp_suid: + SQL_SYM SECURITY_SYM DEFINER_SYM { $$= SP_IS_SUID; } + | SQL_SYM SECURITY_SYM INVOKER_SYM { $$= SP_IS_NOT_SUID; } + ; + +call: + CALL_SYM ident + { + if (unlikely(Lex->call_statement_start(thd, &$2))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + | CALL_SYM ident '.' ident + { + if (unlikely(Lex->call_statement_start(thd, &$2, &$4))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + | CALL_SYM ident '.' ident '.' ident + { + if (unlikely(Lex->call_statement_start(thd, &$2, &$4, &$6))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + ; + +/* CALL parameters */ +opt_sp_cparam_list: + /* Empty */ + | '(' opt_sp_cparams ')' + ; + +opt_sp_cparams: + /* Empty */ + | sp_cparams + ; + +sp_cparams: + sp_cparams ',' expr + { + Lex->value_list.push_back($3, thd->mem_root); + } + | expr + { + Lex->value_list.push_back($1, thd->mem_root); + } + ; + +/* Stored FUNCTION parameter declaration list */ +sp_fdparam_list: + /* Empty */ + { + Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start(); + Lex->sphead->m_param_end= Lex->sphead->m_param_begin; + } + | + { + Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start(); + } + sp_fdparams + { + Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); + } + ; + +sp_fdparams: + sp_fdparams ',' sp_param + | sp_param + ; + +sp_param_name: + ident + { + if (unlikely(!($$= Lex->sp_param_init(&$1)))) + MYSQL_YYABORT; + } + ; + +/* Stored PROCEDURE parameter declaration list */ +sp_pdparam_list: + /* Empty */ + | sp_pdparams + ; + +sp_pdparams: + sp_pdparams ',' sp_param + | sp_param + ; + +sp_parameter_type: + IN_SYM { $$= sp_variable::MODE_IN; } + | OUT_SYM { $$= sp_variable::MODE_OUT; } + | INOUT_SYM { $$= sp_variable::MODE_INOUT; } + ; + +sp_parenthesized_pdparam_list: + '(' + { + Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start() + 1; + } + sp_pdparam_list + ')' + { + Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start(); + } + ; + +sp_parenthesized_fdparam_list: + '(' sp_fdparam_list ')' + ; + +sp_proc_stmts: + /* Empty */ {} + | sp_proc_stmts sp_proc_stmt ';' + ; + +sp_proc_stmts1: + sp_proc_stmt ';' {} + | sp_proc_stmts1 sp_proc_stmt ';' + ; + + +optionally_qualified_column_ident: + sp_decl_ident + { + if (unlikely(!($$= new (thd->mem_root) + Qualified_column_ident(&$1)))) + MYSQL_YYABORT; + } + | sp_decl_ident '.' ident + { + if (unlikely(!($$= new (thd->mem_root) + Qualified_column_ident(&$1, &$3)))) + MYSQL_YYABORT; + } + | sp_decl_ident '.' ident '.' ident + { + if (unlikely(!($$= new (thd->mem_root) + Qualified_column_ident(thd, &$1, &$3, &$5)))) + MYSQL_YYABORT; + } + ; + + +row_field_definition: + row_field_name field_type + { + Lex->last_field->set_attributes(thd, $2, + COLUMN_DEFINITION_ROUTINE_LOCAL); + } + ; + +row_field_definition_list: + row_field_definition + { + if (!($$= Row_definition_list::make(thd->mem_root, $1))) + MYSQL_YYABORT; + } + | row_field_definition_list ',' row_field_definition + { + if (($$= $1)->append_uniq(thd->mem_root, $3)) + MYSQL_YYABORT; + } + ; + +row_type_body: + '(' row_field_definition_list ')' { $$= $2; } + ; + +sp_decl_idents_init_vars: + sp_decl_idents + { + Lex->sp_variable_declarations_init(thd, $1); + } + ; + +sp_decl_variable_list: + sp_decl_idents_init_vars + field_type + { + Lex->last_field->set_attributes(thd, $2, + COLUMN_DEFINITION_ROUTINE_LOCAL); + } + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_finalize(thd, $1, + &Lex->last_field[0], + $4))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + | sp_decl_idents_init_vars + ROW_SYM row_type_body + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_row_finalize(thd, $1, $3, $4))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + | sp_decl_variable_list_anchored + ; + +sp_decl_handler: + sp_handler_type HANDLER_SYM FOR_SYM + { + if (unlikely(Lex->sp_handler_declaration_init(thd, $1))) + MYSQL_YYABORT; + } + sp_hcond_list sp_proc_stmt + { + if (unlikely(Lex->sp_handler_declaration_finalize(thd, $1))) + MYSQL_YYABORT; + $$.vars= $$.conds= $$.curs= 0; + $$.hndlrs= 1; + } + ; + +opt_parenthesized_cursor_formal_parameters: + /* Empty */ + | '(' sp_fdparams ')' + ; + + +sp_cursor_stmt_lex: + { + DBUG_ASSERT(thd->lex->sphead); + if (unlikely(!($$= new (thd->mem_root) + sp_lex_cursor(thd, thd->lex)))) + MYSQL_YYABORT; + } + ; + +sp_cursor_stmt: + sp_cursor_stmt_lex + { + DBUG_ASSERT(thd->free_list == NULL); + Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + select + { + DBUG_ASSERT(Lex == $1); + Lex->pop_select(); //main select + if (unlikely($1->stmt_finalize(thd)) || + unlikely($1->sphead->restore_lex(thd))) + MYSQL_YYABORT; + $$= $1; + } + ; + +sp_handler_type: + EXIT_MARIADB_SYM { $$= sp_handler::EXIT; } + | CONTINUE_MARIADB_SYM { $$= sp_handler::CONTINUE; } + | EXIT_ORACLE_SYM { $$= sp_handler::EXIT; } + | CONTINUE_ORACLE_SYM { $$= sp_handler::CONTINUE; } + /*| UNDO_SYM { QQ No yet } */ + ; + +sp_hcond_list: + sp_hcond_element + { $$= 1; } + | sp_hcond_list ',' sp_hcond_element + { $$+= 1; } + ; + +sp_hcond_element: + sp_hcond + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *ctx= lex->spcont->parent_context(); + + if (unlikely(ctx->check_duplicate_handler($1))) + my_yyabort_error((ER_SP_DUP_HANDLER, MYF(0))); + + sp_instr_hpush_jump *i= (sp_instr_hpush_jump *)sp->last_instruction(); + i->add_condition($1); + } + ; + +sp_cond: + ulong_num + { /* mysql errno */ + if (unlikely($1 == 0)) + my_yyabort_error((ER_WRONG_VALUE, MYF(0), "CONDITION", "0")); + $$= new (thd->mem_root) sp_condition_value($1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | sqlstate + ; + +sqlstate: + SQLSTATE_SYM opt_value TEXT_STRING_literal + { /* SQLSTATE */ + + /* + An error is triggered: + - if the specified string is not a valid SQLSTATE, + - or if it represents the completion condition -- it is not + allowed to SIGNAL, or declare a handler for the completion + condition. + */ + if (unlikely(!is_sqlstate_valid(&$3) || + is_sqlstate_completion($3.str))) + my_yyabort_error((ER_SP_BAD_SQLSTATE, MYF(0), $3.str)); + $$= new (thd->mem_root) sp_condition_value($3.str); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_value: + /* Empty */ {} + | VALUE_SYM {} + ; + +sp_hcond: + sp_cond + { + $$= $1; + } + | ident /* CONDITION name */ + { + $$= Lex->spcont->find_declared_or_predefined_condition(thd, &$1); + if (unlikely($$ == NULL)) + my_yyabort_error((ER_SP_COND_MISMATCH, MYF(0), $1.str)); + } + | SQLWARNING_SYM /* SQLSTATEs 01??? */ + { + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::WARNING); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | not FOUND_SYM /* SQLSTATEs 02??? */ + { + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::NOT_FOUND); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SQLEXCEPTION_SYM /* All other SQLSTATEs */ + { + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::EXCEPTION); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | OTHERS_ORACLE_SYM /* All other SQLSTATEs */ + { + $$= new (thd->mem_root) sp_condition_value(sp_condition_value::EXCEPTION); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + + +raise_stmt_oracle: + RAISE_ORACLE_SYM opt_set_signal_information + { + if (unlikely(Lex->add_resignal_statement(thd, NULL))) + MYSQL_YYABORT; + } + | RAISE_ORACLE_SYM signal_value opt_set_signal_information + { + if (unlikely(Lex->add_signal_statement(thd, $2))) + MYSQL_YYABORT; + } + ; + +signal_stmt: + SIGNAL_SYM signal_value opt_set_signal_information + { + if (Lex->add_signal_statement(thd, $2)) + MYSQL_YYABORT; + } + ; + +signal_value: + ident + { + if (!($$= Lex->stmt_signal_value($1))) + MYSQL_YYABORT; + } + | sqlstate + { $$= $1; } + ; + +opt_signal_value: + /* empty */ + { $$= NULL; } + | signal_value + { $$= $1; } + ; + +opt_set_signal_information: + /* empty */ + { + thd->m_parser_state->m_yacc.m_set_signal_info.clear(); + } + | SET signal_information_item_list + ; + +signal_information_item_list: + signal_condition_information_item_name '=' signal_allowed_expr + { + Set_signal_information *info; + info= &thd->m_parser_state->m_yacc.m_set_signal_info; + int index= (int) $1; + info->clear(); + info->m_item[index]= $3; + } + | signal_information_item_list ',' + signal_condition_information_item_name '=' signal_allowed_expr + { + Set_signal_information *info; + info= &thd->m_parser_state->m_yacc.m_set_signal_info; + int index= (int) $3; + if (unlikely(info->m_item[index] != NULL)) + my_yyabort_error((ER_DUP_SIGNAL_SET, MYF(0), + Diag_condition_item_names[index].str)); + info->m_item[index]= $5; + } + ; + +/* + Only a limited subset of <expr> are allowed in SIGNAL/RESIGNAL. +*/ +signal_allowed_expr: + literal + { $$= $1; } + | variable + { + if ($1->type() == Item::FUNC_ITEM) + { + Item_func *item= (Item_func*) $1; + if (unlikely(item->functype() == Item_func::SUSERVAR_FUNC)) + { + /* + Don't allow the following syntax: + SIGNAL/RESIGNAL ... + SET <signal condition item name> = @foo := expr + */ + thd->parse_error(); + MYSQL_YYABORT; + } + } + $$= $1; + } + | simple_ident + { $$= $1; } + ; + +/* conditions that can be set in signal / resignal */ +signal_condition_information_item_name: + CLASS_ORIGIN_SYM + { $$= DIAG_CLASS_ORIGIN; } + | SUBCLASS_ORIGIN_SYM + { $$= DIAG_SUBCLASS_ORIGIN; } + | CONSTRAINT_CATALOG_SYM + { $$= DIAG_CONSTRAINT_CATALOG; } + | CONSTRAINT_SCHEMA_SYM + { $$= DIAG_CONSTRAINT_SCHEMA; } + | CONSTRAINT_NAME_SYM + { $$= DIAG_CONSTRAINT_NAME; } + | CATALOG_NAME_SYM + { $$= DIAG_CATALOG_NAME; } + | SCHEMA_NAME_SYM + { $$= DIAG_SCHEMA_NAME; } + | TABLE_NAME_SYM + { $$= DIAG_TABLE_NAME; } + | COLUMN_NAME_SYM + { $$= DIAG_COLUMN_NAME; } + | CURSOR_NAME_SYM + { $$= DIAG_CURSOR_NAME; } + | MESSAGE_TEXT_SYM + { $$= DIAG_MESSAGE_TEXT; } + | MYSQL_ERRNO_SYM + { $$= DIAG_MYSQL_ERRNO; } + | ROW_NUMBER_SYM + { $$= DIAG_ROW_NUMBER; } + ; + +resignal_stmt: + RESIGNAL_SYM opt_signal_value opt_set_signal_information + { + if (unlikely(Lex->add_resignal_statement(thd, $2))) + MYSQL_YYABORT; + } + ; + +get_diagnostics: + GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information + { + Diagnostics_information *info= $4; + + info->set_which_da($2); + + Lex->sql_command= SQLCOM_GET_DIAGNOSTICS; + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_get_diagnostics(info); + + if (unlikely(Lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +which_area: + /* If <which area> is not specified, then CURRENT is implicit. */ + { $$= Diagnostics_information::CURRENT_AREA; } + | CURRENT_SYM + { $$= Diagnostics_information::CURRENT_AREA; } + ; + +diagnostics_information: + statement_information + { + $$= new (thd->mem_root) Statement_information($1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CONDITION_SYM condition_number condition_information + { + $$= new (thd->mem_root) Condition_information($2, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +statement_information: + statement_information_item + { + $$= new (thd->mem_root) List<Statement_information_item>; + if (unlikely($$ == NULL) || + unlikely($$->push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | statement_information ',' statement_information_item + { + if (unlikely($1->push_back($3, thd->mem_root))) + MYSQL_YYABORT; + $$= $1; + } + ; + +statement_information_item: + simple_target_specification '=' statement_information_item_name + { + $$= new (thd->mem_root) Statement_information_item($3, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +simple_target_specification: + ident_cli + { + if (unlikely(!($$= thd->lex->create_item_for_sp_var(&$1, NULL)))) + MYSQL_YYABORT; + } + | '@' ident_or_text + { + if (!$2.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + $$= new (thd->mem_root) Item_func_get_user_var(thd, &$2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +statement_information_item_name: + NUMBER_MARIADB_SYM + { $$= Statement_information_item::NUMBER; } + | NUMBER_ORACLE_SYM + { $$= Statement_information_item::NUMBER; } + | ROW_COUNT_SYM + { $$= Statement_information_item::ROW_COUNT; } + ; + +/* + Only a limited subset of <expr> are allowed in GET DIAGNOSTICS + <condition number>, same subset as for SIGNAL/RESIGNAL. +*/ +condition_number: + signal_allowed_expr + { $$= $1; } + ; + +condition_information: + condition_information_item + { + $$= new (thd->mem_root) List<Condition_information_item>; + if (unlikely($$ == NULL) || + unlikely($$->push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | condition_information ',' condition_information_item + { + if (unlikely($1->push_back($3, thd->mem_root))) + MYSQL_YYABORT; + $$= $1; + } + ; + +condition_information_item: + simple_target_specification '=' condition_information_item_name + { + $$= new (thd->mem_root) Condition_information_item($3, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +condition_information_item_name: + CLASS_ORIGIN_SYM + { $$= Condition_information_item::CLASS_ORIGIN; } + | SUBCLASS_ORIGIN_SYM + { $$= Condition_information_item::SUBCLASS_ORIGIN; } + | CONSTRAINT_CATALOG_SYM + { $$= Condition_information_item::CONSTRAINT_CATALOG; } + | CONSTRAINT_SCHEMA_SYM + { $$= Condition_information_item::CONSTRAINT_SCHEMA; } + | CONSTRAINT_NAME_SYM + { $$= Condition_information_item::CONSTRAINT_NAME; } + | CATALOG_NAME_SYM + { $$= Condition_information_item::CATALOG_NAME; } + | SCHEMA_NAME_SYM + { $$= Condition_information_item::SCHEMA_NAME; } + | TABLE_NAME_SYM + { $$= Condition_information_item::TABLE_NAME; } + | COLUMN_NAME_SYM + { $$= Condition_information_item::COLUMN_NAME; } + | CURSOR_NAME_SYM + { $$= Condition_information_item::CURSOR_NAME; } + | MESSAGE_TEXT_SYM + { $$= Condition_information_item::MESSAGE_TEXT; } + | MYSQL_ERRNO_SYM + { $$= Condition_information_item::MYSQL_ERRNO; } + | RETURNED_SQLSTATE_SYM + { $$= Condition_information_item::RETURNED_SQLSTATE; } + | ROW_NUMBER_SYM + { $$= Condition_information_item::ROW_NUMBER; } + ; + +sp_decl_ident: + IDENT_sys + | keyword_sp_decl + { + if (unlikely($$.copy_ident_cli(thd, &$1))) + MYSQL_YYABORT; + } + ; + +sp_decl_idents: + sp_decl_ident + { + /* NOTE: field definition is filled in sp_decl section. */ + + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + + if (unlikely(spc->find_variable(&$1, TRUE))) + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $1.str)); + spc->add_variable(thd, &$1); + $$= 1; + } + | sp_decl_idents ',' ident + { + /* NOTE: field definition is filled in sp_decl section. */ + + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + + if (unlikely(spc->find_variable(&$3, TRUE))) + my_yyabort_error((ER_SP_DUP_VAR, MYF(0), $3.str)); + spc->add_variable(thd, &$3); + $$= $1 + 1; + } + ; + +sp_proc_stmt_if: + IF_SYM + { + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + Lex->sphead->new_cont_backpatch(NULL); + } + sp_if END IF_SYM + { Lex->sphead->do_cont_backpatch(); } + ; + +sp_proc_stmt_statement: + { + LEX *lex= thd->lex; + Lex_input_stream *lip= YYLIP; + + lex->sphead->reset_lex(thd); + /* + We should not push main select here, it will be done or not + done by the statement, we just provide only a new LEX for the + statement here as if it is start of parsing a new statement. + */ + lex->sphead->m_tmp_query= lip->get_tok_start(); + } + sp_statement + { + if (Lex->sp_proc_stmt_statement_finalize(thd, yychar == YYEMPTY) || + Lex->sphead->restore_lex(thd)) + MYSQL_YYABORT; + } + ; + + +RETURN_ALLMODES_SYM: + RETURN_MARIADB_SYM + | RETURN_ORACLE_SYM + ; + +sp_proc_stmt_return: + RETURN_ALLMODES_SYM expr_lex + { + sp_head *sp= $2->sphead; + if (unlikely(sp->m_handler->add_instr_freturn(thd, sp, $2->spcont, + $2->get_item(), $2))) + MYSQL_YYABORT; + } + { /* See the comment 'COMMENT_FOR_DESCTRUCTOR' near %destructor */ } + | RETURN_ORACLE_SYM + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + if (unlikely(sp->m_handler->add_instr_preturn(thd, sp, + lex->spcont))) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_exit_oracle: + EXIT_ORACLE_SYM + { + if (unlikely(Lex->sp_exit_statement(thd, NULL))) + MYSQL_YYABORT; + } + | EXIT_ORACLE_SYM label_ident + { + if (unlikely(Lex->sp_exit_statement(thd, &$2, NULL))) + MYSQL_YYABORT; + } + | EXIT_ORACLE_SYM WHEN_SYM expr_lex + { + if (unlikely($3->sp_exit_statement(thd, $3->get_item()))) + MYSQL_YYABORT; + } + { /* See the comment 'COMMENT_FOR_DESCTRUCTOR' near %destructor */ } + | EXIT_ORACLE_SYM label_ident WHEN_SYM expr_lex + { + if (unlikely($4->sp_exit_statement(thd, &$2, $4->get_item()))) + MYSQL_YYABORT; + } + { /* See the comment 'COMMENT_FOR_DESCTRUCTOR' near %destructor */ } + ; + +sp_proc_stmt_continue_oracle: + CONTINUE_ORACLE_SYM + { + if (unlikely(Lex->sp_continue_statement(thd))) + MYSQL_YYABORT; + } + | CONTINUE_ORACLE_SYM label_ident + { + if (unlikely(Lex->sp_continue_statement(thd, &$2))) + MYSQL_YYABORT; + } + | CONTINUE_ORACLE_SYM WHEN_SYM expr_lex + { + if (unlikely($3->sp_continue_when_statement(thd))) + MYSQL_YYABORT; + } + { /* See the comment 'COMMENT_FOR_DESCTRUCTOR' near %destructor */ } + | CONTINUE_ORACLE_SYM label_ident WHEN_SYM expr_lex + { + if (unlikely($4->sp_continue_when_statement(thd, &$2))) + MYSQL_YYABORT; + } + { /* See the comment 'COMMENT_FOR_DESCTRUCTOR' near %destructor */ } + ; + + +sp_proc_stmt_leave: + LEAVE_SYM label_ident + { + if (unlikely(Lex->sp_leave_statement(thd, &$2))) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_iterate: + ITERATE_SYM label_ident + { + if (unlikely(Lex->sp_iterate_statement(thd, &$2))) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_goto_oracle: + GOTO_ORACLE_SYM label_ident + { + if (unlikely(Lex->sp_goto_statement(thd, &$2))) + MYSQL_YYABORT; + } + ; + + +expr_lex: + { + DBUG_ASSERT(Lex->sphead); + if (unlikely(!($<expr_lex>$= new (thd->mem_root) + sp_expr_lex(thd, thd->lex)))) + MYSQL_YYABORT; + Lex->sphead->reset_lex(thd, $<expr_lex>$); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + expr + { + $$= $<expr_lex>1; + $$->set_item($2); + Lex->pop_select(); //min select + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + if ($$->sphead->restore_lex(thd)) + MYSQL_YYABORT; + } + ; + + +assignment_source_lex: + { + DBUG_ASSERT(Lex->sphead); + if (unlikely(!($$= new (thd->mem_root) + sp_assignment_lex(thd, thd->lex)))) + MYSQL_YYABORT; + } + ; + +assignment_source_expr: + assignment_source_lex + { + DBUG_ASSERT(thd->free_list == NULL); + Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + expr + { + DBUG_ASSERT($1 == thd->lex); + $$= $1; + $$->set_item_and_free_list($3, thd->free_list); + thd->free_list= NULL; + Lex->pop_select(); //min select + if ($$->sphead->restore_lex(thd)) + MYSQL_YYABORT; + } + ; + +for_loop_bound_expr: + assignment_source_lex + { + Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + Lex->current_select->parsing_place= FOR_LOOP_BOUND; + } + expr + { + DBUG_ASSERT($1 == thd->lex); + $$= $1; + $$->set_item_and_free_list($3, NULL); + Lex->pop_select(); //main select + if (unlikely($$->sphead->restore_lex(thd))) + MYSQL_YYABORT; + Lex->current_select->parsing_place= NO_MATTER; + } + ; + +cursor_actual_parameters: + assignment_source_expr + { + if (unlikely(!($$= new (thd->mem_root) List<sp_assignment_lex>))) + MYSQL_YYABORT; + $$->push_back($1, thd->mem_root); + } + | cursor_actual_parameters ',' assignment_source_expr + { + $$= $1; + $$->push_back($3, thd->mem_root); + } + ; + +opt_parenthesized_cursor_actual_parameters: + /* Empty */ { $$= NULL; } + | '(' cursor_actual_parameters ')' { $$= $2; } + ; + +sp_proc_stmt_with_cursor: + sp_proc_stmt_open + | sp_proc_stmt_fetch + | sp_proc_stmt_close + ; + +sp_proc_stmt_open: + OPEN_SYM ident opt_parenthesized_cursor_actual_parameters + { + if (unlikely(Lex->sp_open_cursor(thd, &$2, $3))) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_fetch_head: + FETCH_SYM ident INTO + { + if (unlikely(Lex->sp_add_cfetch(thd, &$2))) + MYSQL_YYABORT; + } + | FETCH_SYM FROM ident INTO + { + if (unlikely(Lex->sp_add_cfetch(thd, &$3))) + MYSQL_YYABORT; + } + | FETCH_SYM NEXT_SYM FROM ident INTO + { + if (unlikely(Lex->sp_add_cfetch(thd, &$4))) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_fetch: + sp_proc_stmt_fetch_head sp_fetch_list { } + | FETCH_SYM GROUP_SYM NEXT_SYM ROW_SYM + { + if (unlikely(Lex->sp_add_agg_cfetch())) + MYSQL_YYABORT; + } + ; + +sp_proc_stmt_close: + CLOSE_SYM ident + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint offset; + sp_instr_cclose *i; + + if (unlikely(!lex->spcont->find_cursor(&$2, &offset, false))) + my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $2.str)); + i= new (thd->mem_root) + sp_instr_cclose(sp->instructions(), lex->spcont, offset); + if (unlikely(i == NULL) || + unlikely(sp->add_instr(i))) + MYSQL_YYABORT; + } + ; + +sp_fetch_list: + ident + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *spc= lex->spcont; + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$1, false) + : NULL; + + if (unlikely(!spv)) + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); + + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); + } + | sp_fetch_list ',' ident + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + sp_pcontext *spc= lex->spcont; + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$3, false) + : NULL; + + if (unlikely(!spv)) + my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); + + /* An SP local variable */ + sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction(); + i->add_to_varlist(spv); + } + ; + +sp_if: + expr_lex THEN_SYM + { + if (unlikely($1->sp_if_expr(thd))) + MYSQL_YYABORT; + } + sp_if_then_statements + { + if (unlikely($1->sp_if_after_statements(thd))) + MYSQL_YYABORT; + } + sp_elseifs + { + LEX *lex= Lex; + + lex->sphead->backpatch(lex->spcont->pop_label()); + } + ; + +sp_elseifs: + /* Empty */ + | ELSEIF_MARIADB_SYM sp_if + | ELSIF_ORACLE_SYM sp_if + | ELSE sp_if_then_statements + ; + +case_stmt_specification: + CASE_SYM + { + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + + /** + An example of the CASE statement in use is + <pre> + CREATE PROCEDURE proc_19194_simple(i int) + BEGIN + DECLARE str CHAR(10); + + CASE i + WHEN 1 THEN SET str="1"; + WHEN 2 THEN SET str="2"; + WHEN 3 THEN SET str="3"; + ELSE SET str="unknown"; + END CASE; + + SELECT str; + END + </pre> + The actions are used to generate the following code: + <pre> + SHOW PROCEDURE CODE proc_19194_simple; + Pos Instruction + 0 set str@1 NULL + 1 set_case_expr (12) 0 i@0 + 2 jump_if_not 5(12) (case_expr@0 = 1) + 3 set str@1 _latin1'1' + 4 jump 12 + 5 jump_if_not 8(12) (case_expr@0 = 2) + 6 set str@1 _latin1'2' + 7 jump 12 + 8 jump_if_not 11(12) (case_expr@0 = 3) + 9 set str@1 _latin1'3' + 10 jump 12 + 11 set str@1 _latin1'unknown' + 12 stmt 0 "SELECT str" + </pre> + */ + + Lex->sphead->new_cont_backpatch(NULL); + + /* + BACKPATCH: Creating target label for the jump to after END CASE + (instruction 12 in the example) + */ + Lex->spcont->push_label(thd, &empty_clex_str, Lex->sphead->instructions()); + } + case_stmt_body + else_clause_opt + END + CASE_SYM + { + /* + BACKPATCH: Resolving forward jump from + "case_stmt_action_then" to after END CASE + (jump from instruction 4 to 12, 7 to 12 ... in the example) + */ + Lex->sphead->backpatch(Lex->spcont->pop_label()); + + if ($3) + Lex->spcont->pop_case_expr_id(); + + Lex->sphead->do_cont_backpatch(); + } + ; + +case_stmt_body: + expr_lex + { + if (unlikely($1->case_stmt_action_expr())) + MYSQL_YYABORT; + } + simple_when_clause_list + { $$= 1; } + | searched_when_clause_list + { $$= 0; } + ; + +simple_when_clause_list: + simple_when_clause + | simple_when_clause_list simple_when_clause + ; + +searched_when_clause_list: + searched_when_clause + | searched_when_clause_list searched_when_clause + ; + +simple_when_clause: + WHEN_SYM expr_lex + { + /* Simple case: <caseval> = <whenval> */ + if (unlikely($2->case_stmt_action_when(true))) + MYSQL_YYABORT; + } + THEN_SYM + sp_case_then_statements + { + if (unlikely(Lex->case_stmt_action_then())) + MYSQL_YYABORT; + } + ; + +searched_when_clause: + WHEN_SYM expr_lex + { + if (unlikely($2->case_stmt_action_when(false))) + MYSQL_YYABORT; + } + THEN_SYM + sp_case_then_statements + { + if (unlikely(Lex->case_stmt_action_then())) + MYSQL_YYABORT; + } + ; + +else_clause_opt: + /* empty */ + { + LEX *lex= Lex; + sp_head *sp= lex->sphead; + uint ip= sp->instructions(); + sp_instr_error *i= new (thd->mem_root) + sp_instr_error(ip, lex->spcont, ER_SP_CASE_NOT_FOUND); + if (unlikely(i == NULL) || + unlikely(sp->add_instr(i))) + MYSQL_YYABORT; + } + | ELSE sp_case_then_statements + ; + +sp_opt_label: + /* Empty */ { $$= null_clex_str; } + | label_ident { $$= $1; } + ; + +/* This adds one shift/reduce conflict */ +opt_sp_for_loop_direction: + /* Empty */ { $$= 1; } + | REVERSE_SYM { $$= -1; } + ; + +sp_for_loop_index_and_bounds: + ident_for_loop_index sp_for_loop_bounds + { + if (unlikely(Lex->sp_for_loop_declarations(thd, &$$, &$1, $2))) + MYSQL_YYABORT; + } + ; + +sp_for_loop_bounds: + IN_SYM opt_sp_for_loop_direction for_loop_bound_expr + DOT_DOT_SYM for_loop_bound_expr + { + $$= Lex_for_loop_bounds_intrange($2, $3, $5); + } + | IN_SYM opt_sp_for_loop_direction for_loop_bound_expr + { + $$.m_direction= $2; + $$.m_index= $3; + $$.m_target_bound= NULL; + $$.m_implicit_cursor= false; + } + | IN_SYM opt_sp_for_loop_direction '(' sp_cursor_stmt ')' + { + if (unlikely(Lex->sp_for_loop_implicit_cursor_statement(thd, &$$, + $4))) + MYSQL_YYABORT; + } + ; + +loop_body: + sp_proc_stmts1 END LOOP_SYM + { + LEX *lex= Lex; + uint ip= lex->sphead->instructions(); + sp_label *lab= lex->spcont->last_label(); /* Jumping back */ + sp_instr_jump *i= new (thd->mem_root) + sp_instr_jump(ip, lex->spcont, lab->ip); + if (unlikely(i == NULL) || + unlikely(lex->sphead->add_instr(i))) + MYSQL_YYABORT; + } + ; + +repeat_body: + sp_proc_stmts1 UNTIL_SYM expr_lex END REPEAT_SYM + { + if ($3->sp_repeat_loop_finalize(thd)) + MYSQL_YYABORT; + } + ; + +pop_sp_loop_label: + sp_opt_label + { + if (unlikely(Lex->sp_pop_loop_label(thd, &$1))) + MYSQL_YYABORT; + } + ; + +sp_labeled_control: + sp_control_label LOOP_SYM + { + if (unlikely(Lex->sp_push_loop_label(thd, &$1))) + MYSQL_YYABORT; + } + loop_body pop_sp_loop_label + { } + | sp_control_label WHILE_SYM + { + if (unlikely(Lex->sp_push_loop_label(thd, &$1))) + MYSQL_YYABORT; + } + while_body pop_sp_loop_label + { } + | sp_control_label FOR_SYM + { + // See "The FOR LOOP statement" comments in sql_lex.cc + Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block + } + sp_for_loop_index_and_bounds + { + if (unlikely(Lex->sp_push_loop_label(thd, &$1))) // The inner WHILE block + MYSQL_YYABORT; + if (unlikely(Lex->sp_for_loop_condition_test(thd, $4))) + MYSQL_YYABORT; + } + for_loop_statements + { + if (unlikely(Lex->sp_for_loop_finalize(thd, $4))) + MYSQL_YYABORT; + } + pop_sp_loop_label // The inner WHILE block + { + if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $4))) + MYSQL_YYABORT; + } + | sp_control_label REPEAT_SYM + { + if (unlikely(Lex->sp_push_loop_label(thd, &$1))) + MYSQL_YYABORT; + } + repeat_body pop_sp_loop_label + { } + ; + +sp_unlabeled_control: + LOOP_SYM + { + if (unlikely(Lex->sp_push_loop_empty_label(thd))) + MYSQL_YYABORT; + } + loop_body + { + Lex->sp_pop_loop_empty_label(thd); + } + | WHILE_SYM + { + if (unlikely(Lex->sp_push_loop_empty_label(thd))) + MYSQL_YYABORT; + } + while_body + { + Lex->sp_pop_loop_empty_label(thd); + } + | FOR_SYM + { + // See "The FOR LOOP statement" comments in sql_lex.cc + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block + } + sp_for_loop_index_and_bounds + { + if (unlikely(Lex->sp_push_loop_empty_label(thd))) // The inner WHILE block + MYSQL_YYABORT; + if (unlikely(Lex->sp_for_loop_condition_test(thd, $3))) + MYSQL_YYABORT; + } + for_loop_statements + { + if (unlikely(Lex->sp_for_loop_finalize(thd, $3))) + MYSQL_YYABORT; + Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block + if (unlikely(Lex->sp_for_loop_outer_block_finalize(thd, $3))) + MYSQL_YYABORT; + } + | REPEAT_SYM + { + if (unlikely(Lex->sp_push_loop_empty_label(thd))) + MYSQL_YYABORT; + } + repeat_body + { + Lex->sp_pop_loop_empty_label(thd); + } + ; + +trg_action_time: + BEFORE_SYM + { Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; } + | AFTER_SYM + { Lex->trg_chistics.action_time= TRG_ACTION_AFTER; } + ; + +trg_event: + INSERT + { Lex->trg_chistics.event= TRG_EVENT_INSERT; } + | UPDATE_SYM + { Lex->trg_chistics.event= TRG_EVENT_UPDATE; } + | DELETE_SYM + { Lex->trg_chistics.event= TRG_EVENT_DELETE; } + ; + +create_body: + create_field_list_parens + { Lex->create_info.option_list= NULL; } + opt_create_table_options opt_create_partitioning opt_create_select {} + | opt_create_table_options opt_create_partitioning opt_create_select {} + | create_like + { + + Lex->create_info.add(DDL_options_st::OPT_LIKE); + TABLE_LIST *src_table= Lex->first_select_lex()-> + add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ); + if (unlikely(! src_table)) + MYSQL_YYABORT; + /* CREATE TABLE ... LIKE is not allowed for views. */ + src_table->required_type= TABLE_TYPE_NORMAL; + } + ; + +create_like: + LIKE table_ident { $$= $2; } + | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; } + ; + +opt_create_select: + /* empty */ {} + | opt_duplicate opt_as create_select_query_expression + opt_versioning_option + { + Lex->create_info.add(DDL_options_st::OPT_CREATE_SELECT); + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + ; + +create_select_query_expression: + query_expression + { + if (Lex->parsed_insert_select($1->first_select())) + MYSQL_YYABORT; + } + | LEFT_PAREN_WITH with_clause query_expression_no_with_clause ')' + { + SELECT_LEX *first_select= $3->first_select(); + $3->set_with_clause($2); + $2->attach_to(first_select); + if (Lex->parsed_insert_select(first_select)) + MYSQL_YYABORT; + } + ; + +opt_create_partitioning: + opt_partitioning + { + /* + Remove all tables used in PARTITION clause from the global table + list. Partitioning with subqueries is not allowed anyway. + */ + TABLE_LIST *last_non_sel_table= Lex->create_last_non_select_table; + last_non_sel_table->next_global= 0; + Lex->query_tables_last= &last_non_sel_table->next_global; + } + ; + +/* + This part of the parser is about handling of the partition information. + + Its first version was written by Mikael Ronström with lots of answers to + questions provided by Antony Curtis. + + The partition grammar can be called from three places. + 1) CREATE TABLE ... PARTITION .. + 2) ALTER TABLE table_name PARTITION ... + 3) PARTITION ... + + The first place is called when a new table is created from a MySQL client. + The second place is called when a table is altered with the ALTER TABLE + command from a MySQL client. + The third place is called when opening an frm file and finding partition + info in the .frm file. It is necessary to avoid allowing PARTITION to be + an allowed entry point for SQL client queries. This is arranged by setting + some state variables before arriving here. + + To be able to handle errors we will only set error code in this code + and handle the error condition in the function calling the parser. This + is necessary to ensure we can also handle errors when calling the parser + from the openfrm function. +*/ +opt_partitioning: + /* empty */ {} + | partitioning + ; + +partitioning: + PARTITION_SYM have_partitioning + { + LEX *lex= Lex; + lex->part_info= new (thd->mem_root) partition_info(); + if (unlikely(!lex->part_info)) + MYSQL_YYABORT; + if (lex->sql_command == SQLCOM_ALTER_TABLE) + { + lex->alter_info.partition_flags|= ALTER_PARTITION_INFO; + } + } + partition + ; + +have_partitioning: + /* empty */ + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + LEX_CSTRING partition_name={STRING_WITH_LEN("partition")}; + if (unlikely(!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN))) + my_yyabort_error((ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition")); +#else + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), "partitioning", + "--with-plugin-partition")); +#endif + } + ; + +partition_entry: + PARTITION_SYM + { + if (unlikely(!Lex->part_info)) + { + thd->parse_error(ER_PARTITION_ENTRY_ERROR); + MYSQL_YYABORT; + } + if (Lex->main_select_push()) + MYSQL_YYABORT; + /* + We enter here when opening the frm file to translate + partition info string into part_info data structure. + */ + } + partition + { + Lex->pop_select(); //main select + } + ; + +partition: + BY + { Lex->safe_to_cache_query= 1; } + part_type_def opt_num_parts opt_sub_part part_defs + ; + +part_type_def: + opt_linear KEY_SYM opt_key_algo '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->list_of_part_fields= TRUE; + part_info->column_list= FALSE; + part_info->part_type= HASH_PARTITION; + } + | opt_linear HASH_SYM + { Lex->part_info->part_type= HASH_PARTITION; } + part_func {} + | RANGE_SYM part_func + { Lex->part_info->part_type= RANGE_PARTITION; } + | RANGE_SYM part_column_list + { Lex->part_info->part_type= RANGE_PARTITION; } + | LIST_SYM + { + Select->parsing_place= IN_PART_FUNC; + } + part_func + { + Lex->part_info->part_type= LIST_PARTITION; + Select->parsing_place= NO_MATTER; + } + | LIST_SYM part_column_list + { Lex->part_info->part_type= LIST_PARTITION; } + | SYSTEM_TIME_SYM + { + if (unlikely(Lex->part_info->vers_init_info(thd))) + MYSQL_YYABORT; + } + opt_versioning_rotation + ; + +opt_linear: + /* empty */ {} + | LINEAR_SYM + { Lex->part_info->linear_hash_ind= TRUE;} + ; + +opt_key_algo: + /* empty */ + { Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_NONE;} + | ALGORITHM_SYM '=' real_ulong_num + { + switch ($3) { + case 1: + Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_51; + break; + case 2: + Lex->part_info->key_algorithm= partition_info::KEY_ALGORITHM_55; + break; + default: + thd->parse_error(); + MYSQL_YYABORT; + } + } + ; + +part_field_list: + /* empty */ {} + | part_field_item_list {} + ; + +part_field_item_list: + part_field_item {} + | part_field_item_list ',' part_field_item {} + ; + +part_field_item: + ident + { + partition_info *part_info= Lex->part_info; + part_info->num_columns++; + if (unlikely(part_info->part_field_list.push_back($1.str, + thd->mem_root))) + MYSQL_YYABORT; + if (unlikely(part_info->num_columns > MAX_REF_PARTS)) + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of partition fields")); + } + ; + +part_column_list: + COLUMNS '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->column_list= TRUE; + part_info->list_of_part_fields= TRUE; + } + ; + + +part_func: + '(' part_func_expr ')' + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->set_part_expr(thd, $2, FALSE))) + MYSQL_YYABORT; + part_info->num_columns= 1; + part_info->column_list= FALSE; + } + ; + +sub_part_func: + '(' part_func_expr ')' + { + if (unlikely(Lex->part_info->set_part_expr(thd, $2, TRUE))) + MYSQL_YYABORT; + } + ; + + +opt_num_parts: + /* empty */ {} + | PARTITIONS_SYM real_ulong_num + { + uint num_parts= $2; + partition_info *part_info= Lex->part_info; + if (unlikely(num_parts == 0)) + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "partitions")); + + part_info->num_parts= num_parts; + part_info->use_default_num_partitions= FALSE; + } + ; + +opt_sub_part: + /* empty */ {} + | SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func + { Lex->part_info->subpart_type= HASH_PARTITION; } + opt_num_subparts {} + | SUBPARTITION_SYM BY opt_linear KEY_SYM opt_key_algo + '(' sub_part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->subpart_type= HASH_PARTITION; + part_info->list_of_subpart_fields= TRUE; + } + opt_num_subparts {} + ; + +sub_part_field_list: + sub_part_field_item {} + | sub_part_field_list ',' sub_part_field_item {} + ; + +sub_part_field_item: + ident + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->subpart_field_list.push_back($1.str, + thd->mem_root))) + MYSQL_YYABORT; + + if (unlikely(part_info->subpart_field_list.elements > MAX_REF_PARTS)) + my_yyabort_error((ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of subpartition fields")); + } + ; + +part_func_expr: + bit_expr + { + if (unlikely(!Lex->safe_to_cache_query)) + { + thd->parse_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR); + MYSQL_YYABORT; + } + $$=$1; + } + ; + +opt_num_subparts: + /* empty */ {} + | SUBPARTITIONS_SYM real_ulong_num + { + uint num_parts= $2; + LEX *lex= Lex; + if (unlikely(num_parts == 0)) + my_yyabort_error((ER_NO_PARTS_ERROR, MYF(0), "subpartitions")); + lex->part_info->num_subparts= num_parts; + lex->part_info->use_default_num_subpartitions= FALSE; + } + ; + +part_defs: + /* empty */ + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->part_type == RANGE_PARTITION)) + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "RANGE")); + if (unlikely(part_info->part_type == LIST_PARTITION)) + my_yyabort_error((ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "LIST")); + } + | '(' part_def_list ')' + { + partition_info *part_info= Lex->part_info; + uint count_curr_parts= part_info->partitions.elements; + if (part_info->num_parts != 0) + { + if (unlikely(part_info->num_parts != + count_curr_parts)) + { + thd->parse_error(ER_PARTITION_WRONG_NO_PART_ERROR); + MYSQL_YYABORT; + } + } + else if (count_curr_parts > 0) + { + part_info->num_parts= count_curr_parts; + } + part_info->count_curr_subparts= 0; + } + ; + +part_def_list: + part_definition {} + | part_def_list ',' part_definition {} + ; + +opt_partition: + /* empty */ + | PARTITION_SYM + ; + +part_definition: + opt_partition + { + partition_info *part_info= Lex->part_info; + partition_element *p_elem= new (thd->mem_root) partition_element(); + + if (unlikely(!p_elem) || + unlikely(part_info->partitions.push_back(p_elem, thd->mem_root))) + MYSQL_YYABORT; + + p_elem->part_state= PART_NORMAL; + p_elem->id= part_info->partitions.elements - 1; + part_info->curr_part_elem= p_elem; + part_info->current_partition= p_elem; + part_info->use_default_partitions= FALSE; + part_info->use_default_num_partitions= FALSE; + } + part_name + opt_part_values + opt_part_options + opt_sub_partition + {} + ; + +part_name: + ident + { + partition_info *part_info= Lex->part_info; + partition_element *p_elem= part_info->curr_part_elem; + if (unlikely(check_ident_length(&$1))) + MYSQL_YYABORT; + p_elem->partition_name= $1.str; + } + ; + +opt_part_values: + /* empty */ + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (unlikely(part_info->error_if_requires_values())) + MYSQL_YYABORT; + if (unlikely(part_info->part_type == VERSIONING_PARTITION)) + my_yyabort_error((ER_VERS_WRONG_PARTS, MYF(0), + lex->create_last_non_select_table-> + table_name.str)); + } + else + part_info->part_type= HASH_PARTITION; + } + | VALUES_LESS_SYM THAN_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (unlikely(part_info->part_type != RANGE_PARTITION)) + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN")); + } + else + part_info->part_type= RANGE_PARTITION; + } + part_func_max {} + | VALUES_IN_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (unlikely(part_info->part_type != LIST_PARTITION)) + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN")); + } + else + part_info->part_type= LIST_PARTITION; + } + part_values_in {} + | CURRENT_SYM + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (Lex->part_values_current(thd)) + MYSQL_YYABORT; +#endif + } + | HISTORY_SYM + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (Lex->part_values_history(thd)) + MYSQL_YYABORT; +#endif + } + | DEFAULT + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + if (! lex->is_partition_management()) + { + if (unlikely(part_info->part_type != LIST_PARTITION)) + my_yyabort_error((ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "DEFAULT")); + } + else + part_info->part_type= LIST_PARTITION; + if (unlikely(part_info->init_column_part(thd))) + MYSQL_YYABORT; + if (unlikely(part_info->add_max_value(thd))) + MYSQL_YYABORT; + } + ; + +part_func_max: + MAXVALUE_SYM + { + partition_info *part_info= Lex->part_info; + + if (unlikely(part_info->num_columns && + part_info->num_columns != 1U)) + { + part_info->print_debug("Kilroy II", NULL); + thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR); + MYSQL_YYABORT; + } + else + part_info->num_columns= 1U; + if (unlikely(part_info->init_column_part(thd))) + MYSQL_YYABORT; + if (unlikely(part_info->add_max_value(thd))) + MYSQL_YYABORT; + } + | part_value_item {} + ; + +part_values_in: + part_value_item + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + part_info->print_debug("part_values_in: part_value_item", NULL); + + if (part_info->num_columns != 1U) + { + if (unlikely(!lex->is_partition_management() || + part_info->num_columns == 0 || + part_info->num_columns > MAX_REF_PARTS)) + { + part_info->print_debug("Kilroy III", NULL); + thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR); + MYSQL_YYABORT; + } + /* + Reorganize the current large array into a list of small + arrays with one entry in each array. This can happen + in the first partition of an ALTER TABLE statement where + we ADD or REORGANIZE partitions. Also can only happen + for LIST partitions. + */ + if (unlikely(part_info->reorganize_into_single_field_col_val(thd))) + MYSQL_YYABORT; + } + } + | '(' part_value_list ')' + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->num_columns < 2U)) + { + thd->parse_error(ER_ROW_SINGLE_PARTITION_FIELD_ERROR); + MYSQL_YYABORT; + } + } + ; + +part_value_list: + part_value_item {} + | part_value_list ',' part_value_item {} + ; + +part_value_item: + '(' + { + partition_info *part_info= Lex->part_info; + part_info->print_debug("( part_value_item", NULL); + /* Initialisation code needed for each list of value expressions */ + if (unlikely(!(part_info->part_type == LIST_PARTITION && + part_info->num_columns == 1U) && + part_info->init_column_part(thd))) + MYSQL_YYABORT; + } + part_value_item_list {} + ')' + { + partition_info *part_info= Lex->part_info; + part_info->print_debug(") part_value_item", NULL); + if (part_info->num_columns == 0) + part_info->num_columns= part_info->curr_list_object; + if (unlikely(part_info->num_columns != part_info->curr_list_object)) + { + /* + All value items lists must be of equal length, in some cases + which is covered by the above if-statement we don't know yet + how many columns is in the partition so the assignment above + ensures that we only report errors when we know we have an + error. + */ + part_info->print_debug("Kilroy I", NULL); + thd->parse_error(ER_PARTITION_COLUMN_LIST_ERROR); + MYSQL_YYABORT; + } + part_info->curr_list_object= 0; + } + ; + +part_value_item_list: + part_value_expr_item {} + | part_value_item_list ',' part_value_expr_item {} + ; + +part_value_expr_item: + MAXVALUE_SYM + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->part_type == LIST_PARTITION)) + { + thd->parse_error(ER_MAXVALUE_IN_VALUES_IN); + MYSQL_YYABORT; + } + if (unlikely(part_info->add_max_value(thd))) + MYSQL_YYABORT; + } + | bit_expr + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + Item *part_expr= $1; + + if (unlikely(!lex->safe_to_cache_query)) + { + thd->parse_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR); + MYSQL_YYABORT; + } + if (unlikely(part_info->add_column_list_value(thd, part_expr))) + MYSQL_YYABORT; + } + ; + + +opt_sub_partition: + /* empty */ + { + partition_info *part_info= Lex->part_info; + if (unlikely(part_info->num_subparts != 0 && + !part_info->use_default_subpartitions)) + { + /* + We come here when we have defined subpartitions on the first + partition but not on all the subsequent partitions. + */ + thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR); + MYSQL_YYABORT; + } + } + | '(' sub_part_list ')' + { + partition_info *part_info= Lex->part_info; + if (part_info->num_subparts != 0) + { + if (unlikely(part_info->num_subparts != + part_info->count_curr_subparts)) + { + thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR); + MYSQL_YYABORT; + } + } + else if (part_info->count_curr_subparts > 0) + { + if (unlikely(part_info->partitions.elements > 1)) + { + thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR); + MYSQL_YYABORT; + } + part_info->num_subparts= part_info->count_curr_subparts; + } + part_info->count_curr_subparts= 0; + } + ; + +sub_part_list: + sub_part_definition {} + | sub_part_list ',' sub_part_definition {} + ; + +sub_part_definition: + SUBPARTITION_SYM + { + partition_info *part_info= Lex->part_info; + partition_element *curr_part= part_info->current_partition; + partition_element *sub_p_elem= new (thd->mem_root) + partition_element(curr_part); + if (unlikely(part_info->use_default_subpartitions && + part_info->partitions.elements >= 2)) + { + /* + create table t1 (a int) + partition by list (a) subpartition by hash (a) + (partition p0 values in (1), + partition p1 values in (2) subpartition sp11); + causes use to arrive since we are on the second + partition, but still use_default_subpartitions + is set. When we come here we're processing at least + the second partition (the current partition processed + have already been put into the partitions list. + */ + thd->parse_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR); + MYSQL_YYABORT; + } + if (unlikely(!sub_p_elem) || + unlikely(curr_part->subpartitions.push_back(sub_p_elem, thd->mem_root))) + MYSQL_YYABORT; + + sub_p_elem->id= curr_part->subpartitions.elements - 1; + part_info->curr_part_elem= sub_p_elem; + part_info->use_default_subpartitions= FALSE; + part_info->use_default_num_subpartitions= FALSE; + part_info->count_curr_subparts++; + } + sub_name opt_subpart_options {} + ; + +sub_name: + ident_or_text + { + if (unlikely(check_ident_length(&$1))) + MYSQL_YYABORT; + Lex->part_info->curr_part_elem->partition_name= $1.str; + } + ; + +opt_part_options: + /* empty */ {} + | part_option_list {} + ; + +part_option_list: + part_option_list part_option {} + | part_option {} + ; + +part_option: + server_part_option {} + | engine_defined_option + { + $1->link(&Lex->part_info->curr_part_elem->option_list, + &Lex->option_list_last); + } + ; + +opt_subpart_options: + /* empty */ {} + | subpart_option_list {} + ; + +subpart_option_list: + subpart_option_list server_part_option {} + | server_part_option {} + ; + +server_part_option: + TABLESPACE opt_equal ident_or_text + { /* Compatibility with MySQL */ } + | opt_storage ENGINE_SYM opt_equal storage_engines + { + partition_info *part_info= Lex->part_info; + part_info->curr_part_elem->engine_type= $4; + part_info->default_engine_type= $4; + } + | CONNECTION_SYM opt_equal TEXT_STRING_sys + { + LEX *lex= Lex; + lex->part_info->curr_part_elem->connect_string.str= $3.str; + lex->part_info->curr_part_elem->connect_string.length= $3.length; + } + | NODEGROUP_SYM opt_equal real_ulong_num + { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; } + | MAX_ROWS opt_equal real_ulonglong_num + { Lex->part_info->curr_part_elem->part_max_rows= (ha_rows) $3; } + | MIN_ROWS opt_equal real_ulonglong_num + { Lex->part_info->curr_part_elem->part_min_rows= (ha_rows) $3; } + | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys + { Lex->part_info->curr_part_elem->data_file_name= $4.str; } + | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys + { Lex->part_info->curr_part_elem->index_file_name= $4.str; } + | COMMENT_SYM opt_equal TEXT_STRING_sys + { Lex->part_info->curr_part_elem->part_comment= $3.str; } + ; + +opt_versioning_rotation: + /* empty */ {} + | { Lex->clause_that_disallows_subselect= "INTERVAL"; } + INTERVAL_SYM expr interval opt_versioning_interval_start opt_vers_auto_part + { + partition_info *part_info= Lex->part_info; + const char *table_name= Lex->create_last_non_select_table->table_name.str; + if (unlikely(part_info->vers_set_interval(thd, $3, $4, $5, $6, + table_name))) + MYSQL_YYABORT; + } + | LIMIT ulonglong_num opt_vers_auto_part + { + partition_info *part_info= Lex->part_info; + const char *table_name= Lex->create_last_non_select_table->table_name.str; + if (unlikely(part_info->vers_set_limit($2, $3, table_name))) + MYSQL_YYABORT; + } + ; + + +opt_versioning_interval_start: + /* empty */ + { + $$= NULL; + } + | STARTS_SYM literal + { + $$= $2; + } + ; + +opt_vers_auto_part: + /* empty */ + { + $$= 0; + } + | AUTO_SYM + { + $$= 1; + } + ; +/* + End of partition parser part +*/ + +opt_as: + /* empty */ {} + | AS {} + ; + +opt_create_database_options: + /* empty */ {} + | create_database_options {} + ; + +create_database_options: + create_database_option {} + | create_database_options create_database_option {} + ; + +create_database_option: + default_collation {} + | default_charset {} + | COMMENT_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.schema_comment= thd->make_clex_string($3); + Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; + } + ; + +opt_if_not_exists_table_element: + /* empty */ + { + Lex->check_exists= FALSE; + } + | IF_SYM not EXISTS + { + Lex->check_exists= TRUE; + } + ; + +opt_if_not_exists: + /* empty */ + { + $$.init(); + } + | IF_SYM not EXISTS + { + $$.set(DDL_options_st::OPT_IF_NOT_EXISTS); + } + ; + +create_or_replace: + CREATE /* empty */ + { + $$.init(); + } + | CREATE OR_SYM REPLACE + { + $$.set(DDL_options_st::OPT_OR_REPLACE); + } + ; + +opt_create_table_options: + /* empty */ + | create_table_options + ; + +create_table_options_space_separated: + create_table_option + | create_table_option create_table_options_space_separated + ; + +create_table_options: + create_table_option + | create_table_option create_table_options + | create_table_option ',' create_table_options + ; + +create_table_option: + ENGINE_SYM opt_equal ident_or_text + { + LEX *lex= Lex; + if (!lex->m_sql_cmd) + { + DBUG_ASSERT(lex->sql_command == SQLCOM_ALTER_TABLE); + if (!(lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table())) + MYSQL_YYABORT; + } + Storage_engine_name *opt= + lex->m_sql_cmd->option_storage_engine_name(); + DBUG_ASSERT(opt); // Expect a proper Sql_cmd + *opt= Storage_engine_name($3); + lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; + } + | MAX_ROWS opt_equal ulonglong_num + { + Lex->create_info.max_rows= $3; + Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS; + } + | MIN_ROWS opt_equal ulonglong_num + { + Lex->create_info.min_rows= $3; + Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS; + } + | AVG_ROW_LENGTH opt_equal ulong_num + { + Lex->create_info.avg_row_length=$3; + Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH; + } + | PASSWORD_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.password=$3.str; + Lex->create_info.used_fields|= HA_CREATE_USED_PASSWORD; + } + | COMMENT_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.comment=$3; + Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; + } + | AUTO_INC opt_equal ulonglong_num + { + Lex->create_info.auto_increment_value=$3; + Lex->create_info.used_fields|= HA_CREATE_USED_AUTO; + } + | PACK_KEYS_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.table_options|= HA_OPTION_NO_PACK_KEYS; + break; + case 1: + Lex->create_info.table_options|= HA_OPTION_PACK_KEYS; + break; + default: + thd->parse_error(); + MYSQL_YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; + } + | PACK_KEYS_SYM opt_equal DEFAULT + { + Lex->create_info.table_options&= + ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); + Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS; + } + | STATS_AUTO_RECALC_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_OFF; + break; + case 1: + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_ON; + break; + default: + thd->parse_error(); + MYSQL_YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC; + } + | STATS_AUTO_RECALC_SYM opt_equal DEFAULT + { + Lex->create_info.stats_auto_recalc= HA_STATS_AUTO_RECALC_DEFAULT; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_AUTO_RECALC; + } + | STATS_PERSISTENT_SYM opt_equal ulong_num + { + switch($3) { + case 0: + Lex->create_info.table_options|= HA_OPTION_NO_STATS_PERSISTENT; + break; + case 1: + Lex->create_info.table_options|= HA_OPTION_STATS_PERSISTENT; + break; + default: + thd->parse_error(); + MYSQL_YYABORT; + } + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT; + } + | STATS_PERSISTENT_SYM opt_equal DEFAULT + { + Lex->create_info.table_options&= + ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT); + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_PERSISTENT; + } + | STATS_SAMPLE_PAGES_SYM opt_equal ulong_num + { + /* From user point of view STATS_SAMPLE_PAGES can be specified as + STATS_SAMPLE_PAGES=N (where 0<N<=65535, it does not make sense to + scan 0 pages) or STATS_SAMPLE_PAGES=default. Internally we record + =default as 0. See create_frm() in sql/table.cc, we use only two + bytes for stats_sample_pages and this is why we do not allow + larger values. 65535 pages, 16kb each means to sample 1GB, which + is impractical. If at some point this needs to be extended, then + we can store the higher bits from stats_sample_pages in .frm too. */ + if (unlikely($3 == 0 || $3 > 0xffff)) + { + thd->parse_error(); + MYSQL_YYABORT; + } + Lex->create_info.stats_sample_pages=$3; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES; + } + | STATS_SAMPLE_PAGES_SYM opt_equal DEFAULT + { + Lex->create_info.stats_sample_pages=0; + Lex->create_info.used_fields|= HA_CREATE_USED_STATS_SAMPLE_PAGES; + } + | CHECKSUM_SYM opt_equal ulong_num + { + Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; + Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; + } + | TABLE_CHECKSUM_SYM opt_equal ulong_num + { + Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; + Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; + } + | PAGE_CHECKSUM_SYM opt_equal choice + { + Lex->create_info.used_fields|= HA_CREATE_USED_PAGE_CHECKSUM; + Lex->create_info.page_checksum= $3; + } + | DELAY_KEY_WRITE_SYM opt_equal ulong_num + { + Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; + Lex->create_info.used_fields|= HA_CREATE_USED_DELAY_KEY_WRITE; + } + | ROW_FORMAT_SYM opt_equal row_types + { + Lex->create_info.row_type= $3; + Lex->create_info.used_fields|= HA_CREATE_USED_ROW_FORMAT; + } + | UNION_SYM opt_equal + { + Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list); + } + '(' opt_table_list ')' + { + /* + Move the union list to the merge_list and exclude its tables + from the global list. + */ + LEX *lex=Lex; + lex->create_info.merge_list= lex->first_select_lex()->table_list.first; + lex->first_select_lex()->table_list= lex->save_list; + /* + When excluding union list from the global list we assume that + elements of the former immediately follow elements which represent + table being created/altered and parent tables. + */ + TABLE_LIST *last_non_sel_table= lex->create_last_non_select_table; + DBUG_ASSERT(last_non_sel_table->next_global == + lex->create_info.merge_list); + last_non_sel_table->next_global= 0; + Lex->query_tables_last= &last_non_sel_table->next_global; + + lex->create_info.used_fields|= HA_CREATE_USED_UNION; + } + | default_charset + | default_collation + | INSERT_METHOD opt_equal merge_insert_types + { + Lex->create_info.merge_insert_method= $3; + Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD; + } + | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.data_file_name= $4.str; + Lex->create_info.used_fields|= HA_CREATE_USED_DATADIR; + } + | INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.index_file_name= $4.str; + Lex->create_info.used_fields|= HA_CREATE_USED_INDEXDIR; + } + | TABLESPACE ident + { /* Compatiblity with MySQL */ } + | STORAGE_SYM DISK_SYM + {Lex->create_info.storage_media= HA_SM_DISK;} + | STORAGE_SYM MEMORY_SYM + {Lex->create_info.storage_media= HA_SM_MEMORY;} + | CONNECTION_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.connect_string.str= $3.str; + Lex->create_info.connect_string.length= $3.length; + Lex->create_info.used_fields|= HA_CREATE_USED_CONNECTION; + } + | KEY_BLOCK_SIZE opt_equal ulong_num + { + Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE; + Lex->create_info.key_block_size= $3; + } + | TRANSACTIONAL_SYM opt_equal choice + { + Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; + Lex->create_info.transactional= $3; + } + | engine_defined_option + { + $1->link(&Lex->create_info.option_list, &Lex->option_list_last); + } + | SEQUENCE_SYM opt_equal choice + { + Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; + Lex->create_info.sequence= ($3 == HA_CHOICE_YES); + } + | versioning_option + ; + +engine_defined_option: + IDENT_sys equal TEXT_STRING_sys + { + if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH)) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); + $$= new (thd->mem_root) engine_option_value($1, $3, true); + MYSQL_YYABORT_UNLESS($$); + } + | IDENT_sys equal ident + { + if (unlikely($3.length > ENGINE_OPTION_MAX_LENGTH)) + my_yyabort_error((ER_VALUE_TOO_LONG, MYF(0), $1.str)); + $$= new (thd->mem_root) engine_option_value($1, $3, false); + MYSQL_YYABORT_UNLESS($$); + } + | IDENT_sys equal real_ulonglong_num + { + $$= new (thd->mem_root) engine_option_value($1, $3, thd->mem_root); + MYSQL_YYABORT_UNLESS($$); + } + | IDENT_sys equal DEFAULT + { + $$= new (thd->mem_root) engine_option_value($1); + MYSQL_YYABORT_UNLESS($$); + } + ; + +opt_versioning_option: + /* empty */ + | versioning_option + ; + +versioning_option: + WITH_SYSTEM_SYM VERSIONING_SYM + { + if (unlikely(Lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) + { + if (!DBUG_IF("sysvers_force")) + { + my_error(ER_VERS_NOT_SUPPORTED, MYF(0), "CREATE TEMPORARY TABLE"); + MYSQL_YYABORT; + } + } + else + { + Lex->alter_info.flags|= ALTER_ADD_SYSTEM_VERSIONING; + Lex->create_info.options|= HA_VERSIONED_TABLE; + } + } + ; + +default_charset: + opt_default charset opt_equal charset_name_or_default + { + if (unlikely(Lex->create_info.add_table_option_default_charset($4))) + MYSQL_YYABORT; + } + ; + +default_collation: + opt_default COLLATE_SYM opt_equal collation_name_or_default + { + Table_specification_st *cinfo= &Lex->create_info; + if (unlikely(cinfo->add_table_option_default_collation($4))) + MYSQL_YYABORT; + } + ; + +storage_engines: + ident_or_text + { + if (Storage_engine_name($1). + resolve_storage_engine_with_error(thd, &$$, + thd->lex->create_info.tmp_table())) + MYSQL_YYABORT; + } + ; + +known_storage_engines: + ident_or_text + { + plugin_ref plugin; + if (likely((plugin= ha_resolve_by_name(thd, &$1, false)))) + $$= plugin_hton(plugin); + else + my_yyabort_error((ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str)); + } + ; + +row_types: + DEFAULT { $$= ROW_TYPE_DEFAULT; } + | FIXED_SYM { $$= ROW_TYPE_FIXED; } + | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; } + | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } + | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } + | COMPACT_SYM { $$= ROW_TYPE_COMPACT; } + | PAGE_SYM { $$= ROW_TYPE_PAGE; } + ; + +merge_insert_types: + NO_SYM { $$= MERGE_INSERT_DISABLED; } + | FIRST_SYM { $$= MERGE_INSERT_TO_FIRST; } + | LAST_SYM { $$= MERGE_INSERT_TO_LAST; } + ; + +udf_type: + STRING_SYM {$$ = (int) STRING_RESULT; } + | REAL {$$ = (int) REAL_RESULT; } + | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; } + | INT_SYM {$$ = (int) INT_RESULT; } + ; + + +create_field_list: + field_list + { + Lex->create_last_non_select_table= Lex->last_table(); + } + ; + +create_field_list_parens: + LEFT_PAREN_ALT field_list ')' + { + Lex->create_last_non_select_table= Lex->last_table(); + } + ; + +field_list: + field_list_item + | field_list ',' field_list_item + ; + +field_list_item: + column_def { } + | key_def + | constraint_def + | period_for_system_time + | PERIOD_SYM period_for_application_time { } + ; + +column_def: + field_spec + { $$= $1; } + | field_spec opt_constraint references + { + if (unlikely(Lex->add_column_foreign_key(&($1->field_name), &$2, + $3, DDL_options()))) + MYSQL_YYABORT; + $$= $1; + } + ; + +key_def: + key_or_index opt_if_not_exists opt_ident opt_USING_key_algorithm + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key(Key::MULTIPLE, &$3, $4, $2))) + MYSQL_YYABORT; + } + '(' key_list ')' normal_key_options { } + | key_or_index opt_if_not_exists ident TYPE_SYM btree_or_rtree + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key(Key::MULTIPLE, &$3, $5, $2))) + MYSQL_YYABORT; + } + '(' key_list ')' normal_key_options { } + | fulltext opt_key_or_index opt_if_not_exists opt_ident + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key($1, &$4, HA_KEY_ALG_UNDEF, $3))) + MYSQL_YYABORT; + } + '(' key_list ')' fulltext_key_options { } + | spatial opt_key_or_index opt_if_not_exists opt_ident + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key($1, &$4, HA_KEY_ALG_UNDEF, $3))) + MYSQL_YYABORT; + } + '(' key_list ')' spatial_key_options { } + | opt_constraint constraint_key_type + opt_if_not_exists opt_ident + opt_USING_key_algorithm + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key($2, $4.str ? &$4 : &$1, $5, $3))) + MYSQL_YYABORT; + } + '(' key_list opt_without_overlaps ')' normal_key_options { } + | opt_constraint constraint_key_type opt_if_not_exists ident + TYPE_SYM btree_or_rtree + { + Lex->option_list= NULL; + if (unlikely(Lex->add_key($2, $4.str ? &$4 : &$1, $6, $3))) + MYSQL_YYABORT; + } + '(' key_list opt_without_overlaps ')' normal_key_options { } + | opt_constraint FOREIGN KEY_SYM opt_if_not_exists opt_ident + { + if (unlikely(Lex->check_add_key($4)) || + unlikely(!(Lex->last_key= (new (thd->mem_root) + Key(Key::MULTIPLE, + $1.str ? &$1 : &$5, + HA_KEY_ALG_UNDEF, true, $4))))) + MYSQL_YYABORT; + Lex->option_list= NULL; + } + '(' key_list ')' references + { + if (unlikely(Lex->add_table_foreign_key($5.str ? &$5 : &$1, + $1.str ? &$1 : &$5, $10, $4))) + MYSQL_YYABORT; + } + ; + +constraint_def: + opt_constraint check_constraint + { + Lex->add_constraint($1, $2, FALSE); + } + ; + +period_for_system_time: + // If FOR_SYM is followed by SYSTEM_TIME_SYM then they are merged to: FOR_SYSTEM_TIME_SYM . + PERIOD_SYM FOR_SYSTEM_TIME_SYM '(' ident ',' ident ')' + { + Vers_parse_info &info= Lex->vers_get_info(); + info.set_period($4, $6); + } + ; + +period_for_application_time: + FOR_SYM ident '(' ident ',' ident ')' + { + if (Lex->add_period($2, $4, $6)) + MYSQL_YYABORT; + } + ; + +opt_check_constraint: + /* empty */ { $$= (Virtual_column_info*) 0; } + | check_constraint { $$= $1;} + ; + +check_constraint: + CHECK_SYM '(' expr ')' + { + Virtual_column_info *v= add_virtual_expression(thd, $3); + if (unlikely(!v)) + MYSQL_YYABORT; + $$= v; + } + ; + +opt_constraint_no_id: + /* Empty */ {} + | CONSTRAINT {} + ; + +opt_constraint: + /* empty */ { $$= null_clex_str; } + | constraint { $$= $1; } + ; + +constraint: + CONSTRAINT opt_ident { $$=$2; } + ; + +field_spec: + field_ident + { + LEX *lex=Lex; + Create_field *f= new (thd->mem_root) Create_field(); + + if (unlikely(check_string_char_length(&$1, 0, NAME_CHAR_LEN, + system_charset_info, 1))) + my_yyabort_error((ER_TOO_LONG_IDENT, MYF(0), $1.str)); + + if (unlikely(!f)) + MYSQL_YYABORT; + + lex->init_last_field(f, &$1); + $<create_field>$= f; + lex->parsing_options.lookup_keywords_after_qualifier= true; + } + field_type_or_serial opt_check_constraint + { + LEX *lex=Lex; + lex->parsing_options.lookup_keywords_after_qualifier= false; + $$= $<create_field>2; + + $$->check_constraint= $4; + + if (unlikely($$->check(thd))) + MYSQL_YYABORT; + + lex->alter_info.create_list.push_back($$, thd->mem_root); + + $$->create_if_not_exists= Lex->check_exists; + if ($$->flags & PRI_KEY_FLAG) + lex->add_key_to_list(&$1, Key::PRIMARY, lex->check_exists); + else if ($$->flags & UNIQUE_KEY_FLAG) + lex->add_key_to_list(&$1, Key::UNIQUE, lex->check_exists); + } + ; + +field_type_or_serial: + qualified_field_type + { + Lex->last_field->set_attributes(thd, $1, + COLUMN_DEFINITION_TABLE_FIELD); + } + field_def + { + auto tmp= $1.charset_collation_attrs(); + if (tmp.merge_column_charset_clause_and_collate_clause($3)) + MYSQL_YYABORT; + Lex->last_field->set_charset_collation_attrs(tmp); + } + | SERIAL_SYM + { + Lex->last_field->set_handler(&type_handler_ulonglong); + Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG + | UNSIGNED_FLAG | UNIQUE_KEY_FLAG; + Lex->alter_info.flags|= ALTER_ADD_INDEX; + } + opt_serial_attribute + ; + +opt_serial_attribute: + /* empty */ {} + | opt_serial_attribute_list {} + ; + +opt_serial_attribute_list: + opt_serial_attribute_list serial_attribute {} + | serial_attribute + ; + +opt_asrow_attribute: + /* empty */ {} + | opt_asrow_attribute_list {} + ; + +opt_asrow_attribute_list: + opt_asrow_attribute_list asrow_attribute {} + | asrow_attribute + ; + +field_def: + /* empty */ { $$.init(); } + | attribute_list + | attribute_list compressed_deprecated_column_attribute { $$= $1; } + | attribute_list compressed_deprecated_column_attribute attribute_list + { + if (($$= $1).merge_column_collate_clause_and_collate_clause($3)) + MYSQL_YYABORT; + } + | opt_generated_always AS virtual_column_func + { + Lex->last_field->vcol_info= $3; + } + vcol_opt_specifier vcol_opt_attribute + { + $$.init(); + } + | opt_generated_always AS ROW_SYM START_SYM opt_asrow_attribute + { + if (Lex->last_field_generated_always_as_row_start()) + MYSQL_YYABORT; + $$.init(); + } + | opt_generated_always AS ROW_SYM END opt_asrow_attribute + { + if (Lex->last_field_generated_always_as_row_end()) + MYSQL_YYABORT; + $$.init(); + } + ; + +opt_generated_always: + /* empty */ {} + | GENERATED_SYM ALWAYS_SYM {} + ; + +vcol_opt_specifier: + /* empty */ + { + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); + } + | VIRTUAL_SYM + { + Lex->last_field->vcol_info->set_stored_in_db_flag(FALSE); + } + | PERSISTENT_SYM + { + Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE); + } + | STORED_SYM + { + Lex->last_field->vcol_info->set_stored_in_db_flag(TRUE); + } + ; + +vcol_opt_attribute: + /* empty */ {} + | vcol_opt_attribute_list {} + ; + +vcol_opt_attribute_list: + vcol_opt_attribute_list vcol_attribute {} + | vcol_attribute + ; + +vcol_attribute: + UNIQUE_SYM + { + LEX *lex=Lex; + lex->last_field->flags|= UNIQUE_KEY_FLAG; + lex->alter_info.flags|= ALTER_ADD_INDEX; + } + | UNIQUE_SYM KEY_SYM + { + LEX *lex=Lex; + lex->last_field->flags|= UNIQUE_KEY_FLAG; + lex->alter_info.flags|= ALTER_ADD_INDEX; + } + | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; } + | INVISIBLE_SYM + { + Lex->last_field->invisible= INVISIBLE_USER; + } + ; + +parse_vcol_expr: + PARSE_VCOL_EXPR_SYM + { + /* + "PARSE_VCOL_EXPR" can only be used by the SQL server + when reading a '*.frm' file. + Prevent the end user from invoking this command. + */ + MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr); + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + expr + { + Virtual_column_info *v= add_virtual_expression(thd, $3); + if (unlikely(!v)) + MYSQL_YYABORT; + Lex->last_field->vcol_info= v; + Lex->pop_select(); //main select + } + ; + +parenthesized_expr: + expr + | expr ',' expr_list + { + $3->push_front($1, thd->mem_root); + $$= new (thd->mem_root) Item_row(thd, *$3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +virtual_column_func: + '(' parenthesized_expr ')' + { + Virtual_column_info *v= + add_virtual_expression(thd, $2); + if (unlikely(!v)) + MYSQL_YYABORT; + $$= v; + } + | subquery + { + Item *item; + if (!(item= new (thd->mem_root) Item_singlerow_subselect(thd, $1))) + MYSQL_YYABORT; + Virtual_column_info *v= add_virtual_expression(thd, item); + if (unlikely(!v)) + MYSQL_YYABORT; + $$= v; + } + ; + +expr_or_literal: column_default_non_parenthesized_expr | signed_literal ; + +column_default_expr: + virtual_column_func + | expr_or_literal + { + if (unlikely(!($$= add_virtual_expression(thd, $1)))) + MYSQL_YYABORT; + } + ; + +field_type: field_type_all + { + Lex->map_data_type(Lex_ident_sys(), &($$= $1)); + } + ; + +qualified_field_type: + field_type_all + { + Lex->map_data_type(Lex_ident_sys(), &($$= $1)); + } + | sp_decl_ident '.' field_type_all + { + if (Lex->map_data_type($1, &($$= $3))) + MYSQL_YYABORT; + } + ; + +udt_name: + IDENT_sys { $$= $1; } + | reserved_keyword_udt { $$= $1; } + | non_reserved_keyword_udt { $$= $1; } + ; + +field_type_all: + field_type_numeric + | field_type_temporal + | field_type_string + | field_type_lob + | field_type_misc + | udt_name float_options srid_option + { + if (Lex->set_field_type_udt(&$$, $1, $2)) + MYSQL_YYABORT; + } + ; + +field_type_numeric: + int_type opt_field_length last_field_options + { + $$.set_handler_length_flags($1, $2, (uint32) $3); + } + | real_type opt_precision last_field_options { $$.set($1, $2); } + | FLOAT_SYM float_options last_field_options + { + $$.set(&type_handler_float, $2); + if ($2.has_explicit_length() && !$2.has_explicit_dec()) + { + if (unlikely($2.length() > PRECISION_FOR_DOUBLE)) + my_yyabort_error((ER_WRONG_FIELD_SPEC, MYF(0), + Lex->last_field->field_name.str)); + if ($2.length() > PRECISION_FOR_FLOAT) + $$.set(&type_handler_double); + else + $$.set(&type_handler_float); + } + } + | BIT_SYM opt_field_length + { + $$.set(&type_handler_bit, $2); + } + | BOOL_SYM + { + $$.set_handler_length(&type_handler_stiny, 1); + } + | BOOLEAN_SYM + { + $$.set_handler_length(&type_handler_stiny, 1); + } + | DECIMAL_SYM float_options last_field_options + { $$.set(&type_handler_newdecimal, $2);} + | NUMBER_ORACLE_SYM float_options last_field_options + { + if ($2.has_explicit_length()) + $$.set(&type_handler_newdecimal, $2); + else + $$.set(&type_handler_double); + } + | NUMERIC_SYM float_options last_field_options + { $$.set(&type_handler_newdecimal, $2);} + | FIXED_SYM float_options last_field_options + { $$.set(&type_handler_newdecimal, $2);} + ; + + +opt_binary_and_compression: + /* empty */ { $$.init(); } + | binary { $$= $1; } + | binary compressed_deprecated_data_type_attribute { $$= $1; } + | compressed opt_binary { $$= $2; } + ; + +field_type_string: + char opt_field_length opt_binary + { + $$.set(&type_handler_string, $2, $3); + } + | nchar opt_field_length opt_bin_mod + { + $$.set(&type_handler_string, $2, + Lex_exact_charset_extended_collation_attrs::national($3)); + } + | BINARY opt_field_length + { + $$.set(&type_handler_string, $2, &my_charset_bin); + } + | varchar opt_field_length opt_binary_and_compression + { + $$.set(&type_handler_varchar, $2, $3); + } + | VARCHAR2_ORACLE_SYM opt_field_length opt_binary_and_compression + { + $$.set(&type_handler_varchar, $2, $3); + } + | nvarchar opt_field_length opt_compressed opt_bin_mod + { + $$.set(&type_handler_varchar, $2, + Lex_exact_charset_extended_collation_attrs::national($4)); + } + | VARBINARY opt_field_length opt_compressed + { + $$.set(&type_handler_varchar, $2, &my_charset_bin); + } + | RAW_ORACLE_SYM opt_field_length opt_compressed + { + $$.set(&type_handler_varchar, $2, &my_charset_bin); + } + ; + +field_type_temporal: + YEAR_SYM opt_field_length last_field_options + { + if ($2.has_explicit_length()) + { + if ($2.length() != 4) + { + char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1]; + my_snprintf(buff, sizeof(buff), "YEAR(%u)", (uint) $2.length()); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_WARN_DEPRECATED_SYNTAX, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), + buff, "YEAR(4)"); + } + } + $$.set(&type_handler_year, $2); + } + | DATE_SYM { $$.set(&type_handler_newdate); } + | TIME_SYM opt_field_length + { + $$.set(opt_mysql56_temporal_format ? + static_cast<const Type_handler*>(&type_handler_time2) : + static_cast<const Type_handler*>(&type_handler_time), + $2); + } + | TIMESTAMP opt_field_length + { + $$.set(opt_mysql56_temporal_format ? + static_cast<const Type_handler*>(&type_handler_timestamp2): + static_cast<const Type_handler*>(&type_handler_timestamp), + $2); + } + | DATETIME opt_field_length + { + $$.set(thd->type_handler_for_datetime(), $2); + } + ; + + +field_type_lob: + TINYBLOB opt_compressed + { + $$.set(&type_handler_tiny_blob, &my_charset_bin); + } + | BLOB_MARIADB_SYM opt_field_length opt_compressed + { + $$.set(&type_handler_blob, $2, &my_charset_bin); + } + | BLOB_ORACLE_SYM field_length opt_compressed + { + $$.set(&type_handler_blob, $2, &my_charset_bin); + } + | BLOB_ORACLE_SYM opt_compressed + { + $$.set(&type_handler_long_blob, &my_charset_bin); + } + | MEDIUMBLOB opt_compressed + { + $$.set(&type_handler_medium_blob, &my_charset_bin); + } + | LONGBLOB opt_compressed + { + $$.set(&type_handler_long_blob, &my_charset_bin); + } + | LONG_SYM VARBINARY opt_compressed + { + $$.set(&type_handler_medium_blob, &my_charset_bin); + } + | LONG_SYM varchar opt_binary_and_compression + { $$.set(&type_handler_medium_blob, $3); } + | TINYTEXT opt_binary_and_compression + { $$.set(&type_handler_tiny_blob, $2); } + | TEXT_SYM opt_field_length opt_binary_and_compression + { $$.set(&type_handler_blob, $2, $3); } + | MEDIUMTEXT opt_binary_and_compression + { $$.set(&type_handler_medium_blob, $2); } + | LONGTEXT opt_binary_and_compression + { $$.set(&type_handler_long_blob, $2); } + | CLOB_ORACLE_SYM opt_binary_and_compression + { $$.set(&type_handler_long_blob, $2); } + | LONG_SYM opt_binary_and_compression + { $$.set(&type_handler_medium_blob, $2); } + | JSON_SYM opt_compressed + { + $$.set(&type_handler_long_blob_json, &my_charset_utf8mb4_bin); + } + ; + +field_type_misc: + ENUM '(' string_list ')' opt_binary + { $$.set(&type_handler_enum, $5); } + | SET '(' string_list ')' opt_binary + { $$.set(&type_handler_set, $5); } + ; + +char: + CHAR_SYM {} + ; + +nchar: + NCHAR_SYM {} + | NATIONAL_SYM CHAR_SYM {} + ; + +varchar: + char VARYING {} + | VARCHAR {} + ; + +nvarchar: + NATIONAL_SYM VARCHAR {} + | NVARCHAR_SYM {} + | NCHAR_SYM VARCHAR {} + | NATIONAL_SYM CHAR_SYM VARYING {} + | NCHAR_SYM VARYING {} + ; + +int_type: + INT_SYM { $$= &type_handler_slong; } + | TINYINT { $$= &type_handler_stiny; } + | SMALLINT { $$= &type_handler_sshort; } + | MEDIUMINT { $$= &type_handler_sint24; } + | BIGINT { $$= &type_handler_slonglong; } + ; + +real_type: + REAL + { + $$= thd->variables.sql_mode & MODE_REAL_AS_FLOAT ? + static_cast<const Type_handler *>(&type_handler_float) : + static_cast<const Type_handler *>(&type_handler_double); + } + | DOUBLE_SYM { $$= &type_handler_double; } + | DOUBLE_SYM PRECISION { $$= &type_handler_double; } + ; + +srid_option: + /* empty */ + { Lex->last_field->srid= 0; } + | + REF_SYSTEM_ID_SYM '=' NUM + { + Lex->last_field->srid=atoi($3.str); + } + ; + +float_options: + /* empty */ { $$.reset(); } + | field_length + | precision + ; + +precision: + '(' NUM ',' NUM ')' { $$.set($2.str, $4.str); } + ; + +field_options: + /* empty */ { $$= 0; } + | SIGNED_SYM { $$= 0; } + | UNSIGNED { $$= UNSIGNED_FLAG; } + | ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; } + | UNSIGNED ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; } + | ZEROFILL UNSIGNED { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; } + ; + +last_field_options: + field_options { Lex->last_field->flags|= ($$= $1); } + ; + +field_length_str: + '(' LONG_NUM ')' { $$= $2.str; } + | '(' ULONGLONG_NUM ')' { $$= $2.str; } + | '(' DECIMAL_NUM ')' { $$= $2.str; } + | '(' NUM ')' { $$= $2.str; } + ; + +field_length: field_length_str { $$.set($1, NULL); } + ; + + +field_scale: field_length_str { $$.set(NULL, $1); } + ; + + +opt_field_length: + /* empty */ { $$.reset(); /* use default length */ } + | field_length + ; + +opt_field_scale: + /* empty */ { $$.reset(); } + | field_scale + ; + +opt_precision: + /* empty */ { $$.reset(); } + | precision { $$= $1; } + ; + + +attribute_list: + attribute_list attribute + { + if (($$= $1).merge_column_collate_clause_and_collate_clause($2)) + MYSQL_YYABORT; + } + | attribute + ; + +attribute: + NULL_SYM + { + Lex->last_field->flags&= ~NOT_NULL_FLAG; + Lex->last_field->explicitly_nullable= true; + $$.init(); + } + | DEFAULT column_default_expr + { + Lex->last_field->default_value= $2; + $$.init(); + } + | ON UPDATE_SYM NOW_SYM opt_default_time_precision + { + Item *item= new (thd->mem_root) Item_func_now_local(thd, $4); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + Lex->last_field->on_update= item; + $$.init(); + } + | AUTO_INC { Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; $$.init(); } + | SERIAL_SYM DEFAULT VALUE_SYM + { + LEX *lex=Lex; + lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_KEY_FLAG; + lex->alter_info.flags|= ALTER_ADD_INDEX; + $$.init(); + } + | COLLATE_SYM collation_name + { + $$= Lex_exact_charset_extended_collation_attrs($2); + } + | serial_attribute { $$.init(); } + ; + +opt_compression_method: + /* empty */ { $$= NULL; } + | equal ident { $$= $2.str; } + ; + +opt_compressed: + /* empty */ {} + | compressed { } + ; + +opt_enable: + /* empty */ {} + | ENABLE_SYM { } + ; + +compressed: + COMPRESSED_SYM opt_compression_method + { + if (unlikely(Lex->last_field->set_compressed($2))) + MYSQL_YYABORT; + } + ; + +compressed_deprecated_data_type_attribute: + COMPRESSED_SYM opt_compression_method + { + if (unlikely(Lex->last_field->set_compressed_deprecated(thd, $2))) + MYSQL_YYABORT; + } + ; + +compressed_deprecated_column_attribute: + COMPRESSED_SYM opt_compression_method + { + if (unlikely(Lex->last_field-> + set_compressed_deprecated_column_attribute(thd, $1.pos(), $2))) + MYSQL_YYABORT; + } + ; + +asrow_attribute: + not NULL_SYM opt_enable + { + Lex->last_field->flags|= NOT_NULL_FLAG; + } + | opt_primary KEY_SYM + { + LEX *lex=Lex; + lex->last_field->flags|= PRI_KEY_FLAG | NOT_NULL_FLAG; + lex->alter_info.flags|= ALTER_ADD_INDEX; + } + | vcol_attribute + ; + +serial_attribute: + asrow_attribute + | engine_defined_option + { + $1->link(&Lex->last_field->option_list, &Lex->option_list_last); + } + | with_or_without_system VERSIONING_SYM + { + Lex->last_field->versioning= $1; + Lex->create_info.options|= HA_VERSIONED_TABLE; + if (Lex->alter_info.flags & ALTER_DROP_SYSTEM_VERSIONING) + { + my_yyabort_error((ER_VERS_NOT_VERSIONED, MYF(0), + Lex->create_last_non_select_table->table_name.str)); + } + } + ; + +with_or_without_system: + WITH_SYSTEM_SYM + { + Lex->alter_info.flags|= ALTER_COLUMN_UNVERSIONED; + Lex->create_info.vers_info.versioned_fields= true; + $$= Column_definition::WITH_VERSIONING; + } + | WITHOUT SYSTEM + { + Lex->alter_info.flags|= ALTER_COLUMN_UNVERSIONED; + Lex->create_info.vers_info.unversioned_fields= true; + $$= Column_definition::WITHOUT_VERSIONING; + } + ; + + +charset: + CHAR_SYM SET { $$= $1; } + | CHARSET { $$= $1; } + ; + +charset_name: + ident_or_text + { + myf utf8_flag= thd->get_utf8_flag(); + if (unlikely(!($$=get_charset_by_csname($1.str, MY_CS_PRIMARY, + MYF(utf8_flag))))) + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); + } + | BINARY { $$= &my_charset_bin; } + ; + +charset_name_or_default: + charset_name { $$=$1; } + | DEFAULT { $$=NULL; } + ; + +opt_load_data_charset: + /* Empty */ { $$= NULL; } + | charset charset_name_or_default { $$= $2; } + ; + +old_or_new_charset_name: + ident_or_text + { + myf utf8_flag= thd->get_utf8_flag(); + if (unlikely(!($$=get_charset_by_csname($1.str, + MY_CS_PRIMARY, + MYF(utf8_flag))) && + !($$=get_old_charset_by_name($1.str)))) + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str)); + } + | BINARY { $$= &my_charset_bin; } + ; + +old_or_new_charset_name_or_default: + old_or_new_charset_name { $$=$1; } + | DEFAULT { $$=NULL; } + ; + +collation_name: + ident_or_text + { + if ($$.set_by_name($1.str, thd->get_utf8_flag())) + MYSQL_YYABORT; + } + ; + +collation_name_or_default: + collation_name { $$=$1; } + | DEFAULT { $$.set_collate_default(); } + ; + +opt_default: + /* empty */ {} + | DEFAULT {} + ; + +charset_or_alias: + charset charset_name { $$= $2; } + | ASCII_SYM { $$= &my_charset_latin1; } + | UNICODE_SYM + { + if (unlikely(!($$= get_charset_by_csname("ucs2", MY_CS_PRIMARY,MYF(0))))) + my_yyabort_error((ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2")); + } + ; + +opt_binary: + /* empty */ { $$.init(); } + | binary + ; + +binary: + BYTE_SYM + { + $$.set_charset(Lex_exact_charset(&my_charset_bin)); + } + | charset_or_alias + { + $$.set_charset(Lex_exact_charset($1)); + } + | charset_or_alias BINARY + { + if ($$.set_charset_collate_binary(Lex_exact_charset($1))) + MYSQL_YYABORT; + } + | BINARY { $$.set_contextually_typed_binary_style(); } + | BINARY charset_or_alias + { + if ($$.set_charset_collate_binary(Lex_exact_charset($2))) + MYSQL_YYABORT; + } + | charset_or_alias COLLATE_SYM DEFAULT + { + $$.set_charset_collate_default(Lex_exact_charset($1)); + } + | charset_or_alias COLLATE_SYM collation_name + { + if ($3.merge_exact_charset(Lex_exact_charset($1))) + MYSQL_YYABORT; + $$= Lex_exact_charset_extended_collation_attrs($3); + } + | COLLATE_SYM collation_name + { + $$= Lex_exact_charset_extended_collation_attrs($2); + } + | COLLATE_SYM DEFAULT + { + $$.set_collate_default(); + } + ; + +opt_bin_mod: + /* empty */ { $$= false; } + | BINARY { $$= true; } + ; + +ws_nweights: + '(' real_ulong_num + { + if (unlikely($2 == 0)) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + ')' + { $$= $2; } + ; + +ws_level_flag_desc: + ASC { $$= 0; } + | DESC { $$= 1 << MY_STRXFRM_DESC_SHIFT; } + ; + +ws_level_flag_reverse: + REVERSE_SYM { $$= 1 << MY_STRXFRM_REVERSE_SHIFT; } ; + +ws_level_flags: + /* empty */ { $$= 0; } + | ws_level_flag_desc { $$= $1; } + | ws_level_flag_desc ws_level_flag_reverse { $$= $1 | $2; } + | ws_level_flag_reverse { $$= $1 ; } + ; + +ws_level_number: + real_ulong_num + { + $$= $1 < 1 ? 1 : ($1 > MY_STRXFRM_NLEVELS ? MY_STRXFRM_NLEVELS : $1); + $$--; + } + ; + +ws_level_list_item: + ws_level_number ws_level_flags + { + $$= (1 | $2) << $1; + } + ; + +ws_level_list: + ws_level_list_item { $$= $1; } + | ws_level_list ',' ws_level_list_item { $$|= $3; } + ; + +ws_level_range: + ws_level_number '-' ws_level_number + { + uint start= $1; + uint end= $3; + for ($$= 0; start <= end; start++) + $$|= (1 << start); + } + ; + +ws_level_list_or_range: + ws_level_list { $$= $1; } + | ws_level_range { $$= $1; } + ; + +opt_ws_levels: + /* empty*/ { $$= 0; } + | LEVEL_SYM ws_level_list_or_range { $$= $2; } + ; + +opt_primary: + /* empty */ + | PRIMARY_SYM + ; + +references: + REFERENCES + table_ident + opt_ref_list + opt_match_clause + opt_on_update_delete + { + $$=$2; + } + ; + +opt_ref_list: + /* empty */ + { Lex->ref_list.empty(); } + | '(' ref_list ')' + ; + +ref_list: + ref_list ',' ident + { + Key_part_spec *key= new (thd->mem_root) Key_part_spec(&$3, 0); + if (unlikely(key == NULL)) + MYSQL_YYABORT; + Lex->ref_list.push_back(key, thd->mem_root); + } + | ident + { + Key_part_spec *key= new (thd->mem_root) Key_part_spec(&$1, 0); + if (unlikely(key == NULL)) + MYSQL_YYABORT; + LEX *lex= Lex; + lex->ref_list.empty(); + lex->ref_list.push_back(key, thd->mem_root); + } + ; + +opt_match_clause: + /* empty */ + { Lex->fk_match_option= Foreign_key::FK_MATCH_UNDEF; } + | MATCH FULL + { Lex->fk_match_option= Foreign_key::FK_MATCH_FULL; } + | MATCH PARTIAL + { Lex->fk_match_option= Foreign_key::FK_MATCH_PARTIAL; } + | MATCH SIMPLE_SYM + { Lex->fk_match_option= Foreign_key::FK_MATCH_SIMPLE; } + ; + +opt_on_update_delete: + /* empty */ + { + LEX *lex= Lex; + lex->fk_update_opt= FK_OPTION_UNDEF; + lex->fk_delete_opt= FK_OPTION_UNDEF; + } + | ON UPDATE_SYM delete_option + { + LEX *lex= Lex; + lex->fk_update_opt= $3; + lex->fk_delete_opt= FK_OPTION_UNDEF; + } + | ON DELETE_SYM delete_option + { + LEX *lex= Lex; + lex->fk_update_opt= FK_OPTION_UNDEF; + lex->fk_delete_opt= $3; + } + | ON UPDATE_SYM delete_option + ON DELETE_SYM delete_option + { + LEX *lex= Lex; + lex->fk_update_opt= $3; + lex->fk_delete_opt= $6; + } + | ON DELETE_SYM delete_option + ON UPDATE_SYM delete_option + { + LEX *lex= Lex; + lex->fk_update_opt= $6; + lex->fk_delete_opt= $3; + } + ; + +delete_option: + RESTRICT { $$= FK_OPTION_RESTRICT; } + | CASCADE { $$= FK_OPTION_CASCADE; } + | SET NULL_SYM { $$= FK_OPTION_SET_NULL; } + | NO_SYM ACTION { $$= FK_OPTION_NO_ACTION; } + | SET DEFAULT { $$= FK_OPTION_SET_DEFAULT; } + ; + +constraint_key_type: + PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; } + | UNIQUE_SYM opt_key_or_index { $$= Key::UNIQUE; } + ; + +key_or_index: + KEY_SYM {} + | INDEX_SYM {} + ; + +opt_key_or_index: + /* empty */ {} + | key_or_index + ; + +keys_or_index: + KEYS {} + | INDEX_SYM {} + | INDEXES {} + ; + +fulltext: + FULLTEXT_SYM { $$= Key::FULLTEXT;} + ; + +spatial: + SPATIAL_SYM + { +#ifdef HAVE_SPATIAL + $$= Key::SPATIAL; +#else + my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, + sym_group_geom.needed_define)); +#endif + } + ; + +normal_key_options: + /* empty */ {} + | normal_key_opts { Lex->last_key->option_list= Lex->option_list; } + ; + +fulltext_key_options: + /* empty */ {} + | fulltext_key_opts { Lex->last_key->option_list= Lex->option_list; } + ; + +spatial_key_options: + /* empty */ {} + | spatial_key_opts { Lex->last_key->option_list= Lex->option_list; } + ; + +normal_key_opts: + normal_key_opt + | normal_key_opts normal_key_opt + ; + +spatial_key_opts: + spatial_key_opt + | spatial_key_opts spatial_key_opt + ; + +fulltext_key_opts: + fulltext_key_opt + | fulltext_key_opts fulltext_key_opt + ; + +opt_USING_key_algorithm: + /* Empty*/ { $$= HA_KEY_ALG_UNDEF; } + | USING btree_or_rtree { $$= $2; } + ; + +/* TYPE is a valid identifier, so it's handled differently than USING */ +opt_key_algorithm_clause: + /* Empty*/ { $$= HA_KEY_ALG_UNDEF; } + | USING btree_or_rtree { $$= $2; } + | TYPE_SYM btree_or_rtree { $$= $2; } + ; + +key_using_alg: + USING btree_or_rtree + { Lex->last_key->key_create_info.algorithm= $2; } + | TYPE_SYM btree_or_rtree + { Lex->last_key->key_create_info.algorithm= $2; } + ; + +all_key_opt: + KEY_BLOCK_SIZE opt_equal ulong_num + { + Lex->last_key->key_create_info.block_size= $3; + Lex->last_key->key_create_info.flags|= HA_USES_BLOCK_SIZE; + } + | COMMENT_SYM TEXT_STRING_sys + { Lex->last_key->key_create_info.comment= $2; } + | VISIBLE_SYM + { + /* This is mainly for MySQL 8.0 compatibility */ + } + | ignorability + { + Lex->last_key->key_create_info.is_ignored= $1; + } + | engine_defined_option + { + $1->link(&Lex->option_list, &Lex->option_list_last); + } + ; + +normal_key_opt: + all_key_opt + | key_using_alg + ; + +spatial_key_opt: + all_key_opt + ; + +fulltext_key_opt: + all_key_opt + | WITH PARSER_SYM IDENT_sys + { + if (likely(plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN))) + Lex->last_key->key_create_info.parser_name= $3; + else + my_yyabort_error((ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str)); + } + ; + +btree_or_rtree: + BTREE_SYM { $$= HA_KEY_ALG_BTREE; } + | RTREE_SYM { $$= HA_KEY_ALG_RTREE; } + | HASH_SYM { $$= HA_KEY_ALG_HASH; } + ; + +ignorability: + IGNORED_SYM { $$= true; } + | NOT_SYM IGNORED_SYM { $$= false; } + ; + +key_list: + key_list ',' key_part order_dir + { + $3->asc= $4; + Lex->last_key->columns.push_back($3, thd->mem_root); + } + | key_part order_dir + { + $1->asc= $2; + Lex->last_key->columns.push_back($1, thd->mem_root); + } + ; + +opt_without_overlaps: + /* nothing */ {} + | ',' ident WITHOUT OVERLAPS_SYM + { + Lex->last_key->without_overlaps= true; + Lex->last_key->period= $2; + } + ; + +key_part: + ident + { + $$= new (thd->mem_root) Key_part_spec(&$1, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ident '(' NUM ')' + { + int key_part_len= atoi($3.str); + if (unlikely(!key_part_len)) + my_yyabort_error((ER_KEY_PART_0, MYF(0), $1.str)); + $$= new (thd->mem_root) Key_part_spec(&$1, (uint) key_part_len); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_ident: + /* empty */ { $$= null_clex_str; } + | field_ident { $$= $1; } + ; + +string_list: + text_string + { Lex->last_field->interval_list.push_back($1, thd->mem_root); } + | string_list ',' text_string + { Lex->last_field->interval_list.push_back($3, thd->mem_root); } + ; + +/* +** Alter table +*/ + +alter: + ALTER + { + Lex->name= null_clex_str; + Lex->table_type= TABLE_TYPE_UNKNOWN; + Lex->sql_command= SQLCOM_ALTER_TABLE; + Lex->duplicates= DUP_ERROR; + Lex->first_select_lex()->order_list.empty(); + Lex->create_info.init(); + Lex->create_info.row_type= ROW_TYPE_NOT_USED; + Lex->alter_info.reset(); + Lex->no_write_to_binlog= 0; + Lex->create_info.storage_media= HA_SM_DEFAULT; + if (Lex->main_select_push()) + MYSQL_YYABORT; + DBUG_ASSERT(!Lex->m_sql_cmd); + } + alter_options TABLE_SYM opt_if_exists table_ident opt_lock_wait_timeout + { + Lex->create_info.set($5); + if (!Lex->first_select_lex()-> + add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) + MYSQL_YYABORT; + Lex->first_select_lex()->db= + (Lex->first_select_lex()->table_list.first)->db; + Lex->create_last_non_select_table= Lex->last_table(); + Lex->mark_first_table_as_inserting(); + } + alter_commands + { + if (likely(!Lex->m_sql_cmd)) + { + /* Create a generic ALTER TABLE statment. */ + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table(); + if (unlikely(Lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + Lex->pop_select(); //main select + } + | ALTER DATABASE ident_or_empty + { + Lex->create_info.init(); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; + } + create_database_options + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_ALTER_DB; + lex->name= $3; + if (lex->name.str == NULL && + unlikely(lex->copy_db_to(&lex->name))) + MYSQL_YYABORT; + Lex->pop_select(); //main select + } + | ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys + { + Lex->create_info.init(); + Lex->create_info.schema_comment= thd->make_clex_string($5); + Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT; + } + opt_create_database_options + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_ALTER_DB; + lex->name= Lex_ident_sys(); + if (lex->name.str == NULL && + unlikely(lex->copy_db_to(&lex->name))) + MYSQL_YYABORT; + } + | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM + { + LEX *lex= Lex; + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "DATABASE")); + lex->sql_command= SQLCOM_ALTER_DB_UPGRADE; + lex->name= $3; + } + | ALTER PROCEDURE_SYM sp_name + { + if (Lex->stmt_alter_procedure_start($3)) + MYSQL_YYABORT; + } + sp_a_chistics + stmt_end {} + | ALTER FUNCTION_SYM sp_name + { + if (Lex->stmt_alter_function_start($3)) + MYSQL_YYABORT; + } + sp_a_chistics + stmt_end {} + | ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, $2, $4, $6)) + MYSQL_YYABORT; + } + view_list_opt AS view_select stmt_end {} + | ALTER definer_opt opt_view_suid VIEW_SYM table_ident + /* + We have two separate rules for ALTER VIEW rather that + optional view_algorithm above, to resolve the ambiguity + with the ALTER EVENT below. + */ + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5)) + MYSQL_YYABORT; + } + view_list_opt AS view_select stmt_end {} + | ALTER definer_opt remember_name EVENT_SYM sp_name + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + /* + It is safe to use Lex->spname because + ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO + is not allowed. Lex->spname is used in the case of RENAME TO + If it had to be supported spname had to be added to + Event_parse_data. + */ + + if (unlikely(!(Lex->event_parse_data= Event_parse_data::new_instance(thd)))) + MYSQL_YYABORT; + Lex->event_parse_data->identifier= $5; + + Lex->sql_command= SQLCOM_ALTER_EVENT; + Lex->stmt_definition_begin= $3; + } + ev_alter_on_schedule_completion + opt_ev_rename_to + opt_ev_status + opt_ev_comment + opt_ev_sql_stmt + { + if (unlikely(!($7 || $8 || $9 || $10 || $11))) + { + thd->parse_error(); + MYSQL_YYABORT; + } + /* + sql_command is set here because some rules in ev_sql_stmt + can overwrite it + */ + Lex->sql_command= SQLCOM_ALTER_EVENT; + Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr(); + + Lex->pop_select(); //main select + } + | ALTER SERVER_SYM ident_or_text + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ALTER_SERVER; + lex->server_options.reset($3); + } OPTIONS_SYM '(' server_options_list ')' { } + /* ALTER USER foo is allowed for MySQL compatibility. */ + | ALTER USER_SYM opt_if_exists clear_privileges grant_list + opt_require_clause opt_resource_options opt_account_locking_and_opt_password_expiration + { + Lex->create_info.set($3); + Lex->sql_command= SQLCOM_ALTER_USER; + } + | ALTER SEQUENCE_SYM opt_if_exists + { + LEX *lex= Lex; + lex->name= null_clex_str; + lex->table_type= TABLE_TYPE_UNKNOWN; + lex->sql_command= SQLCOM_ALTER_SEQUENCE; + lex->create_info.init(); + lex->no_write_to_binlog= 0; + DBUG_ASSERT(!lex->m_sql_cmd); + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + table_ident + { + LEX *lex= Lex; + if (!(lex->create_info.seq_create_info= new (thd->mem_root) + sequence_definition()) || + !lex->first_select_lex()-> + add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) + MYSQL_YYABORT; + } + sequence_defs + { + /* Create a generic ALTER SEQUENCE statment. */ + Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3); + if (unlikely(Lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } stmt_end {} + ; + +account_locking_option: + LOCK_SYM + { + Lex->account_options.account_locked= ACCOUNTLOCK_LOCKED; + } + | UNLOCK_SYM + { + Lex->account_options.account_locked= ACCOUNTLOCK_UNLOCKED; + } + ; + +opt_password_expire_option: + /* empty */ + { + Lex->account_options.password_expire= PASSWORD_EXPIRE_NOW; + } + | NEVER_SYM + { + Lex->account_options.password_expire= PASSWORD_EXPIRE_NEVER; + } + | DEFAULT + { + Lex->account_options.password_expire= PASSWORD_EXPIRE_DEFAULT; + } + | INTERVAL_SYM NUM DAY_SYM + { + Lex->account_options.password_expire= PASSWORD_EXPIRE_INTERVAL; + if (!(Lex->account_options.num_expiration_days= atoi($2.str))) + my_yyabort_error((ER_WRONG_VALUE, MYF(0), "DAY", $2.str)); + } + ; + +opt_account_locking_and_opt_password_expiration: + /* empty */ + | ACCOUNT_SYM account_locking_option + | PASSWORD_SYM EXPIRE_SYM opt_password_expire_option + | ACCOUNT_SYM account_locking_option PASSWORD_SYM EXPIRE_SYM opt_password_expire_option + | PASSWORD_SYM EXPIRE_SYM opt_password_expire_option ACCOUNT_SYM account_locking_option + ; + +ev_alter_on_schedule_completion: + /* empty */ { $$= 0;} + | ON SCHEDULE_SYM ev_schedule_time { $$= 1; } + | ev_on_completion { $$= 1; } + | ON SCHEDULE_SYM ev_schedule_time ev_on_completion { $$= 1; } + ; + +opt_ev_rename_to: + /* empty */ { $$= 0;} + | RENAME TO_SYM sp_name + { + /* + Use lex's spname to hold the new name. + The original name is in the Event_parse_data object + */ + Lex->spname= $3; + $$= 1; + } + ; + +opt_ev_sql_stmt: + /* empty*/ { $$= 0;} + | DO_SYM ev_sql_stmt { $$= 1; } + ; + +ident_or_empty: + /* empty */ + %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE { $$= Lex_ident_sys(); } + | ident + ; + +alter_commands: + /* empty */ + | DISCARD TABLESPACE + { + Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_discard_import_tablespace( + Sql_cmd_discard_import_tablespace::DISCARD_TABLESPACE); + if (unlikely(Lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + | IMPORT TABLESPACE + { + Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_discard_import_tablespace( + Sql_cmd_discard_import_tablespace::IMPORT_TABLESPACE); + if (unlikely(Lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + | alter_list + opt_partitioning + | alter_list + remove_partitioning + | remove_partitioning + | partitioning +/* + This part was added for release 5.1 by Mikael Ronstrm. + From here we insert a number of commands to manage the partitions of a + partitioned table such as adding partitions, dropping partitions, + reorganising partitions in various manners. In future releases the list + will be longer. +*/ + | add_partition_rule + | DROP PARTITION_SYM opt_if_exists alt_part_name_list + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_DROP; + DBUG_ASSERT(!Lex->if_exists()); + Lex->create_info.add($3); + } + | REBUILD_SYM PARTITION_SYM opt_no_write_to_binlog + all_or_alt_part_name_list + { + LEX *lex= Lex; + lex->alter_info.partition_flags|= ALTER_PARTITION_REBUILD; + lex->no_write_to_binlog= $3; + } + | OPTIMIZE PARTITION_SYM opt_no_write_to_binlog + all_or_alt_part_name_list + { + LEX *lex= thd->lex; + lex->no_write_to_binlog= $3; + lex->check_opt.init(); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_optimize_partition(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + opt_no_write_to_binlog + | ANALYZE_SYM PARTITION_SYM opt_no_write_to_binlog + all_or_alt_part_name_list + { + LEX *lex= thd->lex; + lex->no_write_to_binlog= $3; + lex->check_opt.init(); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_analyze_partition(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + | CHECK_SYM PARTITION_SYM all_or_alt_part_name_list + { + LEX *lex= thd->lex; + lex->check_opt.init(); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_check_partition(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + opt_mi_check_type + | REPAIR PARTITION_SYM opt_no_write_to_binlog + all_or_alt_part_name_list + { + LEX *lex= thd->lex; + lex->no_write_to_binlog= $3; + lex->check_opt.init(); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_repair_partition(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + opt_mi_repair_type + | COALESCE PARTITION_SYM opt_no_write_to_binlog real_ulong_num + { + LEX *lex= Lex; + lex->alter_info.partition_flags|= ALTER_PARTITION_COALESCE; + lex->no_write_to_binlog= $3; + lex->alter_info.num_parts= $4; + } + | TRUNCATE_SYM PARTITION_SYM all_or_alt_part_name_list + { + LEX *lex= thd->lex; + lex->check_opt.init(); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_alter_table_truncate_partition(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + | reorg_partition_rule + | EXCHANGE_SYM PARTITION_SYM alt_part_name_item + WITH TABLE_SYM table_ident have_partitioning + { + if (Lex->stmt_alter_table_exchange_partition($6)) + MYSQL_YYABORT; + } + | CONVERT_SYM PARTITION_SYM alt_part_name_item + TO_SYM TABLE_SYM table_ident have_partitioning + { + LEX *lex= Lex; + if (Lex->stmt_alter_table($6)) + MYSQL_YYABORT; + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + lex->alter_info.partition_flags|= ALTER_PARTITION_CONVERT_OUT; + } + | CONVERT_SYM TABLE_SYM table_ident + { + LEX *lex= Lex; + if (!lex->first_select_lex()->add_table_to_list(thd, $3, nullptr, 0, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) + MYSQL_YYABORT; + + /* + This will appear as (new_db, new_name) in alter_ctx. + new_db will be IX-locked and new_name X-locked. + */ + lex->first_select_lex()->db= $3->db; + lex->name= $3->table; + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) + MYSQL_YYABORT; + + lex->part_info= new (thd->mem_root) partition_info(); + if (unlikely(!lex->part_info)) + MYSQL_YYABORT; + + lex->part_info->num_parts= 1; + /* + OR-ed with ALTER_PARTITION_ADD because too many checks of + ALTER_PARTITION_ADD required. + */ + lex->alter_info.partition_flags|= ALTER_PARTITION_ADD | + ALTER_PARTITION_CONVERT_IN; + } + TO_SYM PARTITION_SYM part_definition + { + LEX *lex= Lex; + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +remove_partitioning: + REMOVE_SYM PARTITIONING_SYM + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_REMOVE; + } + ; + +all_or_alt_part_name_list: + ALL + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_ALL; + } + | alt_part_name_list + ; + +add_partition_rule: + ADD PARTITION_SYM opt_if_not_exists + opt_no_write_to_binlog + { + LEX *lex= Lex; + lex->part_info= new (thd->mem_root) partition_info(); + if (unlikely(!lex->part_info)) + MYSQL_YYABORT; + + lex->alter_info.partition_flags|= ALTER_PARTITION_ADD; + DBUG_ASSERT(!Lex->create_info.if_not_exists()); + lex->create_info.set($3); + lex->no_write_to_binlog= $4; + } + add_part_extra + {} + ; + +add_part_extra: + /* empty */ + | '(' part_def_list ')' + { + LEX *lex= Lex; + lex->part_info->num_parts= lex->part_info->partitions.elements; + } + | PARTITIONS_SYM real_ulong_num + { + Lex->part_info->num_parts= $2; + } + ; + +reorg_partition_rule: + REORGANIZE_SYM PARTITION_SYM opt_no_write_to_binlog + { + LEX *lex= Lex; + lex->part_info= new (thd->mem_root) partition_info(); + if (unlikely(!lex->part_info)) + MYSQL_YYABORT; + + lex->no_write_to_binlog= $3; + } + reorg_parts_rule + ; + +reorg_parts_rule: + /* empty */ + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_TABLE_REORG; + } + | alt_part_name_list + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_REORGANIZE; + } + INTO '(' part_def_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->num_parts= part_info->partitions.elements; + } + ; + +alt_part_name_list: + alt_part_name_item {} + | alt_part_name_list ',' alt_part_name_item {} + ; + +alt_part_name_item: + ident + { + if (unlikely(Lex->alter_info.partition_names.push_back($1.str, + thd->mem_root))) + MYSQL_YYABORT; + } + ; + +/* + End of management of partition commands +*/ + +alter_list: + alter_list_item + | alter_list ',' alter_list_item + ; + +add_column: + ADD opt_column opt_if_not_exists_table_element + ; + +alter_list_item: + add_column column_def opt_place + { + LEX *lex=Lex; + lex->create_last_non_select_table= lex->last_table(); + lex->alter_info.flags|= ALTER_PARSER_ADD_COLUMN; + $2->after= $3; + } + | ADD key_def + { + Lex->create_last_non_select_table= Lex->last_table(); + Lex->alter_info.flags|= ALTER_ADD_INDEX; + } + | ADD period_for_system_time + { + Lex->alter_info.flags|= ALTER_ADD_PERIOD; + } + | ADD + PERIOD_SYM opt_if_not_exists_table_element period_for_application_time + { + Table_period_info &period= Lex->create_info.period_info; + period.create_if_not_exists= Lex->check_exists; + Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT; + } + | add_column '(' create_field_list ')' + { + LEX *lex=Lex; + lex->alter_info.flags|= ALTER_PARSER_ADD_COLUMN; + if (!lex->alter_info.key_list.is_empty()) + lex->alter_info.flags|= ALTER_ADD_INDEX; + } + | ADD constraint_def + { + Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT; + } + | ADD CONSTRAINT IF_SYM not EXISTS field_ident check_constraint + { + Lex->alter_info.flags|= ALTER_ADD_CHECK_CONSTRAINT; + Lex->add_constraint($6, $7, TRUE); + } + | CHANGE opt_column opt_if_exists_table_element field_ident + field_spec opt_place + { + Lex->alter_info.flags|= ALTER_CHANGE_COLUMN | ALTER_RENAME_COLUMN; + Lex->create_last_non_select_table= Lex->last_table(); + $5->change= $4; + $5->after= $6; + } + | MODIFY_SYM opt_column opt_if_exists_table_element + field_spec opt_place + { + Lex->alter_info.flags|= ALTER_CHANGE_COLUMN; + Lex->create_last_non_select_table= Lex->last_table(); + $4->change= $4->field_name; + $4->after= $5; + } + | DROP opt_column opt_if_exists_table_element field_ident opt_restrict + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::COLUMN, $4.str, $3)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= ALTER_PARSER_DROP_COLUMN; + } + | DROP CONSTRAINT opt_if_exists_table_element field_ident + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::CHECK_CONSTRAINT, + $4.str, $3)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= ALTER_DROP_CHECK_CONSTRAINT; + } + | DROP FOREIGN KEY_SYM opt_if_exists_table_element field_ident + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::FOREIGN_KEY, $5.str, $4)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= ALTER_DROP_FOREIGN_KEY; + } + | DROP opt_constraint_no_id PRIMARY_SYM KEY_SYM + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, primary_key_name.str, + FALSE)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= ALTER_DROP_INDEX; + } + | DROP key_or_index opt_if_exists_table_element field_ident + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, $4.str, $3)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + lex->alter_info.flags|= ALTER_DROP_INDEX; + } + | DISABLE_SYM KEYS + { + LEX *lex=Lex; + lex->alter_info.keys_onoff= Alter_info::DISABLE; + lex->alter_info.flags|= ALTER_KEYS_ONOFF; + } + | ENABLE_SYM KEYS + { + LEX *lex=Lex; + lex->alter_info.keys_onoff= Alter_info::ENABLE; + lex->alter_info.flags|= ALTER_KEYS_ONOFF; + } + | ALTER opt_column opt_if_exists_table_element field_ident SET DEFAULT column_default_expr + { + if (check_expression($7, &$4, VCOL_DEFAULT)) + MYSQL_YYABORT; + if (unlikely(Lex->add_alter_list($4, $7, $3))) + MYSQL_YYABORT; + } + | ALTER key_or_index opt_if_exists_table_element ident ignorability + { + LEX *lex= Lex; + Alter_index_ignorability *ac= new (thd->mem_root) + Alter_index_ignorability($4.str, $5, $3); + if (ac == NULL) + MYSQL_YYABORT; + lex->alter_info.alter_index_ignorability_list.push_back(ac); + lex->alter_info.flags|= ALTER_INDEX_IGNORABILITY; + } + | ALTER opt_column opt_if_exists_table_element field_ident DROP DEFAULT + { + if (unlikely(Lex->add_alter_list($4, (Virtual_column_info*) 0, $3))) + MYSQL_YYABORT; + } + | RENAME opt_to table_ident + { + if (Lex->stmt_alter_table($3)) + MYSQL_YYABORT; + Lex->alter_info.flags|= ALTER_RENAME; + } + | RENAME COLUMN_SYM opt_if_exists_table_element ident TO_SYM ident + { + if (unlikely(Lex->add_alter_list($4, $6, $3))) + MYSQL_YYABORT; + } + | RENAME key_or_index opt_if_exists_table_element field_ident TO_SYM field_ident + { + LEX *lex=Lex; + Alter_rename_key *ak= new (thd->mem_root) + Alter_rename_key($4, $6, $3); + if (ak == NULL) + MYSQL_YYABORT; + lex->alter_info.alter_rename_key_list.push_back(ak); + lex->alter_info.flags|= ALTER_RENAME_INDEX; + } + | CONVERT_SYM TO_SYM charset charset_name_or_default + { + if (Lex->add_alter_list_item_convert_to_charset($4)) + MYSQL_YYABORT; + } + | CONVERT_SYM TO_SYM charset charset_name_or_default + COLLATE_SYM collation_name_or_default + { + if (Lex->add_alter_list_item_convert_to_charset($4, $6)) + MYSQL_YYABORT; + } + | create_table_options_space_separated + { + LEX *lex=Lex; + lex->alter_info.flags|= ALTER_OPTIONS; + } + | FORCE_SYM + { + Lex->alter_info.flags|= ALTER_RECREATE; + } + | alter_order_clause + { + LEX *lex=Lex; + lex->alter_info.flags|= ALTER_ORDER; + } + | alter_algorithm_option + | alter_lock_option + | ADD SYSTEM VERSIONING_SYM + { + Lex->alter_info.flags|= ALTER_ADD_SYSTEM_VERSIONING; + Lex->create_info.options|= HA_VERSIONED_TABLE; + } + | DROP SYSTEM VERSIONING_SYM + { + Lex->alter_info.flags|= ALTER_DROP_SYSTEM_VERSIONING; + Lex->create_info.options&= ~HA_VERSIONED_TABLE; + } + | DROP PERIOD_SYM FOR_SYSTEM_TIME_SYM + { + Lex->alter_info.flags|= ALTER_DROP_PERIOD; + } + | DROP PERIOD_SYM opt_if_exists_table_element FOR_SYM ident + { + Alter_drop *ad= new Alter_drop(Alter_drop::PERIOD, $5.str, $3); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + Lex->alter_info.drop_list.push_back(ad, thd->mem_root); + Lex->alter_info.flags|= ALTER_DROP_CHECK_CONSTRAINT; + } + ; + +opt_index_lock_algorithm: + /* empty */ + | alter_lock_option + | alter_algorithm_option + | alter_lock_option alter_algorithm_option + | alter_algorithm_option alter_lock_option + ; + +alter_algorithm_option: + ALGORITHM_SYM opt_equal DEFAULT + { + Lex->alter_info.set_requested_algorithm( + Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT); + } + | ALGORITHM_SYM opt_equal ident + { + if (unlikely(Lex->alter_info.set_requested_algorithm(&$3))) + my_yyabort_error((ER_UNKNOWN_ALTER_ALGORITHM, MYF(0), $3.str)); + } + ; + +alter_lock_option: + LOCK_SYM opt_equal DEFAULT + { + Lex->alter_info.requested_lock= + Alter_info::ALTER_TABLE_LOCK_DEFAULT; + } + | LOCK_SYM opt_equal ident + { + if (unlikely(Lex->alter_info.set_requested_lock(&$3))) + my_yyabort_error((ER_UNKNOWN_ALTER_LOCK, MYF(0), $3.str)); + } + ; + +opt_column: + /* empty */ {} %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE + | COLUMN_SYM {} + ; + +opt_ignore: + /* empty */ { Lex->ignore= 0;} + | IGNORE_SYM { Lex->ignore= 1;} + ; + +alter_options: + { Lex->ignore= 0;} alter_options_part2 + ; + +alter_options_part2: + /* empty */ + | alter_option_list + ; + +alter_option_list: + alter_option_list alter_option + | alter_option + ; + +alter_option: + IGNORE_SYM { Lex->ignore= 1;} + | ONLINE_SYM + { + Lex->alter_info.requested_lock= + Alter_info::ALTER_TABLE_LOCK_NONE; + } + ; + +opt_restrict: + /* empty */ { Lex->drop_mode= DROP_DEFAULT; } + | RESTRICT { Lex->drop_mode= DROP_RESTRICT; } + | CASCADE { Lex->drop_mode= DROP_CASCADE; } + ; + +opt_place: + /* empty */ { $$= null_clex_str; } + | AFTER_SYM ident + { + $$= $2; + Lex->alter_info.flags |= ALTER_COLUMN_ORDER; + } + | FIRST_SYM + { + $$.str= first_keyword; + $$.length= 5; /* Length of "first" */ + Lex->alter_info.flags |= ALTER_COLUMN_ORDER; + } + ; + +opt_to: + /* empty */ {} + | TO_SYM {} + | '=' {} + | AS {} + ; + +slave: + START_SYM SLAVE optional_connection_name slave_thread_opts optional_for_channel + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_START; + lex->type = 0; + /* If you change this code don't forget to update SLAVE START too */ + } + slave_until + {} + | START_SYM ALL SLAVES slave_thread_opts + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_ALL_START; + lex->type = 0; + /* If you change this code don't forget to update STOP SLAVE too */ + } + {} + | STOP_SYM SLAVE optional_connection_name slave_thread_opts optional_for_channel + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_STOP; + lex->type = 0; + /* If you change this code don't forget to update SLAVE STOP too */ + } + | STOP_SYM ALL SLAVES slave_thread_opts + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_ALL_STOP; + lex->type = 0; + /* If you change this code don't forget to update SLAVE STOP too */ + } + ; + +start: + START_SYM TRANSACTION_SYM opt_start_transaction_option_list + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_BEGIN; + /* READ ONLY and READ WRITE are mutually exclusive. */ + if (unlikely(($3 & MYSQL_START_TRANS_OPT_READ_WRITE) && + ($3 & MYSQL_START_TRANS_OPT_READ_ONLY))) + { + thd->parse_error(); + MYSQL_YYABORT; + } + lex->start_transaction_opt= $3; + } + ; + +opt_start_transaction_option_list: + /* empty */ + { + $$= 0; + } + | start_transaction_option_list + { + $$= $1; + } + ; + +start_transaction_option_list: + start_transaction_option + { + $$= $1; + } + | start_transaction_option_list ',' start_transaction_option + { + $$= $1 | $3; + } + ; + +start_transaction_option: + WITH CONSISTENT_SYM SNAPSHOT_SYM + { + $$= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT; + } + | READ_SYM ONLY_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_ONLY; + } + | READ_SYM WRITE_SYM + { + $$= MYSQL_START_TRANS_OPT_READ_WRITE; + } + ; + +slave_thread_opts: + { Lex->slave_thd_opt= 0; } + slave_thread_opt_list + {} + ; + +slave_thread_opt_list: + slave_thread_opt + | slave_thread_opt_list ',' slave_thread_opt + ; + +slave_thread_opt: + /*empty*/ {} + | SQL_THREAD { Lex->slave_thd_opt|=SLAVE_SQL; } + | RELAY_THREAD { Lex->slave_thd_opt|=SLAVE_IO; } + ; + +slave_until: + /*empty*/ {} + | UNTIL_SYM slave_until_opts + { + LEX *lex=Lex; + if (unlikely(((lex->mi.log_file_name || lex->mi.pos) && + (lex->mi.relay_log_name || lex->mi.relay_log_pos)) || + !((lex->mi.log_file_name && lex->mi.pos) || + (lex->mi.relay_log_name && lex->mi.relay_log_pos)))) + my_yyabort_error((ER_BAD_SLAVE_UNTIL_COND, MYF(0))); + } + | UNTIL_SYM MASTER_GTID_POS_SYM '=' TEXT_STRING_sys + { + Lex->mi.gtid_pos_str = $4; + } + ; + +slave_until_opts: + master_file_def + | slave_until_opts ',' master_file_def + ; + +checksum: + CHECKSUM_SYM table_or_tables + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_CHECKSUM; + /* Will be overridden during execution. */ + YYPS->m_lock_type= TL_UNLOCK; + } + table_list opt_checksum_type + {} + ; + +opt_checksum_type: + /* nothing */ { Lex->check_opt.flags= 0; } + | QUICK { Lex->check_opt.flags= T_QUICK; } + | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; } + ; + +repair_table_or_view: + table_or_tables table_list opt_mi_repair_type + | VIEW_SYM + { Lex->table_type= TABLE_TYPE_VIEW; } + table_list opt_view_repair_type + ; + +repair: + REPAIR opt_no_write_to_binlog + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_REPAIR; + lex->no_write_to_binlog= $2; + lex->check_opt.init(); + lex->alter_info.reset(); + /* Will be overridden during execution. */ + YYPS->m_lock_type= TL_UNLOCK; + } + repair_table_or_view + { + LEX* lex= thd->lex; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +opt_mi_repair_type: + /* empty */ { Lex->check_opt.flags = T_MEDIUM; } + | mi_repair_types {} + ; + +mi_repair_types: + mi_repair_type {} + | mi_repair_type mi_repair_types {} + ; + +mi_repair_type: + QUICK { Lex->check_opt.flags|= T_QUICK; } + | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; } + | USE_FRM { Lex->check_opt.sql_flags|= TT_USEFRM; } + ; + +opt_view_repair_type: + /* empty */ { } + | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } + | FROM MYSQL_SYM { Lex->check_opt.sql_flags|= TT_FROM_MYSQL; } + ; + +analyze: + ANALYZE_SYM opt_no_write_to_binlog table_or_tables + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_ANALYZE; + lex->no_write_to_binlog= $2; + lex->check_opt.init(); + lex->alter_info.reset(); + /* Will be overridden during execution. */ + YYPS->m_lock_type= TL_UNLOCK; + } + analyze_table_list + { + LEX* lex= thd->lex; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +analyze_table_list: + analyze_table_elem_spec + | analyze_table_list ',' analyze_table_elem_spec + ; + +analyze_table_elem_spec: + table_name opt_persistent_stat_clause + ; + +opt_persistent_stat_clause: + /* empty */ + {} + | PERSISTENT_SYM FOR_SYM persistent_stat_spec + { + thd->lex->with_persistent_for_clause= TRUE; + } + ; + +persistent_stat_spec: + ALL + {} + | COLUMNS persistent_column_stat_spec INDEXES persistent_index_stat_spec + {} + ; + +persistent_column_stat_spec: + ALL {} + | '(' + { + LEX* lex= thd->lex; + lex->column_list= new (thd->mem_root) List<LEX_STRING>; + if (unlikely(lex->column_list == NULL)) + MYSQL_YYABORT; + } + table_column_list + ')' + { } + ; + +persistent_index_stat_spec: + ALL {} + | '(' + { + LEX* lex= thd->lex; + lex->index_list= new (thd->mem_root) List<LEX_STRING>; + if (unlikely(lex->index_list == NULL)) + MYSQL_YYABORT; + } + table_index_list + ')' + { } + ; + +table_column_list: + /* empty */ + {} + | ident + { + Lex->column_list->push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), thd->mem_root); + } + | table_column_list ',' ident + { + Lex->column_list->push_back((LEX_STRING*) + thd->memdup(&$3, sizeof(LEX_STRING)), thd->mem_root); + } + ; + +table_index_list: + /* empty */ + {} + | table_index_name + | table_index_list ',' table_index_name + ; + +table_index_name: + ident + { + Lex->index_list->push_back((LEX_STRING*) + thd->memdup(&$1, sizeof(LEX_STRING)), + thd->mem_root); + } + | + PRIMARY_SYM + { + LEX_STRING str= {(char*) "PRIMARY", 7}; + Lex->index_list->push_back((LEX_STRING*) + thd->memdup(&str, sizeof(LEX_STRING)), + thd->mem_root); + } + ; + +binlog_base64_event: + BINLOG_SYM TEXT_STRING_sys + { + Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; + Lex->comment= $2; + Lex->ident.str= NULL; + Lex->ident.length= 0; + } + | + BINLOG_SYM '@' ident_or_text ',' '@' ident_or_text + { + Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT; + Lex->comment= $3; + Lex->ident= $6; + } + ; + +check_view_or_table: + table_or_tables table_list opt_mi_check_type + | VIEW_SYM + { Lex->table_type= TABLE_TYPE_VIEW; } + table_list opt_view_check_type + ; + +check: CHECK_SYM + { + LEX *lex=Lex; + + lex->sql_command = SQLCOM_CHECK; + lex->check_opt.init(); + lex->alter_info.reset(); + /* Will be overridden during execution. */ + YYPS->m_lock_type= TL_UNLOCK; + } + check_view_or_table + { + LEX* lex= thd->lex; + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "CHECK")); + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +opt_mi_check_type: + /* empty */ { Lex->check_opt.flags = T_MEDIUM; } + | mi_check_types {} + ; + +mi_check_types: + mi_check_type {} + | mi_check_type mi_check_types {} + ; + +mi_check_type: + QUICK { Lex->check_opt.flags|= T_QUICK; } + | FAST_SYM { Lex->check_opt.flags|= T_FAST; } + | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; } + | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; } + | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; } + | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } + ; + +opt_view_check_type: + /* empty */ { } + | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } + ; + +optimize: + OPTIMIZE opt_no_write_to_binlog table_or_tables + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_OPTIMIZE; + lex->no_write_to_binlog= $2; + lex->check_opt.init(); + lex->alter_info.reset(); + /* Will be overridden during execution. */ + YYPS->m_lock_type= TL_UNLOCK; + } + table_list opt_lock_wait_timeout + { + LEX* lex= thd->lex; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + ; + +opt_no_write_to_binlog: + /* empty */ { $$= 0; } + | NO_WRITE_TO_BINLOG { $$= 1; } + | LOCAL_SYM { $$= 1; } + ; + +rename: + RENAME table_or_tables opt_if_exists + { + Lex->sql_command= SQLCOM_RENAME_TABLE; + Lex->create_info.set($3); + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + table_to_table_list + { + Lex->pop_select(); //main select + } + | RENAME USER_SYM clear_privileges rename_list + { + Lex->sql_command = SQLCOM_RENAME_USER; + } + ; + +rename_list: + user TO_SYM user + { + if (unlikely(Lex->users_list.push_back($1, thd->mem_root) || + Lex->users_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + | rename_list ',' user TO_SYM user + { + if (unlikely(Lex->users_list.push_back($3, thd->mem_root) || + Lex->users_list.push_back($5, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +table_to_table_list: + table_to_table + | table_to_table_list ',' table_to_table + ; + +table_to_table: + table_ident opt_lock_wait_timeout TO_SYM table_ident + { + LEX *lex=Lex; + SELECT_LEX *sl= lex->current_select; + if (unlikely(!sl->add_table_to_list(thd, $1,NULL, + TL_OPTION_UPDATING, + TL_IGNORE, MDL_EXCLUSIVE)) || + unlikely(!sl->add_table_to_list(thd, $4, NULL, + TL_OPTION_UPDATING, + TL_IGNORE, MDL_EXCLUSIVE))) + MYSQL_YYABORT; + } + ; + +keycache: + CACHE_SYM INDEX_SYM + { + Lex->alter_info.reset(); + } + keycache_list_or_parts IN_SYM key_cache_name + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE; + lex->ident= $6; + } + ; + +keycache_list_or_parts: + keycache_list + | assign_to_keycache_parts + ; + +keycache_list: + assign_to_keycache + | keycache_list ',' assign_to_keycache + ; + +assign_to_keycache: + table_ident cache_keys_spec + { + if (unlikely(!Select->add_table_to_list(thd, $1, NULL, 0, TL_READ, + MDL_SHARED_READ, + Select-> + pop_index_hints()))) + MYSQL_YYABORT; + } + ; + +assign_to_keycache_parts: + table_ident adm_partition cache_keys_spec + { + if (unlikely(!Select->add_table_to_list(thd, $1, NULL, 0, TL_READ, + MDL_SHARED_READ, + Select-> + pop_index_hints()))) + MYSQL_YYABORT; + } + ; + +key_cache_name: + ident { $$= $1; } + | DEFAULT { $$ = default_key_cache_base; } + ; + +preload: + LOAD INDEX_SYM INTO CACHE_SYM + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_PRELOAD_KEYS; + lex->alter_info.reset(); + if (lex->main_select_push()) + MYSQL_YYABORT; + } + preload_list_or_parts + { + Lex->pop_select(); //main select + } + ; + +preload_list_or_parts: + preload_keys_parts + | preload_list + ; + +preload_list: + preload_keys + | preload_list ',' preload_keys + ; + +preload_keys: + table_ident cache_keys_spec opt_ignore_leaves + { + if (unlikely(!Select->add_table_to_list(thd, $1, NULL, $3, TL_READ, + MDL_SHARED_READ, + Select-> + pop_index_hints()))) + MYSQL_YYABORT; + } + ; + +preload_keys_parts: + table_ident adm_partition cache_keys_spec opt_ignore_leaves + { + if (unlikely(!Select->add_table_to_list(thd, $1, NULL, $4, TL_READ, + MDL_SHARED_READ, + Select-> + pop_index_hints()))) + MYSQL_YYABORT; + } + ; + +adm_partition: + PARTITION_SYM have_partitioning + { + Lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN; + } + '(' all_or_alt_part_name_list ')' + ; + +cache_keys_spec: + { + Lex->first_select_lex()->alloc_index_hints(thd); + Select->set_index_hint_type(INDEX_HINT_USE, + INDEX_HINT_MASK_ALL); + } + cache_key_list_or_empty + ; + +cache_key_list_or_empty: + /* empty */ { } + | key_or_index '(' opt_key_usage_list ')' + ; + +opt_ignore_leaves: + /* empty */ + { $$= 0; } + | IGNORE_SYM LEAVES { $$= TL_OPTION_IGNORE_LEAVES; } + ; + +/* + Select : retrieve data from table +*/ + + +select: + query_expression_no_with_clause + { + if (Lex->push_select($1->fake_select_lex ? + $1->fake_select_lex : + $1->first_select())) + MYSQL_YYABORT; + } + opt_procedure_or_into + { + Lex->pop_select(); + $1->set_with_clause(NULL); + if (Lex->select_finalize($1, $3)) + MYSQL_YYABORT; + } + | with_clause query_expression_no_with_clause + { + if (Lex->push_select($2->fake_select_lex ? + $2->fake_select_lex : + $2->first_select())) + MYSQL_YYABORT; + } + opt_procedure_or_into + { + Lex->pop_select(); + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + if (Lex->select_finalize($2, $4)) + MYSQL_YYABORT; + } + ; + +select_into: + select_into_query_specification + { + if (Lex->push_select($1)) + MYSQL_YYABORT; + } + opt_order_limit_lock + { + SELECT_LEX_UNIT *unit; + if (!(unit = Lex->create_unit($1))) + MYSQL_YYABORT; + if ($3) + unit= Lex->add_tail_to_query_expression_body(unit, $3); + if (Lex->select_finalize(unit)) + MYSQL_YYABORT; + } + | with_clause + select_into_query_specification + { + if (Lex->push_select($2)) + MYSQL_YYABORT; + } + opt_order_limit_lock + { + SELECT_LEX_UNIT *unit; + if (!(unit = Lex->create_unit($2))) + MYSQL_YYABORT; + if ($4) + unit= Lex->add_tail_to_query_expression_body(unit, $4); + unit->set_with_clause($1); + $1->attach_to($2); + if (Lex->select_finalize(unit)) + MYSQL_YYABORT; + } + ; + +simple_table: + query_specification { $$= $1; } + | table_value_constructor { $$= $1; } + ; + +table_value_constructor: + VALUES + { + if (Lex->parsed_TVC_start()) + MYSQL_YYABORT; + } + values_list + { + if (!($$= Lex->parsed_TVC_end())) + MYSQL_YYABORT; + } + ; + +query_specification_start: + SELECT_SYM + { + SELECT_LEX *sel; + LEX *lex= Lex; + if (!(sel= lex->alloc_select(TRUE)) || lex->push_select(sel)) + MYSQL_YYABORT; + sel->init_select(); + sel->braces= FALSE; + } + select_options + { + Select->parsing_place= SELECT_LIST; + } + select_item_list + { + Select->parsing_place= NO_MATTER; + } + ; + +query_specification: + query_specification_start + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause + { + $$= Lex->pop_select(); + } + ; + +select_into_query_specification: + query_specification_start + into + opt_from_clause + opt_where_clause + opt_group_clause + opt_having_clause + opt_window_clause + { + $$= Lex->pop_select(); + } + ; + +/** + + The following grammar for query expressions conformant to + the latest SQL Standard is supported: + + <query expression> ::= + [ <with clause> ] <query expression body> + [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ] + + <with clause> ::= + WITH [ RECURSIVE ] <with_list + + <with list> ::= + <with list element> [ { <comma> <with list element> }... ] + + <with list element> ::= + <query name> [ '(' <with column list> ')' ] + AS <table subquery> + + <with column list> ::= + <column name list> + + <query expression body> :: + <query term> + | <query expression body> UNION [ ALL | DISTINCT ] <query term> + | <query expression body> EXCEPT [ DISTINCT ] <query term> + + <query term> ::= + <query primary> + | <query term> INTERSECT [ DISTINCT ] <query primary> + + <query primary> ::= + <simple table> + | '(' <query expression body> + [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ] + ')' + + <simple table> + <query specification> + | <table value constructor> + + <subquery> + '(' <query_expression> ')' + +*/ + +/* + query_expression produces the same expressions as + <query expression> +*/ + +query_expression: + query_expression_no_with_clause + { + $1->set_with_clause(NULL); + $$= $1; + } + | with_clause + query_expression_no_with_clause + { + $2->set_with_clause($1); + $1->attach_to($2->first_select()); + $$= $2; + } + ; + +/* + query_expression_no_with_clause produces the same expressions as + <query expression> without [ <with clause> ] +*/ + +query_expression_no_with_clause: + query_expression_body_ext { $$= $1; } + | query_expression_body_ext_parens { $$= $1; } + ; + +/* + query_expression_body_ext produces the same expressions as + <query expression body> + [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ] + | '('... <query expression body> + [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ] + ')'... + Note: number of ')' must be equal to the number of '(' in the rule above +*/ + +query_expression_body_ext: + query_expression_body + { + if ($1->first_select()->next_select()) + { + if (Lex->parsed_multi_operand_query_expression_body($1)) + MYSQL_YYABORT; + } + } + opt_query_expression_tail + { + if (!$3) + $$= $1; + else + $$= Lex->add_tail_to_query_expression_body($1, $3); + } + | query_expression_body_ext_parens + { + Lex->push_select(!$1->first_select()->next_select() ? + $1->first_select() : $1->fake_select_lex); + } + query_expression_tail + { + if (!($$= Lex->add_tail_to_query_expression_body_ext_parens($1, $3))) + MYSQL_YYABORT; + } + ; + +query_expression_body_ext_parens: + '(' query_expression_body_ext_parens ')' + { $$= $2; } + | '(' query_expression_body_ext ')' + { + SELECT_LEX *sel= $2->first_select()->next_select() ? + $2->fake_select_lex : $2->first_select(); + sel->braces= true; + $$= $2; + } + ; + +/* + query_expression_body produces the same expressions as + <query expression body> +*/ + +query_expression_body: + query_simple + { + Lex->push_select($1); + if (!($$= Lex->create_unit($1))) + MYSQL_YYABORT; + } + | query_expression_body + unit_type_decl + { + if (!$1->first_select()->next_select()) + { + Lex->pop_select(); + } + } + query_primary + { + if (!($$= Lex->add_primary_to_query_expression_body($1, $4, + $2.unit_type, + $2.distinct))) + MYSQL_YYABORT; + } + | query_expression_body_ext_parens + unit_type_decl + query_primary + { + if (!($$= Lex->add_primary_to_query_expression_body_ext_parens( + $1, $3, + $2.unit_type, + $2.distinct))) + MYSQL_YYABORT; + } + ; + +/* + query_primary produces the same expressions as + <query primary> +*/ + +query_primary: + query_simple + { $$= $1; } + | query_expression_body_ext_parens + { $$= $1->first_select(); } + ; + +/* + query_simple produces the same expressions as + <simple table> +*/ + +query_simple: + simple_table { $$= $1;} + ; + +subselect: + query_expression + { + if (!($$= Lex->parsed_subselect($1))) + MYSQL_YYABORT; + } + ; + +/* + subquery produces the same expressions as + <subquery> + + Consider the production rule of the SQL Standard + subquery: + '(' query_expression ')' + + This rule is equivalent to the rule + subquery: + '(' query_expression_no_with_clause ')' + | '(' with_clause query_expression_no_with_clause ')' + that in its turn is equivalent to + subquery: + '(' query_expression_body_ext ')' + | query_expression_body_ext_parens + | '(' with_clause query_expression_no_with_clause ')' + + The latter can be re-written into + subquery: + query_expression_body_ext_parens + | '(' with_clause query_expression_no_with_clause ')' + + The last rule allows us to resolve properly the shift/reduce conflict + when subquery is used in expressions such as in the following queries + select (select * from t1 limit 1) + t2.a from t2 + select * from t1 where t1.a [not] in (select t2.a from t2) + + In the rule below %prec SUBQUERY_AS_EXPR forces the parser to perform a shift + operation rather then a reduce operation when ')' is encountered and can be + considered as the last symbol a query expression. +*/ + +subquery: + query_expression_body_ext_parens %prec SUBQUERY_AS_EXPR + { + if (!$1->fake_select_lex) + $1->first_select()->braces= false; + else + $1->fake_select_lex->braces= false; + if (!($$= Lex->parsed_subselect($1))) + MYSQL_YYABORT; + } + | '(' with_clause query_expression_no_with_clause ')' + { + $3->set_with_clause($2); + $2->attach_to($3->first_select()); + if (!($$= Lex->parsed_subselect($3))) + MYSQL_YYABORT; + } + ; + +opt_from_clause: + /* empty */ %prec EMPTY_FROM_CLAUSE + | from_clause + ; + +from_clause: + FROM table_reference_list + ; + +table_reference_list: + join_table_list + { + Select->context.table_list= + Select->context.first_name_resolution_table= + Select->table_list.first; + } + | DUAL_SYM + /* oracle compatibility: oracle always requires FROM clause, + and DUAL is system table without fields. + Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ? + Hmmm :) */ + ; + +select_options: + /* empty*/ + | select_option_list + { + if (unlikely((Select->options & SELECT_DISTINCT) && + (Select->options & SELECT_ALL))) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT")); + } + ; + +opt_history_unit: + /* empty*/ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE + { + $$= VERS_TIMESTAMP; + } + | TRANSACTION_SYM + { + $$= VERS_TRX_ID; + } + | TIMESTAMP + { + $$= VERS_TIMESTAMP; + } + ; + +history_point: + TIMESTAMP TEXT_STRING + { + Item *item; + if (!(item= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true))) + MYSQL_YYABORT; + $$= Vers_history_point(VERS_TIMESTAMP, item); + } + | function_call_keyword_timestamp + { + $$= Vers_history_point(VERS_TIMESTAMP, $1); + } + | opt_history_unit bit_expr + { + $$= Vers_history_point($1, $2); + } + ; + +for_portion_of_time_clause: + FOR_SYM PORTION_SYM OF_SYM remember_tok_start ident FROM + bit_expr TO_SYM bit_expr + { + if (unlikely(0 == strcasecmp($5.str, "SYSTEM_TIME"))) + { + thd->parse_error(ER_SYNTAX_ERROR, $4); + MYSQL_YYABORT; + } + Lex->period_conditions.init(SYSTEM_TIME_FROM_TO, + Vers_history_point(VERS_TIMESTAMP, $7), + Vers_history_point(VERS_TIMESTAMP, $9), + $5); + } + ; + +opt_for_portion_of_time_clause: + /* empty */ + { + $$= false; + } + | for_portion_of_time_clause + { + $$= true; + } + ; + +opt_for_system_time_clause: + /* empty */ + { + $$= false; + } + | FOR_SYSTEM_TIME_SYM system_time_expr + { + $$= true; + } + ; + +system_time_expr: + AS OF_SYM history_point + { + Lex->vers_conditions.init(SYSTEM_TIME_AS_OF, $3); + } + | ALL + { + Lex->vers_conditions.init(SYSTEM_TIME_ALL); + } + | FROM history_point TO_SYM history_point + { + Lex->vers_conditions.init(SYSTEM_TIME_FROM_TO, $2, $4); + } + | BETWEEN_SYM history_point AND_SYM history_point + { + Lex->vers_conditions.init(SYSTEM_TIME_BETWEEN, $2, $4); + } + ; + +select_option_list: + select_option_list select_option + | select_option + ; + +select_option: + query_expression_option + | SQL_NO_CACHE_SYM + { + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_NO_QUERY_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE")); + Select->options|= OPTION_NO_QUERY_CACHE; + } + | SQL_CACHE_SYM + { + /* + Allow this flag once per query. + */ + if (Select->options & OPTION_TO_QUERY_CACHE) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE")); + Select->options|= OPTION_TO_QUERY_CACHE; + } + ; + + +select_lock_type: + FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new + { + $$= $3; + $$.defined_lock= TRUE; + $$.update_lock= TRUE; + } + | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new + { + $$= $5; + $$.defined_lock= TRUE; + $$.update_lock= FALSE; + } + ; + + +opt_select_lock_type: + /* empty */ + { + $$.empty(); + } + | select_lock_type + { + $$= $1; + } + ; + +opt_lock_wait_timeout_new: + /* empty */ + { + $$.empty(); + } + | WAIT_SYM ulong_num + { + $$.empty(); + $$.defined_timeout= TRUE; + $$.timeout= $2; + } + | NOWAIT_SYM + { + $$.empty(); + $$.defined_timeout= TRUE; + $$.timeout= 0; + } + | SKIP_SYM LOCKED_SYM + { + $$.empty(); + $$.skip_locked= 1; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SKIP_LOCKED); + } + ; + +select_item_list: + select_item_list ',' select_item + | select_item + | '*' + { + bool is_parsing_returning= + thd->lex->current_select->parsing_place == + IN_RETURNING; + SELECT_LEX *correct_select= is_parsing_returning ? + thd->lex->returning() : + thd->lex->current_select; + Item *item= new (thd->mem_root) + Item_field(thd, &correct_select->context, + star_clex_str); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + if (unlikely(add_item_to_list(thd, item))) + MYSQL_YYABORT; + correct_select->with_wild++; + } + ; + +select_item: + remember_name select_sublist_qualified_asterisk remember_end + { + if (unlikely(add_item_to_list(thd, $2))) + MYSQL_YYABORT; + } + | remember_name expr remember_end select_alias + { + DBUG_ASSERT($1 < $3); + + if (unlikely(add_item_to_list(thd, $2))) + MYSQL_YYABORT; + if ($4.str) + { + if (unlikely(Lex->sql_command == SQLCOM_CREATE_VIEW && + check_column_name($4.str))) + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str)); + $2->base_flags|= item_base_t::IS_EXPLICIT_NAME; + $2->set_name(thd, $4); + } + else if (!$2->name.str || $2->name.str == item_empty_name) + { + $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset()); + } + } + ; + +remember_tok_start: + { + $$= (char*) YYLIP->get_tok_start(); + } + ; + +remember_name: + { + $$= (char*) YYLIP->get_cpp_tok_start(); + } + ; + +remember_end: + { + $$= (char*) YYLIP->get_cpp_tok_end_rtrim(); + } + ; + +select_alias: + /* empty */ { $$=null_clex_str;} + | AS ident { $$=$2; } + | AS TEXT_STRING_sys { $$=$2; } + | ident { $$=$1; } + | TEXT_STRING_sys { $$=$1; } + ; + +opt_default_time_precision: + /* empty */ { $$= NOT_FIXED_DEC; } + | '(' ')' { $$= NOT_FIXED_DEC; } + | '(' real_ulong_num ')' { $$= $2; } + ; + +opt_time_precision: + /* empty */ { $$= 0; } + | '(' ')' { $$= 0; } + | '(' real_ulong_num ')' { $$= $2; } + ; + +optional_braces: + /* empty */ {} + | '(' ')' {} + ; + +/* all possible expressions */ +expr: + expr or expr %prec OR_SYM + { + /* + Design notes: + Do not use a manually maintained stack like thd->lex->xxx_list, + but use the internal bison stack ($$, $1 and $3) instead. + Using the bison stack is: + - more robust to changes in the grammar, + - guaranteed to be in sync with the parser state, + - better for performances (no memory allocation). + */ + Item_cond_or *item1; + Item_cond_or *item3; + if (is_cond_or($1)) + { + item1= (Item_cond_or*) $1; + if (is_cond_or($3)) + { + item3= (Item_cond_or*) $3; + /* + (X1 OR X2) OR (Y1 OR Y2) ==> OR (X1, X2, Y1, Y2) + */ + item3->add_at_head(item1->argument_list()); + $$ = $3; + } + else + { + /* + (X1 OR X2) OR Y ==> OR (X1, X2, Y) + */ + item1->add($3, thd->mem_root); + $$ = $1; + } + } + else if (is_cond_or($3)) + { + item3= (Item_cond_or*) $3; + /* + X OR (Y1 OR Y2) ==> OR (X, Y1, Y2) + */ + item3->add_at_head($1, thd->mem_root); + $$ = $3; + } + else + { + /* X OR Y */ + $$= new (thd->mem_root) Item_cond_or(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + } + | expr XOR expr %prec XOR + { + /* XOR is a proprietary extension */ + $$= new (thd->mem_root) Item_func_xor(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | expr and expr %prec AND_SYM + { + /* See comments in rule expr: expr or expr */ + Item_cond_and *item1; + Item_cond_and *item3; + if (is_cond_and($1)) + { + item1= (Item_cond_and*) $1; + if (is_cond_and($3)) + { + item3= (Item_cond_and*) $3; + /* + (X1 AND X2) AND (Y1 AND Y2) ==> AND (X1, X2, Y1, Y2) + */ + item3->add_at_head(item1->argument_list()); + $$ = $3; + } + else + { + /* + (X1 AND X2) AND Y ==> AND (X1, X2, Y) + */ + item1->add($3, thd->mem_root); + $$ = $1; + } + } + else if (is_cond_and($3)) + { + item3= (Item_cond_and*) $3; + /* + X AND (Y1 AND Y2) ==> AND (X, Y1, Y2) + */ + item3->add_at_head($1, thd->mem_root); + $$ = $3; + } + else + { + /* X AND Y */ + $$= new (thd->mem_root) Item_cond_and(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + } + | NOT_SYM expr + { + $$= negate_expression(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test %prec PREC_BELOW_NOT + ; + +boolean_test: + boolean_test IS TRUE_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_istrue(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS not TRUE_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnottrue(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS FALSE_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isfalse(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS not FALSE_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS UNKNOWN_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnull(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS not UNKNOWN_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS NULL_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnull(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test IS not NULL_SYM %prec IS + { + $$= new (thd->mem_root) Item_func_isnotnull(thd, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test EQUAL_SYM predicate %prec EQUAL_SYM + { + $$= new (thd->mem_root) Item_func_equal(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test comp_op predicate %prec '=' + { + $$= (*$2)(0)->create(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | boolean_test comp_op all_or_any '(' subselect ')' %prec '=' + { + $$= all_any_subquery_creator(thd, $1, $2, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate %prec BETWEEN_SYM + ; + +predicate: + predicate IN_SYM subquery + { + $$= new (thd->mem_root) Item_in_subselect(thd, $1, $3); + if (unlikely(!$$)) + MYSQL_YYABORT; + } + | predicate not IN_SYM subquery + { + Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $4); + if (unlikely(!item)) + MYSQL_YYABORT; + $$= negate_expression(thd, item); + if (unlikely(!$$)) + MYSQL_YYABORT; + } + | predicate IN_SYM '(' expr ')' + { + $$= handle_sql2003_note184_exception(thd, $1, true, $4); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate IN_SYM '(' expr ',' expr_list ')' + { + $6->push_front($4, thd->mem_root); + $6->push_front($1, thd->mem_root); + $$= new (thd->mem_root) Item_func_in(thd, *$6); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate not IN_SYM '(' expr ')' + { + $$= handle_sql2003_note184_exception(thd, $1, false, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate not IN_SYM '(' expr ',' expr_list ')' + { + $7->push_front($5, thd->mem_root); + $7->push_front($1, thd->mem_root); + Item_func_in *item= new (thd->mem_root) Item_func_in(thd, *$7); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM + { + $$= new (thd->mem_root) Item_func_between(thd, $1, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate not BETWEEN_SYM predicate AND_SYM predicate %prec BETWEEN_SYM + { + Item_func_between *item; + item= new (thd->mem_root) Item_func_between(thd, $1, $4, $6); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate SOUNDS_SYM LIKE predicate + { + Item *item1= new (thd->mem_root) Item_func_soundex(thd, $1); + Item *item4= new (thd->mem_root) Item_func_soundex(thd, $4); + if (unlikely(item1 == NULL) || unlikely(item4 == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_func_eq(thd, item1, item4); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate LIKE predicate + { + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, escape(thd), false); + if (unlikely(!$$)) + MYSQL_YYABORT; + } + | predicate LIKE predicate ESCAPE_SYM predicate %prec LIKE + { + Lex->escape_used= true; + $$= new (thd->mem_root) Item_func_like(thd, $1, $3, $5, true); + if (unlikely(!$$)) + MYSQL_YYABORT; + } + | predicate not LIKE predicate + { + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, escape(thd), false); + if (unlikely(!item)) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate not LIKE predicate ESCAPE_SYM predicate %prec LIKE + { + Lex->escape_used= true; + Item *item= new (thd->mem_root) Item_func_like(thd, $1, $4, $6, true); + if (unlikely(!item)) + MYSQL_YYABORT; + $$= item->neg_transformer(thd); + } + | predicate REGEXP predicate + { + $$= new (thd->mem_root) Item_func_regex(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | predicate not REGEXP predicate + { + Item *item= new (thd->mem_root) Item_func_regex(thd, $1, $4); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= negate_expression(thd, item); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr %prec PREC_BELOW_NOT + ; + +bit_expr: + bit_expr '|' bit_expr %prec '|' + { + $$= new (thd->mem_root) Item_func_bit_or(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '&' bit_expr %prec '&' + { + $$= new (thd->mem_root) Item_func_bit_and(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr SHIFT_LEFT bit_expr %prec SHIFT_LEFT + { + $$= new (thd->mem_root) Item_func_shift_left(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr SHIFT_RIGHT bit_expr %prec SHIFT_RIGHT + { + $$= new (thd->mem_root) Item_func_shift_right(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr ORACLE_CONCAT_SYM bit_expr + { + $$= new (thd->mem_root) Item_func_concat_operator_oracle(thd, + $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '+' bit_expr %prec '+' + { + $$= new (thd->mem_root) Item_func_plus(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '-' bit_expr %prec '-' + { + $$= new (thd->mem_root) Item_func_minus(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '+' INTERVAL_SYM expr interval %prec '+' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '-' INTERVAL_SYM expr interval %prec '-' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $1, $4, $5, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | INTERVAL_SYM expr interval '+' expr + /* we cannot put interval before - */ + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $5, $2, $3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | '+' INTERVAL_SYM expr interval '+' expr %prec NEG + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $6, $3, $4, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | '-' INTERVAL_SYM expr interval '+' expr %prec NEG + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $6, $3, $4, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '*' bit_expr %prec '*' + { + $$= new (thd->mem_root) Item_func_mul(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '/' bit_expr %prec '/' + { + $$= new (thd->mem_root) Item_func_div(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '%' bit_expr %prec '%' + { + $$= new (thd->mem_root) Item_func_mod(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr DIV_SYM bit_expr %prec DIV_SYM + { + $$= new (thd->mem_root) Item_func_int_div(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr MOD_SYM bit_expr %prec MOD_SYM + { + $$= new (thd->mem_root) Item_func_mod(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | bit_expr '^' bit_expr + { + $$= new (thd->mem_root) Item_func_bit_xor(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | mysql_concatenation_expr %prec '^' + ; + +or: + OR_SYM + | OR2_SYM + ; + +and: + AND_SYM + | AND_AND_SYM + ; + +not: + NOT_SYM + | NOT2_SYM + ; + +not2: + '!' + | NOT2_SYM + ; + +comp_op: + '=' { $$ = &comp_eq_creator; } + | GE { $$ = &comp_ge_creator; } + | '>' { $$ = &comp_gt_creator; } + | LE { $$ = &comp_le_creator; } + | '<' { $$ = &comp_lt_creator; } + | NE { $$ = &comp_ne_creator; } + ; + +all_or_any: + ALL { $$ = 1; } + | ANY_SYM { $$ = 0; } + ; + +opt_dyncol_type: + /* empty */ + { + $$.set(DYN_COL_NULL); /* automatic type */ + } + | AS dyncol_type { $$= $2; } + ; + +dyncol_type: + numeric_dyncol_type + | temporal_dyncol_type + | string_dyncol_type + ; + +numeric_dyncol_type: + INT_SYM { $$.set(DYN_COL_INT); } + | UNSIGNED INT_SYM { $$.set(DYN_COL_UINT); } + | DOUBLE_SYM { $$.set(DYN_COL_DOUBLE); } + | REAL { $$.set(DYN_COL_DOUBLE); } + | FLOAT_SYM { $$.set(DYN_COL_DOUBLE); } + | DECIMAL_SYM float_options { $$.set(DYN_COL_DECIMAL, $2); } + ; + +temporal_dyncol_type: + DATE_SYM { $$.set(DYN_COL_DATE); } + | TIME_SYM opt_field_scale { $$.set(DYN_COL_TIME, $2); } + | DATETIME opt_field_scale { $$.set(DYN_COL_DATETIME, $2); } + ; + +string_dyncol_type: + char opt_binary + { + if ($$.set(DYN_COL_STRING, $2, thd->variables.collation_connection)) + MYSQL_YYABORT; + } + | nchar + { + $$.set(DYN_COL_STRING, national_charset_info); + } + ; + +dyncall_create_element: + expr ',' expr opt_dyncol_type + { + $$= (DYNCALL_CREATE_DEF *) + alloc_root(thd->mem_root, sizeof(DYNCALL_CREATE_DEF)); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + $$->key= $1; + $$->value= $3; + $$->type= (DYNAMIC_COLUMN_TYPE)$4.dyncol_type(); + $$->cs= $4.charset_collation(); + if ($4.has_explicit_length()) + $$->len= $4.length(); + else + $$->len= 0; + if ($4.has_explicit_dec()) + $$->frac= $4.dec(); + else + $$->len= 0; + } + ; + +dyncall_create_list: + dyncall_create_element + { + $$= new (thd->mem_root) List<DYNCALL_CREATE_DEF>; + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + $$->push_back($1, thd->mem_root); + } + | dyncall_create_list ',' dyncall_create_element + { + $1->push_back($3, thd->mem_root); + $$= $1; + } + ; + + +plsql_cursor_attr: + ISOPEN_SYM { $$= PLSQL_CURSOR_ATTR_ISOPEN; } + | FOUND_SYM { $$= PLSQL_CURSOR_ATTR_FOUND; } + | NOTFOUND_SYM { $$= PLSQL_CURSOR_ATTR_NOTFOUND; } + | ROWCOUNT_SYM { $$= PLSQL_CURSOR_ATTR_ROWCOUNT; } + ; + +explicit_cursor_attr: + ident PERCENT_ORACLE_SYM plsql_cursor_attr + { + if (unlikely(!($$= Lex->make_item_plsql_cursor_attr(thd, &$1, $3)))) + MYSQL_YYABORT; + } + ; + + +trim_operands: + expr { $$.set(TRIM_BOTH, $1); } + | LEADING expr FROM expr { $$.set(TRIM_LEADING, $2, $4); } + | TRAILING expr FROM expr { $$.set(TRIM_TRAILING, $2, $4); } + | BOTH expr FROM expr { $$.set(TRIM_BOTH, $2, $4); } + | LEADING FROM expr { $$.set(TRIM_LEADING, $3); } + | TRAILING FROM expr { $$.set(TRIM_TRAILING, $3); } + | BOTH FROM expr { $$.set(TRIM_BOTH, $3); } + | expr FROM expr { $$.set(TRIM_BOTH, $1, $3); } + ; + +/* + Expressions that the parser allows in a column DEFAULT clause + without parentheses. These expressions cannot end with a COLLATE clause. + + If we allowed any "expr" in DEFAULT clause, there would be a confusion + in queries like this: + CREATE TABLE t1 (a TEXT DEFAULT 'a' COLLATE latin1_bin); + It would be not clear what COLLATE stands for: + - the collation of the column `a`, or + - the collation of the string literal 'a' + + This restriction allows to parse the above query unambiguiusly: + COLLATE belongs to the column rather than the literal. + If one needs COLLATE to belong to the literal, parentheses must be used: + CREATE TABLE t1 (a TEXT DEFAULT ('a' COLLATE latin1_bin)); + Note: the COLLATE clause is rather meaningless here, but the query + is syntactically correct. + + Note, some of the expressions are not actually allowed in DEFAULT, + e.g. sum_expr, window_func_expr, ROW(...), VALUES(). + We could move them to simple_expr, but that would make + these two queries return a different error messages: + CREATE TABLE t1 (a INT DEFAULT AVG(1)); + CREATE TABLE t1 (a INT DEFAULT (AVG(1))); + The first query would return "syntax error". + Currenly both return: + Function or expression 'avg(' is not allowed for 'DEFAULT' ... +*/ +column_default_non_parenthesized_expr: + simple_ident + | function_call_keyword + | function_call_nonkeyword + | function_call_generic + | function_call_conflict + | literal + | param_marker { $$= $1; } + | variable + | sum_expr + { + if (!Lex->select_stack_top || Lex->json_table) + { + my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0)); + MYSQL_YYABORT; + } + } + | window_func_expr + { + if (!Lex->select_stack_top) + { + my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0)); + MYSQL_YYABORT; + } + } + | inverse_distribution_function + | ROW_SYM '(' expr ',' expr_list ')' + { + $5->push_front($3, thd->mem_root); + $$= new (thd->mem_root) Item_row(thd, *$5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | EXISTS '(' subselect ')' + { + $$= new (thd->mem_root) Item_exists_subselect(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | '{' ident expr '}' + { + if (unlikely(!($$= $3->make_odbc_literal(thd, &$2)))) + MYSQL_YYABORT; + } + | MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')' + { + $2->push_front($5, thd->mem_root); + Item_func_match *i1= new (thd->mem_root) Item_func_match(thd, *$2, + $6); + if (unlikely(i1 == NULL)) + MYSQL_YYABORT; + Select->add_ftfunc_to_list(thd, i1); + $$= i1; + } + | CAST_SYM '(' expr AS cast_type ')' + { + if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3)))) + MYSQL_YYABORT; + } + | CASE_SYM when_list_opt_else END + { + if (unlikely(!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))) + MYSQL_YYABORT; + } + | CASE_SYM expr when_list_opt_else END + { + $3->push_front($2, thd->mem_root); + if (unlikely(!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3)))) + MYSQL_YYABORT; + } + | CONVERT_SYM '(' expr ',' cast_type ')' + { + if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3)))) + MYSQL_YYABORT; + } + | CONVERT_SYM '(' expr USING charset_name ')' + { + $$= new (thd->mem_root) Item_func_conv_charset(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DEFAULT '(' simple_ident ')' + { + Item_splocal *il= $3->get_item_splocal(); + if (unlikely(il)) + my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str)); + $$= new (thd->mem_root) Item_default_value(thd, Lex->current_context(), + $3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->default_used= TRUE; + } + | VALUE_SYM '(' simple_ident_nospvar ')' + { + $$= new (thd->mem_root) Item_insert_value(thd, Lex->current_context(), + $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | NEXT_SYM VALUE_SYM FOR_SYM table_ident + { + if (unlikely(!($$= Lex->create_item_func_nextval(thd, $4)))) + MYSQL_YYABORT; + } + | NEXTVAL_SYM '(' table_ident ')' + { + if (unlikely(!($$= Lex->create_item_func_nextval(thd, $3)))) + MYSQL_YYABORT; + } + | PREVIOUS_SYM VALUE_SYM FOR_SYM table_ident + { + if (unlikely(!($$= Lex->create_item_func_lastval(thd, $4)))) + MYSQL_YYABORT; + } + | LASTVAL_SYM '(' table_ident ')' + { + if (unlikely(!($$= Lex->create_item_func_lastval(thd, $3)))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ')' + { + if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, 1)))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ')' + { + if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, 0, $7)))) + MYSQL_YYABORT; + } + | SETVAL_SYM '(' table_ident ',' longlong_num ',' bool ',' ulonglong_num ')' + { + if (unlikely(!($$= Lex->create_item_func_setval(thd, $3, $5, $9, $7)))) + MYSQL_YYABORT; + } + ; + +primary_expr: + column_default_non_parenthesized_expr + | explicit_cursor_attr + | '(' parenthesized_expr ')' { $$= $2; } + | subquery + { + if (!($$= Lex->create_item_query_expression(thd, $1->master_unit()))) + MYSQL_YYABORT; + } + ; + +string_factor_expr: + primary_expr + | string_factor_expr COLLATE_SYM collation_name + { + if (unlikely(!($$= new (thd->mem_root) + Item_func_set_collation(thd, $1, $3)))) + MYSQL_YYABORT; + } + ; + +simple_expr: + string_factor_expr %prec NEG + | BINARY simple_expr + { + Type_cast_attributes at(&my_charset_bin); + if (unlikely(!($$= type_handler_long_blob.create_typecast_item(thd, $2, at)))) + MYSQL_YYABORT; + } + | '+' simple_expr %prec NEG + { + $$= $2; + } + | '-' simple_expr %prec NEG + { + $$= $2->neg(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | '~' simple_expr %prec NEG + { + $$= new (thd->mem_root) Item_func_bit_neg(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | not2 simple_expr %prec NEG + { + $$= negate_expression(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +mysql_concatenation_expr: + simple_expr + | mysql_concatenation_expr MYSQL_CONCAT_SYM simple_expr + { + $$= new (thd->mem_root) Item_func_concat(thd, $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +function_call_keyword_timestamp: + TIMESTAMP '(' expr ')' + { + $$= new (thd->mem_root) Item_datetime_typecast(thd, $3, + AUTO_SEC_PART_DIGITS); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | TIMESTAMP '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; +/* + Function call syntax using official SQL 2003 keywords. + Because the function name is an official token, + a dedicated grammar rule is needed in the parser. + There is no potential for conflicts +*/ +function_call_keyword: + CHAR_SYM '(' expr_list ')' + { + $$= new (thd->mem_root) Item_func_char(thd, *$3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CHAR_SYM '(' expr_list USING charset_name ')' + { + $$= new (thd->mem_root) Item_func_char(thd, *$3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CURRENT_USER optional_braces + { + $$= new (thd->mem_root) Item_func_current_user(thd, + Lex->current_context()); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } + | CURRENT_ROLE optional_braces + { + $$= new (thd->mem_root) Item_func_current_role(thd, + Lex->current_context()); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } + | DATE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_date_typecast(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DAY_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_dayofmonth(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | HOUR_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_hour(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | INSERT '(' expr ',' expr ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_insert(thd, $3, $5, $7, $9); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | INTERVAL_SYM '(' expr ',' expr ')' + { + List<Item> *list= new (thd->mem_root) List<Item>; + if (unlikely(list == NULL)) + MYSQL_YYABORT; + if (unlikely(list->push_front($5, thd->mem_root)) || + unlikely(list->push_front($3, thd->mem_root))) + MYSQL_YYABORT; + Item_row *item= new (thd->mem_root) Item_row(thd, *list); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_func_interval(thd, item); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')' + { + $7->push_front($5, thd->mem_root); + $7->push_front($3, thd->mem_root); + Item_row *item= new (thd->mem_root) Item_row(thd, *$7); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_func_interval(thd, item); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | LEFT '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_left(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MINUTE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_minute(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MONTH_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_month(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | RIGHT '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_right(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SECOND_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_second(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SQL_SYM PERCENT_ORACLE_SYM ROWCOUNT_SYM + { + $$= new (thd->mem_root) Item_func_oracle_sql_rowcount(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } + | TIME_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_time_typecast(thd, $3, + AUTO_SEC_PART_DIGITS); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | function_call_keyword_timestamp + { + $$= $1; + } + | TRIM '(' trim_operands ')' + { + if (unlikely(!($$= Schema::find_implied(thd)-> + make_item_func_trim(thd, $3)))) + MYSQL_YYABORT; + } + | USER_SYM '(' ')' + { + $$= new (thd->mem_root) Item_func_user(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query=0; + } + | YEAR_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_year(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +substring_operands: + expr ',' expr ',' expr + { + $$= Lex_substring_spec_st::init($1, $3, $5); + } + | expr ',' expr + { + $$= Lex_substring_spec_st::init($1, $3); + } + | expr FROM expr FOR_SYM expr + { + $$= Lex_substring_spec_st::init($1, $3, $5); + } + | expr FROM expr + { + $$= Lex_substring_spec_st::init($1, $3); + } + ; + + +/* + Function calls using non reserved keywords, with special syntaxic forms. + Dedicated grammar rules are needed because of the syntax, + but also have the potential to cause incompatibilities with other + parts of the language. + MAINTAINER: + The only reasons a function should be added here are: + - for compatibility reasons with another SQL syntax (CURDATE), + - for typing reasons (GET_FORMAT) + Any other 'Syntaxic sugar' enhancements should be *STRONGLY* + discouraged. +*/ +function_call_nonkeyword: + ADD_MONTHS_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5, + INTERVAL_MONTH, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ADDDATE_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5, + INTERVAL_DAY, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CURDATE optional_braces + { + $$= new (thd->mem_root) Item_func_curdate_local(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | CURTIME opt_time_precision + { + $$= new (thd->mem_root) Item_func_curtime_local(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DATE_FORMAT_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_date_format(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DATE_FORMAT_SYM '(' expr ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_date_format(thd, $3, $5, $7); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | EXTRACT_SYM '(' interval FROM expr ')' + { + $$=new (thd->mem_root) Item_extract(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | GET_FORMAT '(' date_time_type ',' expr ')' + { + $$= new (thd->mem_root) Item_func_get_format(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | NOW_SYM opt_time_precision + { + $$= new (thd->mem_root) Item_func_now_local(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | POSITION_SYM '(' bit_expr IN_SYM expr ')' + { + $$= new (thd->mem_root) Item_func_locate(thd, $5, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ROWNUM_SYM +%ifdef MARIADB + '(' ')' +%else + optional_braces +%endif ORACLE + { + $$= new (thd->mem_root) Item_func_rownum(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SUBDATE_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $5, + INTERVAL_DAY, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $3, $6, $7, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SUBSTRING '(' substring_operands ')' + { + if (unlikely(!($$= Schema::find_implied(thd)-> + make_item_func_substr(thd, $3)))) + MYSQL_YYABORT; + } +%ifdef ORACLE + | SYSDATE + { + if (unlikely(!($$= Lex->make_item_func_sysdate(thd, 0)))) + MYSQL_YYABORT; + } +%endif + | SYSDATE '(' ')' + { + if (unlikely(!($$= Lex->make_item_func_sysdate(thd, 0)))) + MYSQL_YYABORT; + } + | SYSDATE '(' real_ulong_num ')' + { + if (unlikely(!($$= Lex->make_item_func_sysdate(thd, (uint) $3)))) + MYSQL_YYABORT; + } + | TIMESTAMP_ADD '(' interval_time_stamp ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_date_add_interval(thd, $7, $5, $3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | TIMESTAMP_DIFF '(' interval_time_stamp ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_timestamp_diff(thd, $5, $7, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | TRIM_ORACLE '(' trim_operands ')' + { + if (unlikely(!($$= $3.make_item_func_trim_oracle(thd)))) + MYSQL_YYABORT; + } + | UTC_DATE_SYM optional_braces + { + $$= new (thd->mem_root) Item_func_curdate_utc(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | UTC_TIME_SYM opt_time_precision + { + $$= new (thd->mem_root) Item_func_curtime_utc(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | UTC_TIMESTAMP_SYM opt_time_precision + { + $$= new (thd->mem_root) Item_func_now_utc(thd, $2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | + COLUMN_ADD_SYM '(' expr ',' dyncall_create_list ')' + { + $$= create_func_dyncol_add(thd, $3, *$5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + COLUMN_DELETE_SYM '(' expr ',' expr_list ')' + { + $$= create_func_dyncol_delete(thd, $3, *$5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + COLUMN_CHECK_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_dyncol_check(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + COLUMN_CREATE_SYM '(' dyncall_create_list ')' + { + $$= create_func_dyncol_create(thd, *$3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + COLUMN_GET_SYM '(' expr ',' expr AS cast_type ')' + { + $$= create_func_dyncol_get(thd, $3, $5, $7.type_handler(), + $7, $7.charset()); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +/* + Functions calls using a non reserved keyword, and using a regular syntax. + Because the non reserved keyword is used in another part of the grammar, + a dedicated rule is needed here. +*/ +function_call_conflict: + ASCII_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_ascii(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CHARSET '(' expr ')' + { + $$= new (thd->mem_root) Item_func_charset(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | COALESCE '(' expr_list ')' + { + $$= new (thd->mem_root) Item_func_coalesce(thd, *$3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | COLLATION_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_collation(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DATABASE '(' ')' + { + $$= new (thd->mem_root) Item_func_database(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->safe_to_cache_query=0; + } + | IF_SYM '(' expr ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_if(thd, $3, $5, $7); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | FORMAT_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_format(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | FORMAT_SYM '(' expr ',' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_format(thd, $3, $5, $7); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + /* LAST_VALUE here conflicts with the definition for window functions. + We have these 2 separate rules to remove the shift/reduce conflict. + */ + | LAST_VALUE '(' expr ')' + { + List<Item> *list= new (thd->mem_root) List<Item>; + if (unlikely(list == NULL)) + MYSQL_YYABORT; + list->push_back($3, thd->mem_root); + + $$= new (thd->mem_root) Item_func_last_value(thd, *list); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | LAST_VALUE '(' expr_list ',' expr ')' + { + $3->push_back($5, thd->mem_root); + $$= new (thd->mem_root) Item_func_last_value(thd, *$3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MICROSECOND_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_microsecond(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MOD_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_mod(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | OLD_PASSWORD_SYM '(' expr ')' + { + $$= new (thd->mem_root) + Item_func_password(thd, $3, Item_func_password::OLD); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | PASSWORD_SYM '(' expr ')' + { + Item* i1; + i1= new (thd->mem_root) Item_func_password(thd, $3); + if (unlikely(i1 == NULL)) + MYSQL_YYABORT; + $$= i1; + } + | QUARTER_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_quarter(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | REPEAT_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_repeat(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | REPLACE '(' expr ',' expr ',' expr ')' + { + if (unlikely(!($$= Schema::find_implied(thd)-> + make_item_func_replace(thd, $3, $5, $7)))) + MYSQL_YYABORT; + } + | REVERSE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_reverse(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ROW_COUNT_SYM '(' ')' + { + $$= new (thd->mem_root) Item_func_row_count(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->safe_to_cache_query= 0; + } + | TRUNCATE_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_round(thd, $3, $5, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEEK_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_func_week(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEEK_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_func_week(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr opt_ws_levels ')' + { + $$= new (thd->mem_root) Item_func_weight_string(thd, $3, 0, 0, $4); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr AS CHAR_SYM ws_nweights opt_ws_levels ')' + { + $$= new (thd->mem_root) + Item_func_weight_string(thd, $3, 0, $6, + $7 | MY_STRXFRM_PAD_WITH_SPACE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr AS BINARY ws_nweights ')' + { + Item *item= new (thd->mem_root) Item_char_typecast(thd, $3, $6, + &my_charset_bin); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) + Item_func_weight_string(thd, item, 0, $6, + MY_STRXFRM_PAD_WITH_SPACE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | WEIGHT_STRING_SYM '(' expr ',' ulong_num ',' ulong_num ',' ulong_num ')' + { + $$= new (thd->mem_root) Item_func_weight_string(thd, $3, $5, $7, + $9); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +/* + Regular function calls. + The function name is *not* a token, and therefore is guaranteed to not + introduce side effects to the language in general. + MAINTAINER: + All the new functions implemented for new features should fit into + this category. The place to implement the function itself is + in sql/item_create.cc +*/ +function_call_generic: + IDENT_sys '(' + { +#ifdef HAVE_DLOPEN + udf_func *udf= 0; + LEX *lex= Lex; + if (using_udf_functions && + (udf= find_udf($1.str, $1.length)) && + udf->type == UDFTYPE_AGGREGATE) + { + if (unlikely(lex->current_select->inc_in_sum_expr())) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + /* Temporary placing the result of find_udf in $3 */ + $<udf>$= udf; +#endif + } + opt_udf_expr_list ')' + { + const Type_handler *h; + Create_func *builder; + Item *item= NULL; + + if (unlikely(check_routine_name(&$1))) + MYSQL_YYABORT; + + /* + Implementation note: + names are resolved with the following order: + - MySQL native functions, + - User Defined Functions, + - Constructors, like POINT(1,1) + - Stored Functions (assuming the current <use> database) + + This will be revised with WL#2128 (SQL PATH) + */ + if ((builder= native_functions_hash.find(thd, $1))) + { + item= builder->create_func(thd, &$1, $4); + } + else if ((h= Type_handler::handler_by_name(thd, $1)) && + (item= h->make_constructor_item(thd, $4))) + { + // Found a constructor with a proper argument count + } + else + { +#ifdef HAVE_DLOPEN + /* Retrieving the result of find_udf */ + udf_func *udf= $<udf>3; + + if (udf) + { + if (udf->type == UDFTYPE_AGGREGATE) + { + Select->in_sum_expr--; + } + + item= Create_udf_func::s_singleton.create(thd, udf, $4); + } + else +#endif + { + builder= find_qualified_function_builder(thd); + DBUG_ASSERT(builder); + item= builder->create_func(thd, &$1, $4); + } + } + + if (unlikely(! ($$= item))) + MYSQL_YYABORT; + } + | CONTAINS_SYM '(' opt_expr_list ')' + { + if (!($$= Lex->make_item_func_call_native_or_parse_error(thd, + $1, $3))) + MYSQL_YYABORT; + } + | OVERLAPS_SYM '(' opt_expr_list ')' + { + if (!($$= Lex->make_item_func_call_native_or_parse_error(thd, + $1, $3))) + MYSQL_YYABORT; + } + | WITHIN '(' opt_expr_list ')' + { + if (!($$= Lex->make_item_func_call_native_or_parse_error(thd, + $1, $3))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli '(' opt_expr_list ')' + { + if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5)))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list ')' + { + if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, &$5, $7)))) + MYSQL_YYABORT; + } + ; + +fulltext_options: + opt_natural_language_mode opt_query_expansion + { $$= $1 | $2; } + | IN_SYM BOOLEAN_SYM MODE_SYM + { $$= FT_BOOL; } + ; + +opt_natural_language_mode: + /* nothing */ { $$= FT_NL; } + | IN_SYM NATURAL LANGUAGE_SYM MODE_SYM { $$= FT_NL; } + ; + +opt_query_expansion: + /* nothing */ { $$= 0; } + | WITH QUERY_SYM EXPANSION_SYM { $$= FT_EXPAND; } + ; + +opt_udf_expr_list: + /* empty */ { $$= NULL; } + | udf_expr_list { $$= $1; } + ; + +udf_expr_list: + udf_expr + { + $$= new (thd->mem_root) List<Item>; + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + $$->push_back($1, thd->mem_root); + } + | udf_expr_list ',' udf_expr + { + $1->push_back($3, thd->mem_root); + $$= $1; + } + ; + +udf_expr: + remember_name expr remember_end select_alias + { + /* + Use Item::name as a storage for the attribute value of user + defined function argument. It is safe to use Item::name + because the syntax will not allow having an explicit name here. + See WL#1017 re. udf attributes. + */ + if ($4.str) + { + $2->base_flags|= item_base_t::IS_EXPLICIT_NAME; + $2->set_name(thd, $4); + } + /* + A field has to have its proper name in order for name + resolution to work, something we are only guaranteed if we + parse it out. If we hijack the input stream with + remember_name we may get quoted or escaped names. + */ + else if ($2->type() != Item::FIELD_ITEM && + $2->type() != Item::REF_ITEM /* For HAVING */ ) + $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset()); + $$= $2; + } + ; + +sum_expr: + AVG_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_avg(thd, $3, FALSE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | AVG_SYM '(' DISTINCT in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_avg(thd, $4, TRUE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | BIT_AND '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_and(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | BIT_OR '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_or(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | BIT_XOR '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_xor(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | COUNT_SYM '(' opt_all '*' ')' + { + Item *item= new (thd->mem_root) Item_int(thd, (int32) 0L, 1); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_sum_count(thd, item); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | COUNT_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_count(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | COUNT_SYM '(' DISTINCT + { Select->in_sum_expr++; } + expr_list + { Select->in_sum_expr--; } + ')' + { + $$= new (thd->mem_root) Item_sum_count(thd, *$5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MIN_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_min(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + /* + According to ANSI SQL, DISTINCT is allowed and has + no sense inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...) + is processed like an ordinary MIN | MAX() + */ + | MIN_SYM '(' DISTINCT in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_min(thd, $4); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MAX_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_max(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | MAX_SYM '(' DISTINCT in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_max(thd, $4); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | STD_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_std(thd, $3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | VARIANCE_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_variance(thd, $3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | STDDEV_SAMP_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_std(thd, $3, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | VAR_SAMP_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_variance(thd, $3, 1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SUM_SYM '(' in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_sum(thd, $3, FALSE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SUM_SYM '(' DISTINCT in_sum_expr ')' + { + $$= new (thd->mem_root) Item_sum_sum(thd, $4, TRUE); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | GROUP_CONCAT_SYM '(' opt_distinct + { Select->in_sum_expr++; } + expr_list opt_gorder_clause + opt_gconcat_separator opt_glimit_clause + ')' + { + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + $$= new (thd->mem_root) + Item_func_group_concat(thd, Lex->current_context(), + $3, $5, + sel->gorder_list, $7, $8, + sel->limit_params.select_limit, + sel->limit_params.offset_limit); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + sel->limit_params.clear(); + $5->empty(); + sel->gorder_list.empty(); + } + | JSON_ARRAYAGG_SYM '(' opt_distinct + { Select->in_sum_expr++; } + expr_list opt_gorder_clause opt_glimit_clause + ')' + { + SELECT_LEX *sel= Select; + List<Item> *args= $5; + sel->in_sum_expr--; + if (args && args->elements > 1) + { + /* JSON_ARRAYAGG supports only one parameter */ + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), "JSON_ARRAYAGG"); + MYSQL_YYABORT; + } + String* s= new (thd->mem_root) String(",", 1, &my_charset_latin1); + if (unlikely(s == NULL)) + MYSQL_YYABORT; + + $$= new (thd->mem_root) + Item_func_json_arrayagg(thd, Lex->current_context(), + $3, args, + sel->gorder_list, s, $7, + sel->limit_params.select_limit, + sel->limit_params.offset_limit); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + sel->limit_params.clear(); + $5->empty(); + sel->gorder_list.empty(); + } + | JSON_OBJECTAGG_SYM '(' + { Select->in_sum_expr++; } + expr ',' expr ')' + { + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + + $$= new (thd->mem_root) Item_func_json_objectagg(thd, $4, $6); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +window_func_expr: + window_func OVER_SYM window_name + { + $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + if (unlikely(Select->add_window_func((Item_window_func *) $$))) + MYSQL_YYABORT; + } + | + window_func OVER_SYM window_spec + { + LEX *lex= Lex; + if (unlikely(Select->add_window_spec(thd, lex->win_ref, + Select->group_list, + Select->order_list, + lex->win_frame))) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, + thd->lex->win_spec); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + if (unlikely(Select->add_window_func((Item_window_func *) $$))) + MYSQL_YYABORT; + } + ; + +window_func: + simple_window_func + | + sum_expr + | + function_call_generic + { + Item* item = (Item*)$1; + /* Only UDF aggregate here possible */ + if ((item == NULL) || + (item->type() != Item::SUM_FUNC_ITEM) + || (((Item_sum *)item)->sum_func() != Item_sum::UDF_SUM_FUNC)) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + ; + +simple_window_func: + ROW_NUMBER_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_row_number(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_rank(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + DENSE_RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_dense_rank(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + PERCENT_RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_percent_rank(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + CUME_DIST_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_cume_dist(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + NTILE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_sum_ntile(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + FIRST_VALUE_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_sum_first_value(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + LAST_VALUE '(' expr ')' + { + $$= new (thd->mem_root) Item_sum_last_value(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + NTH_VALUE_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_sum_nth_value(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + LEAD_SYM '(' expr ')' + { + /* No second argument defaults to 1. */ + Item* item_offset= new (thd->mem_root) Item_uint(thd, 1); + if (unlikely(item_offset == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_sum_lead(thd, $3, item_offset); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + LEAD_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_sum_lead(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + LAG_SYM '(' expr ')' + { + /* No second argument defaults to 1. */ + Item* item_offset= new (thd->mem_root) Item_uint(thd, 1); + if (unlikely(item_offset == NULL)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_sum_lag(thd, $3, item_offset); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | + LAG_SYM '(' expr ',' expr ')' + { + $$= new (thd->mem_root) Item_sum_lag(thd, $3, $5); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + + + +inverse_distribution_function: + percentile_function OVER_SYM + '(' opt_window_partition_clause ')' + { + LEX *lex= Lex; + if (unlikely(Select->add_window_spec(thd, lex->win_ref, + Select->group_list, + Select->order_list, + NULL))) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, + thd->lex->win_spec); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + if (unlikely(Select->add_window_func((Item_window_func *) $$))) + MYSQL_YYABORT; + } + ; + +percentile_function: + inverse_distribution_function_def WITHIN GROUP_SYM '(' + { Select->prepare_add_window_spec(thd); } + order_by_single_element_list ')' + { + $$= $1; + } + | MEDIAN_SYM '(' expr ')' + { + Item *args= new (thd->mem_root) Item_decimal(thd, "0.5", 3, + thd->charset()); + if (unlikely(args == NULL) || unlikely(thd->is_error())) + MYSQL_YYABORT; + Select->prepare_add_window_spec(thd); + if (unlikely(add_order_to_list(thd, $3,FALSE))) + MYSQL_YYABORT; + + $$= new (thd->mem_root) Item_sum_percentile_cont(thd, args); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +inverse_distribution_function_def: + PERCENTILE_CONT_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_sum_percentile_cont(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | PERCENTILE_DISC_SYM '(' expr ')' + { + $$= new (thd->mem_root) Item_sum_percentile_disc(thd, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +order_by_single_element_list: + ORDER_SYM BY order_ident order_dir + { + if (unlikely(add_order_to_list(thd, $3,(bool) $4))) + MYSQL_YYABORT; + } + ; + + +window_name: + ident + { + $$= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING)); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +variable: + '@' + { + if (unlikely(! Lex->parsing_options.allows_variable)) + my_yyabort_error((ER_VIEW_SELECT_VARIABLE, MYF(0))); + } + variable_aux + { + $$= $3; + } + ; + +variable_aux: + ident_or_text SET_VAR expr + { + Item_func_set_user_var *item; + if (!$1.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + $$= item= new (thd->mem_root) Item_func_set_user_var(thd, &$1, $3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + LEX *lex= Lex; + lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + lex->set_var_list.push_back(item, thd->mem_root); + } + | ident_or_text + { + if (!$1.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + $$= new (thd->mem_root) Item_func_get_user_var(thd, &$1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + LEX *lex= Lex; + lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + } + | '@' opt_var_ident_type ident_sysvar_name + { + if (unlikely(!($$= Lex->make_item_sysvar(thd, $2, &$3)))) + MYSQL_YYABORT; + } + | '@' opt_var_ident_type ident_sysvar_name '.' ident + { + if (unlikely(!($$= Lex->make_item_sysvar(thd, $2, &$3, &$5)))) + MYSQL_YYABORT; + } + ; + +opt_distinct: + /* empty */ { $$ = 0; } + | DISTINCT { $$ = 1; } + ; + +opt_gconcat_separator: + /* empty */ + { + $$= new (thd->mem_root) String(",", 1, &my_charset_latin1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | SEPARATOR_SYM text_string { $$ = $2; } + ; + +opt_gorder_clause: + /* empty */ + | ORDER_SYM BY gorder_list + ; + +gorder_list: + gorder_list ',' order_ident order_dir + { + if (unlikely(add_gorder_to_list(thd, $3,(bool) $4))) + MYSQL_YYABORT; + } + | order_ident order_dir + { + if (unlikely(add_gorder_to_list(thd, $1,(bool) $2))) + MYSQL_YYABORT; + } + ; + +opt_glimit_clause: + /* empty */ { $$ = 0; } + | glimit_clause { $$ = 1; } + ; + + +glimit_clause: + LIMIT glimit_options + { + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + ; + +glimit_options: + limit_options + { + Select->limit_params= $1; + } + ; + + + +in_sum_expr: + opt_all + { + LEX *lex= Lex; + if (unlikely(lex->current_select->inc_in_sum_expr())) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + expr + { + Select->in_sum_expr--; + $$= $3; + } + ; + +cast_type: + BINARY opt_field_length + { $$.set(&type_handler_long_blob, $2, &my_charset_bin); } + | CHAR_SYM opt_field_length opt_binary + { + if ($$.set(&type_handler_long_blob, $2, $3, + thd->variables.collation_connection)) + MYSQL_YYABORT; + } + | VARCHAR field_length opt_binary + { + if ($$.set(&type_handler_long_blob, $2, $3, + thd->variables.collation_connection)) + MYSQL_YYABORT; + } + | VARCHAR2_ORACLE_SYM field_length opt_binary + { + if ($$.set(&type_handler_long_blob, $2, $3, + thd->variables.collation_connection)) + MYSQL_YYABORT; + } + | NCHAR_SYM opt_field_length + { + $$.set(&type_handler_long_blob, $2, national_charset_info); + } + | cast_type_numeric { $$= $1; } + | cast_type_temporal { $$= $1; } + | udt_name + { + if (Lex->set_cast_type_udt(&$$, $1)) + MYSQL_YYABORT; + } + ; + +cast_type_numeric: + INT_SYM { $$.set(&type_handler_slonglong); } + | SIGNED_SYM { $$.set(&type_handler_slonglong); } + | SIGNED_SYM INT_SYM { $$.set(&type_handler_slonglong); } + | UNSIGNED { $$.set(&type_handler_ulonglong); } + | UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); } + | DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); } + | FLOAT_SYM { $$.set(&type_handler_float); } + | DOUBLE_SYM opt_precision { $$.set(&type_handler_double, $2); } + ; + +cast_type_temporal: + DATE_SYM { $$.set(&type_handler_newdate); } + | TIME_SYM opt_field_scale { $$.set(&type_handler_time2, $2); } + | DATETIME opt_field_scale { $$.set(&type_handler_datetime2, $2); } + | INTERVAL_SYM DAY_SECOND_SYM field_scale + { + $$.set(&type_handler_interval_DDhhmmssff, $3); + } + ; + +opt_expr_list: + /* empty */ { $$= NULL; } + | expr_list { $$= $1;} + ; + +expr_list: + expr + { + if (unlikely(!($$= List<Item>::make(thd->mem_root, $1)))) + MYSQL_YYABORT; + } + | expr_list ',' expr + { + $1->push_back($3, thd->mem_root); + $$= $1; + } + ; + +ident_list_arg: + ident_list { $$= $1; } + | '(' ident_list ')' { $$= $2; } + ; + +ident_list: + simple_ident + { + $$= new (thd->mem_root) List<Item>; + if (unlikely($$ == NULL) || + unlikely($$->push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | ident_list ',' simple_ident + { + $1->push_back($3, thd->mem_root); + $$= $1; + } + ; + +when_list: + WHEN_SYM expr THEN_SYM expr + { + $$= new (thd->mem_root) List<Item>; + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + if (unlikely($$->push_back($2, thd->mem_root) || + $$->push_back($4, thd->mem_root))) + MYSQL_YYABORT; + } + | when_list WHEN_SYM expr THEN_SYM expr + { + if (unlikely($1->push_back($3, thd->mem_root) || + $1->push_back($5, thd->mem_root))) + MYSQL_YYABORT; + $$= $1; + } + ; + +when_list_opt_else: + when_list + | when_list ELSE expr + { + if (unlikely($1->push_back($3, thd->mem_root))) + MYSQL_YYABORT; + $$= $1; + } + ; + +/* Equivalent to <table reference> in the SQL:2003 standard. */ +/* Warning - may return NULL in case of incomplete SELECT */ +table_ref: + table_factor { $$= $1; } + | join_table + { + LEX *lex= Lex; + if (unlikely(!($$= lex->current_select->nest_last_join(thd)))) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + ; + +json_text_literal: + TEXT_STRING + { + Lex->json_table->m_text_literal_cs= NULL; + } + | NCHAR_STRING + { + Lex->json_table->m_text_literal_cs= national_charset_info; + } + | UNDERSCORE_CHARSET TEXT_STRING + { + Lex->json_table->m_text_literal_cs= $1; + $$= $2; + } + ; + +json_text_literal_or_num: + json_text_literal + | NUM + { + Lex->json_table->m_text_literal_cs= NULL; + } + | LONG_NUM + { + Lex->json_table->m_text_literal_cs= NULL; + } + | DECIMAL_NUM + { + Lex->json_table->m_text_literal_cs= NULL; + } + | FLOAT_NUM + { + Lex->json_table->m_text_literal_cs= NULL; + } + ; + +join_table_list: + derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); } + ; + +json_table_columns_clause: + COLUMNS '(' json_table_columns_list ')' + {} + ; + +json_table_columns_list: + json_table_column + | json_table_columns_list ',' json_table_column + {} + ; + +json_table_column: + ident + { + LEX *lex=Lex; + Create_field *f= new (thd->mem_root) Create_field(); + + if (unlikely(check_string_char_length(&$1, 0, NAME_CHAR_LEN, + system_charset_info, 1))) + my_yyabort_error((ER_TOO_LONG_IDENT, MYF(0), $1.str)); + + lex->json_table->m_cur_json_table_column= + new (thd->mem_root) Json_table_column(f, + lex->json_table->get_cur_nested_path()); + + if (unlikely(!f || + !lex->json_table->m_cur_json_table_column)) + MYSQL_YYABORT; + + lex->init_last_field(f, &$1); + } + json_table_column_type + { + LEX *lex=Lex; + if (unlikely(lex->json_table-> + m_cur_json_table_column->m_field->check(thd))) + MYSQL_YYABORT; + lex->json_table->m_columns.push_back( + lex->json_table->m_cur_json_table_column, thd->mem_root); + } + | NESTED_SYM PATH_SYM json_text_literal + { + LEX *lex=Lex; + Json_table_nested_path *np= new (thd->mem_root) + Json_table_nested_path(); + np->set_path(thd, $3); + lex->json_table->start_nested_path(np); + } + json_table_columns_clause + { + LEX *lex=Lex; + lex->json_table->end_nested_path(); + } + ; + +json_table_column_type: + FOR_SYM ORDINALITY_SYM + { + Lex_field_type_st type; + type.set(&type_handler_slong); + Lex->last_field->set_attributes(thd, type, + COLUMN_DEFINITION_TABLE_FIELD); + Lex->json_table->m_cur_json_table_column-> + set(Json_table_column::FOR_ORDINALITY); + } + | json_table_field_type PATH_SYM json_text_literal + json_opt_on_empty_or_error + { + Lex->last_field->set_attributes(thd, $1, + COLUMN_DEFINITION_TABLE_FIELD); + if (Lex->json_table->m_cur_json_table_column-> + set(thd, Json_table_column::PATH, $3, + $1.charset_collation_attrs())) + { + MYSQL_YYABORT; + } + } + | json_table_field_type EXISTS PATH_SYM json_text_literal + { + Lex->last_field->set_attributes(thd, $1, + COLUMN_DEFINITION_TABLE_FIELD); + if (Lex->json_table->m_cur_json_table_column-> + set(thd, Json_table_column::EXISTS_PATH, $4, + $1.charset_collation_attrs())) + MYSQL_YYABORT; + } + ; + +json_table_field_type: + field_type_numeric + | field_type_temporal + | field_type_string + | field_type_lob + ; + +json_opt_on_empty_or_error: + /* none */ + {} + | json_on_error_response + | json_on_error_response json_on_empty_response + | json_on_empty_response + | json_on_empty_response json_on_error_response + ; + +json_on_response: + ERROR_SYM + { + $$.m_response= Json_table_column::RESPONSE_ERROR; + } + | NULL_SYM + { + $$.m_response= Json_table_column::RESPONSE_NULL; + } + | DEFAULT json_text_literal_or_num + { + $$.m_response= Json_table_column::RESPONSE_DEFAULT; + $$.m_default= $2; + Lex->json_table->m_cur_json_table_column->m_defaults_cs= + thd->variables.collation_connection; + } + ; + +json_on_error_response: + json_on_response ON ERROR_SYM + { + Lex->json_table->m_cur_json_table_column->m_on_error= $1; + } + ; + +json_on_empty_response: + json_on_response ON EMPTY_SYM + { + Lex->json_table->m_cur_json_table_column->m_on_empty= $1; + } + ; + +table_function: + JSON_TABLE_SYM '(' + { + push_table_function_arg_context(Lex, thd->mem_root); + //TODO: introduce IN_TABLE_FUNC_ARGUMENT? + Select->parsing_place= IN_ON; + } + expr ',' + { + Table_function_json_table *jt= + new (thd->mem_root) Table_function_json_table($4); + if (unlikely(!jt)) + MYSQL_YYABORT; + /* See comment for class Table_function_json_table: */ + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + Lex->json_table= jt; + + Select->parsing_place= NO_MATTER; + jt->set_name_resolution_context(Lex->pop_context()); + } + json_text_literal json_table_columns_clause ')' opt_table_alias_clause + { + SELECT_LEX *sel= Select; + if (unlikely($10 == NULL)) + { + /* Alias is not optional. */ + my_error(ER_JSON_TABLE_ALIAS_REQUIRED, MYF(0)); + MYSQL_YYABORT; + } + if (unlikely(Lex->json_table->m_nested_path.set_path(thd, $7))) + MYSQL_YYABORT; + if (!($$= sel->add_table_to_list(thd, + new (thd->mem_root) Table_ident(thd, &any_db, + $10, TRUE), + NULL, + TL_OPTION_TABLE_FUNCTION, + YYPS->m_lock_type, + YYPS->m_mdl_type, + 0,0,0))) + MYSQL_YYABORT; + $$->table_function= Lex->json_table; + Lex->json_table= 0; + status_var_increment(thd->status_var.feature_json); + } + ; + +/* + The ODBC escape syntax for Outer Join is: '{' OJ join_table '}' + The parser does not define OJ as a token, any ident is accepted + instead in $2 (ident). Also, all productions from table_ref can + be escaped, not only join_table. Both syntax extensions are safe + and are ignored. +*/ +esc_table_ref: + table_ref { $$=$1; } + | '{' ident table_ref '}' { $$=$3; } + ; + +/* Equivalent to <table reference list> in the SQL:2003 standard. */ +/* Warning - may return NULL in case of incomplete SELECT */ +derived_table_list: + esc_table_ref + { + $$=$1; + Select->add_joined_table($1); + } + | derived_table_list ',' esc_table_ref + { + MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + Select->add_joined_table($3); + } + ; + +/* + Notice that JOIN can be a left-associative operator in one context and + a right-associative operator in another context (see the comment for + st_select_lex::add_cross_joined_table). +*/ +join_table: + /* INNER JOIN variants */ + table_ref normal_join table_ref %prec CONDITIONLESS_JOIN + { + MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + if (unlikely(Select->add_cross_joined_table($1, $3, $2))) + MYSQL_YYABORT; + } + | table_ref normal_join table_ref + ON + { + MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); + /* Change the current name resolution context to a local context. */ + if (unlikely(push_new_name_resolution_context(thd, $1, $3))) + MYSQL_YYABORT; + Select->parsing_place= IN_ON; + } + expr + { + $3->straight=$2; + add_join_on(thd, $3, $6); + $3->on_context= Lex->pop_context(); + Select->parsing_place= NO_MATTER; + } + | table_ref normal_join table_ref + USING + { + MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); + } + '(' using_list ')' + { + $3->straight=$2; + add_join_natural($1,$3,$7,Select); + $$=$3; + } + | table_ref NATURAL inner_join table_factor + { + MYSQL_YYABORT_UNLESS($1 && ($$=$4)); + Select->add_joined_table($1); + Select->add_joined_table($4); + $4->straight=$3; + add_join_natural($1,$4,NULL,Select); + } + + /* LEFT JOIN variants */ + | table_ref LEFT opt_outer JOIN_SYM table_ref + ON + { + MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); + /* Change the current name resolution context to a local context. */ + if (unlikely(push_new_name_resolution_context(thd, $1, $5))) + MYSQL_YYABORT; + Select->parsing_place= IN_ON; + } + expr + { + add_join_on(thd, $5, $8); + $5->on_context= Lex->pop_context(); + $5->outer_join|=JOIN_TYPE_LEFT; + $$=$5; + Select->parsing_place= NO_MATTER; + } + | table_ref LEFT opt_outer JOIN_SYM table_factor + { + MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); + } + USING '(' using_list ')' + { + add_join_natural($1,$5,$9,Select); + $5->outer_join|=JOIN_TYPE_LEFT; + $$=$5; + } + | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor + { + MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); + add_join_natural($1,$6,NULL,Select); + $6->outer_join|=JOIN_TYPE_LEFT; + $$=$6; + } + + /* RIGHT JOIN variants */ + | table_ref RIGHT opt_outer JOIN_SYM table_ref + ON + { + MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); + /* Change the current name resolution context to a local context. */ + if (unlikely(push_new_name_resolution_context(thd, $1, $5))) + MYSQL_YYABORT; + Select->parsing_place= IN_ON; + } + expr + { + LEX *lex= Lex; + if (unlikely(!($$= lex->current_select->convert_right_join()))) + MYSQL_YYABORT; + add_join_on(thd, $$, $8); + $1->on_context= Lex->pop_context(); + Select->parsing_place= NO_MATTER; + } + | table_ref RIGHT opt_outer JOIN_SYM table_factor + { + MYSQL_YYABORT_UNLESS($1 && $5); + Select->add_joined_table($1); + Select->add_joined_table($5); + } + USING '(' using_list ')' + { + LEX *lex= Lex; + if (unlikely(!($$= lex->current_select->convert_right_join()))) + MYSQL_YYABORT; + add_join_natural($$,$5,$9,Select); + } + | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor + { + MYSQL_YYABORT_UNLESS($1 && $6); + Select->add_joined_table($1); + Select->add_joined_table($6); + add_join_natural($6,$1,NULL,Select); + LEX *lex= Lex; + if (unlikely(!($$= lex->current_select->convert_right_join()))) + MYSQL_YYABORT; + } + ; + + +inner_join: /* $$ set if using STRAIGHT_JOIN, false otherwise */ + JOIN_SYM { $$ = 0; } + | INNER_SYM JOIN_SYM { $$ = 0; } + | STRAIGHT_JOIN { $$ = 1; } + ; + +normal_join: + inner_join { $$ = $1; } + | CROSS JOIN_SYM { $$ = 0; } + ; + +/* + table PARTITION (list of partitions), reusing using_list instead of creating + a new rule for partition_list. +*/ +opt_use_partition: + /* empty */ { $$= 0;} + | use_partition + ; + +use_partition: + PARTITION_SYM '(' using_list ')' have_partitioning + { + $$= $3; + Select->parsing_place= Select->save_parsing_place; + Select->save_parsing_place= NO_MATTER; + } + ; + +table_factor: + table_primary_ident_opt_parens { $$= $1; } + | table_primary_derived_opt_parens { $$= $1; } + | join_table_parens + { + $1->nested_join->nest_type= 0; + $$= $1; + } + | table_reference_list_parens { $$= $1; } + | table_function { $$= $1; } + ; + +table_primary_ident_opt_parens: + table_primary_ident { $$= $1; } + | '(' table_primary_ident_opt_parens ')' { $$= $2; } + ; + +table_primary_derived_opt_parens: + table_primary_derived { $$= $1; } + | '(' table_primary_derived_opt_parens ')' { $$= $2; } + ; + +table_reference_list_parens: + '(' table_reference_list_parens ')' { $$= $2; } + | '(' nested_table_reference_list ')' + { + if (!($$= Select->end_nested_join(thd))) + MYSQL_YYABORT; + } + ; + +nested_table_reference_list: + table_ref ',' table_ref + { + if (Select->init_nested_join(thd)) + MYSQL_YYABORT; + Select->add_joined_table($1); + Select->add_joined_table($3); + $$= $1->embedding; + } + | nested_table_reference_list ',' table_ref + { + Select->add_joined_table($3); + $$= $1; + } + ; + +join_table_parens: + '(' join_table_parens ')' { $$= $2; } + | '(' join_table ')' + { + LEX *lex= Lex; + if (!($$= lex->current_select->nest_last_join(thd))) + { + thd->parse_error(); + MYSQL_YYABORT; + } + } + ; + + +table_primary_ident: + table_ident opt_use_partition opt_for_system_time_clause + opt_table_alias_clause opt_key_definition + { + if (!($$= Select->add_table_to_list(thd, $1, $4, + 0, + YYPS->m_lock_type, + YYPS->m_mdl_type, + Select->pop_index_hints(), + $2))) + MYSQL_YYABORT; + if ($3) + $$->vers_conditions= Lex->vers_conditions; + } + ; + +table_primary_derived: + subquery + opt_for_system_time_clause table_alias_clause + { + if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3))) + MYSQL_YYABORT; + } +%ifdef ORACLE + | subquery + opt_for_system_time_clause + { + LEX_CSTRING alias; + if ($1->make_unique_derived_name(thd, &alias) || + !($$= Lex->parsed_derived_table($1->master_unit(), $2, &alias))) + MYSQL_YYABORT; + } +%endif + ; + +opt_outer: + /* empty */ {} + | OUTER {} + ; + +index_hint_clause: + /* empty */ + { + $$= (thd->variables.old_behavior & OLD_MODE_IGNORE_INDEX_ONLY_FOR_JOIN) ? + INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL; + } + | FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; } + | FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; } + | FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; } + ; + +index_hint_type: + FORCE_SYM { $$= INDEX_HINT_FORCE; } + | IGNORE_SYM { $$= INDEX_HINT_IGNORE; } + ; + +index_hint_definition: + index_hint_type key_or_index index_hint_clause + { + Select->set_index_hint_type($1, $3); + } + '(' key_usage_list ')' + | USE_SYM key_or_index index_hint_clause + { + Select->set_index_hint_type(INDEX_HINT_USE, $3); + } + '(' opt_key_usage_list ')' + ; + +index_hints_list: + index_hint_definition + | index_hints_list index_hint_definition + ; + +opt_index_hints_list: + /* empty */ + | { Select->alloc_index_hints(thd); } index_hints_list + ; + +opt_key_definition: + { Select->clear_index_hints(); } + opt_index_hints_list + ; + +opt_key_usage_list: + /* empty */ { Select->add_index_hint(thd, NULL, 0); } + | key_usage_list {} + ; + +key_usage_element: + ident + { Select->add_index_hint(thd, $1.str, $1.length); } + | PRIMARY_SYM + { Select->add_index_hint(thd, "PRIMARY", 7); } + ; + +key_usage_list: + key_usage_element + | key_usage_list ',' key_usage_element + ; + +using_list: + ident + { + if (unlikely(!($$= new (thd->mem_root) List<String>))) + MYSQL_YYABORT; + String *s= new (thd->mem_root) String((const char*) $1.str, + $1.length, + system_charset_info); + if (unlikely(unlikely(s == NULL))) + MYSQL_YYABORT; + $$->push_back(s, thd->mem_root); + } + | using_list ',' ident + { + String *s= new (thd->mem_root) String((const char*) $3.str, + $3.length, + system_charset_info); + if (unlikely(unlikely(s == NULL))) + MYSQL_YYABORT; + if (unlikely($1->push_back(s, thd->mem_root))) + MYSQL_YYABORT; + $$= $1; + } + ; + +interval: + interval_time_stamp {} + | DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; } + | DAY_MICROSECOND_SYM { $$=INTERVAL_DAY_MICROSECOND; } + | DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; } + | DAY_SECOND_SYM { $$=INTERVAL_DAY_SECOND; } + | HOUR_MICROSECOND_SYM { $$=INTERVAL_HOUR_MICROSECOND; } + | HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; } + | HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; } + | MINUTE_MICROSECOND_SYM { $$=INTERVAL_MINUTE_MICROSECOND; } + | MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; } + | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; } + | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; } + ; + +interval_time_stamp: + DAY_SYM { $$=INTERVAL_DAY; } + | WEEK_SYM { $$=INTERVAL_WEEK; } + | HOUR_SYM { $$=INTERVAL_HOUR; } + | MINUTE_SYM { $$=INTERVAL_MINUTE; } + | MONTH_SYM { $$=INTERVAL_MONTH; } + | QUARTER_SYM { $$=INTERVAL_QUARTER; } + | SECOND_SYM { $$=INTERVAL_SECOND; } + | MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; } + | YEAR_SYM { $$=INTERVAL_YEAR; } + ; + +date_time_type: + DATE_SYM {$$=MYSQL_TIMESTAMP_DATE;} + | TIME_SYM {$$=MYSQL_TIMESTAMP_TIME;} + | DATETIME {$$=MYSQL_TIMESTAMP_DATETIME;} + | TIMESTAMP {$$=MYSQL_TIMESTAMP_DATETIME;} + ; + +table_alias: + /* empty */ + | AS + | '=' + ; + +opt_table_alias_clause: + /* empty */ { $$=0; } + | table_alias_clause { $$= $1; } + ; + +table_alias_clause: + table_alias ident_table_alias + { + $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING)); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_all: + /* empty */ + | ALL + ; + +opt_where_clause: + /* empty */ { Select->where= 0; } + | WHERE + { + Select->parsing_place= IN_WHERE; + } + expr + { + SELECT_LEX *select= Select; + select->where= normalize_cond(thd, $3); + select->parsing_place= NO_MATTER; + if ($3) + $3->top_level_item(); + } + ; + +opt_having_clause: + /* empty */ + | HAVING + { + Select->parsing_place= IN_HAVING; + } + expr + { + SELECT_LEX *sel= Select; + sel->having= normalize_cond(thd, $3); + sel->parsing_place= NO_MATTER; + if ($3) + $3->top_level_item(); + } + ; + +/* + group by statement in select +*/ + +opt_group_clause: + /* empty */ + | GROUP_SYM BY group_list olap_opt + ; + +group_list: + group_list ',' order_ident order_dir + { + if (unlikely(add_group_to_list(thd, $3,(bool) $4))) + MYSQL_YYABORT; + } + | order_ident order_dir + { + if (unlikely(add_group_to_list(thd, $1,(bool) $2))) + MYSQL_YYABORT; + } + ; + +olap_opt: + /* empty */ {} + | WITH_CUBE_SYM + { + /* + 'WITH CUBE' is reserved in the MySQL syntax, but not implemented, + and cause LALR(2) conflicts. + This syntax is not standard. + MySQL syntax: GROUP BY col1, col2, col3 WITH CUBE + SQL-2003: GROUP BY ... CUBE(col1, col2, col3) + */ + LEX *lex=Lex; + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE", + "global union parameters")); + lex->current_select->olap= CUBE_TYPE; + + my_yyabort_error((ER_NOT_SUPPORTED_YET, MYF(0), "CUBE")); + } + | WITH_ROLLUP_SYM + { + /* + 'WITH ROLLUP' is needed for backward compatibility, + and cause LALR(2) conflicts. + This syntax is not standard. + MySQL syntax: GROUP BY col1, col2, col3 WITH ROLLUP + SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3) + */ + LEX *lex= Lex; + if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE)) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP", + "global union parameters")); + lex->current_select->olap= ROLLUP_TYPE; + } + ; + +/* + optional window clause in select +*/ + +opt_window_clause: + /* empty */ + {} + | WINDOW_SYM + window_def_list + {} + ; + +window_def_list: + window_def_list ',' window_def + | window_def + ; + +window_def: + window_name AS window_spec + { + LEX *lex= Lex; + if (unlikely(Select->add_window_def(thd, $1, lex->win_ref, + Select->group_list, + Select->order_list, + lex->win_frame))) + MYSQL_YYABORT; + } + ; + +window_spec: + '(' + { Select->prepare_add_window_spec(thd); } + opt_window_ref opt_window_partition_clause + opt_window_order_clause opt_window_frame_clause + ')' + { } + ; + +opt_window_ref: + /* empty */ {} + | ident + { + thd->lex->win_ref= (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING)); + if (unlikely(thd->lex->win_ref == NULL)) + MYSQL_YYABORT; + } + ; + +opt_window_partition_clause: + /* empty */ { } + | PARTITION_SYM BY group_list + ; + +opt_window_order_clause: + /* empty */ { } + | ORDER_SYM BY order_list { Select->order_list= *($3); } + ; + +opt_window_frame_clause: + /* empty */ {} + | window_frame_units window_frame_extent opt_window_frame_exclusion + { + LEX *lex= Lex; + lex->win_frame= + new (thd->mem_root) Window_frame($1, + lex->frame_top_bound, + lex->frame_bottom_bound, + $3); + if (unlikely(lex->win_frame == NULL)) + MYSQL_YYABORT; + } + ; + +window_frame_units: + ROWS_SYM { $$= Window_frame::UNITS_ROWS; } + | RANGE_SYM { $$= Window_frame::UNITS_RANGE; } + ; + +window_frame_extent: + window_frame_start + { + LEX *lex= Lex; + lex->frame_top_bound= $1; + lex->frame_bottom_bound= + new (thd->mem_root) + Window_frame_bound(Window_frame_bound::CURRENT, NULL); + if (unlikely(lex->frame_bottom_bound == NULL)) + MYSQL_YYABORT; + } + | BETWEEN_SYM window_frame_bound AND_SYM window_frame_bound + { + LEX *lex= Lex; + lex->frame_top_bound= $2; + lex->frame_bottom_bound= $4; + } + ; + +window_frame_start: + UNBOUNDED_SYM PRECEDING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::PRECEDING, NULL); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | CURRENT_SYM ROW_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::CURRENT, NULL); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | literal PRECEDING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::PRECEDING, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +window_frame_bound: + window_frame_start { $$= $1; } + | UNBOUNDED_SYM FOLLOWING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::FOLLOWING, NULL); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | literal FOLLOWING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::FOLLOWING, $1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_window_frame_exclusion: + /* empty */ { $$= Window_frame::EXCL_NONE; } + | EXCLUDE_SYM CURRENT_SYM ROW_SYM + { $$= Window_frame::EXCL_CURRENT_ROW; } + | EXCLUDE_SYM GROUP_SYM + { $$= Window_frame::EXCL_GROUP; } + | EXCLUDE_SYM TIES_SYM + { $$= Window_frame::EXCL_TIES; } + | EXCLUDE_SYM NO_SYM OTHERS_MARIADB_SYM + { $$= Window_frame::EXCL_NONE; } + | EXCLUDE_SYM NO_SYM OTHERS_ORACLE_SYM + { $$= Window_frame::EXCL_NONE; } + ; + +/* + Order by statement in ALTER TABLE +*/ + +alter_order_clause: + ORDER_SYM BY alter_order_list + ; + +alter_order_list: + alter_order_list ',' alter_order_item + | alter_order_item + ; + +alter_order_item: + simple_ident_nospvar order_dir + { + bool ascending= ($2 == 1) ? true : false; + if (unlikely(add_order_to_list(thd, $1, ascending))) + MYSQL_YYABORT; + } + ; + +/* + Order by statement in select +*/ + +opt_order_clause: + /* empty */ + { $$= NULL; } + | order_clause + { $$= $1; } + ; + +order_clause: + ORDER_SYM BY + { + thd->where= "ORDER clause"; + } + order_list + { + $$= $4; + } + ; + +order_list: + order_list ',' order_ident order_dir + { + $$= $1; + if (add_to_list(thd, *$$, $3,(bool) $4)) + MYSQL_YYABORT; + } + | order_ident order_dir + { + $$= new (thd->mem_root) SQL_I_List<ORDER>(); + if (add_to_list(thd, *$$, $1, (bool) $2)) + MYSQL_YYABORT; + } + ; + +order_dir: + /* empty */ { $$= 1; } + | ASC { $$= 1; } + | DESC { $$= 0; } + ; + + +opt_limit_clause: + /* empty */ + { $$.clear(); } + | limit_clause + { $$= $1; } + ; + +limit_clause: + LIMIT limit_options + { + $$= $2; + if (!$$.select_limit->basic_const_item() || + $$.select_limit->val_int() > 0) + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + | LIMIT limit_options + ROWS_SYM EXAMINED_SYM limit_rows_option + { + $$= $2; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option + { + $$.clear(); + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + | fetch_first_clause + { + $$= $1; + if (!$$.select_limit || + !$$.select_limit->basic_const_item() || + $$.select_limit->val_int() > 0) + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + } + ; + +fetch_first_clause: + FETCH_SYM first_or_next row_or_rows only_or_with_ties + { + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (unlikely(one == NULL)) + MYSQL_YYABORT; + $$.select_limit= one; + $$.offset_limit= 0; + $$.explicit_limit= true; + $$.with_ties= $4; + } + | OFFSET_SYM limit_option row_or_rows + FETCH_SYM first_or_next row_or_rows only_or_with_ties + { + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (unlikely(one == NULL)) + MYSQL_YYABORT; + $$.select_limit= one; + $$.offset_limit= $2; + $$.explicit_limit= true; + $$.with_ties= $7; + } + | FETCH_SYM first_or_next limit_option row_or_rows only_or_with_ties + { + $$.select_limit= $3; + $$.offset_limit= 0; + $$.explicit_limit= true; + $$.with_ties= $5; + } + | OFFSET_SYM limit_option row_or_rows + FETCH_SYM first_or_next limit_option row_or_rows only_or_with_ties + { + $$.select_limit= $6; + $$.offset_limit= $2; + $$.explicit_limit= true; + $$.with_ties= $8; + } + | OFFSET_SYM limit_option row_or_rows + { + $$.select_limit= 0; + $$.offset_limit= $2; + $$.explicit_limit= true; + $$.with_ties= false; + } + ; + +first_or_next: + FIRST_SYM + | NEXT_SYM + ; + +row_or_rows: + ROW_SYM + | ROWS_SYM + ; + +only_or_with_ties: + ONLY_SYM { $$= 0; } + | WITH TIES_SYM { $$= 1; } + ; + + +opt_global_limit_clause: + opt_limit_clause + { + Select->limit_params= $1; + } + ; + +limit_options: + limit_option + { + $$.select_limit= $1; + $$.offset_limit= NULL; + $$.explicit_limit= true; + $$.with_ties= false; + } + | limit_option ',' limit_option + { + $$.select_limit= $3; + $$.offset_limit= $1; + $$.explicit_limit= true; + $$.with_ties= false; + } + | limit_option OFFSET_SYM limit_option + { + $$.select_limit= $1; + $$.offset_limit= $3; + $$.explicit_limit= true; + $$.with_ties= false; + } + ; + +limit_option: + ident_cli + { + if (unlikely(!($$= Lex->create_item_limit(thd, &$1)))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->create_item_limit(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + | param_marker + { + $1->limit_clause_param= TRUE; + } + | ULONGLONG_NUM + { + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | LONG_NUM + { + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | NUM + { + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +limit_rows_option: + limit_option + { + Lex->limit_rows_examined= $1; + } + ; + +delete_limit_clause: + /* empty */ + { + LEX *lex=Lex; + lex->current_select->limit_params.select_limit= 0; + } + | LIMIT limit_option + { + SELECT_LEX *sel= Select; + sel->limit_params.select_limit= $2; + Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT); + sel->limit_params.explicit_limit= 1; + } + | LIMIT ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } + | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } + ; + +order_limit_lock: + order_or_limit + { + $$= $1; + $$->lock.empty(); + } + | order_or_limit select_lock_type + { + $$= $1; + $$->lock= $2; + } + | select_lock_type + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= NULL; + $$->limit.clear(); + $$->lock= $1; + } + ; + +opt_order_limit_lock: + /* empty */ + { + Lex->pop_select(); + $$= NULL; + } + | order_limit_lock { $$= $1; } + ; + +query_expression_tail: + order_limit_lock + ; + +opt_query_expression_tail: + opt_order_limit_lock + ; + +opt_procedure_or_into: + /* empty */ + { + $$.empty(); + } + | procedure_clause opt_select_lock_type + { + $$= $2; + } + | into opt_select_lock_type + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_DEPRECATED_SYNTAX, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX), + "<select expression> INTO <destination>;", + "'SELECT <select list> INTO <destination>" + " FROM...'"); + $$= $2; + } + ; + + +order_or_limit: + order_clause opt_limit_clause + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= $1; + $$->limit= $2; + } + | limit_clause + { + $$= new(thd->mem_root) Lex_order_limit_lock; + if (!$$) + YYABORT; + $$->order_list= NULL; + $$->limit= $1; + } + ; + + +opt_plus: + /* empty */ + | '+' + ; + +int_num: + opt_plus NUM { int error; $$= (int) my_strtoll10($2.str, (char**) 0, &error); } + | '-' NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); } + ; + +ulong_num: + opt_plus NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } + | HEX_NUM { $$= strtoul($1.str, (char**) 0, 16); } + | opt_plus LONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus FLOAT_NUM { int error; $$= (ulong) my_strtoll10($2.str, (char**) 0, &error); } + ; + +real_ulong_num: + NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } + | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); } + | LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } + | ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } + | dec_num_error { MYSQL_YYABORT; } + ; + +longlong_num: + opt_plus NUM { int error; $$= (longlong) my_strtoll10($2.str, (char**) 0, &error); } + | LONG_NUM { int error; $$= (longlong) my_strtoll10($1.str, (char**) 0, &error); } + | '-' NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); } + | '-' LONG_NUM { int error; $$= -(longlong) my_strtoll10($2.str, (char**) 0, &error); } + ; + +ulonglong_num: + opt_plus NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus LONG_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); } + | opt_plus FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($2.str, (char**) 0, &error); } + ; + +real_ulonglong_num: + NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } + | ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } + | HEX_NUM { $$= strtoull($1.str, (char**) 0, 16); } + | LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } + | dec_num_error { MYSQL_YYABORT; } + ; + +dec_num_error: + dec_num + { thd->parse_error(ER_ONLY_INTEGERS_ALLOWED); } + ; + +dec_num: + DECIMAL_NUM + | FLOAT_NUM + ; + +choice: + ulong_num { $$= $1 != 0 ? HA_CHOICE_YES : HA_CHOICE_NO; } + | DEFAULT { $$= HA_CHOICE_UNDEF; } + ; + +bool: + ulong_num { $$= $1 != 0; } + | TRUE_SYM { $$= 1; } + | FALSE_SYM { $$= 0; } + ; + +procedure_clause: + PROCEDURE_SYM ident /* Procedure name */ + { + LEX *lex=Lex; + + lex->proc_list.elements=0; + lex->proc_list.first=0; + lex->proc_list.next= &lex->proc_list.first; + Item_field *item= new (thd->mem_root) + Item_field(thd, &lex->current_select->context, + $2); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + if (unlikely(add_proc_to_list(thd, item))) + MYSQL_YYABORT; + Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + + /* + PROCEDURE CLAUSE cannot handle subquery as one of its parameter, + so disallow any subqueries further. + Alow subqueries back once the parameters are reduced. + */ + Lex->clause_that_disallows_subselect= "PROCEDURE"; + Select->options|= OPTION_PROCEDURE_CLAUSE; + } + '(' procedure_list ')' + { + /* Subqueries are allowed from now.*/ + Lex->clause_that_disallows_subselect= NULL; + } + ; + +procedure_list: + /* empty */ {} + | procedure_list2 {} + ; + +procedure_list2: + procedure_list2 ',' procedure_item + | procedure_item + ; + +procedure_item: + remember_name expr remember_end + { + if (unlikely(add_proc_to_list(thd, $2))) + MYSQL_YYABORT; + if (!$2->name.str || $2->name.str == item_empty_name) + $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset()); + } + ; + +select_var_list_init: + { + LEX *lex=Lex; + if (!lex->describe && + unlikely((!(lex->result= new (thd->mem_root) + select_dumpvar(thd))))) + MYSQL_YYABORT; + } + select_var_list + {} + ; + +select_var_list: + select_var_list ',' select_var_ident + | select_var_ident {} + ; + +select_var_ident: select_outvar + { + if (Lex->result) + { + if (unlikely($1 == NULL)) + MYSQL_YYABORT; + ((select_dumpvar *)Lex->result)->var_list.push_back($1, thd->mem_root); + } + else + { + /* + The parser won't create select_result instance only + if it's an EXPLAIN. + */ + DBUG_ASSERT(Lex->describe); + } + } + ; + +select_outvar: + '@' ident_or_text + { + if (!$2.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + + $$ = Lex->result ? new (thd->mem_root) my_var_user(&$2) : NULL; + } + | ident_or_text + { + if (unlikely(!($$= Lex->create_outvar(thd, &$1)) && Lex->result)) + MYSQL_YYABORT; + } + | ident '.' ident + { + if (unlikely(!($$= Lex->create_outvar(thd, &$1, &$3)) && Lex->result)) + MYSQL_YYABORT; + } + ; + +into: + INTO into_destination + {} + ; + +into_destination: + OUTFILE TEXT_STRING_filesystem + { + LEX *lex= Lex; + lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + if (unlikely(!(lex->exchange= + new (thd->mem_root) sql_exchange($2.str, 0))) || + unlikely(!(lex->result= + new (thd->mem_root) + select_export(thd, lex->exchange)))) + MYSQL_YYABORT; + } + opt_load_data_charset + { Lex->exchange->cs= $4; } + opt_field_term opt_line_term + | DUMPFILE TEXT_STRING_filesystem + { + LEX *lex=Lex; + if (!lex->describe) + { + lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + if (unlikely(!(lex->exchange= + new (thd->mem_root) sql_exchange($2.str,1)))) + MYSQL_YYABORT; + if (unlikely(!(lex->result= + new (thd->mem_root) + select_dump(thd, lex->exchange)))) + MYSQL_YYABORT; + } + } + | select_var_list_init + { + Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + } + ; + +/* + DO statement +*/ + +do: + DO_SYM + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_DO; + if (lex->main_select_push(true)) + MYSQL_YYABORT; + lex->init_select(); + } + expr_list + { + Lex->insert_list= $3; + Lex->pop_select(); //main select + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + ; + +/* + Drop : delete tables or index or user +*/ + +drop: + DROP opt_temporary table_or_tables opt_if_exists + { + LEX *lex=Lex; + lex->set_command(SQLCOM_DROP_TABLE, $2, $4); + YYPS->m_lock_type= TL_UNLOCK; + YYPS->m_mdl_type= MDL_EXCLUSIVE; + } + table_list opt_lock_wait_timeout opt_restrict + {} + | DROP INDEX_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + opt_if_exists_table_element ident ON table_ident opt_lock_wait_timeout + { + LEX *lex=Lex; + Alter_drop *ad= (new (thd->mem_root) + Alter_drop(Alter_drop::KEY, $5.str, $4)); + if (unlikely(ad == NULL)) + MYSQL_YYABORT; + lex->sql_command= SQLCOM_DROP_INDEX; + lex->alter_info.reset(); + lex->alter_info.flags= ALTER_DROP_INDEX; + lex->alter_info.drop_list.push_back(ad, thd->mem_root); + if (unlikely(!lex->current_select-> + add_table_to_list(thd, $7, NULL, TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_UPGRADABLE))) + MYSQL_YYABORT; + Lex->pop_select(); //main select + } + | DROP DATABASE opt_if_exists ident + { + LEX *lex=Lex; + lex->set_command(SQLCOM_DROP_DB, $3); + lex->name= $4; + } + | DROP USER_SYM opt_if_exists clear_privileges user_list + { + Lex->set_command(SQLCOM_DROP_USER, $3); + } + | DROP ROLE_SYM opt_if_exists clear_privileges role_list + { + Lex->set_command(SQLCOM_DROP_ROLE, $3); + } + | DROP VIEW_SYM opt_if_exists + { + LEX *lex= Lex; + lex->set_command(SQLCOM_DROP_VIEW, $3); + YYPS->m_lock_type= TL_UNLOCK; + YYPS->m_mdl_type= MDL_EXCLUSIVE; + } + table_list opt_restrict + {} + | DROP EVENT_SYM opt_if_exists sp_name + { + Lex->spname= $4; + Lex->set_command(SQLCOM_DROP_EVENT, $3); + } + | DROP TRIGGER_SYM opt_if_exists sp_name + { + LEX *lex= Lex; + lex->set_command(SQLCOM_DROP_TRIGGER, $3); + lex->spname= $4; + } + | DROP SERVER_SYM opt_if_exists ident_or_text + { + Lex->set_command(SQLCOM_DROP_SERVER, $3); + Lex->server_options.reset($4); + } + | DROP opt_temporary SEQUENCE_SYM opt_if_exists + + { + LEX *lex= Lex; + lex->set_command(SQLCOM_DROP_SEQUENCE, $2, $4); + lex->table_type= TABLE_TYPE_SEQUENCE; + YYPS->m_lock_type= TL_UNLOCK; + YYPS->m_mdl_type= MDL_EXCLUSIVE; + } + table_list + {} + | drop_routine + ; + +table_list: + table_name + | table_list ',' table_name + ; + +table_name: + table_ident + { + if (!thd->lex->current_select_or_default()-> + add_table_to_list(thd, $1, NULL, + TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type)) + MYSQL_YYABORT; + } + ; + +table_name_with_opt_use_partition: + table_ident opt_use_partition + { + if (unlikely(!Select->add_table_to_list(thd, $1, NULL, + TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, + $2))) + MYSQL_YYABORT; + } + ; + +table_alias_ref_list: + table_alias_ref + | table_alias_ref_list ',' table_alias_ref + ; + +table_alias_ref: + table_ident_opt_wild + { + if (unlikely(!Select-> + add_table_to_list(thd, $1, NULL, + (TL_OPTION_UPDATING | + TL_OPTION_ALIAS), + YYPS->m_lock_type, + YYPS->m_mdl_type))) + MYSQL_YYABORT; + } + ; + +opt_if_exists_table_element: + /* empty */ + { + Lex->check_exists= FALSE; + $$= 0; + } + | IF_SYM EXISTS + { + Lex->check_exists= TRUE; + $$= 1; + } + ; + +opt_if_exists: + /* empty */ + { + $$.set(DDL_options_st::OPT_NONE); + } + | IF_SYM EXISTS + { + $$.set(DDL_options_st::OPT_IF_EXISTS); + } + ; + +opt_temporary: + /* empty */ { $$= 0; } + | TEMPORARY { $$= HA_LEX_CREATE_TMP_TABLE; } + ; +/* +** Insert : add new data to table +*/ + +insert: + INSERT + { + Lex->sql_command= SQLCOM_INSERT; + Lex->duplicates= DUP_ERROR; + thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); + thd->get_stmt_da()->reset_current_row_for_warning(1); + } + insert_start insert_lock_option opt_ignore opt_into insert_table + { + Select->set_lock_for_tables($4, true, false); + } + insert_field_spec opt_insert_update opt_returning + stmt_end + { + Lex->mark_first_table_as_inserting(); + thd->get_stmt_da()->reset_current_row_for_warning(0); + } + ; + +replace: + REPLACE + { + Lex->sql_command = SQLCOM_REPLACE; + Lex->duplicates= DUP_REPLACE; + thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); + thd->get_stmt_da()->reset_current_row_for_warning(1); + } + insert_start replace_lock_option opt_into insert_table + { + Select->set_lock_for_tables($4, true, false); + } + insert_field_spec opt_returning + stmt_end + { + Lex->mark_first_table_as_inserting(); + thd->get_stmt_da()->reset_current_row_for_warning(0); + } + ; + +insert_start: { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->init_select(); + Lex->inc_select_stack_outer_barrier(); + Lex->current_select->parsing_place= BEFORE_OPT_LIST; + } + ; + +stmt_end: { + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } + ; + +insert_lock_option: + /* empty */ + { + /* + 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); + } + | insert_replace_option + | HIGH_PRIORITY { $$= TL_WRITE; } + ; + +replace_lock_option: + /* empty */ { $$= TL_WRITE_DEFAULT; } + | insert_replace_option + ; + +insert_replace_option: + LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; } + | DELAYED_SYM + { + Lex->keyword_delayed_begin_offset= (uint)($1.pos() - thd->query()); + Lex->keyword_delayed_end_offset= (uint)($1.end() - thd->query()); + $$= TL_WRITE_DELAYED; + } + ; + +opt_into: /* nothing */ | INTO ; + +insert_table: + { + Select->save_parsing_place= Select->parsing_place; + } + table_name_with_opt_use_partition + { + LEX *lex=Lex; + //lex->field_list.empty(); + lex->many_values.empty(); + lex->insert_list=0; + } + ; + +insert_field_spec: + insert_values {} + | insert_field_list insert_values {} + | SET + { + LEX *lex=Lex; + if (unlikely(!(lex->insert_list= new (thd->mem_root) List_item)) || + unlikely(lex->many_values.push_back(lex->insert_list, + thd->mem_root))) + MYSQL_YYABORT; + lex->current_select->parsing_place= NO_MATTER; + } + ident_eq_list + ; + +insert_field_list: + LEFT_PAREN_ALT opt_fields ')' + { + Lex->current_select->parsing_place= AFTER_LIST; + } + ; + +opt_fields: + /* empty */ + | fields + ; + +fields: + fields ',' insert_ident + { Lex->field_list.push_back($3, thd->mem_root); } + | insert_ident { Lex->field_list.push_back($1, thd->mem_root); } + ; + + + +insert_values: + create_select_query_expression {} + ; + +values_list: + values_list ',' no_braces + | no_braces_with_names + ; + +ident_eq_list: + ident_eq_list ',' ident_eq_value + | ident_eq_value + ; + +ident_eq_value: + simple_ident_nospvar equal expr_or_ignore_or_default + { + LEX *lex=Lex; + if (unlikely(lex->field_list.push_back($1, thd->mem_root)) || + unlikely(lex->insert_list->push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +equal: + '=' {} + | SET_VAR {} + ; + +opt_equal: + /* empty */ {} + | equal {} + ; + +opt_with: + opt_equal {} + | WITH {} + ; + +opt_by: + opt_equal {} + | BY {} + ; + +no_braces: + '(' + { + if (unlikely(!(Lex->insert_list= new (thd->mem_root) List_item))) + MYSQL_YYABORT; + } + opt_values ')' + { + LEX *lex=Lex; + thd->get_stmt_da()->inc_current_row_for_warning(); + if (unlikely(lex->many_values.push_back(lex->insert_list, + thd->mem_root))) + MYSQL_YYABORT; + } + ; + +no_braces_with_names: + '(' + { + if (unlikely(!(Lex->insert_list= new (thd->mem_root) List_item))) + MYSQL_YYABORT; + } + opt_values_with_names ')' + { + LEX *lex=Lex; + thd->get_stmt_da()->inc_current_row_for_warning(); + if (unlikely(lex->many_values.push_back(lex->insert_list, + thd->mem_root))) + MYSQL_YYABORT; + } + ; + +opt_values: + /* empty */ {} + | values + ; + +opt_values_with_names: + /* empty */ {} + | values_with_names + ; + +values: + values ',' expr_or_ignore_or_default + { + if (unlikely(Lex->insert_list->push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + | expr_or_ignore_or_default + { + if (unlikely(Lex->insert_list->push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +values_with_names: + values_with_names ',' remember_name expr_or_ignore_or_default remember_end + { + if (unlikely(Lex->insert_list->push_back($4, thd->mem_root))) + MYSQL_YYABORT; + // give some name in case of using in table value constuctor (TVC) + if (!$4->name.str || $4->name.str == item_empty_name) + $4->set_name(thd, $3, (uint) ($5 - $3), thd->charset()); + } + | remember_name expr_or_ignore_or_default remember_end + { + if (unlikely(Lex->insert_list->push_back($2, thd->mem_root))) + MYSQL_YYABORT; + // give some name in case of using in table value constuctor (TVC) + if (!$2->name.str || $2->name.str == item_empty_name) + $2->set_name(thd, $1, (uint) ($3 - $1), thd->charset()); + } + ; + +expr_or_ignore: + expr { $$= $1;} + | IGNORE_SYM + { + $$= new (thd->mem_root) Item_ignore_specification(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +expr_or_ignore_or_default: + expr_or_ignore { $$= $1;} + | DEFAULT + { + $$= new (thd->mem_root) Item_default_specification(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_insert_update: + /* empty */ + | ON DUPLICATE_SYM { Lex->duplicates= DUP_UPDATE; } + KEY_SYM UPDATE_SYM + { + Select->parsing_place= IN_UPDATE_ON_DUP_KEY; + } + insert_update_list + { + Select->parsing_place= NO_MATTER; + } + ; + +update_table_list: + table_ident opt_use_partition for_portion_of_time_clause + opt_table_alias_clause opt_key_definition + { + if (!($$= Select->add_table_to_list(thd, $1, $4, + 0, + YYPS->m_lock_type, + YYPS->m_mdl_type, + Select->pop_index_hints(), + $2))) + MYSQL_YYABORT; + $$->period_conditions= Lex->period_conditions; + } + | join_table_list { $$= $1; } + ; + +/* Update rows in a table */ + +update: + UPDATE_SYM + { + LEX *lex= Lex; + if (Lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + lex->sql_command= SQLCOM_UPDATE; + lex->duplicates= DUP_ERROR; + } + opt_low_priority opt_ignore update_table_list + SET update_list + { + SELECT_LEX *slex= Lex->first_select_lex(); + if (slex->table_list.elements > 1) + Lex->sql_command= SQLCOM_UPDATE_MULTI; + else if (slex->get_table_list()->derived) + { + /* it is single table update and it is update of derived table */ + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + slex->get_table_list()->alias.str, "UPDATE"); + MYSQL_YYABORT; + } + /* + In case of multi-update setting write lock for all tables may + be too pessimistic. We will decrease lock level if possible in + mysql_multi_update(). + */ + slex->set_lock_for_tables($3, slex->table_list.elements == 1, false); + } + opt_where_clause opt_order_clause delete_limit_clause + { + if ($10) + Select->order_list= *($10); + } stmt_end {} + ; + +update_list: + update_list ',' update_elem + | update_elem + ; + +update_elem: + simple_ident_nospvar equal DEFAULT + { + Item *def= new (thd->mem_root) Item_default_value(thd, + Lex->current_context(), $1, 1); + if (!def || add_item_to_list(thd, $1) || add_value_to_list(thd, def)) + MYSQL_YYABORT; + } + | simple_ident_nospvar equal expr_or_ignore + { + if (add_item_to_list(thd, $1) || add_value_to_list(thd, $3)) + MYSQL_YYABORT; + } + ; + +insert_update_list: + insert_update_list ',' insert_update_elem + | insert_update_elem + ; + +insert_update_elem: + simple_ident_nospvar equal expr_or_ignore_or_default + { + LEX *lex= Lex; + if (unlikely(lex->update_list.push_back($1, thd->mem_root)) || + unlikely(lex->value_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +opt_low_priority: + /* empty */ { $$= TL_WRITE_DEFAULT; } + | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; } + ; + +/* Delete rows from a table */ + +delete: + DELETE_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE; + YYPS->m_lock_type= TL_WRITE_DEFAULT; + YYPS->m_mdl_type= MDL_SHARED_WRITE; + if (Lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + lex->ignore= 0; + lex->first_select_lex()->order_list.empty(); + } + delete_part2 + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + ; + +opt_delete_system_time: + /* empty */ + { + Lex->vers_conditions.init(SYSTEM_TIME_HISTORY); + } + | BEFORE_SYM SYSTEM_TIME_SYM history_point + { + Lex->vers_conditions.init(SYSTEM_TIME_BEFORE, $3); + } + ; + +delete_part2: + opt_delete_options single_multi {} + | HISTORY_SYM delete_single_table opt_delete_system_time + { + Lex->last_table()->vers_conditions= Lex->vers_conditions; + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } + ; + +delete_single_table: + FROM table_ident opt_use_partition + { + if (unlikely(!Select-> + add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, + $3))) + MYSQL_YYABORT; + YYPS->m_lock_type= TL_READ_DEFAULT; + YYPS->m_mdl_type= MDL_SHARED_READ; + } + ; + +delete_single_table_for_period: + delete_single_table opt_for_portion_of_time_clause + { + if ($2) + Lex->last_table()->period_conditions= Lex->period_conditions; + } + ; + +single_multi: + delete_single_table_for_period + opt_where_clause + opt_order_clause + delete_limit_clause + opt_returning + { + if ($3) + Select->order_list= *($3); + Lex->pop_select(); //main select + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } + | table_wild_list + { + mysql_init_multi_delete(Lex); + YYPS->m_lock_type= TL_READ_DEFAULT; + YYPS->m_mdl_type= MDL_SHARED_READ; + } + FROM join_table_list opt_where_clause + { + if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) + MYSQL_YYABORT; + } stmt_end {} + | FROM table_alias_ref_list + { + mysql_init_multi_delete(Lex); + YYPS->m_lock_type= TL_READ_DEFAULT; + YYPS->m_mdl_type= MDL_SHARED_READ; + } + USING join_table_list opt_where_clause + { + if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex))) + MYSQL_YYABORT; + } stmt_end {} + ; + +opt_returning: + /* empty */ + { + DBUG_ASSERT(!Lex->has_returning()); + } + | RETURNING_SYM + { + DBUG_ASSERT(!Lex->has_returning()); + /* + When parsing_place is IN_RETURNING, we push select items to + item_list of builtin_select instead of current_select. + But set parsing_place of current_select to true. + + Because parsing_place for builtin_select will be IN_RETURNING, + regardless there is SELECT in RETURNING. Example, if + there is RETURNING (SELECT...), then when we parse + SELECT inside RETURNING, builtin_select->parsing_place + will still be true. So the select items of SELECT inside + RETURNING will be added to item_list of builtin_select which + is incorrect. We want to prevent this from happening. + Since for every new select, a new SELECT_LEX + object is created and pushed to select stack, current_select + will point to SELECT inside RETURNING, and also has + parsing_place not set to IN_RETURNING by default. + So items are correctly added to item_list of SELECT inside + RETURNING instead of builtin_select. + */ + + thd->lex->current_select->parsing_place= IN_RETURNING; + thd->lex->push_context(&thd->lex->returning()->context); + } + select_item_list + { + thd->lex->pop_context(); + thd->lex->current_select->parsing_place= NO_MATTER; + } + ; + +table_wild_list: + table_wild_one + | table_wild_list ',' table_wild_one + ; + +table_wild_one: + ident opt_wild + { + Table_ident *ti= new (thd->mem_root) Table_ident(&$1); + if (unlikely(ti == NULL)) + MYSQL_YYABORT; + if (unlikely(!Select-> + add_table_to_list(thd, + ti, + NULL, + (TL_OPTION_UPDATING | + TL_OPTION_ALIAS), + YYPS->m_lock_type, + YYPS->m_mdl_type))) + MYSQL_YYABORT; + } + | ident '.' ident opt_wild + { + Table_ident *ti= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); + if (unlikely(ti == NULL)) + MYSQL_YYABORT; + if (unlikely(!Select-> + add_table_to_list(thd, + ti, + NULL, + (TL_OPTION_UPDATING | + TL_OPTION_ALIAS), + YYPS->m_lock_type, + YYPS->m_mdl_type))) + MYSQL_YYABORT; + } + ; + +opt_wild: + /* empty */ {} + | '.' '*' {} + ; + +opt_delete_options: + /* empty */ {} + | opt_delete_option opt_delete_options {} + ; + +opt_delete_option: + QUICK { Select->options|= OPTION_QUICK; } + | LOW_PRIORITY { YYPS->m_lock_type= TL_WRITE_LOW_PRIORITY; } + | IGNORE_SYM { Lex->ignore= 1; } + ; + +truncate: + TRUNCATE_SYM + { + LEX* lex= Lex; + lex->sql_command= SQLCOM_TRUNCATE; + lex->alter_info.reset(); + lex->first_select_lex()->options= 0; + lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED; + lex->first_select_lex()->order_list.empty(); + YYPS->m_lock_type= TL_WRITE; + YYPS->m_mdl_type= MDL_EXCLUSIVE; + } + opt_table_sym table_name opt_lock_wait_timeout + { + LEX* lex= thd->lex; + DBUG_ASSERT(!lex->m_sql_cmd); + lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table(); + if (unlikely(lex->m_sql_cmd == NULL)) + MYSQL_YYABORT; + } + opt_truncate_table_storage_clause { } + ; + +opt_table_sym: + /* empty */ + | TABLE_SYM + ; + +opt_profile_defs: + /* empty */ + | profile_defs; + +profile_defs: + profile_def + | profile_defs ',' profile_def; + +profile_def: + CPU_SYM + { + Lex->profile_options|= PROFILE_CPU; + } + | MEMORY_SYM + { + Lex->profile_options|= PROFILE_MEMORY; + } + | BLOCK_SYM IO_SYM + { + Lex->profile_options|= PROFILE_BLOCK_IO; + } + | CONTEXT_SYM SWITCHES_SYM + { + Lex->profile_options|= PROFILE_CONTEXT; + } + | PAGE_SYM FAULTS_SYM + { + Lex->profile_options|= PROFILE_PAGE_FAULTS; + } + | IPC_SYM + { + Lex->profile_options|= PROFILE_IPC; + } + | SWAPS_SYM + { + Lex->profile_options|= PROFILE_SWAPS; + } + | SOURCE_SYM + { + Lex->profile_options|= PROFILE_SOURCE; + } + | ALL + { + Lex->profile_options|= PROFILE_ALL; + } + ; + +opt_profile_args: + /* empty */ + { + Lex->profile_query_id= 0; + } + | FOR_SYM QUERY_SYM NUM + { + Lex->profile_query_id= atoi($3.str); + } + ; + +/* Show things */ + +show: + SHOW + { + LEX *lex=Lex; + lex->wild=0; + lex->ident= null_clex_str; + if (Lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + lex->current_select->parsing_place= SELECT_LIST; + lex->create_info.init(); + } + show_param + { + Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select + } + ; + +show_param: + DATABASES wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_DATABASES; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SCHEMATA))) + MYSQL_YYABORT; + } + | opt_full TABLES opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_TABLES; + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)) + MYSQL_YYABORT; + } + | opt_full TRIGGERS_SYM opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_TRIGGERS; + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)) + MYSQL_YYABORT; + } + | EVENTS_SYM opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_EVENTS; + lex->first_select_lex()->db= $2; + if (prepare_schema_table(thd, lex, 0, SCH_EVENTS)) + MYSQL_YYABORT; + } + | TABLE_SYM STATUS_SYM opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_TABLE_STATUS; + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_TABLES)) + MYSQL_YYABORT; + } + | OPEN_SYM TABLES opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; + lex->first_select_lex()->db= $3; + if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)) + MYSQL_YYABORT; + } + | PLUGINS_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_PLUGINS; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PLUGINS))) + MYSQL_YYABORT; + } + | PLUGINS_SYM SONAME_SYM TEXT_STRING_sys + { + Lex->ident= $3; + Lex->sql_command= SQLCOM_SHOW_PLUGINS; + if (unlikely(prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS))) + MYSQL_YYABORT; + } + | PLUGINS_SYM SONAME_SYM wild_and_where + { + Lex->sql_command= SQLCOM_SHOW_PLUGINS; + if (unlikely(prepare_schema_table(thd, Lex, 0, SCH_ALL_PLUGINS))) + MYSQL_YYABORT; + } + | ENGINE_SYM known_storage_engines show_engine_param + { Lex->create_info.db_type= $2; } + | ENGINE_SYM ALL show_engine_param + { Lex->create_info.db_type= NULL; } + | opt_full COLUMNS from_or_in table_ident opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_FIELDS; + if ($5.str) + $4->change_db(&$5); + if (unlikely(prepare_schema_table(thd, lex, $4, SCH_COLUMNS))) + MYSQL_YYABORT; + } + | master_or_binary LOGS_SYM + { + Lex->sql_command = SQLCOM_SHOW_BINLOGS; + } + | SLAVE HOSTS_SYM + { + Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS; + } + | BINLOG_SYM EVENTS_SYM binlog_in binlog_from + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; + } + opt_global_limit_clause + | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS; + } + opt_global_limit_clause optional_for_channel + { } + | keys_or_index from_or_in table_ident opt_db opt_where_clause + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_KEYS; + if ($4.str) + $3->change_db(&$4); + if (unlikely(prepare_schema_table(thd, lex, $3, SCH_STATISTICS))) + MYSQL_YYABORT; + } + | opt_storage ENGINES_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_ENGINES))) + MYSQL_YYABORT; + } + | AUTHORS_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_AUTHORS; + } + | CONTRIBUTORS_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_CONTRIBUTORS; + } + | PRIVILEGES + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_PRIVILEGES; + } + | COUNT_SYM '(' '*' ')' WARNINGS + { + LEX_CSTRING var= {STRING_WITH_LEN("warning_count")}; + (void) create_select_for_variable(thd, &var); + } + | COUNT_SYM '(' '*' ')' ERRORS + { + LEX_CSTRING var= {STRING_WITH_LEN("error_count")}; + (void) create_select_for_variable(thd, &var); + } + | WARNINGS opt_global_limit_clause + { Lex->sql_command = SQLCOM_SHOW_WARNS;} + | ERRORS opt_global_limit_clause + { Lex->sql_command = SQLCOM_SHOW_ERRORS;} + | PROFILES_SYM + { Lex->sql_command = SQLCOM_SHOW_PROFILES; } + | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_PROFILE; + if (unlikely(prepare_schema_table(thd, lex, NULL, SCH_PROFILES))) + MYSQL_YYABORT; + } + | opt_var_type STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS; + lex->option_type= $1; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SESSION_STATUS))) + MYSQL_YYABORT; + } + | opt_full PROCESSLIST_SYM + { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;} + | opt_var_type VARIABLES wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_VARIABLES; + lex->option_type= $1; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_SESSION_VARIABLES))) + MYSQL_YYABORT; + } + | charset wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_CHARSETS; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_CHARSETS))) + MYSQL_YYABORT; + } + | COLLATION_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_COLLATIONS; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_COLLATIONS))) + MYSQL_YYABORT; + } + | GRANTS + { + Lex->sql_command= SQLCOM_SHOW_GRANTS; + if (unlikely(!(Lex->grant_user= + (LEX_USER*)thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + Lex->grant_user->user= current_user_and_current_role; + } + | GRANTS FOR_SYM user_or_role clear_privileges + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_GRANTS; + lex->grant_user=$3; + } + | CREATE DATABASE opt_if_not_exists ident + { + Lex->set_command(SQLCOM_SHOW_CREATE_DB, $3); + Lex->name= $4; + } + | CREATE TABLE_SYM table_ident + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE; + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0)) + MYSQL_YYABORT; + lex->create_info.storage_media= HA_SM_DEFAULT; + } + | CREATE VIEW_SYM table_ident + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE; + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) + MYSQL_YYABORT; + lex->table_type= TABLE_TYPE_VIEW; + } + | CREATE SEQUENCE_SYM table_ident + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE; + if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0)) + MYSQL_YYABORT; + lex->table_type= TABLE_TYPE_SEQUENCE; + } + | BINLOG_SYM STATUS_SYM + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; + } + | MASTER_SYM STATUS_SYM + { + Lex->sql_command = SQLCOM_SHOW_BINLOG_STAT; + } + | ALL SLAVES STATUS_SYM + { + if (!(Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_show_slave_status(true))) + MYSQL_YYABORT; + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + } + | SLAVE optional_connection_name STATUS_SYM optional_for_channel + { + if (!(Lex->m_sql_cmd= new (thd->mem_root) + Sql_cmd_show_slave_status())) + MYSQL_YYABORT; + Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; + } + | CREATE PROCEDURE_SYM sp_name + { + LEX *lex= Lex; + + lex->sql_command = SQLCOM_SHOW_CREATE_PROC; + lex->spname= $3; + } + | CREATE FUNCTION_SYM sp_name + { + LEX *lex= Lex; + + lex->sql_command = SQLCOM_SHOW_CREATE_FUNC; + lex->spname= $3; + } + | CREATE PACKAGE_MARIADB_SYM sp_name + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE; + lex->spname= $3; + } + | CREATE PACKAGE_ORACLE_SYM sp_name + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE; + lex->spname= $3; + } + | CREATE PACKAGE_MARIADB_SYM BODY_MARIADB_SYM sp_name + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY; + lex->spname= $4; + } + | CREATE PACKAGE_ORACLE_SYM BODY_ORACLE_SYM sp_name + { + LEX *lex= Lex; + lex->sql_command = SQLCOM_SHOW_CREATE_PACKAGE_BODY; + lex->spname= $4; + } + | CREATE TRIGGER_SYM sp_name + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_CREATE_TRIGGER; + lex->spname= $3; + } + | CREATE USER_SYM + { + Lex->sql_command= SQLCOM_SHOW_CREATE_USER; + if (unlikely(!(Lex->grant_user= + (LEX_USER*)thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + Lex->grant_user->user= current_user; + } + | CREATE USER_SYM user + { + Lex->sql_command= SQLCOM_SHOW_CREATE_USER; + Lex->grant_user= $3; + } + | PROCEDURE_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_PROC; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | FUNCTION_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_FUNC; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | PACKAGE_MARIADB_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | PACKAGE_ORACLE_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | PACKAGE_MARIADB_SYM BODY_MARIADB_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM STATUS_SYM wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_STATUS_PACKAGE_BODY; + if (unlikely(prepare_schema_table(thd, lex, 0, SCH_PROCEDURES))) + MYSQL_YYABORT; + } + | PROCEDURE_SYM CODE_SYM sp_name + { + Lex->sql_command= SQLCOM_SHOW_PROC_CODE; + Lex->spname= $3; + } + | FUNCTION_SYM CODE_SYM sp_name + { + Lex->sql_command= SQLCOM_SHOW_FUNC_CODE; + Lex->spname= $3; + } + | PACKAGE_MARIADB_SYM BODY_MARIADB_SYM CODE_SYM sp_name + { + Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE; + Lex->spname= $4; + } + | PACKAGE_ORACLE_SYM BODY_ORACLE_SYM CODE_SYM sp_name + { + Lex->sql_command= SQLCOM_SHOW_PACKAGE_BODY_CODE; + Lex->spname= $4; + } + | CREATE EVENT_SYM sp_name + { + Lex->spname= $3; + Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT; + } + | describe_command opt_format_json FOR_SYM expr + /* + The alternaltive syntax for this command is MySQL-compatible + EXPLAIN FOR CONNECTION + */ + { + Lex->sql_command= SQLCOM_SHOW_EXPLAIN; + if (unlikely(prepare_schema_table(thd, Lex, 0, + Lex->explain_json ? SCH_EXPLAIN_JSON : SCH_EXPLAIN_TABULAR))) + MYSQL_YYABORT; + add_value_to_list(thd, $4); + } + | ANALYZE_SYM opt_format_json FOR_SYM expr + { + Lex->sql_command= SQLCOM_SHOW_ANALYZE; + if (unlikely(prepare_schema_table(thd, Lex, 0, + Lex->explain_json ? SCH_ANALYZE_JSON : SCH_ANALYZE_TABULAR))) + MYSQL_YYABORT; + add_value_to_list(thd, $4); + } + | IDENT_sys remember_tok_start wild_and_where + { + LEX *lex= Lex; + bool in_plugin; + lex->sql_command= SQLCOM_SHOW_GENERIC; + ST_SCHEMA_TABLE *table= find_schema_table(thd, &$1, &in_plugin); + if (unlikely(!table || !table->old_format || !in_plugin)) + { + thd->parse_error(ER_SYNTAX_ERROR, $2); + MYSQL_YYABORT; + } + if (unlikely(lex->wild && table->idx_field1 < 0)) + { + thd->parse_error(ER_SYNTAX_ERROR, $3); + MYSQL_YYABORT; + } + if (unlikely(make_schema_select(thd, Lex->current_select, table))) + MYSQL_YYABORT; + } + ; + +show_engine_param: + STATUS_SYM + { Lex->sql_command= SQLCOM_SHOW_ENGINE_STATUS; } + | MUTEX_SYM + { Lex->sql_command= SQLCOM_SHOW_ENGINE_MUTEX; } + | LOGS_SYM + { Lex->sql_command= SQLCOM_SHOW_ENGINE_LOGS; } + ; + +master_or_binary: + MASTER_SYM + | BINARY + ; + +opt_storage: + /* empty */ + | STORAGE_SYM + ; + +opt_db: + /* empty */ { $$= null_clex_str; } + | from_or_in ident { $$= $2; } + ; + +opt_full: + /* empty */ { Lex->verbose=0; } + | FULL { Lex->verbose=1; } + ; + +from_or_in: + FROM + | IN_SYM + ; + +binlog_in: + /* empty */ { Lex->mi.log_file_name = 0; } + | IN_SYM TEXT_STRING_sys { Lex->mi.log_file_name = $2.str; } + ; + +binlog_from: + /* empty */ { Lex->mi.pos = 4; /* skip magic number */ } + | FROM ulonglong_num { Lex->mi.pos = $2; } + ; + +wild_and_where: + /* empty */ { $$= 0; } + | LIKE remember_tok_start TEXT_STRING_sys + { + Lex->wild= new (thd->mem_root) String((const char*) $3.str, + $3.length, + system_charset_info); + if (unlikely(Lex->wild == NULL)) + MYSQL_YYABORT; + $$= $2; + } + | WHERE remember_tok_start expr + { + Select->where= normalize_cond(thd, $3); + if ($3) + $3->top_level_item(); + $$= $2; + } + ; + +/* A Oracle compatible synonym for show */ +describe: + describe_command table_ident + { + LEX *lex= Lex; + if (lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + lex->current_select->parsing_place= SELECT_LIST; + lex->sql_command= SQLCOM_SHOW_FIELDS; + lex->first_select_lex()->db= null_clex_str; + lex->verbose= 0; + if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS))) + MYSQL_YYABORT; + } + opt_describe_column + { + Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select + } + | describe_command opt_extended_describe + { Lex->describe|= DESCRIBE_NORMAL; } + explainable_command + { + LEX *lex=Lex; + lex->first_select_lex()->options|= SELECT_DESCRIBE; + } + ; + +explainable_command: + select + | select_into + | insert + | replace + | update + | delete + ; + +describe_command: + DESC + | DESCRIBE + ; + +analyze_stmt_command: + ANALYZE_SYM opt_format_json explainable_command + { + Lex->analyze_stmt= true; + } + ; + +opt_extended_describe: + EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + | EXTENDED_SYM ALL + { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; } + | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; } + | opt_format_json {} + ; + +opt_format_json: + /* empty */ {} + | FORMAT_SYM '=' ident_or_text + { + if (lex_string_eq(&$3, STRING_WITH_LEN("JSON"))) + Lex->explain_json= true; + else if (lex_string_eq(&$3, STRING_WITH_LEN("TRADITIONAL"))) + DBUG_ASSERT(Lex->explain_json==false); + else + my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), + "EXPLAIN/ANALYZE", $3.str)); + } + ; + +opt_describe_column: + /* empty */ {} + | text_string { Lex->wild= $1; } + | ident + { + Lex->wild= new (thd->mem_root) String((const char*) $1.str, + $1.length, + system_charset_info); + if (unlikely(Lex->wild == NULL)) + MYSQL_YYABORT; + } + ; + +explain_for_connection: + /* + EXPLAIN FOR CONNECTION is an alternative syntax for + SHOW EXPLAIN FOR command. It was introduced for compatibility + with MySQL which implements EXPLAIN FOR CONNECTION command + */ + describe_command opt_format_json FOR_SYM CONNECTION_SYM expr + { + LEX *lex=Lex; + lex->wild=0; + lex->ident= null_clex_str; + if (Lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + lex->current_select->parsing_place= SELECT_LIST; + lex->create_info.init(); + Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select + Lex->sql_command= SQLCOM_SHOW_EXPLAIN; + if (unlikely(prepare_schema_table(thd, Lex, 0, + Lex->explain_json ? SCH_EXPLAIN_JSON : SCH_EXPLAIN_TABULAR))) + MYSQL_YYABORT; + add_value_to_list(thd, $5); + } + ; + +/* flush things */ + +flush: + FLUSH_SYM opt_no_write_to_binlog + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_FLUSH; + lex->type= 0; + lex->no_write_to_binlog= $2; + } + flush_options {} + ; + +flush_options: + table_or_tables + { + Lex->type|= REFRESH_TABLES; + /* + Set type of metadata and table locks for + FLUSH TABLES table_list [WITH READ LOCK]. + */ + YYPS->m_lock_type= TL_READ_NO_INSERT; + YYPS->m_mdl_type= MDL_SHARED_HIGH_PRIO; + } + opt_table_list opt_flush_lock + {} + | flush_options_list + {} + ; + +opt_flush_lock: + /* empty */ {} + | flush_lock + { + TABLE_LIST *tables= Lex->query_tables; + for (; tables; tables= tables->next_global) + { + tables->mdl_request.set_type(MDL_SHARED_NO_WRITE); + /* Ignore temporary tables. */ + tables->open_type= OT_BASE_ONLY; + } + } + ; + +flush_lock: + WITH READ_SYM LOCK_SYM optional_flush_tables_arguments + { Lex->type|= REFRESH_READ_LOCK | $4; } + | FOR_SYM + { + if (unlikely(Lex->query_tables == NULL)) + { + // Table list can't be empty + thd->parse_error(ER_NO_TABLES_USED); + MYSQL_YYABORT; + } + Lex->type|= REFRESH_FOR_EXPORT; + } EXPORT_SYM {} + ; + +flush_options_list: + flush_options_list ',' flush_option + | flush_option + {} + ; + +flush_option: + ERROR_SYM LOGS_SYM + { Lex->type|= REFRESH_ERROR_LOG; } + | ENGINE_SYM LOGS_SYM + { Lex->type|= REFRESH_ENGINE_LOG; } + | GENERAL LOGS_SYM + { Lex->type|= REFRESH_GENERAL_LOG; } + | SLOW LOGS_SYM + { Lex->type|= REFRESH_SLOW_LOG; } + | BINARY LOGS_SYM opt_delete_gtid_domain + { Lex->type|= REFRESH_BINARY_LOG; } + | RELAY LOGS_SYM optional_connection_name optional_for_channel + { + LEX *lex= Lex; + if (unlikely(lex->type & REFRESH_RELAY_LOG)) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH", "RELAY LOGS")); + lex->type|= REFRESH_RELAY_LOG; + lex->relay_log_connection_name= lex->mi.connection_name; + } + | QUERY_SYM CACHE_SYM + { Lex->type|= REFRESH_QUERY_CACHE_FREE; } + | HOSTS_SYM + { Lex->type|= REFRESH_HOSTS; } + | PRIVILEGES + { Lex->type|= REFRESH_GRANT; } + | LOGS_SYM + { + Lex->type|= REFRESH_LOG; + Lex->relay_log_connection_name= empty_clex_str; + } + | STATUS_SYM + { Lex->type|= REFRESH_STATUS; } + | SLAVE optional_connection_name + { + LEX *lex= Lex; + if (unlikely(lex->type & REFRESH_SLAVE)) + my_yyabort_error((ER_WRONG_USAGE, MYF(0), "FLUSH","SLAVE")); + lex->type|= REFRESH_SLAVE; + lex->reset_slave_info.all= false; + } + | MASTER_SYM + { Lex->type|= REFRESH_MASTER; } + | DES_KEY_FILE + { Lex->type|= REFRESH_DES_KEY_FILE; } + | RESOURCES + { Lex->type|= REFRESH_USER_RESOURCES; } + | SSL_SYM + { Lex->type|= REFRESH_SSL;} + | THREADS_SYM + { Lex->type|= REFRESH_THREADS;} + | IDENT_sys remember_tok_start + { + Lex->type|= REFRESH_GENERIC; + ST_SCHEMA_TABLE *table= find_schema_table(thd, &$1); + if (unlikely(!table || !table->reset_table)) + { + thd->parse_error(ER_SYNTAX_ERROR, $2); + MYSQL_YYABORT; + } + if (unlikely(Lex->view_list.push_back((LEX_CSTRING*) + thd->memdup(&$1, sizeof(LEX_CSTRING)), + thd->mem_root))) + MYSQL_YYABORT; + } + ; + +opt_table_list: + /* empty */ {} + | table_list {} + ; + +backup: + BACKUP_SYM backup_statements {} + ; + +backup_statements: + STAGE_SYM ident + { + int type; + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP STAGE")); + if ((type= find_type($2.str, &backup_stage_names, + FIND_TYPE_NO_PREFIX)) <= 0) + my_yyabort_error((ER_BACKUP_UNKNOWN_STAGE, MYF(0), $2.str)); + Lex->sql_command= SQLCOM_BACKUP; + Lex->backup_stage= (backup_stages) (type-1); + break; + } + | LOCK_SYM + { + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP LOCK")); + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + table_ident + { + if (unlikely(!Select->add_table_to_list(thd, $3, NULL, 0, + TL_READ, MDL_SHARED_HIGH_PRIO))) + MYSQL_YYABORT; + Lex->sql_command= SQLCOM_BACKUP_LOCK; + Lex->pop_select(); //main select + } + | UNLOCK_SYM + { + if (unlikely(Lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "BACKUP UNLOCK")); + /* Table list is empty for unlock */ + Lex->sql_command= SQLCOM_BACKUP_LOCK; + } + ; + +opt_delete_gtid_domain: + /* empty */ {} + | DELETE_DOMAIN_ID_SYM '=' '(' delete_domain_id_list ')' + {} + ; +delete_domain_id_list: + /* Empty */ + | delete_domain_id + | delete_domain_id_list ',' delete_domain_id + ; + +delete_domain_id: + ulonglong_num + { + uint32 value= (uint32) $1; + if ($1 > UINT_MAX32) + { + my_printf_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN, + "The value of gtid domain being deleted ('%llu') " + "exceeds its maximum size " + "of 32 bit unsigned integer", MYF(0), $1); + MYSQL_YYABORT; + } + insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &value); + } + ; + +optional_flush_tables_arguments: + /* empty */ {$$= 0;} + | AND_SYM DISABLE_SYM CHECKPOINT_SYM {$$= REFRESH_CHECKPOINT; } + ; + +reset: + RESET_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_RESET; lex->type=0; + } + reset_options + {} + ; + +reset_options: + reset_options ',' reset_option + | reset_option + ; + +reset_option: + SLAVE { Lex->type|= REFRESH_SLAVE; } + optional_connection_name + slave_reset_options optional_for_channel + { } + | MASTER_SYM + { + Lex->type|= REFRESH_MASTER; + Lex->next_binlog_file_number= 0; + } + master_reset_options + | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;} + ; + +slave_reset_options: + /* empty */ { Lex->reset_slave_info.all= false; } + | ALL { Lex->reset_slave_info.all= true; } + ; + +master_reset_options: + /* empty */ {} + | TO_SYM ulong_num + { + Lex->next_binlog_file_number = $2; + } + ; + +purge: + PURGE master_or_binary LOGS_SYM TO_SYM TEXT_STRING_sys + { + Lex->stmt_purge_to($5); + } + | PURGE master_or_binary LOGS_SYM BEFORE_SYM + { Lex->clause_that_disallows_subselect= "PURGE..BEFORE"; } + expr + { + Lex->clause_that_disallows_subselect= NULL; + if (Lex->stmt_purge_before($6)) + MYSQL_YYABORT; + } + ; + + +/* kill threads */ + +kill: + KILL_SYM + { + LEX *lex=Lex; + lex->value_list.empty(); + lex->users_list.empty(); + lex->sql_command= SQLCOM_KILL; + lex->kill_type= KILL_TYPE_ID; + } + kill_type kill_option + { + Lex->kill_signal= (killed_state) ($3 | $4); + } + ; + +kill_type: + /* Empty */ { $$= (int) KILL_HARD_BIT; } + | HARD_SYM { $$= (int) KILL_HARD_BIT; } + | SOFT_SYM { $$= 0; } + ; + +kill_option: + opt_connection kill_expr { $$= (int) KILL_CONNECTION; } + | QUERY_SYM kill_expr { $$= (int) KILL_QUERY; } + | QUERY_SYM ID_SYM expr + { + $$= (int) KILL_QUERY; + Lex->kill_type= KILL_TYPE_QUERY; + Lex->value_list.push_front($3, thd->mem_root); + } + ; + +opt_connection: + /* empty */ { } + | CONNECTION_SYM { } + ; + +kill_expr: + expr + { + Lex->value_list.push_front($$, thd->mem_root); + } + | USER_SYM user + { + Lex->users_list.push_back($2, thd->mem_root); + Lex->kill_type= KILL_TYPE_USER; + } + ; + +shutdown: + SHUTDOWN { Lex->sql_command= SQLCOM_SHUTDOWN; } + shutdown_option {} + ; + +shutdown_option: + /* Empty */ { Lex->is_shutdown_wait_for_slaves= false; } + | WAIT_SYM FOR_SYM ALL SLAVES + { + Lex->is_shutdown_wait_for_slaves= true; + } + ; + +/* change database */ + +use: + USE_SYM ident + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_CHANGE_DB; + lex->first_select_lex()->db= $2; + } + ; + +/* import, export of files */ + +load: + LOAD data_or_xml + { + LEX *lex= thd->lex; + + if (unlikely(lex->sphead)) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), + $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML"); + MYSQL_YYABORT; + } + if (lex->main_select_push()) + MYSQL_YYABORT; + lex->init_select(); + } + load_data_lock opt_local INFILE TEXT_STRING_filesystem + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_LOAD; + lex->local_file= $5; + lex->duplicates= DUP_ERROR; + lex->ignore= 0; + if (unlikely(!(lex->exchange= new (thd->mem_root) + sql_exchange($7.str, 0, $2)))) + MYSQL_YYABORT; + } + opt_duplicate INTO TABLE_SYM table_ident opt_use_partition + { + LEX *lex=Lex; + if (unlikely(!Select->add_table_to_list(thd, $12, NULL, + TL_OPTION_UPDATING, + $4, MDL_SHARED_WRITE, + NULL, $13))) + MYSQL_YYABORT; + lex->field_list.empty(); + lex->update_list.empty(); + lex->value_list.empty(); + lex->many_values.empty(); + } + opt_load_data_charset + { Lex->exchange->cs= $15; } + opt_xml_rows_identified_by + opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec + opt_load_data_set_spec + stmt_end + { + Lex->mark_first_table_as_inserting(); + } + ; + +data_or_xml: + DATA_SYM { $$= FILETYPE_CSV; } + | XML_SYM { $$= FILETYPE_XML; } + ; + +opt_local: + /* empty */ { $$=0;} + | LOCAL_SYM { $$=1;} + ; + +load_data_lock: + /* empty */ { $$= TL_WRITE_DEFAULT; } + | CONCURRENT + { + /* + Ignore this option in SP to avoid problem with query cache and + triggers with non default priority locks + */ + $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT); + } + | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; } + ; + +opt_duplicate: + /* empty */ { Lex->duplicates=DUP_ERROR; } + | REPLACE { Lex->duplicates=DUP_REPLACE; } + | IGNORE_SYM { Lex->ignore= 1; } + ; + +opt_field_term: + /* empty */ + | COLUMNS field_term_list + ; + +field_term_list: + field_term_list field_term + | field_term + ; + +field_term: + TERMINATED BY text_string + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->field_term= $3; + } + | OPTIONALLY ENCLOSED BY text_string + { + LEX *lex= Lex; + DBUG_ASSERT(lex->exchange != 0); + lex->exchange->enclosed= $4; + lex->exchange->opt_enclosed= 1; + } + | ENCLOSED BY text_string + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->enclosed= $3; + } + | ESCAPED BY text_string + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->escaped= $3; + } + ; + +opt_line_term: + /* empty */ + | LINES line_term_list + ; + +line_term_list: + line_term_list line_term + | line_term + ; + +line_term: + TERMINATED BY text_string + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->line_term= $3; + } + | STARTING BY text_string + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->line_start= $3; + } + ; + +opt_xml_rows_identified_by: + /* empty */ { } + | ROWS_SYM IDENTIFIED_SYM BY text_string + { Lex->exchange->line_term = $4; } + ; + +opt_ignore_lines: + /* empty */ + | IGNORE_SYM NUM lines_or_rows + { + DBUG_ASSERT(Lex->exchange != 0); + Lex->exchange->skip_lines= atol($2.str); + } + ; + +lines_or_rows: + LINES { } + | ROWS_SYM { } + ; + +opt_field_or_var_spec: + /* empty */ {} + | '(' fields_or_vars ')' {} + | '(' ')' {} + ; + +fields_or_vars: + fields_or_vars ',' field_or_var + { Lex->field_list.push_back($3, thd->mem_root); } + | field_or_var + { Lex->field_list.push_back($1, thd->mem_root); } + ; + +field_or_var: + simple_ident_nospvar {$$= $1;} + | '@' ident_or_text + { + if (!$2.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + + $$= new (thd->mem_root) Item_user_var_as_out_param(thd, &$2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +opt_load_data_set_spec: + /* empty */ {} + | SET load_data_set_list {} + ; + +load_data_set_list: + load_data_set_list ',' load_data_set_elem + | load_data_set_elem + ; + +load_data_set_elem: + simple_ident_nospvar equal remember_name expr_or_ignore_or_default remember_end + { + LEX *lex= Lex; + if (unlikely(lex->update_list.push_back($1, thd->mem_root)) || + unlikely(lex->value_list.push_back($4, thd->mem_root))) + MYSQL_YYABORT; + $4->set_name_no_truncate(thd, $3, (uint) ($5 - $3), thd->charset()); + } + ; + +/* Common definitions */ + +text_literal: + TEXT_STRING + { + if (unlikely(!($$= thd->make_string_literal($1)))) + MYSQL_YYABORT; + } + | NCHAR_STRING + { + if (unlikely(!($$= thd->make_string_literal_nchar($1)))) + MYSQL_YYABORT; + } + | UNDERSCORE_CHARSET TEXT_STRING + { + if (unlikely(!($$= thd->make_string_literal_charset($2, $1)))) + MYSQL_YYABORT; + } + | text_literal TEXT_STRING_literal + { + if (unlikely(!($$= $1->make_string_literal_concat(thd, &$2)))) + MYSQL_YYABORT; + } + ; + +text_string: + TEXT_STRING_literal + { + $$= new (thd->mem_root) String((const char*) $1.str, + $1.length, + thd->variables.collation_connection); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | hex_or_bin_String { $$= $1; } + ; + + +hex_or_bin_String: + HEX_NUM + { + Item *tmp= new (thd->mem_root) Item_hex_hybrid(thd, $1.str, + $1.length); + if (unlikely(tmp == NULL)) + MYSQL_YYABORT; + $$= tmp->val_str((String*) 0); + } + | HEX_STRING + { + Item *tmp= new (thd->mem_root) Item_hex_string(thd, $1.str, + $1.length); + if (unlikely(tmp == NULL)) + MYSQL_YYABORT; + $$= tmp->val_str((String*) 0); + } + | BIN_NUM + { + Item *tmp= new (thd->mem_root) Item_bin_string(thd, $1.str, + $1.length); + if (unlikely(tmp == NULL)) + MYSQL_YYABORT; + /* + it is OK only emulate fix_fields, because we need only + value of constant + */ + $$= tmp->val_str((String*) 0); + } + ; + +param_marker: + PARAM_MARKER + { + if (unlikely(!($$= Lex->add_placeholder(thd, ¶m_clex_str, + YYLIP->get_tok_start(), + YYLIP->get_tok_start() + 1)))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM ident_cli + { + if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, + $1.pos(), $2.end())))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM NUM + { + if (unlikely(!($$= Lex->add_placeholder(thd, &null_clex_str, + $1.pos(), + YYLIP->get_ptr())))) + MYSQL_YYABORT; + } + ; + +signed_literal: + '+' NUM_literal { $$ = $2; } + | '-' NUM_literal + { + $2->max_length++; + $$= $2->neg(thd); + } + ; + +literal: + text_literal { $$ = $1; } + | NUM_literal { $$ = $1; } + | temporal_literal { $$= $1; } + | NULL_SYM + { + /* + For the digest computation, in this context only, + NULL is considered a literal, hence reduced to '?' + REDUCE: + TOK_GENERIC_VALUE := NULL_SYM + */ + YYLIP->reduce_digest_token(TOK_GENERIC_VALUE, NULL_SYM); + $$= new (thd->mem_root) Item_null(thd); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + YYLIP->next_state= MY_LEX_OPERATOR_OR_IDENT; + } + | FALSE_SYM + { + $$= new (thd->mem_root) Item_bool(thd, (char*) "FALSE",0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | TRUE_SYM + { + $$= new (thd->mem_root) Item_bool(thd, (char*) "TRUE",1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | HEX_NUM + { + $$= new (thd->mem_root) Item_hex_hybrid(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | HEX_STRING + { + $$= new (thd->mem_root) Item_hex_string(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | BIN_NUM + { + $$= new (thd->mem_root) Item_bin_string(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | UNDERSCORE_CHARSET hex_or_bin_String + { + Item_string_with_introducer *item_str; + LEX_CSTRING tmp; + $2->get_value(&tmp); + /* + Pass NULL as name. Name will be set in the "select_item" rule and + will include the introducer and the original hex/bin notation. + */ + item_str= new (thd->mem_root) + Item_string_with_introducer(thd, null_clex_str, + tmp, $1); + if (unlikely(!item_str || + !item_str->check_well_formed_result(true))) + MYSQL_YYABORT; + + $$= item_str; + } + ; + +NUM_literal: + NUM + { + int error; + $$= new (thd->mem_root) + Item_int(thd, $1.str, + (longlong) my_strtoll10($1.str, NULL, &error), + $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | LONG_NUM + { + int error; + $$= new (thd->mem_root) + Item_int(thd, $1.str, + (longlong) my_strtoll10($1.str, NULL, &error), + $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ULONGLONG_NUM + { + $$= new (thd->mem_root) Item_uint(thd, $1.str, $1.length); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | DECIMAL_NUM + { + $$= new (thd->mem_root) Item_decimal(thd, $1.str, $1.length, + thd->charset()); + if (unlikely($$ == NULL) || unlikely(thd->is_error())) + MYSQL_YYABORT; + } + | FLOAT_NUM + { + $$= new (thd->mem_root) Item_float(thd, $1.str, $1.length); + if (unlikely($$ == NULL) || unlikely(thd->is_error())) + MYSQL_YYABORT; + } + ; + + +temporal_literal: + DATE_SYM TEXT_STRING + { + if (unlikely(!($$= type_handler_newdate.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) + MYSQL_YYABORT; + } + | TIME_SYM TEXT_STRING + { + if (unlikely(!($$= type_handler_time2.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) + MYSQL_YYABORT; + } + | TIMESTAMP TEXT_STRING + { + if (unlikely(!($$= type_handler_datetime.create_literal_item(thd, + $2.str, $2.length, + YYCSCL, true)))) + MYSQL_YYABORT; + } + ; + +with_clause: + WITH opt_recursive + { + LEX *lex= Lex; + With_clause *with_clause= + new With_clause($2, Lex->curr_with_clause); + if (unlikely(with_clause == NULL)) + MYSQL_YYABORT; + lex->derived_tables|= DERIVED_WITH; + lex->with_cte_resolution= true; + lex->curr_with_clause= with_clause; + with_clause->add_to_list(&lex->with_clauses_list, + lex->with_clauses_list_last_next); + if (lex->current_select && + lex->current_select->parsing_place == BEFORE_OPT_LIST) + lex->current_select->parsing_place= NO_MATTER; + } + with_list + { + $$= Lex->curr_with_clause; + Lex->curr_with_clause= Lex->curr_with_clause->pop(); + } + ; + + +opt_recursive: + /*empty*/ { $$= 0; } + | RECURSIVE_SYM { $$= 1; } + ; + + +with_list: + with_list_element + | with_list ',' with_list_element + ; + + +with_list_element: + with_element_head + opt_with_column_list + AS '(' query_expression ')' opt_cycle + { + LEX *lex= thd->lex; + const char *query_start= lex->sphead ? lex->sphead->m_tmp_query + : thd->query(); + const char *spec_start= $4.pos() + 1; + With_element *elem= new With_element($1, *$2, $5); + if (elem == NULL || Lex->curr_with_clause->add_with_element(elem)) + MYSQL_YYABORT; + if (elem->set_unparsed_spec(thd, spec_start, $6.pos(), + spec_start - query_start)) + MYSQL_YYABORT; + if ($7) + { + elem->set_cycle_list($7); + } + elem->set_tables_end_pos(lex->query_tables_last); + } + ; + +opt_cycle: + /* empty */ + { $$= NULL; } + | + CYCLE_SYM + { + if (!Lex->curr_with_clause->with_recursive) + { + thd->parse_error(ER_SYNTAX_ERROR, $1.pos()); + } + } + comma_separated_ident_list RESTRICT + { + $$= $3; + } + ; + + +opt_with_column_list: + /* empty */ + { + if (($$= new (thd->mem_root) List<Lex_ident_sys>) == NULL) + MYSQL_YYABORT; + } + | '(' with_column_list ')' + { $$= $2; } + ; + +with_column_list: + comma_separated_ident_list + ; + +ident_sys_alloc: + ident_cli + { + void *buf= thd->alloc(sizeof(Lex_ident_sys)); + if (!buf) + MYSQL_YYABORT; + $$= new (buf) Lex_ident_sys(thd, &$1); + } + ; + +comma_separated_ident_list: + ident_sys_alloc + { + $$= new (thd->mem_root) List<Lex_ident_sys>; + if (unlikely($$ == NULL || $$->push_back($1))) + MYSQL_YYABORT; + } + | comma_separated_ident_list ',' ident_sys_alloc + { + if (($$= $1)->push_back($3)) + MYSQL_YYABORT; + } + ; + + +with_element_head: + ident + { + LEX_CSTRING *name= + (LEX_CSTRING *) thd->memdup(&$1, sizeof(LEX_CSTRING)); + $$= new (thd->mem_root) With_element_head(name); + if (unlikely(name == NULL || $$ == NULL)) + MYSQL_YYABORT; + $$->tables_pos.set_start_pos(Lex->query_tables_last); + } + ; + + + +/********************************************************************** +** Creating different items. +**********************************************************************/ + +insert_ident: + simple_ident_nospvar { $$=$1; } + | table_wild { $$=$1; } + ; + +table_wild: + ident '.' '*' + { + if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1)))) + MYSQL_YYABORT; + } + | ident '.' ident '.' '*' + { + if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + ; + +select_sublist_qualified_asterisk: + ident_cli '.' '*' + { + if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1)))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli '.' '*' + { + if (unlikely(!($$= Lex->create_item_qualified_asterisk(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + ; + +order_ident: + expr { $$=$1; } + ; + + +simple_ident: + ident_cli + { + if (unlikely(!($$= Lex->create_item_ident(thd, &$1)))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + | '.' ident_cli '.' ident_cli + { + Lex_ident_cli empty($2.pos(), 0); + if (unlikely(!($$= Lex->create_item_ident(thd, &empty, &$2, &$4)))) + MYSQL_YYABORT; + } + | ident_cli '.' ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5)))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) + MYSQL_YYABORT; + } + ; + +simple_ident_nospvar: + ident + { + if (unlikely(!($$= Lex->create_item_ident_nosp(thd, &$1)))) + MYSQL_YYABORT; + } + | ident '.' ident + { + if (unlikely(!($$= Lex->create_item_ident_nospvar(thd, &$1, &$3)))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM ident_cli '.' ident_cli + { + if (unlikely(!($$= Lex->make_item_colon_ident_ident(thd, &$2, &$4)))) + MYSQL_YYABORT; + } + | '.' ident '.' ident + { + Lex_ident_sys none; + if (unlikely(!($$= Lex->create_item_ident(thd, &none, &$2, &$4)))) + MYSQL_YYABORT; + } + | ident '.' ident '.' ident + { + if (unlikely(!($$= Lex->create_item_ident(thd, &$1, &$3, &$5)))) + MYSQL_YYABORT; + } + ; + +field_ident: + ident { $$=$1;} + | ident '.' ident '.' ident + { + TABLE_LIST *table= Select->table_list.first; + if (unlikely(my_strcasecmp(table_alias_charset, $1.str, + table->db.str))) + my_yyabort_error((ER_WRONG_DB_NAME, MYF(0), $1.str)); + if (unlikely(my_strcasecmp(table_alias_charset, $3.str, + table->table_name.str))) + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $3.str)); + $$=$5; + } + | ident '.' ident + { + TABLE_LIST *table= Select->table_list.first; + if (unlikely(my_strcasecmp(table_alias_charset, $1.str, + table->alias.str))) + my_yyabort_error((ER_WRONG_TABLE_NAME, MYF(0), $1.str)); + $$=$3; + } + | '.' ident { $$=$2;} /* For Delphi */ + ; + +table_ident: + ident + { + $$= new (thd->mem_root) Table_ident(&$1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ident '.' ident + { + $$= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | '.' ident + { + /* For Delphi */ + $$= new (thd->mem_root) Table_ident(&$2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +table_ident_opt_wild: + ident opt_wild + { + $$= new (thd->mem_root) Table_ident(&$1); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ident '.' ident opt_wild + { + $$= new (thd->mem_root) Table_ident(thd, &$1, &$3, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +table_ident_nodb: + ident + { + LEX_CSTRING db= any_db; + $$= new (thd->mem_root) Table_ident(thd, &db, &$1, 0); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +IDENT_cli: + IDENT + | IDENT_QUOTED + ; + +ident_cli: + IDENT + | IDENT_QUOTED + | keyword_ident { $$= $1; } + ; + +IDENT_sys: + IDENT_cli + { + if (unlikely(thd->to_ident_sys_alloc(&$$, &$1))) + MYSQL_YYABORT; + } + ; + +TEXT_STRING_sys: + TEXT_STRING + { + if (thd->make_text_string_sys(&$$, &$1)) + MYSQL_YYABORT; + } + ; + +TEXT_STRING_literal: + TEXT_STRING + { + if (thd->make_text_string_connection(&$$, &$1)) + MYSQL_YYABORT; + } + ; + +TEXT_STRING_filesystem: + TEXT_STRING + { + if (thd->make_text_string_filesystem(&$$, &$1)) + MYSQL_YYABORT; + } + ; + +ident_table_alias: + IDENT_sys + | keyword_table_alias + { + if (unlikely($$.copy_keyword(thd, &$1))) + MYSQL_YYABORT; + } + ; + +ident_cli_set_usual_case: + IDENT_cli { $$= $1; } + | keyword_set_usual_case { $$= $1; } + ; + +ident_sysvar_name: + IDENT_sys + | keyword_sysvar_name + { + if (unlikely($$.copy_keyword(thd, &$1))) + MYSQL_YYABORT; + } + | TEXT_STRING_sys + { + if (unlikely($$.copy_sys(thd, &$1))) + MYSQL_YYABORT; + } + ; + + +ident: + IDENT_sys + | keyword_ident + { + if (unlikely($$.copy_keyword(thd, &$1))) + MYSQL_YYABORT; + } + ; + +label_ident: + IDENT_sys + | keyword_label + { + if (unlikely($$.copy_keyword(thd, &$1))) + MYSQL_YYABORT; + } + ; + +ident_or_text: + ident { $$=$1;} + | TEXT_STRING_sys { $$=$1;} + | LEX_HOSTNAME { $$=$1;} + ; + +user_maybe_role: + ident_or_text + { + if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + $$->user = $1; + + if (unlikely(check_string_char_length(&$$->user, ER_USERNAME, + username_char_length, + system_charset_info, 0))) + MYSQL_YYABORT; + } + | ident_or_text '@' ident_or_text + { + if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + $$->user = $1; $$->host=$3; + + if (unlikely(check_string_char_length(&$$->user, ER_USERNAME, + username_char_length, + system_charset_info, 0)) || + unlikely(check_host_name(&$$->host))) + MYSQL_YYABORT; + if ($$->host.str[0]) + { + /* + Convert hostname part of username to lowercase. + It's OK to use in-place lowercase as long as + the character set is utf8. + */ + my_casedn_str(system_charset_info, (char*) $$->host.str); + } + else + { + /* + fix historical undocumented convention that empty host is the + same as '%' + */ + $$->host= host_not_specified; + } + } + | CURRENT_USER optional_braces + { + if (unlikely(!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + $$->user= current_user; + $$->auth= new (thd->mem_root) USER_AUTH(); + } + ; + +user_or_role: user_maybe_role | current_role; + +user: user_maybe_role + { + if ($1->user.str != current_user.str && $1->host.str == 0) + $1->host= host_not_specified; + $$= $1; + } + ; + +/* Keywords which we allow as table aliases. */ +keyword_table_alias: + keyword_data_type + | keyword_cast_type + | keyword_set_special_case + | keyword_sp_block_section + | keyword_sp_head + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | keyword_verb_clause + | FUNCTION_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + ; + +/* Keyword that we allow for identifiers (except SP labels) */ +keyword_ident: + keyword_data_type + | keyword_cast_type + | keyword_set_special_case + | keyword_sp_block_section + | keyword_sp_head + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | keyword_verb_clause + | FUNCTION_SYM + | WINDOW_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + ; + +keyword_sysvar_name: + keyword_data_type + | keyword_cast_type + | keyword_set_special_case + | keyword_sp_block_section + | keyword_sp_head + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_verb_clause + | FUNCTION_SYM + | WINDOW_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + | OFFSET_SYM + ; + +keyword_set_usual_case: + keyword_data_type + | keyword_cast_type + | keyword_sp_block_section + | keyword_sp_head + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | keyword_verb_clause + | FUNCTION_SYM + | WINDOW_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + | OFFSET_SYM + ; + +non_reserved_keyword_udt: + keyword_sp_var_not_label + | keyword_sp_head + | keyword_verb_clause + | keyword_set_special_case + | keyword_sp_block_section + | keyword_sysvar_type + | keyword_sp_var_and_label + | OFFSET_SYM + ; + +/* + Keywords that we allow in Oracle-style direct assignments: + xxx := 10; + but do not allow in labels in the default sql_mode: + label: + stmt1; + stmt2; + TODO: check if some of them can migrate to keyword_sp_var_and_label. +*/ +keyword_sp_var_not_label: + ASCII_SYM + | BACKUP_SYM + | BINLOG_SYM + | BYTE_SYM + | CACHE_SYM + | CHECKSUM_SYM + | CHECKPOINT_SYM + | COLUMN_ADD_SYM + | COLUMN_CHECK_SYM + | COLUMN_CREATE_SYM + | COLUMN_DELETE_SYM + | COLUMN_GET_SYM + | COMMENT_SYM + | COMPRESSED_SYM + | DEALLOCATE_SYM + | EXAMINED_SYM + | EXCLUDE_SYM + | EXECUTE_SYM + | FLUSH_SYM + | FOLLOWING_SYM + | FORMAT_SYM + | GET_SYM + | HELP_SYM + | HOST_SYM + | INSTALL_SYM + | OPTION + | OPTIONS_SYM + | OTHERS_MARIADB_SYM + | OWNER_SYM + | PARSER_SYM + | PERIOD_SYM + | PORT_SYM + | PRECEDING_SYM + | PREPARE_SYM + | REMOVE_SYM + | RESET_SYM + | RESTORE_SYM + | SECURITY_SYM + | SERVER_SYM + | SOCKET_SYM + | SLAVE + | SLAVES + | SONAME_SYM + | START_SYM + | STOP_SYM + | STORED_SYM + | TIES_SYM + | UNICODE_SYM + | UNINSTALL_SYM + | UNBOUNDED_SYM + | WITHIN + | WRAPPER_SYM + | XA_SYM + | UPGRADE_SYM + ; + +/* + Keywords that can start optional clauses in SP or trigger declarations + 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. + TODO: Allow "follows" and "precedes" as variables in compound blocks: + BEGIN + follows := 10; + END; + as they conflict only with non-block FOR EACH ROW statement: + CREATE TRIGGER .. FOR EACH ROW follows:= 10; + CREATE TRIGGER .. FOR EACH ROW FOLLOWS tr1 a:= 10; +*/ +keyword_sp_head: + CONTAINS_SYM /* SP characteristic */ + | LANGUAGE_SYM /* SP characteristic */ + | NO_SYM /* SP characteristic */ + | CHARSET /* SET CHARSET utf8; */ + | FOLLOWS_SYM /* Conflicts with assignment in FOR EACH */ + | PRECEDES_SYM /* Conflicts with assignment in FOR EACH */ + ; + +/* + Keywords that start a statement. + Generally allowed as identifiers (e.g. table, column names) + - not allowed as SP label names + - not allowed as variable names in Oracle-style assignments: + xxx:=10 +*/ +keyword_verb_clause: + CLOSE_SYM /* Verb clause. Reserved in Oracle */ + | COMMIT_SYM /* Verb clause. Reserved in Oracle */ + | DO_SYM /* Verb clause */ + | HANDLER_SYM /* Verb clause */ + | OPEN_SYM /* Verb clause. Reserved in Oracle */ + | REPAIR /* Verb clause */ + | ROLLBACK_SYM /* Verb clause. Reserved in Oracle */ + | SAVEPOINT_SYM /* Verb clause. Reserved in Oracle */ + | SHUTDOWN /* Verb clause */ + | TRUNCATE_SYM /* Verb clause. Reserved in Oracle */ + ; + +keyword_set_special_case: + NAMES_SYM + | ROLE_SYM + | PASSWORD_SYM + ; + +keyword_sysvar_type: + GLOBAL_SYM + | LOCAL_SYM + | SESSION_SYM + ; + + +/* + These keywords are generally allowed as identifiers, + but not allowed as non-delimited SP variable names in sql_mode=ORACLE. +*/ +keyword_data_type: + BIT_SYM + | BOOLEAN_SYM + | BOOL_SYM + | CLOB_MARIADB_SYM + | CLOB_ORACLE_SYM + | DATE_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | DATETIME + | ENUM + | FIXED_SYM + | JSON_SYM + | MEDIUM_SYM + | NATIONAL_SYM + | NCHAR_SYM + | NUMBER_MARIADB_SYM + | NUMBER_ORACLE_SYM + | NVARCHAR_SYM + | RAW_MARIADB_SYM + | RAW_ORACLE_SYM + | ROW_SYM + | SERIAL_SYM + | TEXT_SYM + | TIMESTAMP %prec PREC_BELOW_CONTRACTION_TOKEN2 + | TIME_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | VARCHAR2_MARIADB_SYM + | VARCHAR2_ORACLE_SYM + | YEAR_SYM + ; + + +keyword_cast_type: + SIGNED_SYM + ; + + +/* + These keywords are fine for both SP variable names and SP labels. +*/ +keyword_sp_var_and_label: + ACTION + | ACCOUNT_SYM + | ADDDATE_SYM + | ADD_MONTHS_SYM + | ADMIN_SYM + | AFTER_SYM + | AGAINST + | AGGREGATE_SYM + | ALGORITHM_SYM + | ALWAYS_SYM + | ANY_SYM + | AT_SYM + | ATOMIC_SYM + | AUTHORS_SYM + | AUTO_INC + | AUTOEXTEND_SIZE_SYM + | AUTO_SYM + | AVG_ROW_LENGTH + | AVG_SYM + | BLOCK_SYM + | BODY_MARIADB_SYM + | BTREE_SYM + | CASCADED + | CATALOG_NAME_SYM + | CHAIN_SYM + | CHANNEL_SYM + | CHANGED + | CIPHER_SYM + | CLIENT_SYM + | CLASS_ORIGIN_SYM + | COALESCE + | CODE_SYM + | COLLATION_SYM + | COLUMN_NAME_SYM + | COLUMNS + | COMMITTED_SYM + | COMPACT_SYM + | COMPLETION_SYM + | CONCURRENT + | CONNECTION_SYM + | CONSISTENT_SYM + | CONSTRAINT_CATALOG_SYM + | CONSTRAINT_SCHEMA_SYM + | CONSTRAINT_NAME_SYM + | CONTEXT_SYM + | CONTRIBUTORS_SYM + | CURRENT_POS_SYM + | CPU_SYM + | CUBE_SYM + /* + Although a reserved keyword in SQL:2003 (and :2008), + not reserved in MySQL per WL#2111 specification. + */ + | CURRENT_SYM + | CURSOR_NAME_SYM + | CYCLE_SYM + | DATA_SYM + | DATAFILE_SYM + | DATE_FORMAT_SYM + | DAY_SYM + | DEFINER_SYM + | DELAY_KEY_WRITE_SYM + | DES_KEY_FILE + | DIAGNOSTICS_SYM + | DIRECTORY_SYM + | DISABLE_SYM + | DISCARD + | DISK_SYM + | DUMPFILE + | DUPLICATE_SYM + | DYNAMIC_SYM + | ELSEIF_ORACLE_SYM + | ELSIF_MARIADB_SYM + | EMPTY_SYM + | ENDS_SYM + | ENGINE_SYM + | ENGINES_SYM + | ERROR_SYM + | ERRORS + | ESCAPE_SYM + | EVENT_SYM + | EVENTS_SYM + | EVERY_SYM + | EXCEPTION_MARIADB_SYM + | EXCHANGE_SYM + | EXPANSION_SYM + | EXPIRE_SYM + | EXPORT_SYM + | EXTENDED_SYM + | EXTENT_SIZE_SYM + | FAULTS_SYM + | FAST_SYM + | FOUND_SYM + | ENABLE_SYM + | FEDERATED_SYM + | FULL + | FILE_SYM + | FIRST_SYM + | GENERAL + | GENERATED_SYM + | GET_FORMAT + | GRANTS + | GOTO_MARIADB_SYM + | HASH_SYM + | HARD_SYM + | HISTORY_SYM + | HOSTS_SYM + | HOUR_SYM + | ID_SYM + | IDENTIFIED_SYM + | IGNORE_SERVER_IDS_SYM + | INCREMENT_SYM + | IMMEDIATE_SYM + | INVOKER_SYM + | IMPORT + | INDEXES + | INITIAL_SIZE_SYM + | IO_SYM + | IPC_SYM + | ISOLATION + | ISOPEN_SYM + | ISSUER_SYM + | INSERT_METHOD + | INVISIBLE_SYM + | JSON_TABLE_SYM + | KEY_BLOCK_SIZE + | LAST_VALUE + | LAST_SYM + | LASTVAL_SYM + | LEAVES + | LESS_SYM + | LEVEL_SYM + | LIST_SYM + | LOCKED_SYM + | LOCKS_SYM + | LOGFILE_SYM + | LOGS_SYM + | MAX_ROWS + | MASTER_SYM + | MASTER_HEARTBEAT_PERIOD_SYM + | MASTER_GTID_POS_SYM + | MASTER_HOST_SYM + | MASTER_PORT_SYM + | MASTER_LOG_FILE_SYM + | MASTER_LOG_POS_SYM + | MASTER_USER_SYM + | MASTER_USE_GTID_SYM + | MASTER_PASSWORD_SYM + | MASTER_SERVER_ID_SYM + | MASTER_CONNECT_RETRY_SYM + | MASTER_DELAY_SYM + | MASTER_SSL_SYM + | MASTER_SSL_CA_SYM + | MASTER_SSL_CAPATH_SYM + | MASTER_SSL_CERT_SYM + | MASTER_SSL_CIPHER_SYM + | MASTER_SSL_CRL_SYM + | MASTER_SSL_CRLPATH_SYM + | MASTER_SSL_KEY_SYM + | MAX_CONNECTIONS_PER_HOUR + | MAX_QUERIES_PER_HOUR + | MAX_SIZE_SYM + | MAX_STATEMENT_TIME_SYM + | MAX_UPDATES_PER_HOUR + | MAX_USER_CONNECTIONS_SYM + | MEMORY_SYM + | MERGE_SYM + | MESSAGE_TEXT_SYM + | MICROSECOND_SYM + | MIGRATE_SYM + | MINUTE_SYM +%ifdef MARIADB + | MINUS_ORACLE_SYM +%endif + | MINVALUE_SYM + | MIN_ROWS + | MODIFY_SYM + | MODE_SYM + | MONITOR_SYM + | MONTH_SYM + | MUTEX_SYM + | MYSQL_SYM + | MYSQL_ERRNO_SYM + | NAME_SYM + | NESTED_SYM + | NEVER_SYM + | NEXT_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | NEXTVAL_SYM + | NEW_SYM + | NOCACHE_SYM + | NOCYCLE_SYM + | NOMINVALUE_SYM + | NOMAXVALUE_SYM + | NO_WAIT_SYM + | NOWAIT_SYM + | NODEGROUP_SYM + | NONE_SYM + | NOTFOUND_SYM + | OF_SYM + | OLD_PASSWORD_SYM + | ONE_SYM + | ONLINE_SYM + | ONLY_SYM + | ORDINALITY_SYM + | OVERLAPS_SYM + | PACKAGE_MARIADB_SYM + | PACK_KEYS_SYM + | PAGE_SYM + | PARTIAL + | PARTITIONING_SYM + | PARTITIONS_SYM + | PATH_SYM + | PERSISTENT_SYM + | PHASE_SYM + | PLUGIN_SYM + | PLUGINS_SYM + | PRESERVE_SYM + | PREV_SYM + | PREVIOUS_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | PRIVILEGES + | PROCESS + | PROCESSLIST_SYM + | PROFILE_SYM + | PROFILES_SYM + | PROXY_SYM + | QUARTER_SYM + | QUERY_SYM + | QUICK + | RAISE_MARIADB_SYM + | READ_ONLY_SYM + | REBUILD_SYM + | RECOVER_SYM + | REDO_BUFFER_SIZE_SYM + | REDOFILE_SYM + | REDUNDANT_SYM + | RELAY + | RELAYLOG_SYM + | RELAY_LOG_FILE_SYM + | RELAY_LOG_POS_SYM + | RELAY_THREAD + | RELOAD + | REORGANIZE_SYM + | REPEATABLE_SYM + | REPLAY_SYM + | REPLICATION + | RESOURCES + | RESTART_SYM + | RESUME_SYM + | RETURNED_SQLSTATE_SYM + | RETURNS_SYM + | REUSE_SYM + | REVERSE_SYM + | ROLLUP_SYM + | ROUTINE_SYM + | ROWCOUNT_SYM + | ROWTYPE_MARIADB_SYM + | ROW_COUNT_SYM + | ROW_FORMAT_SYM +%ifdef MARIADB + | ROWNUM_SYM +%endif + | RTREE_SYM + | SCHEDULE_SYM + | SCHEMA_NAME_SYM + | SECOND_SYM + | SEQUENCE_SYM + | SERIALIZABLE_SYM + | SETVAL_SYM + | SIMPLE_SYM + | SHARE_SYM + | SKIP_SYM + | SLAVE_POS_SYM + | SLOW + | SNAPSHOT_SYM + | SOFT_SYM + | SOUNDS_SYM + | SOURCE_SYM + | SQL_CACHE_SYM + | SQL_BUFFER_RESULT + | SQL_NO_CACHE_SYM + | SQL_THREAD + | STAGE_SYM + | STARTS_SYM + | STATEMENT_SYM + | STATUS_SYM + | STORAGE_SYM + | STRING_SYM + | SUBCLASS_ORIGIN_SYM + | SUBDATE_SYM + | SUBJECT_SYM + | SUBPARTITION_SYM + | SUBPARTITIONS_SYM + | SUPER_SYM + | SUSPEND_SYM + | SWAPS_SYM + | SWITCHES_SYM +%ifdef MARIADB + | SYSDATE +%endif + | SYSTEM + | SYSTEM_TIME_SYM + | TABLE_NAME_SYM + | TABLES + | TABLE_CHECKSUM_SYM + | TABLESPACE + | TEMPORARY + | TEMPTABLE_SYM + | THAN_SYM + | TRANSACTION_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | TRANSACTIONAL_SYM + | THREADS_SYM + | TRIGGERS_SYM + | TRIM_ORACLE + | TIMESTAMP_ADD + | TIMESTAMP_DIFF + | TYPES_SYM + | TYPE_SYM + | UDF_RETURNS_SYM + | UNCOMMITTED_SYM + | UNDEFINED_SYM + | UNDO_BUFFER_SIZE_SYM + | UNDOFILE_SYM + | UNKNOWN_SYM + | UNTIL_SYM + | USER_SYM %prec PREC_BELOW_CONTRACTION_TOKEN2 + | USE_FRM + | VARIABLES + | VERSIONING_SYM + | VIEW_SYM + | VIRTUAL_SYM + | VISIBLE_SYM + | VALUE_SYM + | WARNINGS + | WAIT_SYM + | WEEK_SYM + | WEIGHT_STRING_SYM + | WITHOUT + | WORK_SYM + | X509_SYM + | XML_SYM + | VIA_SYM + ; + + +reserved_keyword_udt_not_param_type: + ACCESSIBLE_SYM + | ADD + | ALL + | ALTER + | ANALYZE_SYM + | AND_SYM + | AS + | ASC + | ASENSITIVE_SYM + | BEFORE_SYM + | BETWEEN_SYM + | BIT_AND + | BIT_OR + | BIT_XOR + | BODY_ORACLE_SYM + | BOTH + | BY + | CALL_SYM + | CASCADE + | CASE_SYM + | CAST_SYM + | CHANGE + | CHECK_SYM + | COLLATE_SYM + | CONSTRAINT + | CONTINUE_MARIADB_SYM + | CONTINUE_ORACLE_SYM + | CONVERT_SYM + | COUNT_SYM + | CREATE + | CROSS + | CUME_DIST_SYM + | CURDATE + | CURRENT_USER + | CURRENT_ROLE + | CURTIME + | DATABASE + | DATABASES + | DATE_ADD_INTERVAL + | DATE_SUB_INTERVAL + | DAY_HOUR_SYM + | DAY_MICROSECOND_SYM + | DAY_MINUTE_SYM + | DAY_SECOND_SYM + | DECLARE_MARIADB_SYM + | DECLARE_ORACLE_SYM + | DEFAULT + | DELETE_DOMAIN_ID_SYM + | DELETE_SYM + | DENSE_RANK_SYM + | DESC + | DESCRIBE + | DETERMINISTIC_SYM + | DISTINCT + | DIV_SYM + | DO_DOMAIN_IDS_SYM + | DROP + | DUAL_SYM + | EACH_SYM + | ELSE + | ELSEIF_MARIADB_SYM + | ELSIF_ORACLE_SYM + | ENCLOSED + | ESCAPED + | EXCEPT_SYM + | EXISTS + | EXTRACT_SYM + | FALSE_SYM + | FETCH_SYM + | FIRST_VALUE_SYM + | FOREIGN + | FROM + | FULLTEXT_SYM + | GOTO_ORACLE_SYM + | GRANT + | GROUP_SYM + | GROUP_CONCAT_SYM + | LAG_SYM + | LEAD_SYM + | HAVING + | HOUR_MICROSECOND_SYM + | HOUR_MINUTE_SYM + | HOUR_SECOND_SYM + | IF_SYM + | IGNORE_DOMAIN_IDS_SYM + | IGNORE_SYM + | IGNORED_SYM + | INDEX_SYM + | INFILE + | INNER_SYM + | INSENSITIVE_SYM + | INSERT + | INTERSECT_SYM + | INTERVAL_SYM + | INTO + | IS + | ITERATE_SYM + | JOIN_SYM + | KEYS + | KEY_SYM + | KILL_SYM + | LEADING + | LEAVE_SYM + | LEFT + | LIKE + | LIMIT + | LINEAR_SYM + | LINES + | LOAD + | LOCATOR_SYM + | LOCK_SYM + | LOOP_SYM + | LOW_PRIORITY + | MASTER_SSL_VERIFY_SERVER_CERT_SYM + | MATCH + | MAX_SYM + | MAXVALUE_SYM + | MEDIAN_SYM + | MINUTE_MICROSECOND_SYM + | MINUTE_SECOND_SYM + | MIN_SYM +%ifdef ORACLE + | MINUS_ORACLE_SYM +%endif + | MODIFIES_SYM + | MOD_SYM + | NATURAL + | NEG + | NOT_SYM + | NOW_SYM + | NO_WRITE_TO_BINLOG + | NTILE_SYM + | NULL_SYM + | NTH_VALUE_SYM + | ON + | OPTIMIZE + | OPTIONALLY + | ORDER_SYM + | OR_SYM + | OTHERS_ORACLE_SYM + | OUTER + | OUTFILE + | OVER_SYM + | PACKAGE_ORACLE_SYM + | PAGE_CHECKSUM_SYM + | PARSE_VCOL_EXPR_SYM + | PARTITION_SYM + | PERCENT_RANK_SYM + | PERCENTILE_CONT_SYM + | PERCENTILE_DISC_SYM + | PORTION_SYM + | POSITION_SYM + | PRECISION + | PRIMARY_SYM + | PROCEDURE_SYM + | PURGE + | RAISE_ORACLE_SYM + | RANGE_SYM + | RANK_SYM + | READS_SYM + | READ_SYM + | READ_WRITE_SYM + | RECURSIVE_SYM + | REF_SYSTEM_ID_SYM + | REFERENCES + | REGEXP + | RELEASE_SYM + | RENAME + | REPEAT_SYM + | REPLACE + | REQUIRE_SYM + | RESIGNAL_SYM + | RESTRICT + | RETURNING_SYM + | RETURN_MARIADB_SYM + | RETURN_ORACLE_SYM + | REVOKE + | RIGHT + | ROWS_SYM + | ROWTYPE_ORACLE_SYM + | ROW_NUMBER_SYM + | SECOND_MICROSECOND_SYM + | SELECT_SYM + | SENSITIVE_SYM + | SEPARATOR_SYM + | SERVER_OPTIONS + | SHOW + | SIGNAL_SYM + | SPATIAL_SYM + | SPECIFIC_SYM + | SQLEXCEPTION_SYM + | SQLSTATE_SYM + | SQLWARNING_SYM + | SQL_BIG_RESULT + | SQL_SMALL_RESULT + | SQL_SYM + | SSL_SYM + | STARTING + | STATS_AUTO_RECALC_SYM + | STATS_PERSISTENT_SYM + | STATS_SAMPLE_PAGES_SYM + | STDDEV_SAMP_SYM + | STD_SYM + | STRAIGHT_JOIN + | SUBSTRING + | SUM_SYM + | TABLE_REF_PRIORITY + | TABLE_SYM + | TERMINATED + | THEN_SYM + | TO_SYM + | TRAILING + | TRIGGER_SYM + | TRIM + | TRUE_SYM + | UNDO_SYM + | UNION_SYM + | UNIQUE_SYM + | UNLOCK_SYM + | UPDATE_SYM + | USAGE + | USE_SYM + | USING + | UTC_DATE_SYM + | UTC_TIMESTAMP_SYM + | UTC_TIME_SYM + | VALUES + | VALUES_IN_SYM + | VALUES_LESS_SYM + | VARIANCE_SYM + | VARYING + | VAR_SAMP_SYM + | WHEN_SYM + | WHERE + | WHILE_SYM + | WITH + | XOR + | YEAR_MONTH_SYM + | ZEROFILL + ; + +/* + SQLCOM_SET_OPTION statement. + + Note that to avoid shift/reduce conflicts, we have separate rules for the + first option listed in the statement. +*/ + +set: + SET + { + LEX *lex=Lex; + lex->set_stmt_init(); + } + set_param + { + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } + ; + +set_param: + option_value_no_option_type + | option_value_no_option_type ',' option_value_list + | TRANSACTION_SYM + { + Lex->option_type= OPT_DEFAULT; + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + transaction_characteristics + { + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | option_type + { + Lex->option_type= $1; + } + start_option_value_list_following_option_type + | STATEMENT_SYM + set_stmt_option_list + { + LEX *lex= Lex; + if (unlikely(lex->table_or_sp_used())) + my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT")); + lex->stmt_var_list= lex->var_list; + lex->var_list.empty(); + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } + FOR_SYM directly_executable_statement + ; + +set_stmt_option_list: + /* + Only system variables can be used here. If this condition is changed + please check careful code under lex->option_type == OPT_STATEMENT + condition on wrong type casts. + */ + set_stmt_option + | set_stmt_option_list ',' set_stmt_option + ; + +/* Start of option value list, option_type was given */ +start_option_value_list_following_option_type: + option_value_following_option_type + | option_value_following_option_type ',' option_value_list + | TRANSACTION_SYM + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + transaction_characteristics + { + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + ; + +/* Repeating list of option values after first option value. */ +option_value_list: + option_value + | option_value_list ',' option_value + ; + +/* Wrapper around option values following the first option value in the stmt. */ +option_value: + option_type + { + Lex->option_type= $1; + } + option_value_following_option_type + | option_value_no_option_type + ; + +option_type: + GLOBAL_SYM { $$=OPT_GLOBAL; } + | LOCAL_SYM { $$=OPT_SESSION; } + | SESSION_SYM { $$=OPT_SESSION; } + ; + +opt_var_type: + /* empty */ { $$=OPT_SESSION; } + | GLOBAL_SYM { $$=OPT_GLOBAL; } + | LOCAL_SYM { $$=OPT_SESSION; } + | SESSION_SYM { $$=OPT_SESSION; } + ; + +opt_var_ident_type: + /* empty */ { $$=OPT_DEFAULT; } + | GLOBAL_SYM '.' { $$=OPT_GLOBAL; } + | LOCAL_SYM '.' { $$=OPT_SESSION; } + | SESSION_SYM '.' { $$=OPT_SESSION; } + ; + +/* + SET STATEMENT options do not need their own LEX or Query_arena. + Let's put them to the main ones. +*/ +set_stmt_option: + ident_cli equal + { + if (Lex->main_select_push(false)) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4))) + MYSQL_YYABORT; + Lex->pop_select(); //min select + } + | ident_cli '.' ident equal + { + if (Lex->main_select_push(false)) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_system_variable(thd, Lex->option_type, + &tmp, &$3, $6))) + MYSQL_YYABORT; + Lex->pop_select(); //min select + } + | DEFAULT '.' ident equal + { + if (Lex->main_select_push(false)) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_default_system_variable(Lex->option_type, + &$3, $6))) + MYSQL_YYABORT; + Lex->pop_select(); //min select + } + ; + + +/* Option values with preceding option_type. */ +option_value_following_option_type: + ident_cli equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | ident_cli '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | DEFAULT '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + ; + +/* Option values without preceding option_type. */ +option_value_no_option_type: + ident_cli_set_usual_case equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | ident_cli_set_usual_case '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_variable(&tmp, &$3, $6)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | DEFAULT '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6))) + MYSQL_YYABORT; + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | '@' ident_or_text equal + { + if (!$2.length) + { + thd->parse_error(); + MYSQL_YYABORT; + } + + if (sp_create_assignment_lex(thd, $1.str)) + MYSQL_YYABORT; + } + expr + { + if (unlikely(Lex->set_user_variable(thd, &$2, $5)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | '@' '@' opt_var_ident_type ident_sysvar_name equal + { + if (sp_create_assignment_lex(thd, $1.str)) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_system_variable($3, &$4, $7)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.str)) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | '@' '@' opt_var_ident_type DEFAULT '.' ident equal + { + if (sp_create_assignment_lex(thd, $1.str)) + MYSQL_YYABORT; + } + set_expr_or_default + { + if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | charset old_or_new_charset_name_or_default + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + LEX *lex= thd->lex; + CHARSET_INFO *cs2; + cs2= $2 ? $2: global_system_variables.character_set_client; + set_var_collation_client *var; + var= (new (thd->mem_root) + set_var_collation_client(cs2, + thd->variables.collation_database, + cs2)); + if (unlikely(var == NULL)) + MYSQL_YYABORT; + lex->var_list.push_back(var, thd->mem_root); + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | NAMES_SYM equal expr + { + LEX *lex= Lex; + sp_pcontext *spc= lex->spcont; + LEX_CSTRING names= { STRING_WITH_LEN("names") }; + if (unlikely(spc && spc->find_variable(&names, false))) + my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str); + else + thd->parse_error(); + MYSQL_YYABORT; + } + | NAMES_SYM charset_name_or_default + { + CHARSET_INFO *def= global_system_variables.character_set_client; + Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false); + if (Lex->set_names($1.pos(), tmp, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | NAMES_SYM charset_name_or_default + COLLATE_SYM collation_name_or_default + { + CHARSET_INFO *def= global_system_variables.character_set_client; + Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false); + if (tmp.merge_collation($4) || + Lex->set_names($1.pos(), tmp, yychar == YYEMPTY)) + MYSQL_YYABORT; + } + | DEFAULT ROLE_SYM grant_role + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + LEX *lex = Lex; + LEX_USER *user; + if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + user->user= current_user; + set_var_default_role *var= (new (thd->mem_root) + set_var_default_role(user, + $3->user)); + if (unlikely(var == NULL) || + unlikely(lex->var_list.push_back(var, thd->mem_root))) + MYSQL_YYABORT; + + thd->lex->autocommit= TRUE; + if (lex->sphead) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | DEFAULT ROLE_SYM grant_role FOR_SYM user + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + LEX *lex = Lex; + set_var_default_role *var= (new (thd->mem_root) + set_var_default_role($5, $3->user)); + if (unlikely(var == NULL) || + unlikely(lex->var_list.push_back(var, thd->mem_root))) + MYSQL_YYABORT; + thd->lex->autocommit= TRUE; + if (lex->sphead) + lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | ROLE_SYM role_name + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + LEX *lex = Lex; + set_var_role *var= new (thd->mem_root) set_var_role($2->user); + if (unlikely(var == NULL) || + unlikely(lex->var_list.push_back(var, thd->mem_root)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | ROLE_SYM equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | PASSWORD_SYM equal + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + text_or_password + { + if (unlikely(Lex->sp_create_set_password_instr(thd, $4, + yychar == YYEMPTY))) + MYSQL_YYABORT; + } + | PASSWORD_SYM FOR_SYM + { + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + user equal text_or_password + { + if (unlikely(Lex->sp_create_set_password_instr(thd, $4, $6, + yychar == YYEMPTY))) + MYSQL_YYABORT; + } + ; + +transaction_characteristics: + transaction_access_mode + | isolation_level + | transaction_access_mode ',' isolation_level + | isolation_level ',' transaction_access_mode + ; + +transaction_access_mode: + transaction_access_mode_types + { + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int(thd, (int32) $1); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + set_var *var= (new (thd->mem_root) + set_var(thd, lex->option_type, + find_sys_var(thd, "tx_read_only"), + &null_clex_str, + item)); + if (unlikely(var == NULL)) + MYSQL_YYABORT; + if (unlikely(lex->var_list.push_back(var, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +isolation_level: + ISOLATION LEVEL_SYM isolation_types + { + LEX *lex=Lex; + Item *item= new (thd->mem_root) Item_int(thd, (int32) $3); + if (unlikely(item == NULL)) + MYSQL_YYABORT; + set_var *var= (new (thd->mem_root) + set_var(thd, lex->option_type, + find_sys_var(thd, "tx_isolation"), + &null_clex_str, + item)); + if (unlikely(var == NULL) || + unlikely(lex->var_list.push_back(var, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +transaction_access_mode_types: + READ_SYM ONLY_SYM { $$= true; } + | READ_SYM WRITE_SYM { $$= false; } + ; + +isolation_types: + READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } + | READ_SYM COMMITTED_SYM { $$= ISO_READ_COMMITTED; } + | REPEATABLE_SYM READ_SYM { $$= ISO_REPEATABLE_READ; } + | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; } + ; + + +text_or_password: + TEXT_STRING + { + $$= new (thd->mem_root) USER_AUTH(); + $$->auth_str= $1; + } + | PASSWORD_SYM '(' TEXT_STRING ')' + { + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; + } + | OLD_PASSWORD_SYM '(' TEXT_STRING ')' + { + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; + $$->auth_str.str= Item_func_password::alloc(thd, + $3.str, $3.length, Item_func_password::OLD); + $$->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; + } + ; + +set_expr_or_default: + expr { $$=$1; } + | DEFAULT { $$=0; } + | ON + { + $$=new (thd->mem_root) Item_string_sys(thd, "ON", 2); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | ALL + { + $$=new (thd->mem_root) Item_string_sys(thd, "ALL", 3); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + | BINARY + { + $$=new (thd->mem_root) Item_string_sys(thd, "binary", 6); + if (unlikely($$ == NULL)) + MYSQL_YYABORT; + } + ; + +/* Lock function */ + +lock: + LOCK_SYM table_or_tables + { + LEX *lex= Lex; + + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK")); + lex->sql_command= SQLCOM_LOCK_TABLES; + } + table_lock_list opt_lock_wait_timeout + {} + ; + +opt_lock_wait_timeout: + /* empty */ + {} + | WAIT_SYM ulong_num + { + if (unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("lock_wait_timeout"), $2)) || + unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("innodb_lock_wait_timeout"), $2))) + MYSQL_YYABORT; + } + | NOWAIT_SYM + { + if (unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("lock_wait_timeout"), 0)) || + unlikely(set_statement_var_if_exists(thd, STRING_WITH_LEN("innodb_lock_wait_timeout"), 0))) + MYSQL_YYABORT; + } + ; + +table_or_tables: + TABLE_SYM { } + | TABLES { } + ; + +table_lock_list: + table_lock + | table_lock_list ',' table_lock + ; + +table_lock: + table_ident opt_table_alias_clause lock_option + { + thr_lock_type lock_type= (thr_lock_type) $3; + bool lock_for_write= (lock_type >= TL_FIRST_WRITE); + ulong table_options= lock_for_write ? TL_OPTION_UPDATING : 0; + enum_mdl_type mdl_type= !lock_for_write + ? MDL_SHARED_READ + : lock_type == TL_WRITE_CONCURRENT_INSERT + ? MDL_SHARED_WRITE + : MDL_SHARED_NO_READ_WRITE; + + if (unlikely(!Lex->current_select_or_default()-> + add_table_to_list(thd, $1, $2, table_options, + lock_type, mdl_type))) + MYSQL_YYABORT; + } + ; + +lock_option: + READ_SYM { $$= TL_READ_NO_INSERT; } + | WRITE_SYM { $$= TL_WRITE_DEFAULT; } + | WRITE_SYM CONCURRENT + { + $$= (Lex->sphead ? TL_WRITE_DEFAULT : TL_WRITE_CONCURRENT_INSERT); + } + + | LOW_PRIORITY WRITE_SYM { $$= TL_WRITE_LOW_PRIORITY; } + | READ_SYM LOCAL_SYM { $$= TL_READ; } + ; + +unlock: + UNLOCK_SYM + { + LEX *lex= Lex; + + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK")); + lex->sql_command= SQLCOM_UNLOCK_TABLES; + } + table_or_tables + {} + ; + +/* +** Handler: direct access to ISAM functions +*/ + +handler: + HANDLER_SYM + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + handler_tail + { + Lex->pop_select(); //main select + } + ; + +handler_tail: + table_ident OPEN_SYM opt_table_alias_clause + { + LEX *lex= Lex; + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); + lex->sql_command = SQLCOM_HA_OPEN; + if (!lex->current_select->add_table_to_list(thd, $1, $3, 0)) + MYSQL_YYABORT; + } + | table_ident_nodb CLOSE_SYM + { + LEX *lex= Lex; + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); + lex->sql_command = SQLCOM_HA_CLOSE; + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) + MYSQL_YYABORT; + } + | table_ident_nodb READ_SYM + { + LEX *lex=Lex; + SELECT_LEX *select= Select; + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER")); + lex->clause_that_disallows_subselect= "HANDLER..READ"; + lex->sql_command = SQLCOM_HA_READ; + lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (unlikely(one == NULL)) + MYSQL_YYABORT; + select->limit_params.select_limit= one; + select->limit_params.offset_limit= 0; + lex->limit_rows_examined= 0; + if (!lex->current_select->add_table_to_list(thd, $1, 0, 0)) + MYSQL_YYABORT; + } + handler_read_or_scan opt_where_clause opt_global_limit_clause + { + LEX *lex=Lex; + SELECT_LEX *select= Select; + lex->clause_that_disallows_subselect= NULL; + if (!lex->current_select->limit_params.explicit_limit) + { + Item *one= new (thd->mem_root) Item_int(thd, (int32) 1); + if (one == NULL) + MYSQL_YYABORT; + select->limit_params.select_limit= one; + select->limit_params.offset_limit= 0; + lex->limit_rows_examined= 0; + } + /* Stored functions are not supported for HANDLER READ. */ + if (lex->uses_stored_routines()) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "stored functions in HANDLER ... READ"); + MYSQL_YYABORT; + } + } + ; + +handler_read_or_scan: + handler_scan_function { Lex->ident= null_clex_str; } + | ident handler_rkey_function { Lex->ident= $1; } + ; + +handler_scan_function: + FIRST_SYM { Lex->ha_read_mode = RFIRST; } + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + ; + +handler_rkey_function: + FIRST_SYM { Lex->ha_read_mode = RFIRST; } + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + | PREV_SYM { Lex->ha_read_mode = RPREV; } + | LAST_SYM { Lex->ha_read_mode = RLAST; } + | handler_rkey_mode + { + LEX *lex=Lex; + lex->ha_read_mode = RKEY; + lex->ha_rkey_mode=$1; + if (unlikely(!(lex->insert_list= new (thd->mem_root) List_item))) + MYSQL_YYABORT; + } + '(' values ')' + {} + ; + +handler_rkey_mode: + '=' { $$=HA_READ_KEY_EXACT; } + | GE { $$=HA_READ_KEY_OR_NEXT; } + | LE { $$=HA_READ_KEY_OR_PREV; } + | '>' { $$=HA_READ_AFTER_KEY; } + | '<' { $$=HA_READ_BEFORE_KEY; } + ; + +/* GRANT / REVOKE */ + +revoke: + REVOKE clear_privileges revoke_command + {} + ; + +revoke_command: + grant_privileges ON opt_table grant_ident FROM user_and_role_list + { + if (Lex->stmt_revoke_table(thd, $1, *$4)) + MYSQL_YYABORT; + } + | grant_privileges ON sp_handler grant_ident FROM user_and_role_list + { + if (Lex->stmt_revoke_sp(thd, $1, *$4, *$3)) + MYSQL_YYABORT; + } + | ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list + { + Lex->sql_command = SQLCOM_REVOKE_ALL; + } + | PROXY_SYM ON user FROM user_list + { + if (Lex->stmt_revoke_proxy(thd, $3)) + MYSQL_YYABORT; + } + | admin_option_for_role FROM user_and_role_list + { + Lex->sql_command= SQLCOM_REVOKE_ROLE; + if (unlikely(Lex->users_list.push_front($1, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +admin_option_for_role: + ADMIN_SYM OPTION FOR_SYM grant_role + { Lex->with_admin_option= true; $$= $4; } + | grant_role + { Lex->with_admin_option= false; $$= $1; } + ; + +grant: + GRANT clear_privileges grant_command + {} + ; + +grant_command: + grant_privileges ON opt_table grant_ident TO_SYM grant_list + opt_require_clause opt_grant_options + { + if (Lex->stmt_grant_table(thd, $1, *$4, $8)) + MYSQL_YYABORT; + } + | grant_privileges ON sp_handler grant_ident TO_SYM grant_list + opt_require_clause opt_grant_options + { + if (Lex->stmt_grant_sp(thd, $1, *$4, *$3, $8)) + MYSQL_YYABORT; + } + | PROXY_SYM ON user TO_SYM grant_list opt_grant_option + { + if (Lex->stmt_grant_proxy(thd, $3, $6)) + MYSQL_YYABORT; + } + | grant_role TO_SYM grant_list opt_with_admin_option + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_GRANT_ROLE; + /* The first role is the one that is granted */ + if (unlikely(Lex->users_list.push_front($1, thd->mem_root))) + MYSQL_YYABORT; + } + + ; + +opt_with_admin: + /* nothing */ { Lex->definer = 0; } + | WITH ADMIN_SYM user_or_role { Lex->definer = $3; } + ; + +opt_with_admin_option: + /* nothing */ { Lex->with_admin_option= false; } + | WITH ADMIN_SYM OPTION { Lex->with_admin_option= true; } + ; + +role_list: + grant_role + { + if (unlikely(Lex->users_list.push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | role_list ',' grant_role + { + if (unlikely(Lex->users_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +current_role: + CURRENT_ROLE optional_braces + { + if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + $$->user= current_role; + } + ; + + +role_name: ident_or_text + { + CHARSET_INFO *cs= system_charset_info; + /* trim end spaces (as they'll be lost in mysql.user anyway) */ + $1.length= cs->lengthsp($1.str, $1.length); + ((char*) $1.str)[$1.length] = '\0'; + if (unlikely($1.length == 0)) + my_yyabort_error((ER_INVALID_ROLE, MYF(0), "")); + if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER))))) + MYSQL_YYABORT; + if (lex_string_eq(&$1, &none)) + $$->user= none; + else if (lex_string_eq(&$1, &public_name)) + $$->user= public_name; + else if (check_string_char_length(&($$->user= $1), ER_USERNAME, + username_char_length, cs, 0)) + MYSQL_YYABORT; + $$->host= empty_clex_str; + } + ; + +grant_role: role_name | current_role ; + +opt_table: + /* Empty */ + | TABLE_SYM + ; + +grant_privileges: + object_privilege_list + | ALL opt_privileges + { + if (!($$= new (thd->mem_root) Lex_grant_privilege(GLOBAL_ACLS, true))) + MYSQL_YYABORT; + } + ; + +opt_privileges: + /* empty */ + | PRIVILEGES + ; + +object_privilege_list: + object_privilege + { + if (!($$= new (thd->mem_root) Lex_grant_privilege($1))) + MYSQL_YYABORT; + } + | column_list_privilege + { + if (!($$= new (thd->mem_root) Lex_grant_privilege()) || + $$->add_column_list_privilege(thd, $1.m_columns[0], + $1.m_privilege)) + MYSQL_YYABORT; + } + | object_privilege_list ',' object_privilege + { + ($$= $1)->add_object_privilege($3); + } + | object_privilege_list ',' column_list_privilege + { + if (($$= $1)->add_column_list_privilege(thd, $3.m_columns[0], + $3.m_privilege)) + MYSQL_YYABORT; + } + ; + +column_list_privilege: + column_privilege '(' comma_separated_ident_list ')' + { + $$= Lex_column_list_privilege($3, $1); + } + ; + +column_privilege: + SELECT_SYM { $$= SELECT_ACL; } + | INSERT { $$= INSERT_ACL; } + | UPDATE_SYM { $$= UPDATE_ACL; } + | REFERENCES { $$= REFERENCES_ACL; } + ; + +object_privilege: + SELECT_SYM { $$= SELECT_ACL; } + | INSERT { $$= INSERT_ACL; } + | UPDATE_SYM { $$= UPDATE_ACL; } + | REFERENCES { $$= REFERENCES_ACL; } + | DELETE_SYM { $$= DELETE_ACL;} + | USAGE { $$= NO_ACL; } + | INDEX_SYM { $$= INDEX_ACL;} + | ALTER { $$= ALTER_ACL;} + | CREATE { $$= CREATE_ACL;} + | DROP { $$= DROP_ACL;} + | EXECUTE_SYM { $$= EXECUTE_ACL;} + | RELOAD { $$= RELOAD_ACL;} + | SHUTDOWN { $$= SHUTDOWN_ACL;} + | PROCESS { $$= PROCESS_ACL;} + | FILE_SYM { $$= FILE_ACL;} + | GRANT OPTION { $$= GRANT_ACL;} + | SHOW DATABASES { $$= SHOW_DB_ACL;} + | SUPER_SYM { $$= SUPER_ACL;} + | CREATE TEMPORARY TABLES { $$= CREATE_TMP_ACL;} + | LOCK_SYM TABLES { $$= LOCK_TABLES_ACL; } + | REPLICATION SLAVE { $$= REPL_SLAVE_ACL; } + | REPLICATION CLIENT_SYM { $$= BINLOG_MONITOR_ACL; /*Compatibility*/ } + | CREATE VIEW_SYM { $$= CREATE_VIEW_ACL; } + | SHOW VIEW_SYM { $$= SHOW_VIEW_ACL; } + | CREATE ROUTINE_SYM { $$= CREATE_PROC_ACL; } + | ALTER ROUTINE_SYM { $$= ALTER_PROC_ACL; } + | CREATE USER_SYM { $$= CREATE_USER_ACL; } + | EVENT_SYM { $$= EVENT_ACL;} + | TRIGGER_SYM { $$= TRIGGER_ACL; } + | CREATE TABLESPACE { $$= CREATE_TABLESPACE_ACL; } + | DELETE_SYM HISTORY_SYM { $$= DELETE_HISTORY_ACL; } + | SET USER_SYM { $$= SET_USER_ACL; } + | FEDERATED_SYM ADMIN_SYM { $$= FEDERATED_ADMIN_ACL; } + | CONNECTION_SYM ADMIN_SYM { $$= CONNECTION_ADMIN_ACL; } + | READ_SYM ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; } + | READ_ONLY_SYM ADMIN_SYM { $$= READ_ONLY_ADMIN_ACL; } + | BINLOG_SYM MONITOR_SYM { $$= BINLOG_MONITOR_ACL; } + | BINLOG_SYM ADMIN_SYM { $$= BINLOG_ADMIN_ACL; } + | BINLOG_SYM REPLAY_SYM { $$= BINLOG_REPLAY_ACL; } + | REPLICATION MASTER_SYM ADMIN_SYM { $$= REPL_MASTER_ADMIN_ACL; } + | REPLICATION SLAVE ADMIN_SYM { $$= REPL_SLAVE_ADMIN_ACL; } + | SLAVE MONITOR_SYM { $$= SLAVE_MONITOR_ACL; } + ; + +opt_and: + /* empty */ {} + | AND_SYM {} + ; + +require_list: + require_list_element opt_and require_list + | require_list_element + ; + +require_list_element: + SUBJECT_SYM TEXT_STRING + { + LEX *lex=Lex; + if (lex->account_options.x509_subject.str) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SUBJECT")); + lex->account_options.x509_subject= $2; + } + | ISSUER_SYM TEXT_STRING + { + LEX *lex=Lex; + if (lex->account_options.x509_issuer.str) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "ISSUER")); + lex->account_options.x509_issuer= $2; + } + | CIPHER_SYM TEXT_STRING + { + LEX *lex=Lex; + if (lex->account_options.ssl_cipher.str) + my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "CIPHER")); + lex->account_options.ssl_cipher= $2; + } + ; + +grant_ident: + '*' + { + LEX_CSTRING db; + if (unlikely(Lex->copy_db_to(&db))) + MYSQL_YYABORT; + if (!($$= new (thd->mem_root) Lex_grant_object_name(db, + Lex_grant_object_name::STAR))) + MYSQL_YYABORT; + } + | ident '.' '*' + { + if (!($$= new (thd->mem_root) Lex_grant_object_name($1, + Lex_grant_object_name::IDENT_STAR))) + MYSQL_YYABORT; + } + | '*' '.' '*' + { + if (!($$= new (thd->mem_root) Lex_grant_object_name( + null_clex_str, + Lex_grant_object_name::STAR_STAR))) + MYSQL_YYABORT; + } + | table_ident + { + if (!($$= new (thd->mem_root) Lex_grant_object_name($1))) + MYSQL_YYABORT; + } + ; + +user_list: + user + { + if (unlikely(Lex->users_list.push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | user_list ',' user + { + if (unlikely(Lex->users_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +grant_list: + grant_user + { + if (unlikely(Lex->users_list.push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | grant_list ',' grant_user + { + if (unlikely(Lex->users_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +user_and_role_list: + user_or_role + { + if (unlikely(Lex->users_list.push_back($1, thd->mem_root))) + MYSQL_YYABORT; + } + | user_and_role_list ',' user_or_role + { + if (unlikely(Lex->users_list.push_back($3, thd->mem_root))) + MYSQL_YYABORT; + } + ; + +via_or_with: VIA_SYM | WITH ; +using_or_as: USING | AS ; + +grant_user: + user IDENTIFIED_SYM BY TEXT_STRING + { + $$= $1; + $1->auth= new (thd->mem_root) USER_AUTH(); + $1->auth->pwtext= $4; + } + | user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING + { + $$= $1; + $1->auth= new (thd->mem_root) USER_AUTH(); + $1->auth->auth_str= $5; + } + | user IDENTIFIED_SYM via_or_with auth_expression + { + $$= $1; + $1->auth= $4; + } + | user_or_role + { + $$= $1; + } + ; + +auth_expression: + auth_token OR_SYM auth_expression + { + $$= $1; + DBUG_ASSERT($$->next == NULL); + $$->next= $3; + } + | auth_token + { + $$= $1; + } + ; + +auth_token: + ident_or_text opt_auth_str + { + $$= $2; + $$->plugin= $1; + } + ; + +opt_auth_str: + /* empty */ + { + if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH)))) + MYSQL_YYABORT; + } + | using_or_as TEXT_STRING_sys + { + if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH)))) + MYSQL_YYABORT; + $$->auth_str= $2; + } + | using_or_as PASSWORD_SYM '(' TEXT_STRING ')' + { + if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH)))) + MYSQL_YYABORT; + $$->pwtext= $4; + } + ; + +opt_require_clause: + /* empty */ + | REQUIRE_SYM require_list + { + Lex->account_options.ssl_type= SSL_TYPE_SPECIFIED; + } + | REQUIRE_SYM SSL_SYM + { + Lex->account_options.ssl_type= SSL_TYPE_ANY; + } + | REQUIRE_SYM X509_SYM + { + Lex->account_options.ssl_type= SSL_TYPE_X509; + } + | REQUIRE_SYM NONE_SYM + { + Lex->account_options.ssl_type= SSL_TYPE_NONE; + } + ; + +resource_option: + MAX_QUERIES_PER_HOUR ulong_num + { + Lex->account_options.questions=$2; + Lex->account_options.specified_limits|= USER_RESOURCES::QUERIES_PER_HOUR; + } + | MAX_UPDATES_PER_HOUR ulong_num + { + Lex->account_options.updates=$2; + Lex->account_options.specified_limits|= USER_RESOURCES::UPDATES_PER_HOUR; + } + | MAX_CONNECTIONS_PER_HOUR ulong_num + { + Lex->account_options.conn_per_hour= $2; + Lex->account_options.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR; + } + | MAX_USER_CONNECTIONS_SYM int_num + { + Lex->account_options.user_conn= $2; + Lex->account_options.specified_limits|= USER_RESOURCES::USER_CONNECTIONS; + } + | MAX_STATEMENT_TIME_SYM NUM_literal + { + Lex->account_options.max_statement_time= $2->val_real(); + Lex->account_options.specified_limits|= USER_RESOURCES::MAX_STATEMENT_TIME; + } + ; + +resource_option_list: + resource_option_list resource_option {} + | resource_option {} + ; + +opt_resource_options: + /* empty */ {} + | WITH resource_option_list + ; + + +opt_grant_options: + /* empty */ { $$= NO_ACL; } + | WITH grant_option_list { $$= $2; } + ; + +opt_grant_option: + /* empty */ { $$= NO_ACL; } + | WITH GRANT OPTION { $$= GRANT_ACL; } + ; + +grant_option_list: + grant_option_list grant_option { $$= $1 | $2; } + | grant_option + ; + +grant_option: + GRANT OPTION { $$= GRANT_ACL;} + | resource_option { $$= NO_ACL; } + ; + +begin_stmt_mariadb: + BEGIN_MARIADB_SYM + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_BEGIN; + lex->start_transaction_opt= 0; + } + opt_work {} + ; + +compound_statement: + sp_proc_stmt_compound_ok + { + Lex->sql_command= SQLCOM_COMPOUND; + if (Lex->sp_body_finalize_procedure(thd)) + MYSQL_YYABORT; + } + ; + +opt_not: + /* nothing */ { $$= 0; } + | not { $$= 1; } + ; + +opt_work: + /* empty */ {} + | WORK_SYM {} + ; + +opt_chain: + /* empty */ + { $$= TVL_UNKNOWN; } + | AND_SYM NO_SYM CHAIN_SYM { $$= TVL_NO; } + | AND_SYM CHAIN_SYM { $$= TVL_YES; } + ; + +opt_release: + /* empty */ + { $$= TVL_UNKNOWN; } + | RELEASE_SYM { $$= TVL_YES; } + | NO_SYM RELEASE_SYM { $$= TVL_NO; } + ; + +commit: + COMMIT_SYM opt_work opt_chain opt_release + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_COMMIT; + /* Don't allow AND CHAIN RELEASE. */ + MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES); + lex->tx_chain= $3; + lex->tx_release= $4; + } + ; + +rollback: + ROLLBACK_SYM opt_work opt_chain opt_release + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_ROLLBACK; + /* Don't allow AND CHAIN RELEASE. */ + MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES); + lex->tx_chain= $3; + lex->tx_release= $4; + } + | 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: + SAVEPOINT_SYM ident + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SAVEPOINT; + lex->ident= $2; + } + ; + +release: + RELEASE_SYM SAVEPOINT_SYM ident + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_RELEASE_SAVEPOINT; + lex->ident= $3; + } + ; + +/* + UNIONS : glue selects together +*/ + +unit_type_decl: + UNION_SYM union_option + { $$.unit_type= UNION_TYPE; $$.distinct= $2; } + | INTERSECT_SYM union_option + { $$.unit_type= INTERSECT_TYPE; $$.distinct= $2; } + | EXCEPT_SYM union_option + { $$.unit_type= EXCEPT_TYPE; $$.distinct= $2; } + ; + +/* + Start a UNION, for non-top level query expressions. +*/ +union_option: + /* empty */ { $$=1; } + | DISTINCT { $$=1; } + | ALL { $$=0; } + ; + +query_expression_option: + STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; } + | HIGH_PRIORITY + { + YYPS->m_lock_type= TL_READ_HIGH_PRIORITY; + YYPS->m_mdl_type= MDL_SHARED_READ; + Select->options|= SELECT_HIGH_PRIORITY; + } + | DISTINCT { Select->options|= SELECT_DISTINCT; } + | UNIQUE_SYM { Select->options|= SELECT_DISTINCT; } + | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } + | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; } + | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; } + | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; } + | ALL { Select->options|= SELECT_ALL; } + ; + +/************************************************************************** + + DEFINER clause support. + +**************************************************************************/ + +definer_opt: + no_definer + | definer + ; + +no_definer: + /* empty */ + { + /* + We have to distinguish missing DEFINER-clause from case when + CURRENT_USER specified as definer explicitly in order to properly + handle CREATE TRIGGER statements which come to replication thread + from older master servers (i.e. to create non-suid trigger in this + case). + */ + thd->lex->definer= 0; + } + ; + +definer: + DEFINER_SYM '=' user_or_role + { + Lex->definer= $3; + Lex->account_options.reset(); + } + ; + +/************************************************************************** + + CREATE VIEW statement parts. + +**************************************************************************/ + +view_algorithm: + ALGORITHM_SYM '=' UNDEFINED_SYM { $$= DTYPE_ALGORITHM_UNDEFINED; } + | ALGORITHM_SYM '=' MERGE_SYM { $$= VIEW_ALGORITHM_MERGE; } + | ALGORITHM_SYM '=' TEMPTABLE_SYM { $$= VIEW_ALGORITHM_TMPTABLE; } + ; + +opt_view_suid: + /* empty */ { $$= VIEW_SUID_DEFAULT; } + | view_suid { $$= $1; } + ; + +view_suid: + SQL_SYM SECURITY_SYM DEFINER_SYM { $$= VIEW_SUID_DEFINER; } + | SQL_SYM SECURITY_SYM INVOKER_SYM { $$= VIEW_SUID_INVOKER; } + ; + +view_list_opt: + /* empty */ + {} + | '(' view_list ')' { } + ; + +view_list: + ident + { + Lex->view_list.push_back((LEX_CSTRING*) + thd->memdup(&$1, sizeof(LEX_CSTRING)), + thd->mem_root); + } + | view_list ',' ident + { + Lex->view_list.push_back((LEX_CSTRING*) + thd->memdup(&$3, sizeof(LEX_CSTRING)), + thd->mem_root); + } + ; + +view_select: + { + LEX *lex= Lex; + lex->parsing_options.allows_variable= FALSE; + lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr(); + } + query_expression + view_check_option + { + if (Lex->parsed_create_view($2, $3)) + MYSQL_YYABORT; + } + ; + +view_check_option: + /* empty */ { $$= VIEW_CHECK_NONE; } + | WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; } + | WITH CASCADED CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; } + | WITH LOCAL_SYM CHECK_SYM OPTION { $$= VIEW_CHECK_LOCAL; } + ; + +/************************************************************************** + + CREATE TRIGGER statement parts. + +**************************************************************************/ + +trigger_action_order: + FOLLOWS_SYM + { $$= TRG_ORDER_FOLLOWS; } + | PRECEDES_SYM + { $$= TRG_ORDER_PRECEDES; } + ; + +trigger_follows_precedes_clause: + /* empty */ + { + $$.ordering_clause= TRG_ORDER_NONE; + $$.anchor_trigger_name.str= NULL; + $$.anchor_trigger_name.length= 0; + } + | + trigger_action_order ident_or_text + { + $$.ordering_clause= $1; + $$.anchor_trigger_name= $2; + } + ; + +trigger_tail: + remember_name + opt_if_not_exists + { + if (unlikely(Lex->add_create_options_with_check($2))) + MYSQL_YYABORT; + } + sp_name + trg_action_time + trg_event + ON + remember_name /* $8 */ + { /* $9 */ + Lex->raw_trg_on_table_name_begin= YYLIP->get_tok_start(); + } + table_ident /* $10 */ + FOR_SYM + remember_name /* $12 */ + { /* $13 */ + Lex->raw_trg_on_table_name_end= YYLIP->get_tok_start(); + } + EACH_SYM + ROW_SYM + { + Lex->trg_chistics.ordering_clause_begin= YYLIP->get_cpp_ptr(); + } + trigger_follows_precedes_clause /* $17 */ + { /* $18 */ + LEX *lex= thd->lex; + Lex_input_stream *lip= YYLIP; + + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER")); + + lex->stmt_definition_begin= $1; + lex->ident.str= $8; + lex->ident.length= $12 - $8; + lex->spname= $4; + (*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17); + lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr(); + + if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger, + DEFAULT_AGGREGATE))) + MYSQL_YYABORT; + + lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); + } + sp_proc_stmt /* $19 */ force_lookahead /* $20 */ + { /* $21 */ + LEX *lex= Lex; + + lex->sql_command= SQLCOM_CREATE_TRIGGER; + if (lex->sp_body_finalize_trigger(thd)) + MYSQL_YYABORT; + + /* + 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. + */ + if (!lex->first_select_lex()-> + add_table_to_list(thd, $10, (LEX_CSTRING*) 0, + TL_OPTION_UPDATING, TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) + MYSQL_YYABORT; + } + ; + +/************************************************************************** + + CREATE FUNCTION | PROCEDURE statements parts. + +**************************************************************************/ + + +sf_return_type: + { + LEX *lex= Lex; + lex->init_last_field(&lex->sphead->m_return_field_def, + &empty_clex_str); + } + field_type + { + if (unlikely(Lex->sf_return_fill_definition($2))) + MYSQL_YYABORT; + } + ; + +/*************************************************************************/ + +xa: + XA_SYM begin_or_start xid opt_join_or_resume + { + Lex->sql_command = SQLCOM_XA_START; + } + | XA_SYM END xid opt_suspend + { + Lex->sql_command = SQLCOM_XA_END; + } + | XA_SYM PREPARE_SYM xid + { + Lex->sql_command = SQLCOM_XA_PREPARE; + } + | XA_SYM COMMIT_SYM xid opt_one_phase + { + Lex->sql_command = SQLCOM_XA_COMMIT; + } + | XA_SYM ROLLBACK_SYM xid + { + Lex->sql_command = SQLCOM_XA_ROLLBACK; + } + | XA_SYM RECOVER_SYM opt_format_xid + { + Lex->sql_command = SQLCOM_XA_RECOVER; + Lex->verbose= $3; + } + ; + +opt_format_xid: + /* empty */ { $$= false; } + | FORMAT_SYM '=' ident_or_text + { + if (lex_string_eq(&$3, STRING_WITH_LEN("SQL"))) + $$= true; + else if (lex_string_eq(&$3, STRING_WITH_LEN("RAW"))) + $$= false; + else + { + my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), + "XA RECOVER", $3.str)); + $$= false; + } + } + ; + +xid: + text_string + { + MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE); + if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID))))) + MYSQL_YYABORT; + Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0); + } + | text_string ',' text_string + { + MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE); + if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID))))) + MYSQL_YYABORT; + Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length()); + } + | text_string ',' text_string ',' ulong_num + { + MYSQL_YYABORT_UNLESS($1->length() <= MAXGTRIDSIZE && + $3->length() <= MAXBQUALSIZE && + $5 <= static_cast<ulong>( + std::numeric_limits<int32_t>::max())); + if (unlikely(!(Lex->xid=(XID *)thd->alloc(sizeof(XID))))) + MYSQL_YYABORT; + Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length()); + } + ; + +begin_or_start: + BEGIN_MARIADB_SYM {} + | BEGIN_ORACLE_SYM {} + | START_SYM {} + ; + +opt_join_or_resume: + /* nothing */ { Lex->xa_opt=XA_NONE; } + | JOIN_SYM { Lex->xa_opt=XA_JOIN; } + | RESUME_SYM { Lex->xa_opt=XA_RESUME; } + ; + +opt_one_phase: + /* nothing */ { Lex->xa_opt=XA_NONE; } + | ONE_SYM PHASE_SYM { Lex->xa_opt=XA_ONE_PHASE; } + ; + +opt_suspend: + /* nothing */ + { Lex->xa_opt=XA_NONE; } + | SUSPEND_SYM + { Lex->xa_opt=XA_SUSPEND; } + opt_migrate + ; + +opt_migrate: + /* nothing */ {} + | FOR_SYM MIGRATE_SYM { Lex->xa_opt=XA_FOR_MIGRATE; } + ; + +install: + INSTALL_SYM PLUGIN_SYM opt_if_not_exists ident SONAME_SYM TEXT_STRING_sys + { + if (Lex->stmt_install_plugin($3, $4, $6)) + MYSQL_YYABORT; + } + | INSTALL_SYM SONAME_SYM TEXT_STRING_sys + { + Lex->stmt_install_plugin($3); + } + ; + +uninstall: + UNINSTALL_SYM PLUGIN_SYM opt_if_exists ident + { + if (Lex->stmt_uninstall_plugin_by_name($3, $4)) + MYSQL_YYABORT; + } + | UNINSTALL_SYM SONAME_SYM opt_if_exists TEXT_STRING_sys + { + if (Lex->stmt_uninstall_plugin_by_soname($3, $4)) + MYSQL_YYABORT; + } + ; + +/* Avoid compiler warning from yy_*.cc where yyerrlab1 is not used */ +keep_gcc_happy: + IMPOSSIBLE_ACTION + { + YYERROR; + } + ; + +_empty: + /* Empty */ + ; + +%ifdef MARIADB + + +statement: + verb_clause + ; + +sp_statement: + statement + ; + +sp_if_then_statements: + sp_proc_stmts1 + ; + +sp_case_then_statements: + sp_proc_stmts1 + ; + +reserved_keyword_udt_param_type: + INOUT_SYM + | IN_SYM + | OUT_SYM + ; + +reserved_keyword_udt: + reserved_keyword_udt_not_param_type + | reserved_keyword_udt_param_type + ; + +// Keywords that start an SP block section +keyword_sp_block_section: + BEGIN_MARIADB_SYM + | END + ; + +// Keywords that we allow for labels in SPs. +// Should not include keywords that start a statement or SP characteristics. +keyword_label: + keyword_data_type + | keyword_set_special_case + | keyword_sp_var_and_label + | keyword_sysvar_type + | FUNCTION_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + ; + +keyword_sp_decl: + keyword_data_type + | keyword_cast_type + | keyword_set_special_case + | keyword_sp_block_section + | keyword_sp_head + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | keyword_verb_clause + | FUNCTION_SYM + | WINDOW_SYM + | IGNORED_SYM + ; + +opt_truncate_table_storage_clause: + _empty + ; + + +ident_for_loop_index: + ident + ; + +row_field_name: + ident + { + if (!($$= Lex->row_field_name(thd, $1))) + MYSQL_YYABORT; + } + ; + +while_body: + expr_lex DO_SYM + { + if (unlikely($1->sp_while_loop_expression(thd))) + MYSQL_YYABORT; + } + sp_proc_stmts1 END WHILE_SYM + { + if (unlikely(Lex->sp_while_loop_finalize(thd))) + MYSQL_YYABORT; + } + ; + +for_loop_statements: + DO_SYM sp_proc_stmts1 END FOR_SYM + { } + ; + +sp_label: + label_ident ':' { $$= $1; } + ; + +sp_control_label: + sp_label + ; + +sp_block_label: + sp_label + { + if (unlikely(Lex->spcont->block_label_declare(&$1))) + MYSQL_YYABORT; + $$= $1; + } + ; + +sp_opt_default: + _empty { $$ = NULL; } + | DEFAULT expr { $$ = $2; } + ; + +sp_decl_variable_list_anchored: + sp_decl_idents_init_vars + TYPE_SYM OF_SYM optionally_qualified_column_ident + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $4, $5))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + | sp_decl_idents_init_vars + ROW_SYM TYPE_SYM OF_SYM optionally_qualified_column_ident + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $5, $6))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + ; + +sp_param_name_and_mode: + sp_parameter_type sp_param_name + { + $2->mode= $1; + $$= $2; + } + | sp_param_name + ; + +sp_param: + sp_param_name_and_mode field_type + { + if (unlikely(Lex->sp_param_fill_definition($$= $1, $2))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode ROW_SYM row_type_body + { + if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3))) + MYSQL_YYABORT; + } + | sp_param_anchored + ; + +sp_param_anchored: + sp_param_name_and_mode TYPE_SYM OF_SYM ident '.' ident + { + if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, + $$= $1, $4, + $6))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode TYPE_SYM OF_SYM ident '.' ident '.' ident + { + if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, + $4, $6, $8))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode ROW_SYM TYPE_SYM OF_SYM ident + { + if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode ROW_SYM TYPE_SYM OF_SYM ident '.' ident + { + if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $5, $7))) + MYSQL_YYABORT; + } + ; + + +sf_c_chistics_and_body_standalone: + sp_c_chistics + { + LEX *lex= thd->lex; + lex->sphead->set_c_chistics(lex->sp_chistics); + lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_proc_stmt_in_returns_clause force_lookahead + { + if (unlikely(Lex->sp_body_finalize_function(thd))) + MYSQL_YYABORT; + } + ; + +sp_tail_standalone: + sp_name + { + if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, + &sp_handler_procedure, + DEFAULT_AGGREGATE))) + MYSQL_YYABORT; + } + sp_parenthesized_pdparam_list + sp_c_chistics + { + Lex->sphead->set_c_chistics(Lex->sp_chistics); + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_proc_stmt force_lookahead + { + if (unlikely(Lex->sp_body_finalize_procedure(thd))) + MYSQL_YYABORT; + } + ; + +drop_routine: + DROP FUNCTION_SYM opt_if_exists ident '.' ident + { + if (Lex->stmt_drop_function($3, $4, $6)) + MYSQL_YYABORT; + } + | DROP FUNCTION_SYM opt_if_exists ident + { + if (Lex->stmt_drop_function($3, $4)) + MYSQL_YYABORT; + } + | DROP PROCEDURE_SYM opt_if_exists sp_name + { + if (Lex->stmt_drop_procedure($3, $4)) + MYSQL_YYABORT; + } + ; + + +create_routine: + create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists + { + if (Lex->stmt_create_procedure_start($1 | $4)) + MYSQL_YYABORT; + } + sp_tail_standalone + { + Lex->stmt_create_routine_finalize(); + } + | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists + sp_name + { + if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6)) + MYSQL_YYABORT; + } + sp_parenthesized_fdparam_list + RETURNS_SYM sf_return_type + sf_c_chistics_and_body_standalone + { + Lex->stmt_create_routine_finalize(); + } + | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists + sp_name + { + if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6)) + MYSQL_YYABORT; + } + sp_parenthesized_fdparam_list + RETURNS_SYM sf_return_type + sf_c_chistics_and_body_standalone + { + Lex->stmt_create_routine_finalize(); + } + | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists + ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys + { + if (Lex->stmt_create_udf_function($1 | $5, $3, $6, + (Item_result) $8, $10)) + MYSQL_YYABORT; + } + ; + + +sp_decls: + _empty + { + $$.init(); + } + | sp_decls sp_decl ';' + { + // We check for declarations out of (standard) order this way + // because letting the grammar rules reflect it caused tricky + // shift/reduce conflicts with the wrong result. (And we get + // better error handling this way.) + if (unlikely(Lex->sp_declarations_join(&$$, $1, $2))) + MYSQL_YYABORT; + } + ; + +sp_decl: + DECLARE_MARIADB_SYM sp_decl_body { $$= $2; } + ; + + +sp_decl_body: + sp_decl_variable_list + | sp_decl_ident CONDITION_SYM FOR_SYM sp_cond + { + if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4))) + MYSQL_YYABORT; + $$.vars= $$.hndlrs= $$.curs= 0; + $$.conds= 1; + } + | sp_decl_handler + | sp_decl_ident CURSOR_SYM + { + Lex->sp_block_init(thd); + } + opt_parenthesized_cursor_formal_parameters + FOR_SYM sp_cursor_stmt + { + sp_pcontext *param_ctx= Lex->spcont; + if (unlikely(Lex->sp_block_finalize(thd))) + MYSQL_YYABORT; + if (unlikely(Lex->sp_declare_cursor(thd, &$1, $6, param_ctx, true))) + MYSQL_YYABORT; + $$.vars= $$.conds= $$.hndlrs= 0; + $$.curs= 1; + } + ; + + + +// ps_proc_stmt_in_returns_clause is a statement that is allowed +// in the RETURNS clause of a stored function definition directly, +// without the BEGIN..END block. +// It should not include any syntax structures starting with '(', to avoid +// shift/reduce conflicts with the rule "field_type" and its sub-rules +// that scan an optional length, like CHAR(1) or YEAR(4). +// See MDEV-9166. + +sp_proc_stmt_in_returns_clause: + sp_proc_stmt_return + | sp_labeled_block + | sp_unlabeled_block + | sp_labeled_control + | sp_proc_stmt_compound_ok + ; + +sp_proc_stmt: + sp_proc_stmt_in_returns_clause + | sp_proc_stmt_statement + | sp_proc_stmt_continue_oracle + | sp_proc_stmt_exit_oracle + | sp_proc_stmt_leave + | sp_proc_stmt_iterate + | sp_proc_stmt_goto_oracle + | sp_proc_stmt_with_cursor + ; + +sp_proc_stmt_compound_ok: + sp_proc_stmt_if + | case_stmt_specification + | sp_unlabeled_block_not_atomic + | sp_unlabeled_control + ; + + +sp_labeled_block: + sp_block_label + BEGIN_MARIADB_SYM + { + Lex->sp_block_init(thd, &$1); + } + sp_decls + sp_proc_stmts + END + sp_opt_label + { + if (unlikely(Lex->sp_block_finalize(thd, $4, &$7))) + MYSQL_YYABORT; + } + ; + +sp_unlabeled_block: + BEGIN_MARIADB_SYM + { + Lex->sp_block_init(thd); + } + sp_decls + sp_proc_stmts + END + { + if (unlikely(Lex->sp_block_finalize(thd, $3))) + MYSQL_YYABORT; + } + ; + +sp_unlabeled_block_not_atomic: + BEGIN_MARIADB_SYM not ATOMIC_SYM // TODO: BEGIN ATOMIC (not -> opt_not) + { + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + Lex->sp_block_init(thd); + } + sp_decls + sp_proc_stmts + END + { + if (unlikely(Lex->sp_block_finalize(thd, $5))) + MYSQL_YYABORT; + } + ; + + +%endif MARIADB + + +%ifdef ORACLE + +statement: + verb_clause + | set_assign + ; + +sp_statement: + statement + | ident_cli_directly_assignable + { + // Direct procedure call (without the CALL keyword) + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->call_statement_start(thd, &tmp))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + | ident_cli_directly_assignable '.' ident + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->call_statement_start(thd, &tmp, &$3))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + | ident_cli_directly_assignable '.' ident '.' ident + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(Lex->call_statement_start(thd, &tmp, &$3, &$5))) + MYSQL_YYABORT; + } + opt_sp_cparam_list + { + if (Lex->check_cte_dependencies_and_resolve_references()) + MYSQL_YYABORT; + } + ; + +sp_if_then_statements: + sp_proc_stmts1_implicit_block { } + ; + +sp_case_then_statements: + sp_proc_stmts1_implicit_block { } + ; + +reserved_keyword_udt: + reserved_keyword_udt_not_param_type + ; + +// Keywords that start an SP block section. +keyword_sp_block_section: + BEGIN_ORACLE_SYM + | END + ; + +// Keywords that we allow for labels in SPs. +// Should not include keywords that start a statement or SP characteristics. +keyword_label: + keyword_data_type + | keyword_set_special_case + | keyword_sp_var_and_label + | keyword_sysvar_type + | FUNCTION_SYM + | COMPRESSED_SYM + | EXCEPTION_ORACLE_SYM + | IGNORED_SYM + ; + +keyword_sp_decl: + keyword_sp_head + | keyword_set_special_case + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | keyword_verb_clause + | WINDOW_SYM + | IGNORED_SYM + ; + +opt_truncate_table_storage_clause: + _empty + | DROP STORAGE_SYM + | REUSE_SYM STORAGE_SYM + ; + + +ident_for_loop_index: + ident_directly_assignable + ; + +row_field_name: + ident_directly_assignable + { + if (!($$= Lex->row_field_name(thd, $1))) + MYSQL_YYABORT; + } + ; + +while_body: + expr_lex LOOP_SYM + { + if (unlikely($1->sp_while_loop_expression(thd))) + MYSQL_YYABORT; + } + sp_proc_stmts1 END LOOP_SYM + { + if (unlikely(Lex->sp_while_loop_finalize(thd))) + MYSQL_YYABORT; + } + ; + +for_loop_statements: + LOOP_SYM sp_proc_stmts1 END LOOP_SYM + { } + ; + + +sp_control_label: + labels_declaration_oracle + ; + +sp_block_label: + labels_declaration_oracle + { + if (unlikely(Lex->spcont->block_label_declare(&$1))) + MYSQL_YYABORT; + $$= $1; + } + ; + + +remember_end_opt: + { + if (yychar == YYEMPTY) + $$= (char*) YYLIP->get_cpp_ptr_rtrim(); + else + $$= (char*) YYLIP->get_cpp_tok_end_rtrim(); + } + ; + +sp_opt_default: + _empty { $$ = NULL; } + | DEFAULT expr { $$ = $2; } + | SET_VAR expr { $$ = $2; } + ; + +sp_opt_inout: + _empty { $$= sp_variable::MODE_IN; } + | sp_parameter_type + | IN_SYM OUT_SYM { $$= sp_variable::MODE_INOUT; } + ; + +sp_proc_stmts1_implicit_block: + { + Lex->sp_block_init(thd); + } + sp_proc_stmts1 + { + if (unlikely(Lex->sp_block_finalize(thd))) + MYSQL_YYABORT; + } + ; + + +remember_lex: + { + $$= thd->lex; + } + ; + +keyword_directly_assignable: + keyword_data_type + | keyword_cast_type + | keyword_set_special_case + | keyword_sp_var_and_label + | keyword_sp_var_not_label + | keyword_sysvar_type + | FUNCTION_SYM + | WINDOW_SYM + ; + +ident_directly_assignable: + IDENT_sys + | keyword_directly_assignable + { + if (unlikely($$.copy_keyword(thd, &$1))) + MYSQL_YYABORT; + } + ; + +ident_cli_directly_assignable: + IDENT_cli + | keyword_directly_assignable { $$= $1; } + ; + + +set_assign: + ident_cli_directly_assignable SET_VAR + { + LEX *lex=Lex; + lex->set_stmt_init(); + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(Lex->set_variable(&tmp, $4)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, + false))) + MYSQL_YYABORT; + } + | ident_cli_directly_assignable '.' ident SET_VAR + { + LEX *lex=Lex; + lex->set_stmt_init(); + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + LEX *lex= Lex; + DBUG_ASSERT(lex->var_list.is_empty()); + Lex_ident_sys tmp(thd, &$1); + if (unlikely(!tmp.str) || + unlikely(lex->set_variable(&tmp, &$3, $6)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, + false))) + MYSQL_YYABORT; + } + | COLON_ORACLE_SYM ident '.' ident SET_VAR + { + LEX *lex= Lex; + if (unlikely(!lex->is_trigger_new_or_old_reference(&$2))) + { + thd->parse_error(ER_SYNTAX_ERROR, $1.pos()); + MYSQL_YYABORT; + } + lex->set_stmt_init(); + if (sp_create_assignment_lex(thd, $1.pos())) + MYSQL_YYABORT; + } + set_expr_or_default + { + LEX_CSTRING tmp= { $2.str, $2.length }; + if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) || + unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY, + false))) + MYSQL_YYABORT; + } + ; + + +labels_declaration_oracle: + label_declaration_oracle { $$= $1; } + | labels_declaration_oracle label_declaration_oracle { $$= $2; } + ; + +label_declaration_oracle: + SHIFT_LEFT label_ident SHIFT_RIGHT + { + if (unlikely(Lex->sp_push_goto_label(thd, &$2))) + MYSQL_YYABORT; + $$= $2; + } + ; + +opt_exception_clause: + _empty { $$= 0; } + | EXCEPTION_ORACLE_SYM exception_handlers { $$= $2; } + ; + +exception_handlers: + exception_handler { $$= 1; } + | exception_handlers exception_handler { $$= $1 + 1; } + ; + +exception_handler: + WHEN_SYM + { + if (unlikely(Lex->sp_handler_declaration_init(thd, sp_handler::EXIT))) + MYSQL_YYABORT; + } + sp_hcond_list + THEN_SYM + sp_proc_stmts1_implicit_block + { + if (unlikely(Lex->sp_handler_declaration_finalize(thd, sp_handler::EXIT))) + MYSQL_YYABORT; + } + ; + +sp_no_param: + _empty + { + Lex->sphead->m_param_begin= Lex->sphead->m_param_end= + YYLIP->get_cpp_tok_start() + 1; + } + ; + +opt_sp_parenthesized_fdparam_list: + sp_no_param + | sp_parenthesized_fdparam_list + ; + +opt_sp_parenthesized_pdparam_list: + sp_no_param + | sp_parenthesized_pdparam_list + ; + + +opt_sp_name: + _empty { $$= NULL; } + | sp_name { $$= $1; } + ; + + +opt_package_routine_end_name: + _empty { $$= null_clex_str; } + | ident { $$= $1; } + ; + +sp_tail_is: + IS + | AS + ; + +sp_instr_addr: + { $$= Lex->sphead->instructions(); } + ; + +sp_body: + { + Lex->sp_block_init(thd); + } + opt_sp_decl_body_list + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + BEGIN_ORACLE_SYM + sp_block_statements_and_exceptions + { + $2.hndlrs+= $5.hndlrs; + if (unlikely(Lex->sp_block_finalize(thd, $2))) + MYSQL_YYABORT; + } + END + ; + +create_package_chistic: + COMMENT_SYM TEXT_STRING_sys + { Lex->sp_chistics.comment= $2; } + | sp_suid + { Lex->sp_chistics.suid= $1; } + ; + +create_package_chistics: + create_package_chistic {} + | create_package_chistics create_package_chistic { } + ; + +opt_create_package_chistics: + _empty + | create_package_chistics { } + ; + +opt_create_package_chistics_init: + { Lex->sp_chistics.init(); } + opt_create_package_chistics + ; + + +package_implementation_executable_section: + END + { + if (unlikely(Lex->sp_block_with_exceptions_add_empty(thd))) + MYSQL_YYABORT; + $$.init(0); + } + | BEGIN_ORACLE_SYM sp_block_statements_and_exceptions END { $$= $2; } + ; + + +// Inside CREATE PACKAGE BODY, package-wide items (e.g. variables) +// must be declared before routine definitions. + +package_implementation_declare_section: + package_implementation_declare_section_list1 + | package_implementation_declare_section_list2 + | package_implementation_declare_section_list1 + package_implementation_declare_section_list2 + { $$.join($1, $2); } + ; + +package_implementation_declare_section_list1: + package_implementation_item_declaration + | package_implementation_declare_section_list1 + package_implementation_item_declaration + { $$.join($1, $2); } + ; + +package_implementation_declare_section_list2: + package_implementation_routine_definition + | package_implementation_declare_section_list2 + package_implementation_routine_definition + { $$.join($1, $2); } + ; + +package_routine_lex: + { + if (unlikely(!($$= new (thd->mem_root) + sp_lex_local(thd, thd->lex)))) + MYSQL_YYABORT; + thd->m_parser_state->m_yacc.reset_before_substatement(); + } + ; + + +package_specification_function: + remember_lex package_routine_lex ident + { + DBUG_ASSERT($1->sphead->get_package()); + $2->sql_command= SQLCOM_CREATE_FUNCTION; + sp_name *spname= $1->make_sp_name_package_routine(thd, &$3); + if (unlikely(!spname)) + MYSQL_YYABORT; + thd->lex= $2; + if (unlikely(!$2->make_sp_head_no_recursive(thd, spname, + &sp_handler_package_function, + NOT_AGGREGATE))) + MYSQL_YYABORT; + $1->sphead->get_package()->m_current_routine= $2; + (void) is_native_function_with_warn(thd, &$3); + } + opt_sp_parenthesized_fdparam_list + RETURN_ORACLE_SYM sf_return_type + sp_c_chistics + { + sp_head *sp= thd->lex->sphead; + sp->restore_thd_mem_root(thd); + thd->lex= $1; + $$= $2; + } + ; + +package_specification_procedure: + remember_lex package_routine_lex ident + { + DBUG_ASSERT($1->sphead->get_package()); + $2->sql_command= SQLCOM_CREATE_PROCEDURE; + sp_name *spname= $1->make_sp_name_package_routine(thd, &$3); + if (unlikely(!spname)) + MYSQL_YYABORT; + thd->lex= $2; + if (unlikely(!$2->make_sp_head_no_recursive(thd, spname, + &sp_handler_package_procedure, + DEFAULT_AGGREGATE))) + MYSQL_YYABORT; + $1->sphead->get_package()->m_current_routine= $2; + } + opt_sp_parenthesized_pdparam_list + sp_c_chistics + { + sp_head *sp= thd->lex->sphead; + sp->restore_thd_mem_root(thd); + thd->lex= $1; + $$= $2; + } + ; + + +package_implementation_routine_definition: + FUNCTION_SYM package_specification_function + package_implementation_function_body ';' + { + sp_package *pkg= Lex->get_sp_package(); + if (unlikely(pkg->add_routine_implementation($2))) + MYSQL_YYABORT; + pkg->m_current_routine= NULL; + $$.init(); + } + | PROCEDURE_SYM package_specification_procedure + package_implementation_procedure_body ';' + { + sp_package *pkg= Lex->get_sp_package(); + if (unlikely(pkg->add_routine_implementation($2))) + MYSQL_YYABORT; + pkg->m_current_routine= NULL; + $$.init(); + } + | package_specification_element { $$.init(); } + ; + + +package_implementation_function_body: + sp_tail_is remember_lex + { + sp_package *pkg= Lex->get_sp_package(); + sp_head *sp= pkg->m_current_routine->sphead; + thd->lex= pkg->m_current_routine; + sp->reset_thd_mem_root(thd); + sp->set_c_chistics(thd->lex->sp_chistics); + sp->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_body opt_package_routine_end_name + { + if (unlikely(thd->lex->sp_body_finalize_function(thd) || + thd->lex->sphead->check_package_routine_end_name($5))) + MYSQL_YYABORT; + thd->lex= $2; + } + ; + +package_implementation_procedure_body: + sp_tail_is remember_lex + { + sp_package *pkg= Lex->get_sp_package(); + sp_head *sp= pkg->m_current_routine->sphead; + thd->lex= pkg->m_current_routine; + sp->reset_thd_mem_root(thd); + sp->set_c_chistics(thd->lex->sp_chistics); + sp->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_body opt_package_routine_end_name + { + if (unlikely(thd->lex->sp_body_finalize_procedure(thd) || + thd->lex->sphead->check_package_routine_end_name($5))) + MYSQL_YYABORT; + thd->lex= $2; + } + ; + + +package_implementation_item_declaration: + sp_decl_variable_list ';' + ; + +opt_package_specification_element_list: + _empty + | package_specification_element_list + ; + +package_specification_element_list: + package_specification_element + | package_specification_element_list package_specification_element + ; + +package_specification_element: + FUNCTION_SYM package_specification_function ';' + { + sp_package *pkg= Lex->get_sp_package(); + if (unlikely(pkg->add_routine_declaration($2))) + MYSQL_YYABORT; + pkg->m_current_routine= NULL; + } + | PROCEDURE_SYM package_specification_procedure ';' + { + sp_package *pkg= Lex->get_sp_package(); + if (unlikely(pkg->add_routine_declaration($2))) + MYSQL_YYABORT; + pkg->m_current_routine= NULL; + } + ; + +sp_decl_variable_list_anchored: + sp_decl_idents_init_vars + optionally_qualified_column_ident PERCENT_ORACLE_SYM TYPE_SYM + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $2, $5))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + | sp_decl_idents_init_vars + optionally_qualified_column_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM + sp_opt_default + { + if (unlikely(Lex->sp_variable_declarations_rowtype_finalize(thd, $1, $2, $5))) + MYSQL_YYABORT; + $$.init_using_vars($1); + } + ; + +sp_param_name_and_mode: + sp_param_name sp_opt_inout + { + $1->mode= $2; + $$= $1; + } + ; + +sp_param: + sp_param_name_and_mode field_type + { + if (unlikely(Lex->sp_param_fill_definition($$= $1, $2))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode ROW_SYM row_type_body + { + if (unlikely(Lex->sphead->spvar_fill_row(thd, $$= $1, $3))) + MYSQL_YYABORT; + } + | sp_param_anchored + ; + +sp_param_anchored: + sp_param_name_and_mode sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM + { + if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM + { + if (unlikely(Lex->sphead->spvar_fill_type_reference(thd, $$= $1, $2, $4, $6))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode sp_decl_ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM + { + if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2))) + MYSQL_YYABORT; + } + | sp_param_name_and_mode sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM + { + if (unlikely(Lex->sphead->spvar_fill_table_rowtype_reference(thd, $$= $1, $2, $4))) + MYSQL_YYABORT; + } + ; + + +sf_c_chistics_and_body_standalone: + sp_c_chistics + { + LEX *lex= thd->lex; + lex->sphead->set_c_chistics(lex->sp_chistics); + lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_tail_is sp_body force_lookahead + { + if (unlikely(Lex->sp_body_finalize_function(thd))) + MYSQL_YYABORT; + } + ; + +sp_tail_standalone: + sp_name + { + if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, + &sp_handler_procedure, + DEFAULT_AGGREGATE))) + MYSQL_YYABORT; + } + opt_sp_parenthesized_pdparam_list + sp_c_chistics + { + Lex->sphead->set_c_chistics(Lex->sp_chistics); + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_tail_is + sp_body + opt_sp_name + { + if (unlikely(Lex->sp_body_finalize_procedure_standalone(thd, $8))) + MYSQL_YYABORT; + } + ; + +drop_routine: + DROP FUNCTION_SYM opt_if_exists ident '.' ident + { + if (Lex->stmt_drop_function($3, $4, $6)) + MYSQL_YYABORT; + } + | DROP FUNCTION_SYM opt_if_exists ident + { + if (Lex->stmt_drop_function($3, $4)) + MYSQL_YYABORT; + } + | DROP PROCEDURE_SYM opt_if_exists sp_name + { + if (Lex->stmt_drop_procedure($3, $4)) + MYSQL_YYABORT; + } + | DROP PACKAGE_ORACLE_SYM opt_if_exists sp_name + { + LEX *lex= Lex; + lex->set_command(SQLCOM_DROP_PACKAGE, $3); + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE")); + lex->spname= $4; + } + | DROP PACKAGE_ORACLE_SYM BODY_ORACLE_SYM opt_if_exists sp_name + { + LEX *lex= Lex; + lex->set_command(SQLCOM_DROP_PACKAGE_BODY, $4); + if (unlikely(lex->sphead)) + my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PACKAGE BODY")); + lex->spname= $5; + } + ; + + +create_routine: + create_or_replace definer_opt PROCEDURE_SYM opt_if_not_exists + { + if (Lex->stmt_create_procedure_start($1 | $4)) + MYSQL_YYABORT; + } + sp_tail_standalone + { + Lex->stmt_create_routine_finalize(); + } + | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists + sp_name + { + if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6)) + MYSQL_YYABORT; + } + opt_sp_parenthesized_fdparam_list + RETURN_ORACLE_SYM sf_return_type + sf_c_chistics_and_body_standalone + opt_sp_name + { + if (Lex->stmt_create_stored_function_finalize_standalone($12)) + MYSQL_YYABORT; + } + | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists + sp_name + { + if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6)) + MYSQL_YYABORT; + } + opt_sp_parenthesized_fdparam_list + RETURN_ORACLE_SYM sf_return_type + sf_c_chistics_and_body_standalone + opt_sp_name + { + if (Lex->stmt_create_stored_function_finalize_standalone($12)) + MYSQL_YYABORT; + } + | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists + ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys + { + if (Lex->stmt_create_udf_function($1 | $5, $3, $6, + (Item_result) $8, $10)) + MYSQL_YYABORT; + } + | create_or_replace definer_opt PACKAGE_ORACLE_SYM + opt_if_not_exists sp_name opt_create_package_chistics_init + { + sp_package *pkg; + if (unlikely(!(pkg= Lex-> + create_package_start(thd, + SQLCOM_CREATE_PACKAGE, + &sp_handler_package_spec, + $5, $1 | $4)))) + MYSQL_YYABORT; + pkg->set_c_chistics(Lex->sp_chistics); + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + } + sp_tail_is + opt_package_specification_element_list END + remember_end_opt opt_sp_name + { + if (unlikely(Lex->create_package_finalize(thd, $5, $12, $11))) + MYSQL_YYABORT; + } + | create_or_replace definer_opt PACKAGE_ORACLE_SYM BODY_ORACLE_SYM + opt_if_not_exists sp_name opt_create_package_chistics_init + { + sp_package *pkg; + if (unlikely(!(pkg= Lex-> + create_package_start(thd, + SQLCOM_CREATE_PACKAGE_BODY, + &sp_handler_package_body, + $6, $1 | $5)))) + MYSQL_YYABORT; + pkg->set_c_chistics(Lex->sp_chistics); + Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); + Lex->sp_block_init(thd); + } + sp_tail_is + package_implementation_declare_section + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + package_implementation_executable_section + { + $10.hndlrs+= $12.hndlrs; + if (unlikely(Lex->sp_block_finalize(thd, $10))) + MYSQL_YYABORT; + } + remember_end_opt opt_sp_name + { + if (unlikely(Lex->create_package_finalize(thd, $6, $15, $14))) + MYSQL_YYABORT; + } + ; + +opt_sp_decl_body_list: + _empty + { + $$.init(); + } + | sp_decl_body_list { $$= $1; } + ; + +sp_decl_body_list: + sp_decl_non_handler_list + { + if (unlikely(Lex->sphead->sp_add_instr_cpush_for_cursors(thd, Lex->spcont))) + MYSQL_YYABORT; + } + opt_sp_decl_handler_list + { + $$.join($1, $3); + } + | sp_decl_handler_list + ; + +sp_decl_non_handler_list: + sp_decl_non_handler ';' { $$= $1; } + | sp_decl_non_handler_list sp_decl_non_handler ';' + { + $$.join($1, $2); + } + ; + +sp_decl_handler_list: + sp_decl_handler ';' { $$= $1; } + | sp_decl_handler_list sp_decl_handler ';' + { + $$.join($1, $2); + } + ; + +opt_sp_decl_handler_list: + _empty { $$.init(); } + | sp_decl_handler_list + ; + +sp_decl_non_handler: + sp_decl_variable_list + | ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond + { + if (unlikely(Lex->spcont->declare_condition(thd, &$1, $4))) + MYSQL_YYABORT; + $$.vars= $$.hndlrs= $$.curs= 0; + $$.conds= 1; + } + | ident_directly_assignable EXCEPTION_ORACLE_SYM + { + sp_condition_value *spcond= new (thd->mem_root) + sp_condition_value_user_defined(); + if (unlikely(!spcond) || + unlikely(Lex->spcont->declare_condition(thd, &$1, spcond))) + MYSQL_YYABORT; + $$.vars= $$.hndlrs= $$.curs= 0; + $$.conds= 1; + } + | CURSOR_SYM ident_directly_assignable + { + Lex->sp_block_init(thd); + } + opt_parenthesized_cursor_formal_parameters + IS sp_cursor_stmt + { + sp_pcontext *param_ctx= Lex->spcont; + if (unlikely(Lex->sp_block_finalize(thd))) + MYSQL_YYABORT; + if (unlikely(Lex->sp_declare_cursor(thd, &$2, $6, param_ctx, false))) + MYSQL_YYABORT; + $$.vars= $$.conds= $$.hndlrs= 0; + $$.curs= 1; + } + ; + + +sp_proc_stmt: + sp_labeled_block + | sp_unlabeled_block + | sp_labeled_control + | sp_unlabeled_control + | sp_labelable_stmt + | labels_declaration_oracle sp_labelable_stmt {} + ; + +sp_labelable_stmt: + sp_proc_stmt_statement + | sp_proc_stmt_continue_oracle + | sp_proc_stmt_exit_oracle + | sp_proc_stmt_leave + | sp_proc_stmt_iterate + | sp_proc_stmt_goto_oracle + | sp_proc_stmt_with_cursor + | sp_proc_stmt_return + | sp_proc_stmt_if + | case_stmt_specification + | NULL_SYM { } + ; + +sp_proc_stmt_compound_ok: + sp_proc_stmt_if + | case_stmt_specification + | sp_unlabeled_block + | sp_unlabeled_control + ; + + +sp_labeled_block: + sp_block_label + BEGIN_ORACLE_SYM + { + Lex->sp_block_init(thd, &$1); + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + sp_block_statements_and_exceptions + END + sp_opt_label + { + if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4), &$6))) + MYSQL_YYABORT; + } + | sp_block_label + DECLARE_ORACLE_SYM + { + Lex->sp_block_init(thd, &$1); + } + opt_sp_decl_body_list + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + BEGIN_ORACLE_SYM + sp_block_statements_and_exceptions + END + sp_opt_label + { + $4.hndlrs+= $7.hndlrs; + if (unlikely(Lex->sp_block_finalize(thd, $4, &$9))) + MYSQL_YYABORT; + } + ; + +opt_not_atomic: + _empty + | not ATOMIC_SYM // TODO: BEGIN ATOMIC (not -> opt_not) + ; + +sp_unlabeled_block: + BEGIN_ORACLE_SYM opt_not_atomic + { + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + Lex->sp_block_init(thd); + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + sp_block_statements_and_exceptions + END + { + if (unlikely(Lex->sp_block_finalize(thd, Lex_spblock($4)))) + MYSQL_YYABORT; + } + | DECLARE_ORACLE_SYM + { + if (unlikely(Lex->maybe_start_compound_statement(thd))) + MYSQL_YYABORT; + Lex->sp_block_init(thd); + } + opt_sp_decl_body_list + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_declarations(thd))) + MYSQL_YYABORT; + } + BEGIN_ORACLE_SYM + sp_block_statements_and_exceptions + END + { + $3.hndlrs+= $6.hndlrs; + if (unlikely(Lex->sp_block_finalize(thd, $3))) + MYSQL_YYABORT; + } + ; + +sp_block_statements_and_exceptions: + sp_instr_addr + sp_proc_stmts + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_executable_section(thd, $1))) + MYSQL_YYABORT; + } + opt_exception_clause + { + if (unlikely(Lex->sp_block_with_exceptions_finalize_exceptions(thd, $1, $4))) + MYSQL_YYABORT; + $$.init($4); + } + ; + +%endif ORACLE + +/** + @} (end of group Parser) +*/ |