mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
92e68d49d7
Changed header to GPL version 2 only client/mysqlslap.c: Changed header to GPL version 2 only include/atomic/nolock.h: Changed header to GPL version 2 only include/atomic/rwlock.h: Changed header to GPL version 2 only include/atomic/x86-gcc.h: Changed header to GPL version 2 only include/atomic/x86-msvc.h: Changed header to GPL version 2 only include/my_atomic.h: Changed header to GPL version 2 only include/my_trie.h: Changed header to GPL version 2 only include/my_vle.h: Changed header to GPL version 2 only include/mysql/plugin.h: Changed header to GPL version 2 only mysys/my_atomic.c: Changed header to GPL version 2 only mysys/my_getncpus.c: Changed header to GPL version 2 only mysys/my_memmem.c: Changed header to GPL version 2 only mysys/my_vle.c: Changed header to GPL version 2 only mysys/trie.c: Changed header to GPL version 2 only plugin/Makefile.am: Changed header to GPL version 2 only server-tools/instance-manager/IMService.h: Changed header to GPL version 2 only server-tools/instance-manager/WindowsService.h: Changed header to GPL version 2 only server-tools/instance-manager/exit_codes.h: Changed header to GPL version 2 only server-tools/instance-manager/user_management_commands.h: Changed header to GPL version 2 only sql/authors.h: Changed header to GPL version 2 only sql/contributors.h: Changed header to GPL version 2 only sql/event_data_objects.cc: Changed header to GPL version 2 only sql/event_data_objects.h: Changed header to GPL version 2 only sql/event_db_repository.cc: Changed header to GPL version 2 only sql/event_db_repository.h: Changed header to GPL version 2 only sql/event_queue.cc: Changed header to GPL version 2 only sql/event_queue.h: Changed header to GPL version 2 only sql/event_scheduler.cc: Changed header to GPL version 2 only sql/event_scheduler.h: Changed header to GPL version 2 only sql/events.cc: Changed header to GPL version 2 only sql/events.h: Changed header to GPL version 2 only sql/ha_ndbcluster_binlog.cc: Changed header to GPL version 2 only sql/ha_ndbcluster_binlog.h: Changed header to GPL version 2 only sql/ha_ndbcluster_tables.h: Changed header to GPL version 2 only sql/ha_partition.cc: Changed header to GPL version 2 only sql/ha_partition.h: Changed header to GPL version 2 only sql/item_xmlfunc.cc: Changed header to GPL version 2 only sql/item_xmlfunc.h: Changed header to GPL version 2 only sql/log.h: Changed header to GPL version 2 only sql/partition_element.h: Changed header to GPL version 2 only sql/partition_info.cc: Changed header to GPL version 2 only sql/partition_info.h: Changed header to GPL version 2 only sql/rpl_filter.cc: Changed header to GPL version 2 only sql/rpl_filter.h: Changed header to GPL version 2 only sql/rpl_injector.cc: Changed header to GPL version 2 only sql/rpl_injector.h: Changed header to GPL version 2 only sql/rpl_mi.cc: Changed header to GPL version 2 only sql/rpl_mi.h: Changed header to GPL version 2 only sql/rpl_rli.cc: Changed header to GPL version 2 only sql/rpl_rli.h: Changed header to GPL version 2 only sql/rpl_tblmap.cc: Changed header to GPL version 2 only sql/rpl_tblmap.h: Changed header to GPL version 2 only sql/rpl_utility.cc: Changed header to GPL version 2 only sql/rpl_utility.h: Changed header to GPL version 2 only sql/sql_binlog.cc: Changed header to GPL version 2 only sql/sql_partition.cc: Changed header to GPL version 2 only sql/sql_partition.h: Changed header to GPL version 2 only sql/sql_plugin.cc: Changed header to GPL version 2 only sql/sql_plugin.h: Changed header to GPL version 2 only sql/sql_servers.cc: Changed header to GPL version 2 only sql/sql_servers.h: Changed header to GPL version 2 only sql/sql_tablespace.cc: Changed header to GPL version 2 only sql/sql_yacc.yy.bak: Changed header to GPL version 2 only storage/Makefile.am: Changed header to GPL version 2 only storage/archive/Makefile.am: Changed header to GPL version 2 only storage/blackhole/Makefile.am: Changed header to GPL version 2 only storage/csv/Makefile.am: Changed header to GPL version 2 only storage/example/Makefile.am: Changed header to GPL version 2 only storage/federated/Makefile.am: Changed header to GPL version 2 only storage/innobase/handler/Makefile.am: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/AllocNodeId.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateObj.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DictObjOp.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DihFragCount.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropFilegroup.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropObj.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/Extent.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RestoreImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RouteOrd.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/ndbapi/NdbIndexStat.hpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/mgmapi_logevent/mgmapi_logevent.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/mgmapi_logevent_dual/mgmapi_logevent_dual.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_async/ndbapi_async.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_async1/ndbapi_async1.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_retries/ndbapi_retries.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple/ndbapi_simple.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple_dual/ndbapi_simple_dual.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple_index/ndbapi_simple_index.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/diskpage.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/lgman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/lgman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/pgman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/pgman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/print_file.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/record_types.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/restore.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/restore.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/tsman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/tsman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DLCFifoList.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DLCHashTable.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DynArr256.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DynArr256.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/KeyTable2Ref.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/LinearPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/NdbdSuperPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/NdbdSuperPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Pool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Pool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/RWPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/RWPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Rope.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/SLFifoList.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/WOPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/WOPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/bench_pool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp: Changed header to GPL version 2 only storage/ndb/src/mgmsrv/ParamInfo.cpp: Changed header to GPL version 2 only storage/ndb/src/ndbapi/NdbIndexStat.cpp: Changed header to GPL version 2 only storage/ndb/test/ndbapi/testIndexStat.cpp: Changed header to GPL version 2 only storage/ndb/test/tools/listen.cpp: Changed header to GPL version 2 only storage/ndb/tools/restore/ndb_nodegroup_map.h: Changed header to GPL version 2 only strings/my_strchr.c: Changed header to GPL version 2 only unittest/mysys/base64-t.c: Changed header to GPL version 2 only unittest/mysys/bitmap-t.c: Changed header to GPL version 2 only unittest/mysys/my_atomic-t.c: Changed header to GPL version 2 only unittest/mytap/tap.c: Changed header to GPL version 2 only unittest/mytap/tap.h: Changed header to GPL version 2 only win/Makefile.am: Changed header to GPL version 2 only
11278 lines
301 KiB
Text
11278 lines
301 KiB
Text
/* Copyright (C) 2000-2003 MySQL AB
|
||
|
||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||
|
||
/* sql_yacc.yy */
|
||
|
||
%{
|
||
/* thd is passed as an arg to yyparse(), and subsequently to yylex().
|
||
** The type will be void*, so it must be cast to (THD*) when used.
|
||
** Use the YYTHD macro for this.
|
||
*/
|
||
#define YYPARSE_PARAM yythd
|
||
#define YYLEX_PARAM yythd
|
||
#define YYTHD ((THD *)yythd)
|
||
|
||
#define MYSQL_YACC
|
||
#define YYINITDEPTH 100
|
||
#define YYMAXDEPTH 3200 /* Because of 64K stack */
|
||
#define Lex (YYTHD->lex)
|
||
#define Select Lex->current_select
|
||
#include "mysql_priv.h"
|
||
#include "slave.h"
|
||
#include "lex_symbol.h"
|
||
#include "item_create.h"
|
||
#include "sp_head.h"
|
||
#include "sp_pcontext.h"
|
||
#include "sp_rcontext.h"
|
||
#include "sp.h"
|
||
#include "event_data_objects.h"
|
||
#include <myisam.h>
|
||
#include <myisammrg.h>
|
||
|
||
int yylex(void *yylval, void *yythd);
|
||
|
||
const LEX_STRING null_lex_str={0,0};
|
||
|
||
#define yyoverflow(A,B,C,D,E,F) {ulong val= *(F); if (my_yyoverflow((B), (D), &val)) { yyerror((char*) (A)); return 2; } else { *(F)= (YYSIZE_T)val; }}
|
||
|
||
#define YYERROR_UNLESS(A) \
|
||
if (!(A)) \
|
||
{ \
|
||
yyerror(ER(ER_SYNTAX_ERROR)); \
|
||
YYABORT; \
|
||
}
|
||
|
||
/* Helper for parsing "IS [NOT] truth_value" */
|
||
inline Item *is_truth_value(THD *thd, Item *A, bool v1, bool v2)
|
||
{
|
||
Item *v1_t= new (thd->mem_root) Item_int((char *) (v1 ? "TRUE" : "FALSE"),
|
||
v1, 1);
|
||
Item *v1_f= new (thd->mem_root) Item_int((char *) (v1 ? "FALSE" : "TRUE"),
|
||
!v1, 1);
|
||
Item *v2_t= new (thd->mem_root) Item_int((char *) (v2 ? "TRUE" : "FALSE"),
|
||
v2, 1);
|
||
Item *ifnull= new (thd->mem_root) Item_func_ifnull(A, v2_t);
|
||
|
||
return new (thd->mem_root) Item_func_if(ifnull, v1_t, v1_f);
|
||
}
|
||
|
||
#ifndef DBUG_OFF
|
||
#define YYDEBUG 1
|
||
#else
|
||
#define YYDEBUG 0
|
||
#endif
|
||
|
||
#ifndef DBUG_OFF
|
||
void turn_parser_debug_on()
|
||
{
|
||
/*
|
||
MYSQLdebug is in sql/sql_yacc.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="d,parser_debug" ...
|
||
- Running a test :
|
||
mysql-test-run.pl --mysqld="--debug=d,parser_debug" ...
|
||
|
||
The result will be in the process stderr (var/log/master.err)
|
||
*/
|
||
|
||
extern int yydebug;
|
||
yydebug= 1;
|
||
}
|
||
#endif
|
||
|
||
static bool is_native_function(THD *thd, const LEX_STRING *name)
|
||
{
|
||
if (find_native_function_builder(thd, *name))
|
||
return true;
|
||
|
||
if (is_lex_native_function(name))
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
%}
|
||
%union {
|
||
int num;
|
||
ulong ulong_num;
|
||
ulonglong ulonglong_number;
|
||
longlong longlong_number;
|
||
LEX_STRING lex_str;
|
||
LEX_STRING *lex_str_ptr;
|
||
LEX_SYMBOL symbol;
|
||
Table_ident *table;
|
||
char *simple_string;
|
||
Item *item;
|
||
Item_num *item_num;
|
||
List<Item> *item_list;
|
||
List<String> *string_list;
|
||
String *string;
|
||
key_part_spec *key_part;
|
||
TABLE_LIST *table_list;
|
||
udf_func *udf;
|
||
LEX_USER *lex_user;
|
||
struct sys_var_with_base variable;
|
||
enum enum_var_type var_type;
|
||
Key::Keytype key_type;
|
||
enum ha_key_alg key_alg;
|
||
handlerton *db_type;
|
||
enum row_type row_type;
|
||
enum ha_rkey_function ha_rkey_mode;
|
||
enum enum_tx_isolation tx_isolation;
|
||
enum Cast_target cast_type;
|
||
enum Item_udftype udf_type;
|
||
CHARSET_INFO *charset;
|
||
thr_lock_type lock_type;
|
||
interval_type interval, interval_time_st;
|
||
timestamp_type date_time_type;
|
||
st_select_lex *select_lex;
|
||
chooser_compare_func_creator boolfunc2creator;
|
||
struct sp_cond_type *spcondtype;
|
||
struct { int vars, conds, hndlrs, curs; } spblock;
|
||
sp_name *spname;
|
||
struct st_lex *lex;
|
||
sp_head *sphead;
|
||
struct p_elem_val *p_elem_value;
|
||
}
|
||
|
||
%{
|
||
bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||
%}
|
||
|
||
%pure_parser /* We have threads */
|
||
|
||
/*
|
||
Comments for TOKENS.
|
||
For each token, please include in the same line a comment that contains
|
||
the following tags:
|
||
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 futur use
|
||
|
||
This makes the code grep-able, and helps maintenance.
|
||
*/
|
||
|
||
%token ABORT_SYM /* INTERNAL (used in lex) */
|
||
%token ACCESSIBLE_SYM
|
||
%token ACTION /* SQL-2003-N */
|
||
%token ADD /* SQL-2003-R */
|
||
%token ADDDATE_SYM /* MYSQL-FUNC */
|
||
%token AFTER_SYM /* SQL-2003-N */
|
||
%token AGAINST
|
||
%token AGGREGATE_SYM
|
||
%token ALGORITHM_SYM
|
||
%token ALL /* SQL-2003-R */
|
||
%token ALTER /* SQL-2003-R */
|
||
%token ANALYZE_SYM
|
||
%token AND_AND_SYM /* OPERATOR */
|
||
%token AND_SYM /* SQL-2003-R */
|
||
%token ANY_SYM /* SQL-2003-R */
|
||
%token AS /* SQL-2003-R */
|
||
%token ASC /* SQL-2003-N */
|
||
%token ASCII_SYM /* MYSQL-FUNC */
|
||
%token ASENSITIVE_SYM /* FUTURE-USE */
|
||
%token AT_SYM /* SQL-2003-R */
|
||
%token AUTHORS_SYM
|
||
%token AUTOEXTEND_SIZE_SYM
|
||
%token AUTO_INC
|
||
%token AVG_ROW_LENGTH
|
||
%token AVG_SYM /* SQL-2003-N */
|
||
%token BACKUP_SYM
|
||
%token BEFORE_SYM /* SQL-2003-N */
|
||
%token BEGIN_SYM /* SQL-2003-R */
|
||
%token BETWEEN_SYM /* SQL-2003-R */
|
||
%token BIGINT /* SQL-2003-R */
|
||
%token BINARY /* SQL-2003-R */
|
||
%token BINLOG_SYM
|
||
%token BIN_NUM
|
||
%token BIT_AND /* MYSQL-FUNC */
|
||
%token BIT_OR /* MYSQL-FUNC */
|
||
%token BIT_SYM /* MYSQL-FUNC */
|
||
%token BIT_XOR /* MYSQL-FUNC */
|
||
%token BLOB_SYM /* SQL-2003-R */
|
||
%token BOOLEAN_SYM /* SQL-2003-R */
|
||
%token BOOL_SYM
|
||
%token BOTH /* SQL-2003-R */
|
||
%token BTREE_SYM
|
||
%token BY /* SQL-2003-R */
|
||
%token BYTE_SYM
|
||
%token CACHE_SYM
|
||
%token CALL_SYM /* SQL-2003-R */
|
||
%token CASCADE /* SQL-2003-N */
|
||
%token CASCADED /* SQL-2003-R */
|
||
%token CASE_SYM /* SQL-2003-R */
|
||
%token CAST_SYM /* SQL-2003-R */
|
||
%token CHAIN_SYM /* SQL-2003-N */
|
||
%token CHANGE
|
||
%token CHANGED
|
||
%token CHARSET
|
||
%token CHAR_SYM /* SQL-2003-R */
|
||
%token CHECKSUM_SYM
|
||
%token CHECK_SYM /* SQL-2003-R */
|
||
%token CIPHER_SYM
|
||
%token CLIENT_SYM
|
||
%token CLOSE_SYM /* SQL-2003-R */
|
||
%token COALESCE /* SQL-2003-N */
|
||
%token CODE_SYM
|
||
%token COLLATE_SYM /* SQL-2003-R */
|
||
%token COLLATION_SYM /* SQL-2003-N */
|
||
%token COLUMNS
|
||
%token COLUMN_SYM /* SQL-2003-R */
|
||
%token COMMENT_SYM
|
||
%token COMMITTED_SYM /* SQL-2003-N */
|
||
%token COMMIT_SYM /* SQL-2003-R */
|
||
%token COMPACT_SYM
|
||
%token COMPLETION_SYM
|
||
%token COMPRESSED_SYM
|
||
%token CONCURRENT
|
||
%token CONDITION_SYM /* SQL-2003-N */
|
||
%token CONNECTION_SYM
|
||
%token CONSISTENT_SYM
|
||
%token CONSTRAINT /* SQL-2003-R */
|
||
%token CONTAINS_SYM /* SQL-2003-N */
|
||
%token CONTINUE_SYM /* SQL-2003-R */
|
||
%token CONTRIBUTORS_SYM
|
||
%token CONVERT_SYM /* SQL-2003-N */
|
||
%token COUNT_SYM /* SQL-2003-N */
|
||
%token CREATE /* SQL-2003-R */
|
||
%token CROSS /* SQL-2003-R */
|
||
%token CUBE_SYM /* SQL-2003-R */
|
||
%token CURDATE /* MYSQL-FUNC */
|
||
%token CURRENT_USER /* SQL-2003-R */
|
||
%token CURSOR_SYM /* SQL-2003-R */
|
||
%token CURTIME /* MYSQL-FUNC */
|
||
%token DATABASE
|
||
%token DATABASES
|
||
%token DATAFILE_SYM
|
||
%token DATA_SYM /* SQL-2003-N */
|
||
%token DATETIME
|
||
%token DATE_ADD_INTERVAL /* MYSQL-FUNC */
|
||
%token DATE_SUB_INTERVAL /* MYSQL-FUNC */
|
||
%token DATE_SYM /* SQL-2003-R */
|
||
%token DAY_HOUR_SYM
|
||
%token DAY_MICROSECOND_SYM
|
||
%token DAY_MINUTE_SYM
|
||
%token DAY_SECOND_SYM
|
||
%token DAY_SYM /* SQL-2003-R */
|
||
%token DEALLOCATE_SYM /* SQL-2003-R */
|
||
%token DECIMAL_NUM
|
||
%token DECIMAL_SYM /* SQL-2003-R */
|
||
%token DECLARE_SYM /* SQL-2003-R */
|
||
%token DEFAULT /* SQL-2003-R */
|
||
%token DEFINER_SYM
|
||
%token DELAYED_SYM
|
||
%token DELAY_KEY_WRITE_SYM
|
||
%token DELETE_SYM /* SQL-2003-R */
|
||
%token DESC /* SQL-2003-N */
|
||
%token DESCRIBE /* SQL-2003-R */
|
||
%token DES_KEY_FILE
|
||
%token DETERMINISTIC_SYM /* SQL-2003-R */
|
||
%token DIRECTORY_SYM
|
||
%token DISABLE_SYM
|
||
%token DISCARD
|
||
%token DISK_SYM
|
||
%token DISTINCT /* SQL-2003-R */
|
||
%token DIV_SYM
|
||
%token DOUBLE_SYM /* SQL-2003-R */
|
||
%token DO_SYM
|
||
%token DROP /* SQL-2003-R */
|
||
%token DUAL_SYM
|
||
%token DUMPFILE
|
||
%token DUPLICATE_SYM
|
||
%token DYNAMIC_SYM /* SQL-2003-R */
|
||
%token EACH_SYM /* SQL-2003-R */
|
||
%token ELSE /* SQL-2003-R */
|
||
%token ELSEIF_SYM
|
||
%token ENABLE_SYM
|
||
%token ENCLOSED
|
||
%token END /* SQL-2003-R */
|
||
%token ENDS_SYM
|
||
%token END_OF_INPUT /* INTERNAL */
|
||
%token ENGINES_SYM
|
||
%token ENGINE_SYM
|
||
%token ENUM
|
||
%token EQ /* OPERATOR */
|
||
%token EQUAL_SYM /* OPERATOR */
|
||
%token ERRORS
|
||
%token ESCAPED
|
||
%token ESCAPE_SYM /* SQL-2003-R */
|
||
%token EVENTS_SYM
|
||
%token EVENT_SYM
|
||
%token EVERY_SYM /* SQL-2003-N */
|
||
%token EXECUTE_SYM /* SQL-2003-R */
|
||
%token EXISTS /* SQL-2003-R */
|
||
%token EXIT_SYM
|
||
%token EXPANSION_SYM
|
||
%token EXTENDED_SYM
|
||
%token EXTENT_SIZE_SYM
|
||
%token EXTRACT_SYM /* SQL-2003-N */
|
||
%token FALSE_SYM /* SQL-2003-R */
|
||
%token FAST_SYM
|
||
%token FETCH_SYM /* SQL-2003-R */
|
||
%token FILE_SYM
|
||
%token FIRST_SYM /* SQL-2003-N */
|
||
%token FIXED_SYM
|
||
%token FLOAT_NUM
|
||
%token FLOAT_SYM /* SQL-2003-R */
|
||
%token FLUSH_SYM
|
||
%token FORCE_SYM
|
||
%token FOREIGN /* SQL-2003-R */
|
||
%token FOR_SYM /* SQL-2003-R */
|
||
%token FOUND_SYM /* SQL-2003-R */
|
||
%token FRAC_SECOND_SYM
|
||
%token FROM
|
||
%token FULL /* SQL-2003-R */
|
||
%token FULLTEXT_SYM
|
||
%token FUNCTION_SYM /* SQL-2003-R */
|
||
%token GE
|
||
%token GEOMETRYCOLLECTION
|
||
%token GEOMETRY_SYM
|
||
%token GET_FORMAT /* MYSQL-FUNC */
|
||
%token GLOBAL_SYM /* SQL-2003-R */
|
||
%token GRANT /* SQL-2003-R */
|
||
%token GRANTS
|
||
%token GROUP /* SQL-2003-R */
|
||
%token GROUP_CONCAT_SYM
|
||
%token GROUP_UNIQUE_USERS
|
||
%token GT_SYM /* OPERATOR */
|
||
%token HANDLER_SYM
|
||
%token HASH_SYM
|
||
%token HAVING /* SQL-2003-R */
|
||
%token HELP_SYM
|
||
%token HEX_NUM
|
||
%token HIGH_PRIORITY
|
||
%token HOST_SYM
|
||
%token HOSTS_SYM
|
||
%token HOUR_MICROSECOND_SYM
|
||
%token HOUR_MINUTE_SYM
|
||
%token HOUR_SECOND_SYM
|
||
%token HOUR_SYM /* SQL-2003-R */
|
||
%token IDENT
|
||
%token IDENTIFIED_SYM
|
||
%token IDENT_QUOTED
|
||
%token IF
|
||
%token IGNORE_SYM
|
||
%token IMPORT
|
||
%token INDEXES
|
||
%token INDEX_SYM
|
||
%token INFILE
|
||
%token INITIAL_SIZE_SYM
|
||
%token INNER_SYM /* SQL-2003-R */
|
||
%token INNOBASE_SYM
|
||
%token INOUT_SYM /* SQL-2003-R */
|
||
%token INSENSITIVE_SYM /* SQL-2003-R */
|
||
%token INSERT /* SQL-2003-R */
|
||
%token INSERT_METHOD
|
||
%token INSTALL_SYM
|
||
%token INTERVAL_SYM /* SQL-2003-R */
|
||
%token INTO /* SQL-2003-R */
|
||
%token INT_SYM /* SQL-2003-R */
|
||
%token INVOKER_SYM
|
||
%token IN_SYM /* SQL-2003-R */
|
||
%token IS /* SQL-2003-R */
|
||
%token ISOLATION /* SQL-2003-R */
|
||
%token ISSUER_SYM
|
||
%token ITERATE_SYM
|
||
%token JOIN_SYM /* SQL-2003-R */
|
||
%token KEYS
|
||
%token KEY_BLOCK_SIZE
|
||
%token KEY_SYM /* SQL-2003-N */
|
||
%token KILL_SYM
|
||
%token LANGUAGE_SYM /* SQL-2003-R */
|
||
%token LAST_SYM /* SQL-2003-N */
|
||
%token LE /* OPERATOR */
|
||
%token LEADING /* SQL-2003-R */
|
||
%token LEAVES
|
||
%token LEAVE_SYM
|
||
%token LEFT /* SQL-2003-R */
|
||
%token LESS_SYM
|
||
%token LEVEL_SYM
|
||
%token LEX_HOSTNAME
|
||
%token LIKE /* SQL-2003-R */
|
||
%token LIMIT
|
||
%token LINEAR_SYM
|
||
%token LINES
|
||
%token LINESTRING
|
||
%token LIST_SYM
|
||
%token LOAD
|
||
%token LOCAL_SYM /* SQL-2003-R */
|
||
%token LOCATOR_SYM /* SQL-2003-N */
|
||
%token LOCKS_SYM
|
||
%token LOCK_SYM
|
||
%token LOGFILE_SYM
|
||
%token LOGS_SYM
|
||
%token LONGBLOB
|
||
%token LONGTEXT
|
||
%token LONG_NUM
|
||
%token LONG_SYM
|
||
%token LOOP_SYM
|
||
%token LOW_PRIORITY
|
||
%token LT /* OPERATOR */
|
||
%token MASTER_CONNECT_RETRY_SYM
|
||
%token MASTER_HOST_SYM
|
||
%token MASTER_LOG_FILE_SYM
|
||
%token MASTER_LOG_POS_SYM
|
||
%token MASTER_PASSWORD_SYM
|
||
%token MASTER_PORT_SYM
|
||
%token MASTER_SERVER_ID_SYM
|
||
%token MASTER_SSL_CAPATH_SYM
|
||
%token MASTER_SSL_CA_SYM
|
||
%token MASTER_SSL_CERT_SYM
|
||
%token MASTER_SSL_CIPHER_SYM
|
||
%token MASTER_SSL_KEY_SYM
|
||
%token MASTER_SSL_SYM
|
||
%token MASTER_SYM
|
||
%token MASTER_USER_SYM
|
||
%token MATCH /* SQL-2003-R */
|
||
%token MAX_CONNECTIONS_PER_HOUR
|
||
%token MAX_QUERIES_PER_HOUR
|
||
%token MAX_ROWS
|
||
%token MAX_SIZE_SYM
|
||
%token MAX_SYM /* SQL-2003-N */
|
||
%token MAX_UPDATES_PER_HOUR
|
||
%token MAX_USER_CONNECTIONS_SYM
|
||
%token MAX_VALUE_SYM /* SQL-2003-N */
|
||
%token MEDIUMBLOB
|
||
%token MEDIUMINT
|
||
%token MEDIUMTEXT
|
||
%token MEDIUM_SYM
|
||
%token MEMORY_SYM
|
||
%token MERGE_SYM /* SQL-2003-R */
|
||
%token MICROSECOND_SYM /* MYSQL-FUNC */
|
||
%token MIGRATE_SYM
|
||
%token MINUTE_MICROSECOND_SYM
|
||
%token MINUTE_SECOND_SYM
|
||
%token MINUTE_SYM /* SQL-2003-R */
|
||
%token MIN_ROWS
|
||
%token MIN_SYM /* SQL-2003-N */
|
||
%token MODE_SYM
|
||
%token MODIFIES_SYM /* SQL-2003-R */
|
||
%token MODIFY_SYM
|
||
%token MOD_SYM /* SQL-2003-N */
|
||
%token MONTH_SYM /* SQL-2003-R */
|
||
%token MULTILINESTRING
|
||
%token MULTIPOINT
|
||
%token MULTIPOLYGON
|
||
%token MUTEX_SYM
|
||
%token NAMES_SYM /* SQL-2003-N */
|
||
%token NAME_SYM /* SQL-2003-N */
|
||
%token NATIONAL_SYM /* SQL-2003-R */
|
||
%token NATURAL /* SQL-2003-R */
|
||
%token NCHAR_STRING
|
||
%token NCHAR_SYM /* SQL-2003-R */
|
||
%token NDBCLUSTER_SYM
|
||
%token NE /* OPERATOR */
|
||
%token NEG
|
||
%token NEW_SYM /* SQL-2003-R */
|
||
%token NEXT_SYM /* SQL-2003-N */
|
||
%token NODEGROUP_SYM
|
||
%token NONE_SYM /* SQL-2003-R */
|
||
%token NOT2_SYM
|
||
%token NOT_SYM /* SQL-2003-R */
|
||
%token NOW_SYM
|
||
%token NO_SYM /* SQL-2003-R */
|
||
%token NO_WAIT_SYM
|
||
%token NO_WRITE_TO_BINLOG
|
||
%token NULL_SYM /* SQL-2003-R */
|
||
%token NUM
|
||
%token NUMERIC_SYM /* SQL-2003-R */
|
||
%token NVARCHAR_SYM
|
||
%token OFFSET_SYM
|
||
%token OLD_PASSWORD
|
||
%token ON /* SQL-2003-R */
|
||
%token ONE_SHOT_SYM
|
||
%token ONE_SYM
|
||
%token OPEN_SYM /* SQL-2003-R */
|
||
%token OPTIMIZE
|
||
%token OPTIONS_SYM
|
||
%token OPTION /* SQL-2003-N */
|
||
%token OPTIONALLY
|
||
%token OR2_SYM
|
||
%token ORDER_SYM /* SQL-2003-R */
|
||
%token OR_OR_SYM /* OPERATOR */
|
||
%token OR_SYM /* SQL-2003-R */
|
||
%token OUTER
|
||
%token OUTFILE
|
||
%token OUT_SYM /* SQL-2003-R */
|
||
%token OWNER_SYM
|
||
%token PACK_KEYS_SYM
|
||
%token PARAM_MARKER
|
||
%token PARSER_SYM
|
||
%token PARTIAL /* SQL-2003-N */
|
||
%token PARTITIONING_SYM
|
||
%token PARTITIONS_SYM
|
||
%token PARTITION_SYM /* SQL-2003-R */
|
||
%token PASSWORD
|
||
%token PHASE_SYM
|
||
%token PLUGINS_SYM
|
||
%token PLUGIN_SYM
|
||
%token POINT_SYM
|
||
%token POLYGON
|
||
%token PORT_SYM
|
||
%token POSITION_SYM /* SQL-2003-N */
|
||
%token PRECISION /* SQL-2003-R */
|
||
%token PREPARE_SYM /* SQL-2003-R */
|
||
%token PRESERVE_SYM
|
||
%token PREV_SYM
|
||
%token PRIMARY_SYM /* SQL-2003-R */
|
||
%token PRIVILEGES /* SQL-2003-N */
|
||
%token PROCEDURE /* SQL-2003-R */
|
||
%token PROCESS
|
||
%token PROCESSLIST_SYM
|
||
%token PURGE
|
||
%token QUARTER_SYM
|
||
%token QUERY_SYM
|
||
%token QUICK
|
||
%token RANGE_SYM /* SQL-2003-R */
|
||
%token READS_SYM /* SQL-2003-R */
|
||
%token READ_ONLY_SYM
|
||
%token READ_SYM /* SQL-2003-N */
|
||
%token READ_WRITE_SYM
|
||
%token REAL /* SQL-2003-R */
|
||
%token REBUILD_SYM
|
||
%token RECOVER_SYM
|
||
%token REDOFILE_SYM
|
||
%token REDO_BUFFER_SIZE_SYM
|
||
%token REDUNDANT_SYM
|
||
%token REFERENCES /* SQL-2003-R */
|
||
%token REGEXP
|
||
%token RELAY_LOG_FILE_SYM
|
||
%token RELAY_LOG_POS_SYM
|
||
%token RELAY_THREAD
|
||
%token RELEASE_SYM /* SQL-2003-R */
|
||
%token RELOAD
|
||
%token REMOVE_SYM
|
||
%token RENAME
|
||
%token REORGANIZE_SYM
|
||
%token REPAIR
|
||
%token REPEATABLE_SYM /* SQL-2003-N */
|
||
%token REPEAT_SYM /* MYSQL-FUNC */
|
||
%token REPLACE /* MYSQL-FUNC */
|
||
%token REPLICATION
|
||
%token REQUIRE_SYM
|
||
%token RESET_SYM
|
||
%token RESOURCES
|
||
%token RESTORE_SYM
|
||
%token RESTRICT
|
||
%token RESUME_SYM
|
||
%token RETURNS_SYM /* SQL-2003-R */
|
||
%token RETURN_SYM /* SQL-2003-R */
|
||
%token REVOKE /* SQL-2003-R */
|
||
%token RIGHT /* SQL-2003-R */
|
||
%token ROLLBACK_SYM /* SQL-2003-R */
|
||
%token ROLLUP_SYM /* SQL-2003-R */
|
||
%token ROUTINE_SYM /* SQL-2003-N */
|
||
%token ROWS_SYM /* SQL-2003-R */
|
||
%token ROW_FORMAT_SYM
|
||
%token ROW_SYM /* SQL-2003-R */
|
||
%token RTREE_SYM
|
||
%token SAVEPOINT_SYM /* SQL-2003-R */
|
||
%token SCHEDULE_SYM
|
||
%token SECOND_MICROSECOND_SYM
|
||
%token SECOND_SYM /* SQL-2003-R */
|
||
%token SECURITY_SYM /* SQL-2003-N */
|
||
%token SELECT_SYM /* SQL-2003-R */
|
||
%token SENSITIVE_SYM /* FUTURE-USE */
|
||
%token SEPARATOR_SYM
|
||
%token SERIALIZABLE_SYM /* SQL-2003-N */
|
||
%token SERIAL_SYM
|
||
%token SESSION_SYM /* SQL-2003-N */
|
||
%token SERVER_SYM
|
||
%token SERVER_OPTIONS
|
||
%token SET /* SQL-2003-R */
|
||
%token SET_VAR
|
||
%token SHARE_SYM
|
||
%token SHIFT_LEFT /* OPERATOR */
|
||
%token SHIFT_RIGHT /* OPERATOR */
|
||
%token SHOW
|
||
%token SHUTDOWN
|
||
%token SIGNED_SYM
|
||
%token SIMPLE_SYM /* SQL-2003-N */
|
||
%token SLAVE
|
||
%token SMALLINT /* SQL-2003-R */
|
||
%token SNAPSHOT_SYM
|
||
%token SOCKET_SYM
|
||
%token SONAME_SYM
|
||
%token SOUNDS_SYM
|
||
%token SPATIAL_SYM
|
||
%token SPECIFIC_SYM /* SQL-2003-R */
|
||
%token SQLEXCEPTION_SYM /* SQL-2003-R */
|
||
%token SQLSTATE_SYM /* SQL-2003-R */
|
||
%token SQLWARNING_SYM /* SQL-2003-R */
|
||
%token SQL_BIG_RESULT
|
||
%token SQL_BUFFER_RESULT
|
||
%token SQL_CACHE_SYM
|
||
%token SQL_CALC_FOUND_ROWS
|
||
%token SQL_NO_CACHE_SYM
|
||
%token SQL_SMALL_RESULT
|
||
%token SQL_SYM /* SQL-2003-R */
|
||
%token SQL_THREAD
|
||
%token SSL_SYM
|
||
%token STARTING
|
||
%token STARTS_SYM
|
||
%token START_SYM /* SQL-2003-R */
|
||
%token STATUS_SYM
|
||
%token STDDEV_SAMP_SYM /* SQL-2003-N */
|
||
%token STD_SYM
|
||
%token STOP_SYM
|
||
%token STORAGE_SYM
|
||
%token STRAIGHT_JOIN
|
||
%token STRING_SYM
|
||
%token SUBDATE_SYM
|
||
%token SUBJECT_SYM
|
||
%token SUBPARTITIONS_SYM
|
||
%token SUBPARTITION_SYM
|
||
%token SUBSTRING /* SQL-2003-N */
|
||
%token SUM_SYM /* SQL-2003-N */
|
||
%token SUPER_SYM
|
||
%token SUSPEND_SYM
|
||
%token SYSDATE
|
||
%token TABLES
|
||
%token TABLESPACE
|
||
%token TABLE_REF_PRIORITY
|
||
%token TABLE_SYM /* SQL-2003-R */
|
||
%token TEMPORARY /* SQL-2003-N */
|
||
%token TEMPTABLE_SYM
|
||
%token TERMINATED
|
||
%token TEXT_STRING
|
||
%token TEXT_SYM
|
||
%token THAN_SYM
|
||
%token THEN_SYM /* SQL-2003-R */
|
||
%token TIMESTAMP /* SQL-2003-R */
|
||
%token TIMESTAMP_ADD
|
||
%token TIMESTAMP_DIFF
|
||
%token TIME_SYM /* SQL-2003-R */
|
||
%token TINYBLOB
|
||
%token TINYINT
|
||
%token TINYTEXT
|
||
%token TO_SYM /* SQL-2003-R */
|
||
%token TRAILING /* SQL-2003-R */
|
||
%token TRANSACTION_SYM
|
||
%token TRIGGERS_SYM
|
||
%token TRIGGER_SYM /* SQL-2003-R */
|
||
%token TRIM /* SQL-2003-N */
|
||
%token TRUE_SYM /* SQL-2003-R */
|
||
%token TRUNCATE_SYM
|
||
%token TYPES_SYM
|
||
%token TYPE_SYM /* SQL-2003-N */
|
||
%token UDF_RETURNS_SYM
|
||
%token ULONGLONG_NUM
|
||
%token UNCOMMITTED_SYM /* SQL-2003-N */
|
||
%token UNDEFINED_SYM
|
||
%token UNDERSCORE_CHARSET
|
||
%token UNDOFILE_SYM
|
||
%token UNDO_BUFFER_SIZE_SYM
|
||
%token UNDO_SYM /* FUTURE-USE */
|
||
%token UNICODE_SYM
|
||
%token UNINSTALL_SYM
|
||
%token UNION_SYM /* SQL-2003-R */
|
||
%token UNIQUE_SYM
|
||
%token UNIQUE_USERS
|
||
%token UNKNOWN_SYM /* SQL-2003-R */
|
||
%token UNLOCK_SYM
|
||
%token UNSIGNED
|
||
%token UNTIL_SYM
|
||
%token UPDATE_SYM /* SQL-2003-R */
|
||
%token UPGRADE_SYM
|
||
%token USAGE /* SQL-2003-N */
|
||
%token USER /* SQL-2003-R */
|
||
%token USE_FRM
|
||
%token USE_SYM
|
||
%token USING /* SQL-2003-R */
|
||
%token UTC_DATE_SYM
|
||
%token UTC_TIMESTAMP_SYM
|
||
%token UTC_TIME_SYM
|
||
%token VALUES /* SQL-2003-R */
|
||
%token VALUE_SYM /* SQL-2003-R */
|
||
%token VARBINARY
|
||
%token VARCHAR /* SQL-2003-R */
|
||
%token VARIABLES
|
||
%token VARIANCE_SYM
|
||
%token VARYING /* SQL-2003-R */
|
||
%token VAR_SAMP_SYM
|
||
%token VIEW_SYM /* SQL-2003-N */
|
||
%token WAIT_SYM
|
||
%token WARNINGS
|
||
%token WEEK_SYM
|
||
%token WHEN_SYM /* SQL-2003-R */
|
||
%token WHERE /* SQL-2003-R */
|
||
%token WHILE_SYM
|
||
%token WITH /* SQL-2003-R */
|
||
%token WORK_SYM /* SQL-2003-N */
|
||
%token WRAPPER_SYM
|
||
%token WRITE_SYM /* SQL-2003-N */
|
||
%token X509_SYM
|
||
%token XA_SYM
|
||
%token XOR
|
||
%token YEAR_MONTH_SYM
|
||
%token YEAR_SYM /* SQL-2003-R */
|
||
%token ZEROFILL
|
||
|
||
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
|
||
/* A dummy token to force the priority of table_ref production in a join. */
|
||
%left TABLE_REF_PRIORITY
|
||
%left SET_VAR
|
||
%left OR_OR_SYM OR_SYM OR2_SYM XOR
|
||
%left AND_SYM AND_AND_SYM
|
||
%left BETWEEN_SYM CASE_SYM WHEN_SYM THEN_SYM ELSE
|
||
%left EQ EQUAL_SYM GE GT_SYM LE LT NE IS LIKE REGEXP IN_SYM
|
||
%left '|'
|
||
%left '&'
|
||
%left SHIFT_LEFT SHIFT_RIGHT
|
||
%left '-' '+'
|
||
%left '*' '/' '%' DIV_SYM MOD_SYM
|
||
%left '^'
|
||
%left NEG '~'
|
||
%right NOT_SYM NOT2_SYM
|
||
%right BINARY COLLATE_SYM
|
||
|
||
%type <lex_str>
|
||
IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
|
||
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
|
||
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
|
||
NCHAR_STRING opt_component key_cache_name
|
||
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
|
||
|
||
%type <lex_str_ptr>
|
||
opt_table_alias
|
||
|
||
%type <table>
|
||
table_ident table_ident_nodb references xid
|
||
|
||
%type <simple_string>
|
||
remember_name remember_end opt_ident opt_db text_or_password
|
||
opt_constraint constraint
|
||
|
||
%type <string>
|
||
text_string opt_gconcat_separator
|
||
|
||
%type <num>
|
||
type int_type real_type order_dir lock_option
|
||
udf_type if_exists opt_local opt_table_options table_options
|
||
table_option opt_if_not_exists opt_no_write_to_binlog
|
||
delete_option opt_temporary all_or_any opt_distinct
|
||
opt_ignore_leaves fulltext_options spatial_type union_option
|
||
start_transaction_opts opt_chain opt_release
|
||
union_opt select_derived_init option_type2
|
||
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
|
||
|
||
%type <ulong_num>
|
||
ulong_num real_ulong_num merge_insert_types
|
||
|
||
%type <ulonglong_number>
|
||
ulonglong_num real_ulonglong_num size_number
|
||
|
||
%type <p_elem_value>
|
||
part_bit_expr
|
||
|
||
%type <lock_type>
|
||
replace_lock_option opt_low_priority insert_lock_option load_data_lock
|
||
|
||
%type <item>
|
||
literal text_literal insert_ident order_ident
|
||
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
|
||
variable variable_aux bool_term bool_factor bool_test bool_pri
|
||
predicate bit_expr bit_term bit_factor value_expr term factor
|
||
table_wild simple_expr udf_expr
|
||
expr_or_default set_expr_or_default interval_expr
|
||
param_marker geometry_function
|
||
signed_literal now_or_signed_literal opt_escape
|
||
sp_opt_default
|
||
simple_ident_nospvar simple_ident_q
|
||
field_or_var limit_option
|
||
part_func_expr
|
||
function_call_keyword
|
||
function_call_nonkeyword
|
||
function_call_generic
|
||
function_call_conflict
|
||
|
||
%type <item_num>
|
||
NUM_literal
|
||
|
||
%type <item_list>
|
||
expr_list udf_expr_list udf_expr_list2 when_list
|
||
ident_list ident_list_arg opt_expr_list
|
||
|
||
%type <var_type>
|
||
option_type opt_var_type opt_var_ident_type
|
||
|
||
%type <key_type>
|
||
key_type opt_unique_or_fulltext constraint_key_type
|
||
|
||
%type <key_alg>
|
||
btree_or_rtree
|
||
|
||
%type <string_list>
|
||
key_usage_list using_list
|
||
|
||
%type <key_part>
|
||
key_part
|
||
|
||
%type <table_list>
|
||
join_table_list join_table
|
||
table_factor table_ref
|
||
select_derived derived_table_list
|
||
|
||
%type <date_time_type> date_time_type;
|
||
%type <interval> interval
|
||
|
||
%type <interval_time_st> interval_time_st
|
||
|
||
%type <db_type> storage_engines
|
||
|
||
%type <row_type> row_types
|
||
|
||
%type <tx_isolation> isolation_types
|
||
|
||
%type <ha_rkey_mode> handler_rkey_mode
|
||
|
||
%type <cast_type> cast_type
|
||
|
||
%type <udf_type> udf_func_type
|
||
|
||
%type <symbol> keyword keyword_sp
|
||
|
||
%type <lex_user> user grant_user
|
||
|
||
%type <charset>
|
||
opt_collate
|
||
charset_name
|
||
charset_name_or_default
|
||
old_or_new_charset_name
|
||
old_or_new_charset_name_or_default
|
||
collation_name
|
||
collation_name_or_default
|
||
|
||
%type <variable> internal_variable_name
|
||
|
||
%type <select_lex> subselect subselect_init
|
||
get_select_lex
|
||
|
||
%type <boolfunc2creator> comp_op
|
||
|
||
%type <NONE>
|
||
query verb_clause create change select do drop insert replace insert2
|
||
insert_values update delete truncate rename
|
||
show describe load alter optimize keycache preload flush
|
||
reset purge begin commit rollback savepoint release
|
||
slave master_def master_defs master_file_def slave_until_opts
|
||
repair restore backup analyze check start checksum
|
||
field_list field_list_item field_spec kill column_def key_def
|
||
keycache_list assign_to_keycache preload_list preload_keys
|
||
select_item_list select_item values_list no_braces
|
||
opt_limit_clause delete_limit_clause fields opt_values values
|
||
procedure_list procedure_list2 procedure_item
|
||
when_list2 expr_list2 udf_expr_list3 handler
|
||
opt_precision opt_ignore opt_column opt_restrict
|
||
grant revoke set lock unlock string_list field_options field_option
|
||
field_opt_list opt_binary table_lock_list table_lock
|
||
ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use
|
||
opt_delete_options opt_delete_option varchar nchar nvarchar
|
||
opt_outer table_list table_name opt_option opt_place
|
||
opt_attribute opt_attribute_list attribute column_list column_list_id
|
||
opt_column_list grant_privileges grant_ident grant_list grant_option
|
||
object_privilege object_privilege_list user_list rename_list
|
||
clear_privileges flush_options flush_option
|
||
equal optional_braces opt_key_definition key_usage_list2
|
||
opt_mi_check_type opt_to mi_check_types normal_join
|
||
db_to_db 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
|
||
union_clause union_list
|
||
precision subselect_start opt_and charset
|
||
subselect_end select_var_list select_var_list_init help opt_len
|
||
opt_extended_describe
|
||
prepare prepare_src execute deallocate
|
||
statement sp_suid
|
||
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
|
||
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
|
||
definer view_replace_or_algorithm view_replace view_algorithm_opt
|
||
view_algorithm view_or_trigger_or_sp_or_event
|
||
view_or_trigger_or_sp_or_event_tail
|
||
view_suid view_tail view_list_opt view_list view_select
|
||
view_check_option trigger_tail sp_tail
|
||
install uninstall partition_entry binlog_base64_event
|
||
init_key_options key_options key_opts key_opt key_using_alg
|
||
server_def server_options_list server_option
|
||
END_OF_INPUT
|
||
|
||
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
|
||
%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
|
||
%type <NONE> sp_proc_stmt_if sp_proc_stmt_case_simple sp_proc_stmt_case
|
||
%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled sp_proc_stmt_leave
|
||
%type <NONE> sp_proc_stmt_iterate
|
||
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
|
||
|
||
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
|
||
%type <spcondtype> sp_cond sp_hcond
|
||
%type <spblock> sp_decls sp_decl
|
||
%type <lex> sp_cursor_stmt
|
||
%type <spname> sp_name
|
||
|
||
%type <NONE>
|
||
'-' '+' '*' '/' '%' '(' ')'
|
||
',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM
|
||
THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM
|
||
%%
|
||
|
||
|
||
query:
|
||
END_OF_INPUT
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (!thd->bootstrap &&
|
||
(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
|
||
{
|
||
my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
|
||
}
|
||
}
|
||
| verb_clause END_OF_INPUT {};
|
||
|
||
verb_clause:
|
||
statement
|
||
| begin
|
||
;
|
||
|
||
/* Verb clauses, except begin */
|
||
statement:
|
||
alter
|
||
| analyze
|
||
| backup
|
||
| binlog_base64_event
|
||
| call
|
||
| change
|
||
| check
|
||
| checksum
|
||
| commit
|
||
| create
|
||
| deallocate
|
||
| delete
|
||
| describe
|
||
| do
|
||
| drop
|
||
| execute
|
||
| flush
|
||
| grant
|
||
| handler
|
||
| help
|
||
| insert
|
||
| install
|
||
| kill
|
||
| load
|
||
| lock
|
||
| optimize
|
||
| keycache
|
||
| partition_entry
|
||
| preload
|
||
| prepare
|
||
| purge
|
||
| release
|
||
| rename
|
||
| repair
|
||
| replace
|
||
| reset
|
||
| restore
|
||
| revoke
|
||
| rollback
|
||
| savepoint
|
||
| select
|
||
| set
|
||
| show
|
||
| slave
|
||
| start
|
||
| truncate
|
||
| uninstall
|
||
| unlock
|
||
| update
|
||
| use
|
||
| xa
|
||
;
|
||
|
||
deallocate:
|
||
deallocate_or_drop PREPARE_SYM ident
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
if (lex->stmt_prepare_mode)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_DEALLOCATE_PREPARE;
|
||
lex->prepared_stmt_name= $3;
|
||
};
|
||
|
||
deallocate_or_drop:
|
||
DEALLOCATE_SYM |
|
||
DROP
|
||
;
|
||
|
||
|
||
prepare:
|
||
PREPARE_SYM ident FROM prepare_src
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
if (lex->stmt_prepare_mode)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_PREPARE;
|
||
lex->prepared_stmt_name= $2;
|
||
};
|
||
|
||
prepare_src:
|
||
TEXT_STRING_sys
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
lex->prepared_stmt_code= $1;
|
||
lex->prepared_stmt_code_is_varref= FALSE;
|
||
}
|
||
| '@' ident_or_text
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
lex->prepared_stmt_code= $2;
|
||
lex->prepared_stmt_code_is_varref= TRUE;
|
||
};
|
||
|
||
execute:
|
||
EXECUTE_SYM ident
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
if (lex->stmt_prepare_mode)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_EXECUTE;
|
||
lex->prepared_stmt_name= $2;
|
||
}
|
||
execute_using
|
||
{}
|
||
;
|
||
|
||
execute_using:
|
||
/* nothing */
|
||
| USING execute_var_list
|
||
;
|
||
|
||
execute_var_list:
|
||
execute_var_list ',' execute_var_ident
|
||
| execute_var_ident
|
||
;
|
||
|
||
execute_var_ident: '@' ident_or_text
|
||
{
|
||
LEX *lex=Lex;
|
||
LEX_STRING *lexstr= (LEX_STRING*)sql_memdup(&$2, sizeof(LEX_STRING));
|
||
if (!lexstr || lex->prepared_stmt_params.push_back(lexstr))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
/* help */
|
||
|
||
help:
|
||
HELP_SYM
|
||
{
|
||
if (Lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "HELP");
|
||
YYABORT;
|
||
}
|
||
}
|
||
ident_or_text
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_HELP;
|
||
lex->help_arg= $3.str;
|
||
};
|
||
|
||
/* change master */
|
||
|
||
change:
|
||
CHANGE MASTER_SYM TO_SYM
|
||
{
|
||
LEX *lex = Lex;
|
||
lex->sql_command = SQLCOM_CHANGE_MASTER;
|
||
bzero((char*) &lex->mi, sizeof(lex->mi));
|
||
}
|
||
master_defs
|
||
{}
|
||
;
|
||
|
||
master_defs:
|
||
master_def
|
||
| master_defs ',' master_def;
|
||
|
||
master_def:
|
||
MASTER_HOST_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.host = $3.str;
|
||
}
|
||
|
|
||
MASTER_USER_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.user = $3.str;
|
||
}
|
||
|
|
||
MASTER_PASSWORD_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.password = $3.str;
|
||
}
|
||
|
|
||
MASTER_PORT_SYM EQ ulong_num
|
||
{
|
||
Lex->mi.port = $3;
|
||
}
|
||
|
|
||
MASTER_CONNECT_RETRY_SYM EQ ulong_num
|
||
{
|
||
Lex->mi.connect_retry = $3;
|
||
}
|
||
| MASTER_SSL_SYM EQ ulong_num
|
||
{
|
||
Lex->mi.ssl= $3 ?
|
||
LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
|
||
}
|
||
| MASTER_SSL_CA_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.ssl_ca= $3.str;
|
||
}
|
||
| MASTER_SSL_CAPATH_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.ssl_capath= $3.str;
|
||
}
|
||
| MASTER_SSL_CERT_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.ssl_cert= $3.str;
|
||
}
|
||
| MASTER_SSL_CIPHER_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.ssl_cipher= $3.str;
|
||
}
|
||
| MASTER_SSL_KEY_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.ssl_key= $3.str;
|
||
}
|
||
|
|
||
master_file_def
|
||
;
|
||
|
||
master_file_def:
|
||
MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.log_file_name = $3.str;
|
||
}
|
||
| MASTER_LOG_POS_SYM EQ ulonglong_num
|
||
{
|
||
Lex->mi.pos = $3;
|
||
/*
|
||
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 explicitely specified. On the contrary
|
||
in change_master() (sql_repl.cc) we cannot distinguish between 0
|
||
(MASTER_LOG_POS explicitely 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 = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos);
|
||
}
|
||
| RELAY_LOG_FILE_SYM EQ TEXT_STRING_sys
|
||
{
|
||
Lex->mi.relay_log_name = $3.str;
|
||
}
|
||
| RELAY_LOG_POS_SYM EQ 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 = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
|
||
}
|
||
;
|
||
|
||
/* create a table */
|
||
|
||
create:
|
||
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_CREATE_TABLE;
|
||
if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
|
||
TL_OPTION_UPDATING,
|
||
(using_update_log ?
|
||
TL_READ_NO_INSERT:
|
||
TL_READ)))
|
||
YYABORT;
|
||
lex->create_list.empty();
|
||
lex->key_list.empty();
|
||
lex->col_list.empty();
|
||
lex->change=NullS;
|
||
bzero((char*) &lex->create_info,sizeof(lex->create_info));
|
||
lex->create_info.options=$2 | $4;
|
||
lex->create_info.db_type= lex->thd->variables.table_type;
|
||
lex->create_info.default_table_charset= NULL;
|
||
lex->name.str= 0;
|
||
lex->name.length= 0;
|
||
lex->like_name= 0;
|
||
}
|
||
create2
|
||
{ Lex->current_select= &Lex->select_lex; }
|
||
| CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON
|
||
table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_CREATE_INDEX;
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $7,
|
||
NULL,
|
||
TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
lex->create_list.empty();
|
||
lex->key_list.empty();
|
||
lex->col_list.empty();
|
||
lex->change=NullS;
|
||
}
|
||
'(' key_list ')' key_options
|
||
{
|
||
LEX *lex=Lex;
|
||
if ($2 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->key_list.push_back(new Key($2, $4.str, &lex->key_create_info, 0,
|
||
lex->col_list));
|
||
lex->col_list.empty();
|
||
}
|
||
| CREATE DATABASE opt_if_not_exists ident
|
||
{
|
||
Lex->create_info.default_table_charset= NULL;
|
||
Lex->create_info.used_fields= 0;
|
||
}
|
||
opt_create_database_options
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command=SQLCOM_CREATE_DB;
|
||
lex->name= $4;
|
||
lex->create_info.options=$3;
|
||
}
|
||
| CREATE
|
||
{
|
||
Lex->create_view_mode= VIEW_CREATE_NEW;
|
||
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
|
||
Lex->create_view_suid= TRUE;
|
||
}
|
||
view_or_trigger_or_sp_or_event
|
||
{}
|
||
| CREATE USER clear_privileges grant_list
|
||
{
|
||
Lex->sql_command = SQLCOM_CREATE_USER;
|
||
}
|
||
| CREATE LOGFILE_SYM GROUP logfile_group_info
|
||
{
|
||
Lex->alter_tablespace_info->ts_cmd_type= CREATE_LOGFILE_GROUP;
|
||
}
|
||
| CREATE TABLESPACE tablespace_info
|
||
{
|
||
Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE;
|
||
}
|
||
| CREATE server_def
|
||
{
|
||
Lex->sql_command= SQLCOM_CREATE_SERVER;
|
||
}
|
||
;
|
||
server_def:
|
||
SERVER_SYM ident_or_text FOREIGN DATA_SYM WRAPPER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')'
|
||
{
|
||
Lex->server_options.server_name= $2.str;
|
||
Lex->server_options.server_name_length= $2.length;
|
||
Lex->server_options.scheme= $6.str;
|
||
}
|
||
;
|
||
|
||
server_options_list:
|
||
server_option
|
||
| server_options_list ',' server_option
|
||
;
|
||
|
||
server_option:
|
||
USER TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.username= $2.str;
|
||
}
|
||
|
|
||
HOST_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.host= $2.str;
|
||
}
|
||
|
|
||
DATABASE TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.db= $2.str;
|
||
}
|
||
|
|
||
OWNER_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.owner= $2.str;
|
||
}
|
||
|
|
||
PASSWORD TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.password= $2.str;
|
||
}
|
||
|
|
||
SOCKET_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->server_options.socket= $2.str;
|
||
}
|
||
|
|
||
PORT_SYM ulong_num
|
||
{
|
||
Lex->server_options.port= $2;
|
||
}
|
||
;
|
||
|
||
event_tail:
|
||
EVENT_SYM opt_if_not_exists sp_name
|
||
/*
|
||
BE CAREFUL when you add a new rule to update the block where
|
||
YYTHD->client_capabilities is set back to original value
|
||
*/
|
||
{
|
||
Lex->create_info.options= $2;
|
||
|
||
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
|
||
YYABORT;
|
||
Lex->event_parse_data->identifier= $3;
|
||
|
||
/*
|
||
We have to turn of CLIENT_MULTI_QUERIES while parsing a
|
||
stored procedure, otherwise yylex will chop it into pieces
|
||
at each ';'.
|
||
*/
|
||
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
|
||
|
||
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
|
||
{
|
||
/*
|
||
Restore flag if it was cleared above
|
||
$1 - EVENT_SYM
|
||
$2 - opt_if_not_exists
|
||
$3 - sp_name
|
||
$4 - the block above
|
||
*/
|
||
YYTHD->client_capabilities |= $<ulong_num>4;
|
||
|
||
/*
|
||
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;
|
||
$$= 1;
|
||
}
|
||
| DISABLE_SYM
|
||
{
|
||
Lex->event_parse_data->status= Event_parse_data::DISABLED;
|
||
$$= 1;
|
||
}
|
||
;
|
||
|
||
ev_starts: /* empty */
|
||
{
|
||
Lex->event_parse_data->item_starts= new Item_func_now_local();
|
||
}
|
||
| 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 PRESERVE_SYM
|
||
{
|
||
Lex->event_parse_data->on_completion=
|
||
Event_parse_data::ON_COMPLETION_PRESERVE;
|
||
$$= 1;
|
||
}
|
||
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
|
||
{
|
||
Lex->event_parse_data->on_completion=
|
||
Event_parse_data::ON_COMPLETION_DROP;
|
||
$$= 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= Lex;
|
||
|
||
/*
|
||
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 (lex->sphead)
|
||
{
|
||
my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
|
||
YYABORT;
|
||
}
|
||
|
||
if (!(lex->sphead= new sp_head()))
|
||
YYABORT;
|
||
|
||
lex->sphead->reset_thd_mem_root(YYTHD);
|
||
lex->sphead->init(lex);
|
||
lex->sphead->init_sp_name(YYTHD, Lex->event_parse_data->identifier);
|
||
|
||
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
|
||
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
lex->sphead->m_chistics= &lex->sp_chistics;
|
||
|
||
lex->sphead->m_body_begin= lex->ptr;
|
||
|
||
Lex->event_parse_data->body_begin= lex->ptr;
|
||
|
||
}
|
||
ev_sql_stmt_inner
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
/* return back to the original memory root ASAP */
|
||
lex->sphead->init_strings(YYTHD, lex);
|
||
lex->sphead->restore_thd_mem_root(YYTHD);
|
||
|
||
lex->sp_chistics.suid= SP_IS_SUID; //always the definer!
|
||
|
||
Lex->event_parse_data->init_body(YYTHD);
|
||
}
|
||
;
|
||
|
||
ev_sql_stmt_inner:
|
||
sp_proc_stmt_statement
|
||
| sp_proc_stmt_return
|
||
| sp_proc_stmt_if
|
||
| sp_proc_stmt_case_simple
|
||
| sp_proc_stmt_case
|
||
| sp_labeled_control
|
||
| sp_proc_stmt_unlabeled
|
||
| sp_proc_stmt_leave
|
||
| sp_proc_stmt_iterate
|
||
| sp_proc_stmt_open
|
||
| sp_proc_stmt_fetch
|
||
| sp_proc_stmt_close
|
||
;
|
||
|
||
|
||
clear_privileges:
|
||
/* Nothing */
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->users_list.empty();
|
||
lex->columns.empty();
|
||
lex->grant= lex->grant_tot_col= 0;
|
||
lex->all_privileges= 0;
|
||
lex->select_lex.db= 0;
|
||
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
|
||
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
|
||
bzero((char *)&(lex->mqh),sizeof(lex->mqh));
|
||
}
|
||
;
|
||
|
||
sp_name:
|
||
ident '.' ident
|
||
{
|
||
if (!$1.str || check_db_name(&$1))
|
||
{
|
||
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
if (check_routine_name($3))
|
||
{
|
||
my_error(ER_SP_WRONG_NAME, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
$$= new sp_name($1, $3);
|
||
$$->init_qname(YYTHD);
|
||
}
|
||
| ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX_STRING db;
|
||
if (check_routine_name($1))
|
||
{
|
||
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
if (thd->copy_db_to(&db.str, &db.length))
|
||
YYABORT;
|
||
$$= new sp_name(db, $1);
|
||
if ($$)
|
||
$$->init_qname(YYTHD);
|
||
}
|
||
;
|
||
|
||
create_function_tail:
|
||
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex=Lex;
|
||
if (lex->definer != NULL)
|
||
{
|
||
/*
|
||
DEFINER is a concept meaningful when interpreting SQL code.
|
||
UDF functions are compiled.
|
||
Using DEFINER with UDF has therefore no semantic,
|
||
and is considered a parsing error.
|
||
*/
|
||
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
|
||
YYABORT;
|
||
}
|
||
if (is_native_function(thd, & lex->spname->m_name))
|
||
{
|
||
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
|
||
lex->spname->m_name.str);
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_CREATE_FUNCTION;
|
||
lex->udf.name = lex->spname->m_name;
|
||
lex->udf.returns=(Item_result) $2;
|
||
lex->udf.dl=$4.str;
|
||
}
|
||
| '('
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp;
|
||
|
||
/*
|
||
First check if AGGREGATE was used, in that case it's a
|
||
syntax error.
|
||
*/
|
||
if (lex->udf.type == UDFTYPE_AGGREGATE)
|
||
{
|
||
my_error(ER_SP_NO_AGGREGATE, MYF(0));
|
||
YYABORT;
|
||
}
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
|
||
YYABORT;
|
||
}
|
||
/* Order is important here: new - reset - init */
|
||
sp= new sp_head();
|
||
sp->reset_thd_mem_root(YYTHD);
|
||
sp->init(lex);
|
||
sp->init_sp_name(YYTHD, lex->spname);
|
||
|
||
sp->m_type= TYPE_ENUM_FUNCTION;
|
||
lex->sphead= sp;
|
||
/*
|
||
We have to turn off CLIENT_MULTI_QUERIES while parsing a
|
||
stored procedure, otherwise yylex will chop it into pieces
|
||
at each ';'.
|
||
*/
|
||
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
|
||
lex->sphead->m_param_begin= lex->tok_start+1;
|
||
}
|
||
sp_fdparam_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->m_param_end= lex->tok_start;
|
||
}
|
||
RETURNS_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->charset= NULL;
|
||
lex->length= lex->dec= NULL;
|
||
lex->interval_list.empty();
|
||
lex->type= 0;
|
||
}
|
||
type
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
/*
|
||
This was disabled in 5.1.12. See bug #20701
|
||
When collation support in SP is implemented, then this test
|
||
should be removed.
|
||
*/
|
||
if (($8 == FIELD_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR)
|
||
&& (lex->type & BINCMP_FLAG))
|
||
{
|
||
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
|
||
YYABORT;
|
||
}
|
||
|
||
if (sp->fill_field_definition(YYTHD, lex,
|
||
(enum enum_field_types) $8,
|
||
&sp->m_return_field_def))
|
||
YYABORT;
|
||
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
}
|
||
sp_c_chistics
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->m_chistics= &lex->sp_chistics;
|
||
lex->sphead->m_body_begin= lex->tok_start;
|
||
}
|
||
sp_proc_stmt
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
|
||
if (sp->is_not_allowed_in_function("function"))
|
||
YYABORT;
|
||
|
||
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
|
||
sp->init_strings(thd, lex);
|
||
if (!(sp->m_flags & sp_head::HAS_RETURN))
|
||
{
|
||
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
|
||
YYABORT;
|
||
}
|
||
if (is_native_function(thd, & sp->m_name))
|
||
{
|
||
/*
|
||
This warning will be printed when
|
||
[1] A client query is parsed,
|
||
[2] A stored function is loaded by db_load_routine.
|
||
Printing the warning for [2] is intentional, to cover the
|
||
following scenario:
|
||
- A user define a SF 'foo' using MySQL 5.N
|
||
- An application uses select foo(), and works.
|
||
- MySQL 5.{N+1} defines a new native function 'foo', as
|
||
part of a new feature.
|
||
- MySQL 5.{N+1} documentation is updated, and should mention
|
||
that there is a potential incompatible change in case of
|
||
existing stored function named 'foo'.
|
||
- The user deploys 5.{N+1}. At this point, 'select foo()'
|
||
means something different, and the user code is most likely
|
||
broken (it's only safe if the code is 'select db.foo()').
|
||
With a warning printed when the SF is loaded (which has to occur
|
||
before the call), the warning will provide a hint explaining
|
||
the root cause of a later failure of 'select foo()'.
|
||
With no warning printed, the user code will fail with no
|
||
apparent reason.
|
||
Printing a warning each time db_load_routine is executed for
|
||
an ambiguous function is annoying, since that can happen a lot,
|
||
but in practice should not happen unless there *are* name
|
||
collisions.
|
||
If a collision exists, it should not be silenced but fixed.
|
||
*/
|
||
push_warning_printf(thd,
|
||
MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||
ER_NATIVE_FCT_NAME_COLLISION,
|
||
ER(ER_NATIVE_FCT_NAME_COLLISION),
|
||
sp->m_name.str);
|
||
}
|
||
/* Restore flag if it was cleared above */
|
||
thd->client_capabilities |= $<ulong_num>2;
|
||
sp->restore_thd_mem_root(thd);
|
||
}
|
||
;
|
||
|
||
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
|
||
{ }
|
||
;
|
||
|
||
/* Create characteristics */
|
||
sp_c_chistic:
|
||
sp_chistic { }
|
||
| DETERMINISTIC_SYM { Lex->sp_chistics.detistic= TRUE; }
|
||
| not DETERMINISTIC_SYM { Lex->sp_chistics.detistic= FALSE; }
|
||
;
|
||
|
||
sp_suid:
|
||
SQL_SYM SECURITY_SYM DEFINER_SYM
|
||
{
|
||
Lex->sp_chistics.suid= SP_IS_SUID;
|
||
}
|
||
| SQL_SYM SECURITY_SYM INVOKER_SYM
|
||
{
|
||
Lex->sp_chistics.suid= SP_IS_NOT_SUID;
|
||
}
|
||
;
|
||
|
||
call:
|
||
CALL_SYM sp_name
|
||
{
|
||
LEX *lex = Lex;
|
||
|
||
lex->sql_command= SQLCOM_CALL;
|
||
lex->spname= $2;
|
||
lex->value_list.empty();
|
||
sp_add_used_routine(lex, YYTHD, $2, TYPE_ENUM_PROCEDURE);
|
||
}
|
||
opt_sp_cparam_list {}
|
||
;
|
||
|
||
/* 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);
|
||
}
|
||
| expr
|
||
{
|
||
Lex->value_list.push_back($1);
|
||
}
|
||
;
|
||
|
||
/* Stored FUNCTION parameter declaration list */
|
||
sp_fdparam_list:
|
||
/* Empty */
|
||
| sp_fdparams
|
||
;
|
||
|
||
sp_fdparams:
|
||
sp_fdparams ',' sp_fdparam
|
||
| sp_fdparam
|
||
;
|
||
|
||
sp_init_param:
|
||
/* Empty */
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->length= 0;
|
||
lex->dec= 0;
|
||
lex->type= 0;
|
||
|
||
lex->default_value= 0;
|
||
lex->on_update_value= 0;
|
||
|
||
lex->comment= null_lex_str;
|
||
lex->charset= NULL;
|
||
|
||
lex->interval_list.empty();
|
||
lex->uint_geom_type= 0;
|
||
}
|
||
;
|
||
|
||
sp_fdparam:
|
||
ident sp_init_param type
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
|
||
if (spc->find_variable(&$1, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_PARAM, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
sp_variable_t *spvar= spc->push_variable(&$1,
|
||
(enum enum_field_types)$3,
|
||
sp_param_in);
|
||
|
||
if (lex->sphead->fill_field_definition(YYTHD, lex,
|
||
(enum enum_field_types) $3,
|
||
&spvar->field_def))
|
||
{
|
||
YYABORT;
|
||
}
|
||
spvar->field_def.field_name= spvar->name.str;
|
||
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||
}
|
||
;
|
||
|
||
/* Stored PROCEDURE parameter declaration list */
|
||
sp_pdparam_list:
|
||
/* Empty */
|
||
| sp_pdparams
|
||
;
|
||
|
||
sp_pdparams:
|
||
sp_pdparams ',' sp_pdparam
|
||
| sp_pdparam
|
||
;
|
||
|
||
sp_pdparam:
|
||
sp_opt_inout sp_init_param ident type
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
|
||
if (spc->find_variable(&$3, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_PARAM, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
sp_variable_t *spvar= spc->push_variable(&$3,
|
||
(enum enum_field_types)$4,
|
||
(sp_param_mode_t)$1);
|
||
|
||
if (lex->sphead->fill_field_definition(YYTHD, lex,
|
||
(enum enum_field_types) $4,
|
||
&spvar->field_def))
|
||
{
|
||
YYABORT;
|
||
}
|
||
spvar->field_def.field_name= spvar->name.str;
|
||
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||
}
|
||
;
|
||
|
||
sp_opt_inout:
|
||
/* Empty */ { $$= sp_param_in; }
|
||
| IN_SYM { $$= sp_param_in; }
|
||
| OUT_SYM { $$= sp_param_out; }
|
||
| INOUT_SYM { $$= sp_param_inout; }
|
||
;
|
||
|
||
sp_proc_stmts:
|
||
/* Empty */ {}
|
||
| sp_proc_stmts sp_proc_stmt ';'
|
||
;
|
||
|
||
sp_proc_stmts1:
|
||
sp_proc_stmt ';' {}
|
||
| sp_proc_stmts1 sp_proc_stmt ';'
|
||
;
|
||
|
||
sp_decls:
|
||
/* Empty */
|
||
{
|
||
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||
}
|
||
| 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 (($2.vars || $2.conds) && ($1.curs || $1.hndlrs))
|
||
{ /* Variable or condition following cursor or handler */
|
||
my_message(ER_SP_VARCOND_AFTER_CURSHNDLR,
|
||
ER(ER_SP_VARCOND_AFTER_CURSHNDLR), MYF(0));
|
||
YYABORT;
|
||
}
|
||
if ($2.curs && $1.hndlrs)
|
||
{ /* Cursor following handler */
|
||
my_message(ER_SP_CURSOR_AFTER_HANDLER,
|
||
ER(ER_SP_CURSOR_AFTER_HANDLER), MYF(0));
|
||
YYABORT;
|
||
}
|
||
$$.vars= $1.vars + $2.vars;
|
||
$$.conds= $1.conds + $2.conds;
|
||
$$.hndlrs= $1.hndlrs + $2.hndlrs;
|
||
$$.curs= $1.curs + $2.curs;
|
||
}
|
||
;
|
||
|
||
sp_decl:
|
||
DECLARE_SYM sp_decl_idents
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->reset_lex(YYTHD);
|
||
lex->spcont->declare_var_boundary($2);
|
||
}
|
||
type
|
||
sp_opt_default
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *pctx= lex->spcont;
|
||
uint num_vars= pctx->context_var_count();
|
||
enum enum_field_types var_type= (enum enum_field_types) $4;
|
||
Item *dflt_value_item= $5;
|
||
create_field *create_field_op;
|
||
|
||
if (!dflt_value_item)
|
||
{
|
||
dflt_value_item= new Item_null();
|
||
/* QQ Set to the var_type with null_value? */
|
||
}
|
||
|
||
for (uint i = num_vars-$2 ; i < num_vars ; i++)
|
||
{
|
||
uint var_idx= pctx->var_context2runtime(i);
|
||
sp_variable_t *spvar= pctx->find_variable(var_idx);
|
||
|
||
if (!spvar)
|
||
YYABORT;
|
||
|
||
spvar->type= var_type;
|
||
spvar->dflt= dflt_value_item;
|
||
|
||
if (lex->sphead->fill_field_definition(YYTHD, lex, var_type,
|
||
&spvar->field_def))
|
||
{
|
||
YYABORT;
|
||
}
|
||
|
||
spvar->field_def.field_name= spvar->name.str;
|
||
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||
|
||
/* The last instruction is responsible for freeing LEX. */
|
||
|
||
lex->sphead->add_instr(
|
||
new sp_instr_set(lex->sphead->instructions(), pctx, var_idx,
|
||
dflt_value_item, var_type, lex,
|
||
(i == num_vars - 1)));
|
||
}
|
||
|
||
pctx->declare_var_boundary(0);
|
||
lex->sphead->restore_lex(YYTHD);
|
||
|
||
$$.vars= $2;
|
||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||
}
|
||
| DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
|
||
if (spc->find_cond(&$2, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_COND, MYF(0), $2.str);
|
||
YYABORT;
|
||
}
|
||
YYTHD->lex->spcont->push_cond(&$2, $5);
|
||
$$.vars= $$.hndlrs= $$.curs= 0;
|
||
$$.conds= 1;
|
||
}
|
||
| DECLARE_SYM sp_handler_type HANDLER_SYM FOR_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_instr_hpush_jump *i=
|
||
new sp_instr_hpush_jump(sp->instructions(), ctx, $2,
|
||
ctx->current_var_count());
|
||
|
||
sp->add_instr(i);
|
||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||
sp->m_flags|= sp_head::IN_HANDLER;
|
||
}
|
||
sp_hcond_list sp_proc_stmt
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
|
||
sp_instr_hreturn *i;
|
||
|
||
if ($2 == SP_HANDLER_CONTINUE)
|
||
{
|
||
i= new sp_instr_hreturn(sp->instructions(), ctx,
|
||
ctx->current_var_count());
|
||
sp->add_instr(i);
|
||
}
|
||
else
|
||
{ /* EXIT or UNDO handler, just jump to the end of the block */
|
||
i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
|
||
|
||
sp->add_instr(i);
|
||
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
|
||
}
|
||
lex->sphead->backpatch(hlab);
|
||
sp->m_flags&= ~sp_head::IN_HANDLER;
|
||
$$.vars= $$.conds= $$.curs= 0;
|
||
$$.hndlrs= $6;
|
||
ctx->add_handlers($6);
|
||
}
|
||
| DECLARE_SYM ident CURSOR_SYM FOR_SYM sp_cursor_stmt
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
uint offp;
|
||
sp_instr_cpush *i;
|
||
|
||
if (ctx->find_cursor(&$2, &offp, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
|
||
delete $5;
|
||
YYABORT;
|
||
}
|
||
i= new sp_instr_cpush(sp->instructions(), ctx, $5,
|
||
ctx->current_cursor_count());
|
||
sp->add_instr(i);
|
||
ctx->push_cursor(&$2);
|
||
$$.vars= $$.conds= $$.hndlrs= 0;
|
||
$$.curs= 1;
|
||
}
|
||
;
|
||
|
||
sp_cursor_stmt:
|
||
{
|
||
Lex->sphead->reset_lex(YYTHD);
|
||
|
||
/*
|
||
We use statement here just be able to get a better
|
||
error message. Using 'select' works too, but will then
|
||
result in a generic "syntax error" if a non-select
|
||
statement is given.
|
||
*/
|
||
}
|
||
statement
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sql_command != SQLCOM_SELECT &&
|
||
!(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND))
|
||
{
|
||
my_message(ER_SP_BAD_CURSOR_QUERY, ER(ER_SP_BAD_CURSOR_QUERY),
|
||
MYF(0));
|
||
YYABORT;
|
||
}
|
||
if (lex->result)
|
||
{
|
||
my_message(ER_SP_BAD_CURSOR_SELECT, ER(ER_SP_BAD_CURSOR_SELECT),
|
||
MYF(0));
|
||
YYABORT;
|
||
}
|
||
lex->sp_lex_in_use= TRUE;
|
||
$$= lex;
|
||
lex->sphead->restore_lex(YYTHD);
|
||
}
|
||
;
|
||
|
||
sp_handler_type:
|
||
EXIT_SYM { $$= SP_HANDLER_EXIT; }
|
||
| CONTINUE_SYM { $$= SP_HANDLER_CONTINUE; }
|
||
/* | UNDO_SYM { QQ No yet } */
|
||
;
|
||
|
||
sp_hcond_list:
|
||
sp_hcond
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
|
||
if (ctx->find_handler($1))
|
||
{
|
||
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
sp_instr_hpush_jump *i=
|
||
(sp_instr_hpush_jump *)sp->last_instruction();
|
||
|
||
i->add_condition($1);
|
||
ctx->push_handler($1);
|
||
$$= 1;
|
||
}
|
||
}
|
||
| sp_hcond_list ',' sp_hcond
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
|
||
if (ctx->find_handler($3))
|
||
{
|
||
my_message(ER_SP_DUP_HANDLER, ER(ER_SP_DUP_HANDLER), MYF(0));
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
sp_instr_hpush_jump *i=
|
||
(sp_instr_hpush_jump *)sp->last_instruction();
|
||
|
||
i->add_condition($3);
|
||
ctx->push_handler($3);
|
||
$$= $1 + 1;
|
||
}
|
||
}
|
||
;
|
||
|
||
sp_cond:
|
||
ulong_num
|
||
{ /* mysql errno */
|
||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||
$$->type= sp_cond_type_t::number;
|
||
$$->mysqlerr= $1;
|
||
}
|
||
| SQLSTATE_SYM opt_value TEXT_STRING_literal
|
||
{ /* SQLSTATE */
|
||
if (!sp_cond_check(&$3))
|
||
{
|
||
my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||
$$->type= sp_cond_type_t::state;
|
||
memcpy($$->sqlstate, $3.str, 5);
|
||
$$->sqlstate[5]= '\0';
|
||
}
|
||
;
|
||
|
||
opt_value:
|
||
/* Empty */ {}
|
||
| VALUE_SYM {}
|
||
;
|
||
|
||
sp_hcond:
|
||
sp_cond
|
||
{
|
||
$$= $1;
|
||
}
|
||
| ident /* CONDITION name */
|
||
{
|
||
$$= Lex->spcont->find_cond(&$1);
|
||
if ($$ == NULL)
|
||
{
|
||
my_error(ER_SP_COND_MISMATCH, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
}
|
||
| SQLWARNING_SYM /* SQLSTATEs 01??? */
|
||
{
|
||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||
$$->type= sp_cond_type_t::warning;
|
||
}
|
||
| not FOUND_SYM /* SQLSTATEs 02??? */
|
||
{
|
||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||
$$->type= sp_cond_type_t::notfound;
|
||
}
|
||
| SQLEXCEPTION_SYM /* All other SQLSTATEs */
|
||
{
|
||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||
$$->type= sp_cond_type_t::exception;
|
||
}
|
||
;
|
||
|
||
sp_decl_idents:
|
||
ident
|
||
{
|
||
/* NOTE: field definition is filled in sp_decl section. */
|
||
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
|
||
if (spc->find_variable(&$1, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_VAR, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
spc->push_variable(&$1, (enum_field_types)0, sp_param_in);
|
||
$$= 1;
|
||
}
|
||
| sp_decl_idents ',' ident
|
||
{
|
||
/* NOTE: field definition is filled in sp_decl section. */
|
||
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
|
||
if (spc->find_variable(&$3, TRUE))
|
||
{
|
||
my_error(ER_SP_DUP_VAR, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
spc->push_variable(&$3, (enum_field_types)0, sp_param_in);
|
||
$$= $1 + 1;
|
||
}
|
||
;
|
||
|
||
sp_opt_default:
|
||
/* Empty */ { $$ = NULL; }
|
||
| DEFAULT expr { $$ = $2; }
|
||
;
|
||
|
||
sp_proc_stmt:
|
||
sp_proc_stmt_statement
|
||
| sp_proc_stmt_return
|
||
| sp_proc_stmt_if
|
||
| sp_proc_stmt_case_simple
|
||
| sp_proc_stmt_case
|
||
| sp_labeled_control
|
||
| sp_proc_stmt_unlabeled
|
||
| sp_proc_stmt_leave
|
||
| sp_proc_stmt_iterate
|
||
| sp_proc_stmt_open
|
||
| sp_proc_stmt_fetch
|
||
| sp_proc_stmt_close
|
||
;
|
||
|
||
sp_proc_stmt_if:
|
||
IF { Lex->sphead->new_cont_backpatch(NULL); }
|
||
sp_if END IF
|
||
{ Lex->sphead->do_cont_backpatch(); }
|
||
;
|
||
|
||
sp_proc_stmt_statement:
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->reset_lex(YYTHD);
|
||
lex->sphead->m_tmp_query= lex->tok_start;
|
||
}
|
||
statement
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
|
||
sp->m_flags|= sp_get_flags_for_command(lex);
|
||
if (lex->sql_command == SQLCOM_CHANGE_DB)
|
||
{ /* "USE db" doesn't work in a procedure */
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "USE");
|
||
YYABORT;
|
||
}
|
||
/*
|
||
Don't add an instruction for SET statements, since all
|
||
instructions for them were already added during processing
|
||
of "set" rule.
|
||
*/
|
||
DBUG_ASSERT(lex->sql_command != SQLCOM_SET_OPTION ||
|
||
lex->var_list.is_empty());
|
||
if (lex->sql_command != SQLCOM_SET_OPTION)
|
||
{
|
||
sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
|
||
lex->spcont, lex);
|
||
|
||
/*
|
||
Extract the query statement from the tokenizer. The
|
||
end is either lex->ptr, if there was no lookahead,
|
||
lex->tok_end otherwise.
|
||
*/
|
||
if (yychar == YYEMPTY)
|
||
i->m_query.length= lex->ptr - sp->m_tmp_query;
|
||
else
|
||
i->m_query.length= lex->tok_end - sp->m_tmp_query;
|
||
i->m_query.str= strmake_root(YYTHD->mem_root,
|
||
(char *)sp->m_tmp_query,
|
||
i->m_query.length);
|
||
sp->add_instr(i);
|
||
}
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_return:
|
||
RETURN_SYM
|
||
{ Lex->sphead->reset_lex(YYTHD); }
|
||
expr
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
|
||
if (sp->m_type != TYPE_ENUM_FUNCTION)
|
||
{
|
||
my_message(ER_SP_BADRETURN, ER(ER_SP_BADRETURN), MYF(0));
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
sp_instr_freturn *i;
|
||
|
||
i= new sp_instr_freturn(sp->instructions(), lex->spcont, $3,
|
||
sp->m_return_field_def.sql_type, lex);
|
||
sp->add_instr(i);
|
||
sp->m_flags|= sp_head::HAS_RETURN;
|
||
}
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_case_simple:
|
||
CASE_SYM WHEN_SYM
|
||
{
|
||
Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE;
|
||
Lex->sphead->new_cont_backpatch(NULL);
|
||
}
|
||
sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); }
|
||
;
|
||
|
||
sp_proc_stmt_case:
|
||
CASE_SYM
|
||
{
|
||
Lex->sphead->reset_lex(YYTHD);
|
||
Lex->sphead->new_cont_backpatch(NULL);
|
||
}
|
||
expr WHEN_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *parsing_ctx= lex->spcont;
|
||
int case_expr_id= parsing_ctx->register_case_expr();
|
||
sp_instr_set_case_expr *i;
|
||
|
||
if (parsing_ctx->push_case_expr_id(case_expr_id))
|
||
YYABORT;
|
||
|
||
i= new sp_instr_set_case_expr(sp->instructions(),
|
||
parsing_ctx,
|
||
case_expr_id,
|
||
$3,
|
||
lex);
|
||
sp->add_cont_backpatch(i);
|
||
sp->add_instr(i);
|
||
sp->m_flags|= sp_head::IN_SIMPLE_CASE;
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
sp_case END CASE_SYM
|
||
{
|
||
Lex->spcont->pop_case_expr_id();
|
||
Lex->sphead->do_cont_backpatch();
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_unlabeled:
|
||
{ /* Unlabeled controls get a secret label. */
|
||
LEX *lex= Lex;
|
||
|
||
lex->spcont->push_label((char *)"", lex->sphead->instructions());
|
||
}
|
||
sp_unlabeled_control
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->backpatch(lex->spcont->pop_label());
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_leave:
|
||
LEAVE_SYM label_ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp = lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_label_t *lab= ctx->find_label($2.str);
|
||
|
||
if (! lab)
|
||
{
|
||
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "LEAVE", $2.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
sp_instr_jump *i;
|
||
uint ip= sp->instructions();
|
||
uint n;
|
||
|
||
n= ctx->diff_handlers(lab->ctx, TRUE); /* Exclusive the dest. */
|
||
if (n)
|
||
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
||
n= ctx->diff_cursors(lab->ctx, TRUE); /* Exclusive the dest. */
|
||
if (n)
|
||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||
i= new sp_instr_jump(ip, ctx);
|
||
sp->push_backpatch(i, lab); /* Jumping forward */
|
||
sp->add_instr(i);
|
||
}
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_iterate:
|
||
ITERATE_SYM label_ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_label_t *lab= ctx->find_label($2.str);
|
||
|
||
if (! lab || lab->type != SP_LAB_ITER)
|
||
{
|
||
my_error(ER_SP_LILABEL_MISMATCH, MYF(0), "ITERATE", $2.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
sp_instr_jump *i;
|
||
uint ip= sp->instructions();
|
||
uint n;
|
||
|
||
n= ctx->diff_handlers(lab->ctx, FALSE); /* Inclusive the dest. */
|
||
if (n)
|
||
sp->add_instr(new sp_instr_hpop(ip++, ctx, n));
|
||
n= ctx->diff_cursors(lab->ctx, FALSE); /* Inclusive the dest. */
|
||
if (n)
|
||
sp->add_instr(new sp_instr_cpop(ip++, ctx, n));
|
||
i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */
|
||
sp->add_instr(i);
|
||
}
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_open:
|
||
OPEN_SYM ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
uint offset;
|
||
sp_instr_copen *i;
|
||
|
||
if (! lex->spcont->find_cursor(&$2, &offset))
|
||
{
|
||
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
|
||
YYABORT;
|
||
}
|
||
i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
|
||
sp->add_instr(i);
|
||
}
|
||
;
|
||
|
||
sp_proc_stmt_fetch:
|
||
FETCH_SYM sp_opt_fetch_noise ident INTO
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
uint offset;
|
||
sp_instr_cfetch *i;
|
||
|
||
if (! lex->spcont->find_cursor(&$3, &offset))
|
||
{
|
||
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
i= new sp_instr_cfetch(sp->instructions(), lex->spcont, offset);
|
||
sp->add_instr(i);
|
||
}
|
||
sp_fetch_list
|
||
{ }
|
||
;
|
||
|
||
sp_proc_stmt_close:
|
||
CLOSE_SYM ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
uint offset;
|
||
sp_instr_cclose *i;
|
||
|
||
if (! lex->spcont->find_cursor(&$2, &offset))
|
||
{
|
||
my_error(ER_SP_CURSOR_MISMATCH, MYF(0), $2.str);
|
||
YYABORT;
|
||
}
|
||
i= new sp_instr_cclose(sp->instructions(), lex->spcont, offset);
|
||
sp->add_instr(i);
|
||
}
|
||
;
|
||
|
||
sp_opt_fetch_noise:
|
||
/* Empty */
|
||
| NEXT_SYM FROM
|
||
| FROM
|
||
;
|
||
|
||
sp_fetch_list:
|
||
ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *spc= lex->spcont;
|
||
sp_variable_t *spv;
|
||
|
||
if (!spc || !(spv = spc->find_variable(&$1)))
|
||
{
|
||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
/* 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_t *spv;
|
||
|
||
if (!spc || !(spv = spc->find_variable(&$3)))
|
||
{
|
||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
/* An SP local variable */
|
||
sp_instr_cfetch *i= (sp_instr_cfetch *)sp->last_instruction();
|
||
|
||
i->add_to_varlist(spv);
|
||
}
|
||
}
|
||
;
|
||
|
||
sp_if:
|
||
{ Lex->sphead->reset_lex(YYTHD); }
|
||
expr THEN_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
uint ip= sp->instructions();
|
||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, ctx,
|
||
$2, lex);
|
||
|
||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||
sp->add_cont_backpatch(i);
|
||
sp->add_instr(i);
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
sp_proc_stmts1
|
||
{
|
||
sp_head *sp= Lex->sphead;
|
||
sp_pcontext *ctx= Lex->spcont;
|
||
uint ip= sp->instructions();
|
||
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
|
||
|
||
sp->add_instr(i);
|
||
sp->backpatch(ctx->pop_label());
|
||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||
}
|
||
sp_elseifs
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->backpatch(lex->spcont->pop_label());
|
||
}
|
||
;
|
||
|
||
sp_elseifs:
|
||
/* Empty */
|
||
| ELSEIF_SYM sp_if
|
||
| ELSE sp_proc_stmts1
|
||
;
|
||
|
||
sp_case:
|
||
{ Lex->sphead->reset_lex(YYTHD); }
|
||
expr THEN_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= Lex->spcont;
|
||
uint ip= sp->instructions();
|
||
sp_instr_jump_if_not *i;
|
||
|
||
if (! (sp->m_flags & sp_head::IN_SIMPLE_CASE))
|
||
i= new sp_instr_jump_if_not(ip, ctx, $2, lex);
|
||
else
|
||
{ /* Simple case: <caseval> = <whenval> */
|
||
|
||
Item_case_expr *var;
|
||
Item *expr;
|
||
|
||
var= new Item_case_expr(ctx->get_current_case_expr_id());
|
||
|
||
#ifndef DBUG_OFF
|
||
if (var)
|
||
var->m_sp= sp;
|
||
#endif
|
||
|
||
expr= new Item_func_eq(var, $2);
|
||
|
||
i= new sp_instr_jump_if_not(ip, ctx, expr, lex);
|
||
}
|
||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||
sp->add_cont_backpatch(i);
|
||
sp->add_instr(i);
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
sp_proc_stmts1
|
||
{
|
||
sp_head *sp= Lex->sphead;
|
||
sp_pcontext *ctx= Lex->spcont;
|
||
uint ip= sp->instructions();
|
||
sp_instr_jump *i = new sp_instr_jump(ip, ctx);
|
||
|
||
sp->add_instr(i);
|
||
sp->backpatch(ctx->pop_label());
|
||
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
|
||
}
|
||
sp_whens
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->backpatch(lex->spcont->pop_label());
|
||
}
|
||
;
|
||
|
||
sp_whens:
|
||
/* Empty */
|
||
{
|
||
sp_head *sp= Lex->sphead;
|
||
uint ip= sp->instructions();
|
||
sp_instr_error *i= new sp_instr_error(ip, Lex->spcont,
|
||
ER_SP_CASE_NOT_FOUND);
|
||
|
||
sp->add_instr(i);
|
||
}
|
||
| ELSE sp_proc_stmts1 {}
|
||
| WHEN_SYM sp_case {}
|
||
;
|
||
|
||
sp_labeled_control:
|
||
label_ident ':'
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_label_t *lab= ctx->find_label($1.str);
|
||
|
||
if (lab)
|
||
{
|
||
my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
lab= lex->spcont->push_label($1.str,
|
||
lex->sphead->instructions());
|
||
lab->type= SP_LAB_ITER;
|
||
}
|
||
}
|
||
sp_unlabeled_control sp_opt_label
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if ($5.str)
|
||
{
|
||
sp_label_t *lab= lex->spcont->find_label($5.str);
|
||
|
||
if (!lab ||
|
||
my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
|
||
{
|
||
my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
|
||
YYABORT;
|
||
}
|
||
}
|
||
lex->sphead->backpatch(lex->spcont->pop_label());
|
||
}
|
||
;
|
||
|
||
sp_opt_label:
|
||
/* Empty */ { $$= null_lex_str; }
|
||
| label_ident { $$= $1; }
|
||
;
|
||
|
||
sp_unlabeled_control:
|
||
BEGIN_SYM
|
||
{ /* QQ This is just a dummy for grouping declarations and statements
|
||
together. No [[NOT] ATOMIC] yet, and we need to figure out how
|
||
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
|
||
LEX *lex= Lex;
|
||
sp_label_t *lab= lex->spcont->last_label();
|
||
|
||
lab->type= SP_LAB_BEGIN;
|
||
lex->spcont= lex->spcont->push_context();
|
||
}
|
||
sp_decls
|
||
sp_proc_stmts
|
||
END
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
sp_pcontext *ctx= lex->spcont;
|
||
|
||
sp->backpatch(ctx->last_label()); /* We always have a label */
|
||
if ($3.hndlrs)
|
||
sp->add_instr(new sp_instr_hpop(sp->instructions(), ctx,
|
||
$3.hndlrs));
|
||
if ($3.curs)
|
||
sp->add_instr(new sp_instr_cpop(sp->instructions(), ctx,
|
||
$3.curs));
|
||
lex->spcont= ctx->pop_context();
|
||
}
|
||
| LOOP_SYM
|
||
sp_proc_stmts1 END LOOP_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
uint ip= lex->sphead->instructions();
|
||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
|
||
|
||
lex->sphead->add_instr(i);
|
||
}
|
||
| WHILE_SYM
|
||
{ Lex->sphead->reset_lex(YYTHD); }
|
||
expr DO_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
uint ip= sp->instructions();
|
||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
|
||
$3, lex);
|
||
|
||
/* Jumping forward */
|
||
sp->push_backpatch(i, lex->spcont->last_label());
|
||
sp->new_cont_backpatch(i);
|
||
sp->add_instr(i);
|
||
sp->restore_lex(YYTHD);
|
||
}
|
||
sp_proc_stmts1 END WHILE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
uint ip= lex->sphead->instructions();
|
||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||
sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip);
|
||
|
||
lex->sphead->add_instr(i);
|
||
lex->sphead->do_cont_backpatch();
|
||
}
|
||
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
|
||
{ Lex->sphead->reset_lex(YYTHD); }
|
||
expr END REPEAT_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
uint ip= lex->sphead->instructions();
|
||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, lex->spcont,
|
||
$5, lab->ip,
|
||
lex);
|
||
lex->sphead->add_instr(i);
|
||
lex->sphead->restore_lex(YYTHD);
|
||
/* We can shortcut the cont_backpatch here */
|
||
i->m_cont_dest= ip+1;
|
||
}
|
||
;
|
||
|
||
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; }
|
||
;
|
||
/*
|
||
This part of the parser contains common code for all TABLESPACE
|
||
commands.
|
||
CREATE TABLESPACE name ...
|
||
ALTER TABLESPACE name CHANGE DATAFILE ...
|
||
ALTER TABLESPACE name ADD DATAFILE ...
|
||
ALTER TABLESPACE name access_mode
|
||
CREATE LOGFILE GROUP name ...
|
||
ALTER LOGFILE GROUP name ADD UNDOFILE ..
|
||
ALTER LOGFILE GROUP name ADD REDOFILE ..
|
||
DROP TABLESPACE name
|
||
DROP LOGFILE GROUP name
|
||
*/
|
||
change_tablespace_access:
|
||
tablespace_name
|
||
ts_access_mode
|
||
;
|
||
|
||
change_tablespace_info:
|
||
tablespace_name
|
||
CHANGE ts_datafile
|
||
change_ts_option_list
|
||
;
|
||
|
||
tablespace_info:
|
||
tablespace_name
|
||
ADD ts_datafile
|
||
opt_logfile_group_name
|
||
tablespace_option_list
|
||
;
|
||
|
||
opt_logfile_group_name:
|
||
/* empty */ {}
|
||
| USE_SYM LOGFILE_SYM GROUP ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->logfile_group_name= $4.str;
|
||
};
|
||
|
||
alter_tablespace_info:
|
||
tablespace_name
|
||
ADD ts_datafile
|
||
alter_tablespace_option_list
|
||
{
|
||
Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_ADD_FILE;
|
||
}
|
||
|
|
||
tablespace_name
|
||
DROP ts_datafile
|
||
alter_tablespace_option_list
|
||
{
|
||
Lex->alter_tablespace_info->ts_alter_tablespace_type= ALTER_TABLESPACE_DROP_FILE;
|
||
};
|
||
|
||
logfile_group_info:
|
||
logfile_group_name
|
||
add_log_file
|
||
logfile_group_option_list
|
||
;
|
||
|
||
alter_logfile_group_info:
|
||
logfile_group_name
|
||
add_log_file
|
||
alter_logfile_group_option_list
|
||
;
|
||
|
||
add_log_file:
|
||
ADD lg_undofile
|
||
| ADD lg_redofile
|
||
;
|
||
|
||
change_ts_option_list:
|
||
/* empty */ {}
|
||
change_ts_options
|
||
;
|
||
|
||
change_ts_options:
|
||
change_ts_option
|
||
| change_ts_options change_ts_option
|
||
| change_ts_options ',' change_ts_option
|
||
;
|
||
|
||
change_ts_option:
|
||
opt_ts_initial_size
|
||
| opt_ts_autoextend_size
|
||
| opt_ts_max_size
|
||
;
|
||
|
||
tablespace_option_list:
|
||
/* empty */ {}
|
||
tablespace_options
|
||
;
|
||
|
||
tablespace_options:
|
||
tablespace_option
|
||
| tablespace_options tablespace_option
|
||
| tablespace_options ',' tablespace_option
|
||
;
|
||
|
||
tablespace_option:
|
||
opt_ts_initial_size
|
||
| opt_ts_autoextend_size
|
||
| opt_ts_max_size
|
||
| opt_ts_extent_size
|
||
| opt_ts_nodegroup
|
||
| opt_ts_engine
|
||
| ts_wait
|
||
| opt_ts_comment
|
||
;
|
||
|
||
alter_tablespace_option_list:
|
||
/* empty */ {}
|
||
alter_tablespace_options
|
||
;
|
||
|
||
alter_tablespace_options:
|
||
alter_tablespace_option
|
||
| alter_tablespace_options alter_tablespace_option
|
||
| alter_tablespace_options ',' alter_tablespace_option
|
||
;
|
||
|
||
alter_tablespace_option:
|
||
opt_ts_initial_size
|
||
| opt_ts_autoextend_size
|
||
| opt_ts_max_size
|
||
| opt_ts_engine
|
||
| ts_wait
|
||
;
|
||
|
||
logfile_group_option_list:
|
||
/* empty */ {}
|
||
logfile_group_options
|
||
;
|
||
|
||
logfile_group_options:
|
||
logfile_group_option
|
||
| logfile_group_options logfile_group_option
|
||
| logfile_group_options ',' logfile_group_option
|
||
;
|
||
|
||
logfile_group_option:
|
||
opt_ts_initial_size
|
||
| opt_ts_undo_buffer_size
|
||
| opt_ts_redo_buffer_size
|
||
| opt_ts_nodegroup
|
||
| opt_ts_engine
|
||
| ts_wait
|
||
| opt_ts_comment
|
||
;
|
||
|
||
alter_logfile_group_option_list:
|
||
/* empty */ {}
|
||
alter_logfile_group_options
|
||
;
|
||
|
||
alter_logfile_group_options:
|
||
alter_logfile_group_option
|
||
| alter_logfile_group_options alter_logfile_group_option
|
||
| alter_logfile_group_options ',' alter_logfile_group_option
|
||
;
|
||
|
||
alter_logfile_group_option:
|
||
opt_ts_initial_size
|
||
| opt_ts_engine
|
||
| ts_wait
|
||
;
|
||
|
||
|
||
ts_datafile:
|
||
DATAFILE_SYM TEXT_STRING_sys
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->data_file_name= $2.str;
|
||
};
|
||
|
||
lg_undofile:
|
||
UNDOFILE_SYM TEXT_STRING_sys
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->undo_file_name= $2.str;
|
||
};
|
||
|
||
lg_redofile:
|
||
REDOFILE_SYM TEXT_STRING_sys
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->redo_file_name= $2.str;
|
||
};
|
||
|
||
tablespace_name:
|
||
ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info= new st_alter_tablespace();
|
||
lex->alter_tablespace_info->tablespace_name= $1.str;
|
||
lex->sql_command= SQLCOM_ALTER_TABLESPACE;
|
||
};
|
||
|
||
logfile_group_name:
|
||
ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info= new st_alter_tablespace();
|
||
lex->alter_tablespace_info->logfile_group_name= $1.str;
|
||
lex->sql_command= SQLCOM_ALTER_TABLESPACE;
|
||
};
|
||
|
||
ts_access_mode:
|
||
READ_ONLY_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_access_mode= TS_READ_ONLY;
|
||
}
|
||
| READ_WRITE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_access_mode= TS_READ_WRITE;
|
||
}
|
||
| NOT_SYM ACCESSIBLE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_access_mode= TS_NOT_ACCESSIBLE;
|
||
};
|
||
|
||
opt_ts_initial_size:
|
||
INITIAL_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->initial_size= $3;
|
||
};
|
||
|
||
opt_ts_autoextend_size:
|
||
AUTOEXTEND_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->autoextend_size= $3;
|
||
};
|
||
|
||
opt_ts_max_size:
|
||
MAX_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->max_size= $3;
|
||
};
|
||
|
||
opt_ts_extent_size:
|
||
EXTENT_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->extent_size= $3;
|
||
};
|
||
|
||
opt_ts_undo_buffer_size:
|
||
UNDO_BUFFER_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->undo_buffer_size= $3;
|
||
};
|
||
|
||
opt_ts_redo_buffer_size:
|
||
REDO_BUFFER_SIZE_SYM opt_equal size_number
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->redo_buffer_size= $3;
|
||
};
|
||
|
||
opt_ts_nodegroup:
|
||
NODEGROUP_SYM opt_equal real_ulong_num
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->alter_tablespace_info->nodegroup_id != UNDEF_NODEGROUP)
|
||
{
|
||
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NODEGROUP");
|
||
YYABORT;
|
||
}
|
||
lex->alter_tablespace_info->nodegroup_id= $3;
|
||
};
|
||
|
||
opt_ts_comment:
|
||
COMMENT_SYM opt_equal TEXT_STRING_sys
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->alter_tablespace_info->ts_comment != NULL)
|
||
{
|
||
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"COMMENT");
|
||
YYABORT;
|
||
}
|
||
lex->alter_tablespace_info->ts_comment= $3.str;
|
||
};
|
||
|
||
opt_ts_engine:
|
||
opt_storage ENGINE_SYM opt_equal storage_engines
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->alter_tablespace_info->storage_engine != NULL)
|
||
{
|
||
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),
|
||
"STORAGE ENGINE");
|
||
YYABORT;
|
||
}
|
||
lex->alter_tablespace_info->storage_engine= $4;
|
||
};
|
||
|
||
opt_ts_wait:
|
||
/* empty */
|
||
| ts_wait
|
||
;
|
||
|
||
ts_wait:
|
||
WAIT_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->wait_until_completed= TRUE;
|
||
}
|
||
| NO_WAIT_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!(lex->alter_tablespace_info->wait_until_completed))
|
||
{
|
||
my_error(ER_FILEGROUP_OPTION_ONLY_ONCE,MYF(0),"NO_WAIT");
|
||
YYABORT;
|
||
}
|
||
lex->alter_tablespace_info->wait_until_completed= FALSE;
|
||
};
|
||
|
||
size_number:
|
||
real_ulong_num { $$= $1;}
|
||
| IDENT
|
||
{
|
||
ulonglong number, test_number;
|
||
uint text_shift_number= 0;
|
||
longlong prefix_number;
|
||
char *start_ptr= $1.str;
|
||
uint str_len= $1.length;
|
||
char *end_ptr= start_ptr + str_len;
|
||
int error;
|
||
prefix_number= my_strtoll10(start_ptr, &end_ptr, &error);
|
||
if ((start_ptr + str_len - 1) == end_ptr)
|
||
{
|
||
switch (end_ptr[0])
|
||
{
|
||
case 'g':
|
||
case 'G':
|
||
text_shift_number+=10;
|
||
case 'm':
|
||
case 'M':
|
||
text_shift_number+=10;
|
||
case 'k':
|
||
case 'K':
|
||
text_shift_number+=10;
|
||
break;
|
||
default:
|
||
{
|
||
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
if (prefix_number >> 31)
|
||
{
|
||
my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0));
|
||
YYABORT;
|
||
}
|
||
number= prefix_number << text_shift_number;
|
||
}
|
||
else
|
||
{
|
||
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
|
||
YYABORT;
|
||
}
|
||
$$= number;
|
||
}
|
||
;
|
||
|
||
/*
|
||
End tablespace part
|
||
*/
|
||
|
||
create2:
|
||
'(' create2a {}
|
||
| opt_create_table_options
|
||
opt_partitioning {}
|
||
create3 {}
|
||
| LIKE table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
THD *thd= lex->thd;
|
||
if (!(lex->like_name= $2))
|
||
YYABORT;
|
||
if ($2->db.str == NULL &&
|
||
thd->copy_db_to(&($2->db.str), &($2->db.length)))
|
||
{
|
||
YYABORT;
|
||
}
|
||
}
|
||
| '(' LIKE table_ident ')'
|
||
{
|
||
LEX *lex=Lex;
|
||
THD *thd= lex->thd;
|
||
if (!(lex->like_name= $3))
|
||
YYABORT;
|
||
if ($3->db.str == NULL &&
|
||
thd->copy_db_to(&($3->db.str), &($3->db.length)))
|
||
{
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
create2a:
|
||
field_list ')' opt_create_table_options
|
||
opt_partitioning {}
|
||
create3 {}
|
||
| opt_partitioning {}
|
||
create_select ')'
|
||
{ Select->set_braces(1);} union_opt {}
|
||
;
|
||
|
||
create3:
|
||
/* empty */ {}
|
||
| opt_duplicate opt_as create_select
|
||
{ Select->set_braces(0);} union_clause {}
|
||
| opt_duplicate opt_as '(' create_select ')'
|
||
{ Select->set_braces(1);} union_opt {}
|
||
;
|
||
|
||
/*
|
||
This part of the parser is about handling of the partition information.
|
||
|
||
It's 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
|
||
{
|
||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||
LEX *lex= Lex;
|
||
lex->part_info= new partition_info();
|
||
if (!lex->part_info)
|
||
{
|
||
mem_alloc_error(sizeof(partition_info));
|
||
YYABORT;
|
||
}
|
||
if (lex->sql_command == SQLCOM_ALTER_TABLE)
|
||
{
|
||
lex->alter_info.flags|= ALTER_PARTITION;
|
||
}
|
||
#else
|
||
my_error(ER_FEATURE_DISABLED, MYF(0),
|
||
"partitioning", "--with-partition");
|
||
YYABORT;
|
||
#endif
|
||
|
||
}
|
||
partition
|
||
;
|
||
|
||
partition_entry:
|
||
PARTITION_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!lex->part_info)
|
||
{
|
||
yyerror(ER(ER_PARTITION_ENTRY_ERROR));
|
||
YYABORT;
|
||
}
|
||
/*
|
||
We enter here when opening the frm file to translate
|
||
partition info string into part_info data structure.
|
||
*/
|
||
}
|
||
partition {}
|
||
;
|
||
|
||
partition:
|
||
BY part_type_def opt_no_parts {} opt_sub_part {} part_defs
|
||
;
|
||
|
||
part_type_def:
|
||
opt_linear KEY_SYM '(' part_field_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->list_of_part_fields= TRUE;
|
||
lex->part_info->part_type= HASH_PARTITION;
|
||
}
|
||
| opt_linear HASH_SYM
|
||
{ Lex->part_info->part_type= HASH_PARTITION; }
|
||
part_func {}
|
||
| RANGE_SYM
|
||
{ Lex->part_info->part_type= RANGE_PARTITION; }
|
||
part_func {}
|
||
| LIST_SYM
|
||
{ Lex->part_info->part_type= LIST_PARTITION; }
|
||
part_func {}
|
||
;
|
||
|
||
opt_linear:
|
||
/* empty */ {}
|
||
| LINEAR_SYM
|
||
{ Lex->part_info->linear_hash_ind= TRUE;}
|
||
;
|
||
|
||
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
|
||
{
|
||
if (Lex->part_info->part_field_list.push_back($1.str))
|
||
{
|
||
mem_alloc_error(1);
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
part_func:
|
||
'(' remember_name part_func_expr remember_end ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
uint expr_len= (uint)($4 - $2) - 1;
|
||
lex->part_info->list_of_part_fields= FALSE;
|
||
lex->part_info->part_expr= $3;
|
||
lex->part_info->part_func_string= (char* ) sql_memdup($2+1, expr_len);
|
||
lex->part_info->part_func_len= expr_len;
|
||
}
|
||
;
|
||
|
||
sub_part_func:
|
||
'(' remember_name part_func_expr remember_end ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
uint expr_len= (uint)($4 - $2) - 1;
|
||
lex->part_info->list_of_subpart_fields= FALSE;
|
||
lex->part_info->subpart_expr= $3;
|
||
lex->part_info->subpart_func_string= (char* ) sql_memdup($2+1, expr_len);
|
||
lex->part_info->subpart_func_len= expr_len;
|
||
}
|
||
;
|
||
|
||
|
||
opt_no_parts:
|
||
/* empty */ {}
|
||
| PARTITIONS_SYM real_ulong_num
|
||
{
|
||
uint no_parts= $2;
|
||
LEX *lex= Lex;
|
||
if (no_parts == 0)
|
||
{
|
||
my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions");
|
||
YYABORT;
|
||
}
|
||
|
||
lex->part_info->no_parts= no_parts;
|
||
lex->part_info->use_default_no_partitions= FALSE;
|
||
}
|
||
;
|
||
|
||
opt_sub_part:
|
||
/* empty */ {}
|
||
| SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func
|
||
{ Lex->part_info->subpart_type= HASH_PARTITION; }
|
||
opt_no_subparts {}
|
||
| SUBPARTITION_SYM BY opt_linear KEY_SYM
|
||
'(' sub_part_field_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->subpart_type= HASH_PARTITION;
|
||
lex->part_info->list_of_subpart_fields= TRUE;
|
||
}
|
||
opt_no_subparts {}
|
||
;
|
||
|
||
sub_part_field_list:
|
||
sub_part_field_item {}
|
||
| sub_part_field_list ',' sub_part_field_item {}
|
||
;
|
||
|
||
sub_part_field_item:
|
||
ident
|
||
{
|
||
if (Lex->part_info->subpart_field_list.push_back($1.str))
|
||
{
|
||
mem_alloc_error(1);
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
part_func_expr:
|
||
bit_expr
|
||
{
|
||
LEX *lex= Lex;
|
||
bool not_corr_func;
|
||
not_corr_func= !lex->safe_to_cache_query;
|
||
lex->safe_to_cache_query= 1;
|
||
if (not_corr_func)
|
||
{
|
||
yyerror(ER(ER_CONST_EXPR_IN_PARTITION_FUNC_ERROR));
|
||
YYABORT;
|
||
}
|
||
$$=$1;
|
||
}
|
||
;
|
||
|
||
opt_no_subparts:
|
||
/* empty */ {}
|
||
| SUBPARTITIONS_SYM real_ulong_num
|
||
{
|
||
uint no_parts= $2;
|
||
LEX *lex= Lex;
|
||
if (no_parts == 0)
|
||
{
|
||
my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions");
|
||
YYABORT;
|
||
}
|
||
lex->part_info->no_subparts= no_parts;
|
||
lex->part_info->use_default_no_subpartitions= FALSE;
|
||
}
|
||
;
|
||
|
||
part_defs:
|
||
/* empty */
|
||
{}
|
||
| '(' part_def_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
partition_info *part_info= lex->part_info;
|
||
uint count_curr_parts= part_info->partitions.elements;
|
||
if (part_info->no_parts != 0)
|
||
{
|
||
if (part_info->no_parts !=
|
||
count_curr_parts)
|
||
{
|
||
yyerror(ER(ER_PARTITION_WRONG_NO_PART_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
else if (count_curr_parts > 0)
|
||
{
|
||
part_info->no_parts= count_curr_parts;
|
||
}
|
||
part_info->count_curr_subparts= 0;
|
||
}
|
||
;
|
||
|
||
part_def_list:
|
||
part_definition {}
|
||
| part_def_list ',' part_definition {}
|
||
;
|
||
|
||
part_definition:
|
||
PARTITION_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
partition_info *part_info= lex->part_info;
|
||
partition_element *p_elem= new partition_element();
|
||
uint part_id= part_info->partitions.elements;
|
||
|
||
if (!p_elem || part_info->partitions.push_back(p_elem))
|
||
{
|
||
mem_alloc_error(sizeof(partition_element));
|
||
YYABORT;
|
||
}
|
||
p_elem->part_state= PART_NORMAL;
|
||
part_info->curr_part_elem= p_elem;
|
||
part_info->current_partition= p_elem;
|
||
part_info->use_default_partitions= FALSE;
|
||
part_info->use_default_no_partitions= FALSE;
|
||
}
|
||
part_name {}
|
||
opt_part_values {}
|
||
opt_part_options {}
|
||
opt_sub_partition {}
|
||
;
|
||
|
||
part_name:
|
||
ident
|
||
{
|
||
LEX *lex= Lex;
|
||
partition_info *part_info= lex->part_info;
|
||
partition_element *p_elem= part_info->curr_part_elem;
|
||
p_elem->partition_name= $1.str;
|
||
}
|
||
;
|
||
|
||
opt_part_values:
|
||
/* empty */
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!is_partition_management(lex))
|
||
{
|
||
if (lex->part_info->part_type == RANGE_PARTITION)
|
||
{
|
||
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
|
||
"RANGE", "LESS THAN");
|
||
YYABORT;
|
||
}
|
||
if (lex->part_info->part_type == LIST_PARTITION)
|
||
{
|
||
my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
|
||
"LIST", "IN");
|
||
YYABORT;
|
||
}
|
||
}
|
||
else
|
||
lex->part_info->part_type= HASH_PARTITION;
|
||
}
|
||
| VALUES LESS_SYM THAN_SYM part_func_max
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!is_partition_management(lex))
|
||
{
|
||
if (Lex->part_info->part_type != RANGE_PARTITION)
|
||
{
|
||
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
|
||
"RANGE", "LESS THAN");
|
||
YYABORT;
|
||
}
|
||
}
|
||
else
|
||
lex->part_info->part_type= RANGE_PARTITION;
|
||
}
|
||
| VALUES IN_SYM '(' part_list_func ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!is_partition_management(lex))
|
||
{
|
||
if (Lex->part_info->part_type != LIST_PARTITION)
|
||
{
|
||
my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
|
||
"LIST", "IN");
|
||
YYABORT;
|
||
}
|
||
}
|
||
else
|
||
lex->part_info->part_type= LIST_PARTITION;
|
||
}
|
||
;
|
||
|
||
part_func_max:
|
||
max_value_sym
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->part_info->defined_max_value)
|
||
{
|
||
yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->part_info->defined_max_value= TRUE;
|
||
lex->part_info->curr_part_elem->max_value= TRUE;
|
||
lex->part_info->curr_part_elem->range_value= LONGLONG_MAX;
|
||
}
|
||
| part_range_func
|
||
{
|
||
if (Lex->part_info->defined_max_value)
|
||
{
|
||
yyerror(ER(ER_PARTITION_MAXVALUE_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (Lex->part_info->curr_part_elem->has_null_value)
|
||
{
|
||
yyerror(ER(ER_NULL_IN_VALUES_LESS_THAN));
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
max_value_sym:
|
||
MAX_VALUE_SYM
|
||
| '(' MAX_VALUE_SYM ')'
|
||
;
|
||
|
||
part_range_func:
|
||
'(' part_bit_expr ')'
|
||
{
|
||
partition_info *part_info= Lex->part_info;
|
||
if (!($2->unsigned_flag))
|
||
part_info->curr_part_elem->signed_flag= TRUE;
|
||
part_info->curr_part_elem->range_value= $2->value;
|
||
}
|
||
;
|
||
|
||
part_list_func:
|
||
part_list_item {}
|
||
| part_list_func ',' part_list_item {}
|
||
;
|
||
|
||
part_list_item:
|
||
part_bit_expr
|
||
{
|
||
part_elem_value *value_ptr= $1;
|
||
partition_info *part_info= Lex->part_info;
|
||
if (!value_ptr->unsigned_flag)
|
||
part_info->curr_part_elem->signed_flag= TRUE;
|
||
if (!value_ptr->null_value &&
|
||
part_info->curr_part_elem->
|
||
list_val_list.push_back(value_ptr))
|
||
{
|
||
mem_alloc_error(sizeof(part_elem_value));
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
part_bit_expr:
|
||
bit_expr
|
||
{
|
||
Item *part_expr= $1;
|
||
bool not_corr_func;
|
||
int part_expression_ok= 1;
|
||
LEX *lex= Lex;
|
||
THD *thd= YYTHD;
|
||
longlong item_value;
|
||
Name_resolution_context *context= &lex->current_select->context;
|
||
TABLE_LIST *save_list= context->table_list;
|
||
const char *save_where= thd->where;
|
||
|
||
context->table_list= 0;
|
||
thd->where= "partition function";
|
||
|
||
part_elem_value *value_ptr=
|
||
(part_elem_value*)sql_alloc(sizeof(part_elem_value));
|
||
if (!value_ptr)
|
||
{
|
||
mem_alloc_error(sizeof(part_elem_value));
|
||
YYABORT;
|
||
}
|
||
if (part_expr->walk(&Item::check_partition_func_processor, 0,
|
||
NULL))
|
||
{
|
||
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
|
||
YYABORT;
|
||
}
|
||
if (part_expr->fix_fields(YYTHD, (Item**)0) ||
|
||
((context->table_list= save_list), FALSE) ||
|
||
(!part_expr->const_item()) ||
|
||
(!lex->safe_to_cache_query))
|
||
{
|
||
my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0));
|
||
YYABORT;
|
||
}
|
||
thd->where= save_where;
|
||
value_ptr->value= part_expr->val_int();
|
||
value_ptr->unsigned_flag= TRUE;
|
||
if (!part_expr->unsigned_flag &&
|
||
value_ptr->value < 0)
|
||
value_ptr->unsigned_flag= FALSE;
|
||
if ((value_ptr->null_value= part_expr->null_value))
|
||
{
|
||
if (Lex->part_info->curr_part_elem->has_null_value)
|
||
{
|
||
my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
|
||
YYABORT;
|
||
}
|
||
Lex->part_info->curr_part_elem->has_null_value= TRUE;
|
||
}
|
||
else if (part_expr->result_type() != INT_RESULT &&
|
||
!part_expr->null_value)
|
||
{
|
||
yyerror(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR));
|
||
YYABORT;
|
||
}
|
||
$$= value_ptr;
|
||
}
|
||
;
|
||
|
||
opt_sub_partition:
|
||
/* empty */
|
||
{
|
||
if (Lex->part_info->no_subparts != 0 &&
|
||
!Lex->part_info->use_default_subpartitions)
|
||
{
|
||
yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
| '(' sub_part_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
partition_info *part_info= lex->part_info;
|
||
if (part_info->no_subparts != 0)
|
||
{
|
||
if (part_info->no_subparts !=
|
||
part_info->count_curr_subparts)
|
||
{
|
||
yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
else if (part_info->count_curr_subparts > 0)
|
||
{
|
||
if (part_info->partitions.elements > 1)
|
||
{
|
||
yyerror(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR));
|
||
YYABORT;
|
||
}
|
||
part_info->no_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
|
||
{
|
||
LEX *lex= Lex;
|
||
partition_info *part_info= lex->part_info;
|
||
partition_element *curr_part= part_info->current_partition;
|
||
partition_element *sub_p_elem= new partition_element(curr_part);
|
||
if (!sub_p_elem ||
|
||
curr_part->subpartitions.push_back(sub_p_elem))
|
||
{
|
||
mem_alloc_error(sizeof(partition_element));
|
||
YYABORT;
|
||
}
|
||
part_info->curr_part_elem= sub_p_elem;
|
||
part_info->use_default_subpartitions= FALSE;
|
||
part_info->use_default_no_subpartitions= FALSE;
|
||
part_info->count_curr_subparts++;
|
||
}
|
||
sub_name opt_part_options {}
|
||
;
|
||
|
||
sub_name:
|
||
ident_or_text
|
||
{ Lex->part_info->curr_part_elem->partition_name= $1.str; }
|
||
;
|
||
|
||
opt_part_options:
|
||
/* empty */ {}
|
||
| opt_part_option_list {}
|
||
;
|
||
|
||
opt_part_option_list:
|
||
opt_part_option_list opt_part_option {}
|
||
| opt_part_option {}
|
||
;
|
||
|
||
opt_part_option:
|
||
TABLESPACE opt_equal ident_or_text
|
||
{ Lex->part_info->curr_part_elem->tablespace_name= $3.str; }
|
||
| opt_storage ENGINE_SYM opt_equal storage_engines
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->curr_part_elem->engine_type= $4;
|
||
lex->part_info->default_engine_type= $4;
|
||
}
|
||
| NODEGROUP_SYM opt_equal real_ulong_num
|
||
{ Lex->part_info->curr_part_elem->nodegroup_id= $3; }
|
||
| MAX_ROWS opt_equal real_ulonglong_num
|
||
{ Lex->part_info->curr_part_elem->part_max_rows= $3; }
|
||
| MIN_ROWS opt_equal real_ulonglong_num
|
||
{ Lex->part_info->curr_part_elem->part_min_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; }
|
||
;
|
||
|
||
/*
|
||
End of partition parser part
|
||
*/
|
||
|
||
create_select:
|
||
SELECT_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
|
||
if (lex->sql_command == SQLCOM_INSERT)
|
||
lex->sql_command= SQLCOM_INSERT_SELECT;
|
||
else if (lex->sql_command == SQLCOM_REPLACE)
|
||
lex->sql_command= SQLCOM_REPLACE_SELECT;
|
||
/*
|
||
The following work only with the local list, the global list
|
||
is created correctly in this case
|
||
*/
|
||
lex->current_select->table_list.save_and_clear(&lex->save_list);
|
||
mysql_init_select(lex);
|
||
lex->current_select->parsing_place= SELECT_LIST;
|
||
}
|
||
select_options select_item_list
|
||
{
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
opt_select_from
|
||
{
|
||
/*
|
||
The following work only with the local list, the global list
|
||
is created correctly in this case
|
||
*/
|
||
Lex->current_select->table_list.push_front(&Lex->save_list);
|
||
}
|
||
;
|
||
|
||
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 {};
|
||
|
||
opt_table_options:
|
||
/* empty */ { $$= 0; }
|
||
| table_options { $$= $1;};
|
||
|
||
table_options:
|
||
table_option { $$=$1; }
|
||
| table_option table_options { $$= $1 | $2; };
|
||
|
||
table_option:
|
||
TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; };
|
||
|
||
opt_if_not_exists:
|
||
/* empty */ { $$= 0; }
|
||
| IF not EXISTS { $$=HA_LEX_CREATE_IF_NOT_EXISTS; };
|
||
|
||
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 storage_engines { Lex->create_info.db_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; }
|
||
| TYPE_SYM opt_equal storage_engines
|
||
{
|
||
Lex->create_info.db_type= $3;
|
||
WARN_DEPRECATED(yythd, "5.2", "TYPE=storage_engine",
|
||
"'ENGINE=storage_engine'");
|
||
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 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:
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
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;
|
||
}
|
||
| 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; }
|
||
| 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 '(' table_list ')'
|
||
{
|
||
/* Move the union list to the merge_list */
|
||
LEX *lex=Lex;
|
||
TABLE_LIST *table_list= lex->select_lex.get_table_list();
|
||
lex->create_info.merge_list= lex->select_lex.table_list;
|
||
lex->create_info.merge_list.elements--;
|
||
lex->create_info.merge_list.first=
|
||
(byte*) (table_list->next_local);
|
||
lex->select_lex.table_list.elements=1;
|
||
lex->select_lex.table_list.next=
|
||
(byte**) &(table_list->next_local);
|
||
table_list->next_local= 0;
|
||
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 {Lex->create_info.tablespace= $2.str;}
|
||
| STORAGE_SYM DISK_SYM {Lex->create_info.store_on_disk= TRUE;}
|
||
| STORAGE_SYM MEMORY_SYM {Lex->create_info.store_on_disk= FALSE;}
|
||
| 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;
|
||
}
|
||
;
|
||
|
||
default_charset:
|
||
opt_default charset opt_equal charset_name_or_default
|
||
{
|
||
HA_CREATE_INFO *cinfo= &Lex->create_info;
|
||
if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
|
||
cinfo->default_table_charset && $4 &&
|
||
!my_charset_same(cinfo->default_table_charset,$4))
|
||
{
|
||
my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
|
||
"CHARACTER SET ", cinfo->default_table_charset->csname,
|
||
"CHARACTER SET ", $4->csname);
|
||
YYABORT;
|
||
}
|
||
Lex->create_info.default_table_charset= $4;
|
||
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
|
||
};
|
||
|
||
default_collation:
|
||
opt_default COLLATE_SYM opt_equal collation_name_or_default
|
||
{
|
||
HA_CREATE_INFO *cinfo= &Lex->create_info;
|
||
if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
|
||
cinfo->default_table_charset && $4 &&
|
||
!my_charset_same(cinfo->default_table_charset,$4))
|
||
{
|
||
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
|
||
$4->name, cinfo->default_table_charset->csname);
|
||
YYABORT;
|
||
}
|
||
Lex->create_info.default_table_charset= $4;
|
||
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
|
||
};
|
||
|
||
storage_engines:
|
||
ident_or_text
|
||
{
|
||
$$ = ha_resolve_by_name(YYTHD, &$1);
|
||
if ($$ == NULL)
|
||
if (YYTHD->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION)
|
||
{
|
||
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_ERROR,
|
||
ER_UNKNOWN_STORAGE_ENGINE,
|
||
ER(ER_UNKNOWN_STORAGE_ENGINE), $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; };
|
||
|
||
merge_insert_types:
|
||
NO_SYM { $$= MERGE_INSERT_DISABLED; }
|
||
| FIRST_SYM { $$= MERGE_INSERT_TO_FIRST; }
|
||
| LAST_SYM { $$= MERGE_INSERT_TO_LAST; };
|
||
|
||
opt_select_from:
|
||
opt_limit_clause {}
|
||
| select_from select_lock_type;
|
||
|
||
udf_func_type:
|
||
/* empty */ { $$ = UDFTYPE_FUNCTION; }
|
||
| AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; };
|
||
|
||
udf_type:
|
||
STRING_SYM {$$ = (int) STRING_RESULT; }
|
||
| REAL {$$ = (int) REAL_RESULT; }
|
||
| DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; }
|
||
| INT_SYM {$$ = (int) INT_RESULT; };
|
||
|
||
field_list:
|
||
field_list_item
|
||
| field_list ',' field_list_item;
|
||
|
||
|
||
field_list_item:
|
||
column_def
|
||
| key_def
|
||
;
|
||
|
||
column_def:
|
||
field_spec opt_check_constraint
|
||
| field_spec references
|
||
{
|
||
Lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
}
|
||
;
|
||
|
||
key_def:
|
||
key_type opt_ident key_alg '(' key_list ')' key_options
|
||
{
|
||
LEX *lex=Lex;
|
||
if ($1 != Key::FULLTEXT && lex->key_create_info.parser_name.str)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->key_list.push_back(new Key($1,$2, &lex->key_create_info, 0,
|
||
lex->col_list));
|
||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
}
|
||
| opt_constraint constraint_key_type opt_ident key_alg
|
||
'(' key_list ')' key_options
|
||
{
|
||
LEX *lex=Lex;
|
||
const char *key_name= $3 ? $3 : $1;
|
||
lex->key_list.push_back(new Key($2, key_name, &lex->key_create_info, 0,
|
||
lex->col_list));
|
||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
}
|
||
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->key_list.push_back(new foreign_key($4 ? $4:$1, lex->col_list,
|
||
$8,
|
||
lex->ref_list,
|
||
lex->fk_delete_opt,
|
||
lex->fk_update_opt,
|
||
lex->fk_match_option));
|
||
lex->key_list.push_back(new Key(Key::MULTIPLE, $4 ? $4 : $1,
|
||
&default_key_create_info, 1,
|
||
lex->col_list));
|
||
lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
|
||
/* Only used for ALTER TABLE. Ignored otherwise. */
|
||
lex->alter_info.flags|= ALTER_FOREIGN_KEY;
|
||
}
|
||
| constraint opt_check_constraint
|
||
{
|
||
Lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
}
|
||
| opt_constraint check_constraint
|
||
{
|
||
Lex->col_list.empty(); /* Alloced by sql_alloc */
|
||
}
|
||
;
|
||
|
||
opt_check_constraint:
|
||
/* empty */
|
||
| check_constraint
|
||
;
|
||
|
||
check_constraint:
|
||
CHECK_SYM expr
|
||
;
|
||
|
||
opt_constraint:
|
||
/* empty */ { $$=(char*) 0; }
|
||
| constraint { $$= $1; }
|
||
;
|
||
|
||
constraint:
|
||
CONSTRAINT opt_ident { $$=$2; }
|
||
;
|
||
|
||
field_spec:
|
||
field_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->length=lex->dec=0; lex->type=0;
|
||
lex->default_value= lex->on_update_value= 0;
|
||
lex->comment=null_lex_str;
|
||
lex->charset=NULL;
|
||
}
|
||
type opt_attribute
|
||
{
|
||
LEX *lex=Lex;
|
||
if (add_field_to_list(lex->thd, $1.str,
|
||
(enum enum_field_types) $3,
|
||
lex->length,lex->dec,lex->type,
|
||
lex->default_value, lex->on_update_value,
|
||
&lex->comment,
|
||
lex->change,&lex->interval_list,lex->charset,
|
||
lex->uint_geom_type))
|
||
YYABORT;
|
||
};
|
||
|
||
type:
|
||
int_type opt_len field_options { $$=$1; }
|
||
| real_type opt_precision field_options { $$=$1; }
|
||
| FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
|
||
| BIT_SYM { Lex->length= (char*) "1";
|
||
$$=FIELD_TYPE_BIT; }
|
||
| BIT_SYM '(' NUM ')' { Lex->length= $3.str;
|
||
$$=FIELD_TYPE_BIT; }
|
||
| BOOL_SYM { Lex->length=(char*) "1";
|
||
$$=FIELD_TYPE_TINY; }
|
||
| BOOLEAN_SYM { Lex->length=(char*) "1";
|
||
$$=FIELD_TYPE_TINY; }
|
||
| char '(' NUM ')' opt_binary { Lex->length=$3.str;
|
||
$$=FIELD_TYPE_STRING; }
|
||
| char opt_binary { Lex->length=(char*) "1";
|
||
$$=FIELD_TYPE_STRING; }
|
||
| nchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str;
|
||
$$=FIELD_TYPE_STRING;
|
||
Lex->charset=national_charset_info; }
|
||
| nchar opt_bin_mod { Lex->length=(char*) "1";
|
||
$$=FIELD_TYPE_STRING;
|
||
Lex->charset=national_charset_info; }
|
||
| BINARY '(' NUM ')' { Lex->length=$3.str;
|
||
Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_STRING; }
|
||
| BINARY { Lex->length= (char*) "1";
|
||
Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_STRING; }
|
||
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
|
||
$$= MYSQL_TYPE_VARCHAR; }
|
||
| nvarchar '(' NUM ')' opt_bin_mod { Lex->length=$3.str;
|
||
$$= MYSQL_TYPE_VARCHAR;
|
||
Lex->charset=national_charset_info; }
|
||
| VARBINARY '(' NUM ')' { Lex->length=$3.str;
|
||
Lex->charset=&my_charset_bin;
|
||
$$= MYSQL_TYPE_VARCHAR; }
|
||
| YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; }
|
||
| DATE_SYM { $$=FIELD_TYPE_DATE; }
|
||
| TIME_SYM { $$=FIELD_TYPE_TIME; }
|
||
| TIMESTAMP opt_len
|
||
{
|
||
if (YYTHD->variables.sql_mode & MODE_MAXDB)
|
||
$$=FIELD_TYPE_DATETIME;
|
||
else
|
||
{
|
||
/*
|
||
Unlike other types TIMESTAMP fields are NOT NULL by default.
|
||
*/
|
||
Lex->type|= NOT_NULL_FLAG;
|
||
$$=FIELD_TYPE_TIMESTAMP;
|
||
}
|
||
}
|
||
| DATETIME { $$=FIELD_TYPE_DATETIME; }
|
||
| TINYBLOB { Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_TINY_BLOB; }
|
||
| BLOB_SYM opt_len { Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_BLOB; }
|
||
| spatial_type
|
||
{
|
||
#ifdef HAVE_SPATIAL
|
||
Lex->charset=&my_charset_bin;
|
||
Lex->uint_geom_type= (uint)$1;
|
||
$$=FIELD_TYPE_GEOMETRY;
|
||
#else
|
||
my_error(ER_FEATURE_DISABLED, MYF(0),
|
||
sym_group_geom.name, sym_group_geom.needed_define);
|
||
YYABORT;
|
||
#endif
|
||
}
|
||
| MEDIUMBLOB { Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_MEDIUM_BLOB; }
|
||
| LONGBLOB { Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_LONG_BLOB; }
|
||
| LONG_SYM VARBINARY { Lex->charset=&my_charset_bin;
|
||
$$=FIELD_TYPE_MEDIUM_BLOB; }
|
||
| LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
|
||
| TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; }
|
||
| TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; }
|
||
| MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
|
||
| LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; }
|
||
| DECIMAL_SYM float_options field_options
|
||
{ $$=FIELD_TYPE_NEWDECIMAL;}
|
||
| NUMERIC_SYM float_options field_options
|
||
{ $$=FIELD_TYPE_NEWDECIMAL;}
|
||
| FIXED_SYM float_options field_options
|
||
{ $$=FIELD_TYPE_NEWDECIMAL;}
|
||
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
|
||
{ $$=FIELD_TYPE_ENUM; }
|
||
| SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
|
||
{ $$=FIELD_TYPE_SET; }
|
||
| LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
|
||
| SERIAL_SYM
|
||
{
|
||
$$=FIELD_TYPE_LONGLONG;
|
||
Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
|
||
UNIQUE_FLAG);
|
||
}
|
||
;
|
||
|
||
spatial_type:
|
||
GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
|
||
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
|
||
| POINT_SYM { Lex->length= (char*)"21";
|
||
$$= Field::GEOM_POINT;
|
||
}
|
||
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
|
||
| LINESTRING { $$= Field::GEOM_LINESTRING; }
|
||
| MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
|
||
| POLYGON { $$= Field::GEOM_POLYGON; }
|
||
| MULTIPOLYGON { $$= Field::GEOM_MULTIPOLYGON; }
|
||
;
|
||
|
||
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 { $$=FIELD_TYPE_LONG; }
|
||
| TINYINT { $$=FIELD_TYPE_TINY; }
|
||
| SMALLINT { $$=FIELD_TYPE_SHORT; }
|
||
| MEDIUMINT { $$=FIELD_TYPE_INT24; }
|
||
| BIGINT { $$=FIELD_TYPE_LONGLONG; };
|
||
|
||
real_type:
|
||
REAL { $$= YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ?
|
||
FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
|
||
| DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; }
|
||
| DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; };
|
||
|
||
|
||
float_options:
|
||
/* empty */ { Lex->dec=Lex->length= (char*)0; }
|
||
| '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; }
|
||
| precision {};
|
||
|
||
precision:
|
||
'(' NUM ',' NUM ')'
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->length=$2.str; lex->dec=$4.str;
|
||
};
|
||
|
||
field_options:
|
||
/* empty */ {}
|
||
| field_opt_list {};
|
||
|
||
field_opt_list:
|
||
field_opt_list field_option {}
|
||
| field_option {};
|
||
|
||
field_option:
|
||
SIGNED_SYM {}
|
||
| UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
|
||
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; };
|
||
|
||
opt_len:
|
||
/* empty */ { Lex->length=(char*) 0; } /* use default length */
|
||
| '(' NUM ')' { Lex->length= $2.str; };
|
||
|
||
opt_precision:
|
||
/* empty */ {}
|
||
| precision {};
|
||
|
||
opt_attribute:
|
||
/* empty */ {}
|
||
| opt_attribute_list {};
|
||
|
||
opt_attribute_list:
|
||
opt_attribute_list attribute {}
|
||
| attribute;
|
||
|
||
attribute:
|
||
NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; }
|
||
| not NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
|
||
| DEFAULT now_or_signed_literal { Lex->default_value=$2; }
|
||
| ON UPDATE_SYM NOW_SYM optional_braces
|
||
{ Lex->on_update_value= new Item_func_now_local(); }
|
||
| AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
|
||
| SERIAL_SYM DEFAULT VALUE_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG;
|
||
lex->alter_info.flags|= ALTER_ADD_INDEX;
|
||
}
|
||
| opt_primary KEY_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG;
|
||
lex->alter_info.flags|= ALTER_ADD_INDEX;
|
||
}
|
||
| UNIQUE_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->type|= UNIQUE_FLAG;
|
||
lex->alter_info.flags|= ALTER_ADD_INDEX;
|
||
}
|
||
| UNIQUE_SYM KEY_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->type|= UNIQUE_KEY_FLAG;
|
||
lex->alter_info.flags|= ALTER_ADD_INDEX;
|
||
}
|
||
| COMMENT_SYM TEXT_STRING_sys { Lex->comment= $2; }
|
||
| COLLATE_SYM collation_name
|
||
{
|
||
if (Lex->charset && !my_charset_same(Lex->charset,$2))
|
||
{
|
||
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
|
||
$2->name,Lex->charset->csname);
|
||
YYABORT;
|
||
}
|
||
else
|
||
{
|
||
Lex->charset=$2;
|
||
}
|
||
}
|
||
;
|
||
|
||
now_or_signed_literal:
|
||
NOW_SYM optional_braces { $$= new Item_func_now_local(); }
|
||
| signed_literal { $$=$1; }
|
||
;
|
||
|
||
charset:
|
||
CHAR_SYM SET {}
|
||
| CHARSET {}
|
||
;
|
||
|
||
charset_name:
|
||
ident_or_text
|
||
{
|
||
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))))
|
||
{
|
||
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
}
|
||
| BINARY { $$= &my_charset_bin; }
|
||
;
|
||
|
||
charset_name_or_default:
|
||
charset_name { $$=$1; }
|
||
| DEFAULT { $$=NULL; } ;
|
||
|
||
|
||
old_or_new_charset_name:
|
||
ident_or_text
|
||
{
|
||
if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))) &&
|
||
!($$=get_old_charset_by_name($1.str)))
|
||
{
|
||
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
}
|
||
| 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 (!($$=get_charset_by_name($1.str,MYF(0))))
|
||
{
|
||
my_error(ER_UNKNOWN_COLLATION, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
};
|
||
|
||
opt_collate:
|
||
/* empty */ { $$=NULL; }
|
||
| COLLATE_SYM collation_name_or_default { $$=$2; }
|
||
;
|
||
|
||
collation_name_or_default:
|
||
collation_name { $$=$1; }
|
||
| DEFAULT { $$=NULL; } ;
|
||
|
||
opt_default:
|
||
/* empty */ {}
|
||
| DEFAULT {};
|
||
|
||
opt_binary:
|
||
/* empty */ { Lex->charset=NULL; }
|
||
| ASCII_SYM opt_bin_mod { Lex->charset=&my_charset_latin1; }
|
||
| BYTE_SYM { Lex->charset=&my_charset_bin; }
|
||
| UNICODE_SYM opt_bin_mod
|
||
{
|
||
if (!(Lex->charset=get_charset_by_csname("ucs2",
|
||
MY_CS_PRIMARY,MYF(0))))
|
||
{
|
||
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
|
||
YYABORT;
|
||
}
|
||
}
|
||
| charset charset_name opt_bin_mod { Lex->charset=$2; }
|
||
| BINARY opt_bin_charset { Lex->type|= BINCMP_FLAG; };
|
||
|
||
opt_bin_mod:
|
||
/* empty */ { }
|
||
| BINARY { Lex->type|= BINCMP_FLAG; };
|
||
|
||
opt_bin_charset:
|
||
/* empty */ { Lex->charset= NULL; }
|
||
| ASCII_SYM { Lex->charset=&my_charset_latin1; }
|
||
| UNICODE_SYM
|
||
{
|
||
if (!(Lex->charset=get_charset_by_csname("ucs2",
|
||
MY_CS_PRIMARY,MYF(0))))
|
||
{
|
||
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
|
||
YYABORT;
|
||
}
|
||
}
|
||
| charset charset_name { Lex->charset=$2; } ;
|
||
|
||
opt_primary:
|
||
/* empty */
|
||
| PRIMARY_SYM
|
||
;
|
||
|
||
references:
|
||
REFERENCES table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->fk_delete_opt= lex->fk_update_opt= lex->fk_match_option= 0;
|
||
lex->ref_list.empty();
|
||
}
|
||
opt_ref_list
|
||
{
|
||
$$=$2;
|
||
};
|
||
|
||
opt_ref_list:
|
||
/* empty */ opt_on_delete {}
|
||
| '(' ref_list ')' opt_on_delete {};
|
||
|
||
ref_list:
|
||
ref_list ',' ident { Lex->ref_list.push_back(new key_part_spec($3.str)); }
|
||
| ident { Lex->ref_list.push_back(new key_part_spec($1.str)); };
|
||
|
||
|
||
opt_on_delete:
|
||
/* empty */ {}
|
||
| opt_on_delete_list {};
|
||
|
||
opt_on_delete_list:
|
||
opt_on_delete_list opt_on_delete_item {}
|
||
| opt_on_delete_item {};
|
||
|
||
opt_on_delete_item:
|
||
ON DELETE_SYM delete_option { Lex->fk_delete_opt= $3; }
|
||
| ON UPDATE_SYM delete_option { Lex->fk_update_opt= $3; }
|
||
| 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; };
|
||
|
||
delete_option:
|
||
RESTRICT { $$= (int) foreign_key::FK_OPTION_RESTRICT; }
|
||
| CASCADE { $$= (int) foreign_key::FK_OPTION_CASCADE; }
|
||
| SET NULL_SYM { $$= (int) foreign_key::FK_OPTION_SET_NULL; }
|
||
| NO_SYM ACTION { $$= (int) foreign_key::FK_OPTION_NO_ACTION; }
|
||
| SET DEFAULT { $$= (int) foreign_key::FK_OPTION_DEFAULT; };
|
||
|
||
key_type:
|
||
key_or_index { $$= Key::MULTIPLE; }
|
||
| FULLTEXT_SYM opt_key_or_index { $$= Key::FULLTEXT; }
|
||
| SPATIAL_SYM opt_key_or_index
|
||
{
|
||
#ifdef HAVE_SPATIAL
|
||
$$= Key::SPATIAL;
|
||
#else
|
||
my_error(ER_FEATURE_DISABLED, MYF(0),
|
||
sym_group_geom.name, sym_group_geom.needed_define);
|
||
YYABORT;
|
||
#endif
|
||
};
|
||
|
||
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 {};
|
||
|
||
opt_unique_or_fulltext:
|
||
/* empty */ { $$= Key::MULTIPLE; }
|
||
| UNIQUE_SYM { $$= Key::UNIQUE; }
|
||
| FULLTEXT_SYM { $$= Key::FULLTEXT;}
|
||
| SPATIAL_SYM
|
||
{
|
||
#ifdef HAVE_SPATIAL
|
||
$$= Key::SPATIAL;
|
||
#else
|
||
my_error(ER_FEATURE_DISABLED, MYF(0),
|
||
sym_group_geom.name, sym_group_geom.needed_define);
|
||
YYABORT;
|
||
#endif
|
||
}
|
||
;
|
||
|
||
init_key_options:
|
||
{
|
||
Lex->key_create_info= default_key_create_info;
|
||
}
|
||
;
|
||
|
||
/*
|
||
For now, key_alg initializies lex->key_create_info.
|
||
In the future, when all key options are after key definition,
|
||
we can remove key_alg and move init_key_options to key_options
|
||
*/
|
||
|
||
key_alg:
|
||
/* empty */ init_key_options
|
||
| init_key_options key_using_alg
|
||
;
|
||
|
||
key_options:
|
||
/* empty */ {}
|
||
| key_opts
|
||
;
|
||
|
||
key_opts:
|
||
key_opt
|
||
| key_opts key_opt
|
||
;
|
||
|
||
key_using_alg:
|
||
USING btree_or_rtree { Lex->key_create_info.algorithm= $2; }
|
||
| TYPE_SYM btree_or_rtree { Lex->key_create_info.algorithm= $2; }
|
||
;
|
||
|
||
key_opt:
|
||
key_using_alg
|
||
| KEY_BLOCK_SIZE opt_equal ulong_num
|
||
{ Lex->key_create_info.block_size= $3; }
|
||
| WITH PARSER_SYM IDENT_sys
|
||
{
|
||
if (plugin_is_ready(&$3, MYSQL_FTPARSER_PLUGIN))
|
||
Lex->key_create_info.parser_name= $3;
|
||
else
|
||
{
|
||
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
|
||
btree_or_rtree:
|
||
BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
|
||
| RTREE_SYM
|
||
{
|
||
$$= HA_KEY_ALG_RTREE;
|
||
}
|
||
| HASH_SYM { $$= HA_KEY_ALG_HASH; };
|
||
|
||
key_list:
|
||
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
|
||
| key_part order_dir { Lex->col_list.push_back($1); };
|
||
|
||
key_part:
|
||
ident { $$=new key_part_spec($1.str); }
|
||
| ident '(' NUM ')'
|
||
{
|
||
int key_part_len= atoi($3.str);
|
||
if (!key_part_len)
|
||
{
|
||
my_error(ER_KEY_PART_0, MYF(0), $1.str);
|
||
}
|
||
$$=new key_part_spec($1.str,(uint) key_part_len);
|
||
};
|
||
|
||
opt_ident:
|
||
/* empty */ { $$=(char*) 0; } /* Defaultlength */
|
||
| field_ident { $$=$1.str; };
|
||
|
||
opt_component:
|
||
/* empty */ { $$= null_lex_str; }
|
||
| '.' ident { $$= $2; };
|
||
|
||
string_list:
|
||
text_string { Lex->interval_list.push_back($1); }
|
||
| string_list ',' text_string { Lex->interval_list.push_back($3); };
|
||
|
||
/*
|
||
** Alter table
|
||
*/
|
||
|
||
alter:
|
||
ALTER opt_ignore TABLE_SYM table_ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
lex->name.str= 0;
|
||
lex->name.length= 0;
|
||
lex->sql_command= SQLCOM_ALTER_TABLE;
|
||
lex->duplicates= DUP_ERROR;
|
||
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
|
||
TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
lex->create_list.empty();
|
||
lex->key_list.empty();
|
||
lex->col_list.empty();
|
||
lex->select_lex.init_order();
|
||
lex->like_name= 0;
|
||
lex->select_lex.db=
|
||
((TABLE_LIST*) lex->select_lex.table_list.first)->db;
|
||
bzero((char*) &lex->create_info,sizeof(lex->create_info));
|
||
lex->create_info.db_type= 0;
|
||
lex->create_info.default_table_charset= NULL;
|
||
lex->create_info.row_type= ROW_TYPE_NOT_USED;
|
||
lex->alter_info.reset();
|
||
lex->alter_info.flags= 0;
|
||
lex->no_write_to_binlog= 0;
|
||
}
|
||
alter_commands
|
||
{}
|
||
| ALTER DATABASE ident_or_empty
|
||
{
|
||
Lex->create_info.default_table_charset= NULL;
|
||
Lex->create_info.used_fields= 0;
|
||
}
|
||
opt_create_database_options
|
||
{
|
||
LEX *lex=Lex;
|
||
THD *thd= Lex->thd;
|
||
lex->sql_command=SQLCOM_ALTER_DB;
|
||
lex->name= $3;
|
||
if (lex->name.str == NULL &&
|
||
thd->copy_db_to(&lex->name.str, &lex->name.length))
|
||
YYABORT;
|
||
}
|
||
| ALTER PROCEDURE sp_name
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
|
||
YYABORT;
|
||
}
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
}
|
||
sp_a_chistics
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
|
||
lex->spname= $3;
|
||
}
|
||
| ALTER FUNCTION_SYM sp_name
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
|
||
YYABORT;
|
||
}
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
}
|
||
sp_a_chistics
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
lex->sql_command= SQLCOM_ALTER_FUNCTION;
|
||
lex->spname= $3;
|
||
}
|
||
| ALTER view_algorithm_opt definer view_suid
|
||
VIEW_SYM table_ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
lex->sql_command= SQLCOM_CREATE_VIEW;
|
||
lex->create_view_mode= VIEW_ALTER;
|
||
/* first table in list is target VIEW name */
|
||
lex->select_lex.add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING);
|
||
}
|
||
view_list_opt AS view_select view_check_option
|
||
{}
|
||
| ALTER EVENT_SYM sp_name
|
||
/*
|
||
BE CAREFUL when you add a new rule to update the block where
|
||
YYTHD->client_capabilities is set back to original value
|
||
*/
|
||
{
|
||
/*
|
||
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 (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
|
||
YYABORT;
|
||
Lex->event_parse_data->identifier= $3;
|
||
|
||
/*
|
||
We have to turn off CLIENT_MULTI_QUERIES while parsing a
|
||
stored procedure, otherwise yylex will chop it into pieces
|
||
at each ';'.
|
||
*/
|
||
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
|
||
|
||
Lex->sql_command= SQLCOM_ALTER_EVENT;
|
||
}
|
||
ev_alter_on_schedule_completion
|
||
opt_ev_rename_to
|
||
opt_ev_status
|
||
opt_ev_comment
|
||
opt_ev_sql_stmt
|
||
{
|
||
/*
|
||
$1 - ALTER
|
||
$2 - EVENT_SYM
|
||
$3 - sp_name
|
||
$4 - the block above
|
||
*/
|
||
YYTHD->client_capabilities |= $<ulong_num>4;
|
||
|
||
if (!($5 || $6 || $7 || $8 || $9))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
/*
|
||
sql_command is set here because some rules in ev_sql_stmt
|
||
can overwrite it
|
||
*/
|
||
Lex->sql_command= SQLCOM_ALTER_EVENT;
|
||
}
|
||
| ALTER TABLESPACE alter_tablespace_info
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= ALTER_TABLESPACE;
|
||
}
|
||
| ALTER LOGFILE_SYM GROUP alter_logfile_group_info
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= ALTER_LOGFILE_GROUP;
|
||
}
|
||
| ALTER TABLESPACE change_tablespace_info
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= CHANGE_FILE_TABLESPACE;
|
||
}
|
||
| ALTER TABLESPACE change_tablespace_access
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= ALTER_ACCESS_MODE_TABLESPACE;
|
||
}
|
||
| ALTER SERVER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
Lex->sql_command= SQLCOM_ALTER_SERVER;
|
||
Lex->server_options.server_name= $3.str;
|
||
Lex->server_options.server_name_length= $3.length;
|
||
}
|
||
;
|
||
|
||
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 */ { $$.str= 0; $$.length= 0; }
|
||
| ident { $$= $1; };
|
||
|
||
alter_commands:
|
||
| DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; }
|
||
| IMPORT TABLESPACE { Lex->alter_info.tablespace_op= IMPORT_TABLESPACE; }
|
||
| alter_list
|
||
opt_partitioning
|
||
| alter_list
|
||
remove_partitioning
|
||
| remove_partitioning
|
||
| partitioning
|
||
/*
|
||
This part was added for release 5.1 by Mikael Ronstr<74>m.
|
||
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 and also include moving partitions to a
|
||
new table and so forth.
|
||
*/
|
||
| add_partition_rule
|
||
| DROP PARTITION_SYM alt_part_name_list
|
||
{
|
||
Lex->alter_info.flags|= ALTER_DROP_PARTITION;
|
||
}
|
||
| REBUILD_SYM PARTITION_SYM opt_no_write_to_binlog
|
||
all_or_alt_part_name_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_REBUILD_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
}
|
||
| OPTIMIZE PARTITION_SYM opt_no_write_to_binlog
|
||
all_or_alt_part_name_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_OPTIMIZE_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
lex->check_opt.init();
|
||
}
|
||
opt_no_write_to_binlog opt_mi_check_type
|
||
| ANALYZE_SYM PARTITION_SYM opt_no_write_to_binlog
|
||
all_or_alt_part_name_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_ANALYZE_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
lex->check_opt.init();
|
||
}
|
||
opt_mi_check_type
|
||
| CHECK_SYM PARTITION_SYM all_or_alt_part_name_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_CHECK_PARTITION;
|
||
lex->check_opt.init();
|
||
}
|
||
opt_mi_check_type
|
||
| REPAIR PARTITION_SYM opt_no_write_to_binlog
|
||
all_or_alt_part_name_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_REPAIR_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
lex->check_opt.init();
|
||
}
|
||
opt_mi_repair_type
|
||
| COALESCE PARTITION_SYM opt_no_write_to_binlog real_ulong_num
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_info.flags|= ALTER_COALESCE_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
lex->alter_info.no_parts= $4;
|
||
}
|
||
| reorg_partition_rule
|
||
;
|
||
|
||
remove_partitioning:
|
||
REMOVE_SYM PARTITIONING_SYM
|
||
{
|
||
Lex->alter_info.flags|= ALTER_REMOVE_PARTITIONING;
|
||
}
|
||
;
|
||
|
||
all_or_alt_part_name_list:
|
||
ALL
|
||
{
|
||
Lex->alter_info.flags|= ALTER_ALL_PARTITION;
|
||
}
|
||
| alt_part_name_list
|
||
;
|
||
|
||
add_partition_rule:
|
||
ADD PARTITION_SYM opt_no_write_to_binlog
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info= new partition_info();
|
||
if (!lex->part_info)
|
||
{
|
||
mem_alloc_error(sizeof(partition_info));
|
||
YYABORT;
|
||
}
|
||
lex->alter_info.flags|= ALTER_ADD_PARTITION;
|
||
lex->no_write_to_binlog= $3;
|
||
}
|
||
add_part_extra
|
||
{}
|
||
;
|
||
|
||
add_part_extra:
|
||
| '(' part_def_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->no_parts= lex->part_info->partitions.elements;
|
||
}
|
||
| PARTITIONS_SYM real_ulong_num
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->no_parts= $2;
|
||
}
|
||
;
|
||
|
||
reorg_partition_rule:
|
||
REORGANIZE_SYM PARTITION_SYM opt_no_write_to_binlog
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info= new partition_info();
|
||
if (!lex->part_info)
|
||
{
|
||
mem_alloc_error(sizeof(partition_info));
|
||
YYABORT;
|
||
}
|
||
lex->no_write_to_binlog= $3;
|
||
}
|
||
reorg_parts_rule
|
||
;
|
||
|
||
reorg_parts_rule:
|
||
/* empty */
|
||
{
|
||
Lex->alter_info.flags|= ALTER_TABLE_REORG;
|
||
}
|
||
|
|
||
alt_part_name_list
|
||
{
|
||
Lex->alter_info.flags|= ALTER_REORGANIZE_PARTITION;
|
||
}
|
||
INTO '(' part_def_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->part_info->no_parts= lex->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 (Lex->alter_info.partition_names.push_back($1.str))
|
||
{
|
||
mem_alloc_error(1);
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
/*
|
||
End of management of partition commands
|
||
*/
|
||
|
||
alter_list:
|
||
alter_list_item
|
||
| alter_list ',' alter_list_item
|
||
;
|
||
|
||
add_column:
|
||
ADD opt_column
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->change=0;
|
||
lex->alter_info.flags|= ALTER_ADD_COLUMN;
|
||
};
|
||
|
||
alter_list_item:
|
||
add_column column_def opt_place { }
|
||
| ADD key_def
|
||
{
|
||
Lex->alter_info.flags|= ALTER_ADD_INDEX;
|
||
}
|
||
| add_column '(' field_list ')'
|
||
{
|
||
Lex->alter_info.flags|= ALTER_ADD_COLUMN | ALTER_ADD_INDEX;
|
||
}
|
||
| CHANGE opt_column field_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->change= $3.str;
|
||
lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
|
||
}
|
||
field_spec opt_place
|
||
| MODIFY_SYM opt_column field_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->length=lex->dec=0; lex->type=0;
|
||
lex->default_value= lex->on_update_value= 0;
|
||
lex->comment=null_lex_str;
|
||
lex->charset= NULL;
|
||
lex->alter_info.flags|= ALTER_CHANGE_COLUMN;
|
||
}
|
||
type opt_attribute
|
||
{
|
||
LEX *lex=Lex;
|
||
if (add_field_to_list(lex->thd,$3.str,
|
||
(enum enum_field_types) $5,
|
||
lex->length,lex->dec,lex->type,
|
||
lex->default_value, lex->on_update_value,
|
||
&lex->comment,
|
||
$3.str, &lex->interval_list, lex->charset,
|
||
lex->uint_geom_type))
|
||
YYABORT;
|
||
}
|
||
opt_place
|
||
| DROP opt_column field_ident opt_restrict
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::COLUMN,
|
||
$3.str));
|
||
lex->alter_info.flags|= ALTER_DROP_COLUMN;
|
||
}
|
||
| DROP FOREIGN KEY_SYM opt_ident
|
||
{
|
||
Lex->alter_info.flags|= ALTER_DROP_INDEX | ALTER_FOREIGN_KEY;
|
||
}
|
||
| DROP PRIMARY_SYM KEY_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
|
||
primary_key_name));
|
||
lex->alter_info.flags|= ALTER_DROP_INDEX;
|
||
}
|
||
| DROP key_or_index field_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
|
||
$3.str));
|
||
lex->alter_info.flags|= ALTER_DROP_INDEX;
|
||
}
|
||
| DISABLE_SYM KEYS
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.keys_onoff= DISABLE;
|
||
lex->alter_info.flags|= ALTER_KEYS_ONOFF;
|
||
}
|
||
| ENABLE_SYM KEYS
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.keys_onoff= ENABLE;
|
||
lex->alter_info.flags|= ALTER_KEYS_ONOFF;
|
||
}
|
||
| ALTER opt_column field_ident SET DEFAULT signed_literal
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.alter_list.push_back(new Alter_column($3.str,$6));
|
||
lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
|
||
}
|
||
| ALTER opt_column field_ident DROP DEFAULT
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.alter_list.push_back(new Alter_column($3.str,
|
||
(Item*) 0));
|
||
lex->alter_info.flags|= ALTER_CHANGE_COLUMN_DEFAULT;
|
||
}
|
||
| RENAME opt_to table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
THD *thd= lex->thd;
|
||
uint dummy;
|
||
lex->select_lex.db=$3->db.str;
|
||
if (lex->select_lex.db == NULL &&
|
||
thd->copy_db_to(&lex->select_lex.db, &dummy))
|
||
{
|
||
YYABORT;
|
||
}
|
||
if (check_table_name($3->table.str,$3->table.length) ||
|
||
$3->db.str && check_db_name(&$3->db))
|
||
{
|
||
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
|
||
YYABORT;
|
||
}
|
||
lex->name= $3->table;
|
||
lex->alter_info.flags|= ALTER_RENAME;
|
||
}
|
||
| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
|
||
{
|
||
if (!$4)
|
||
{
|
||
THD *thd= YYTHD;
|
||
$4= thd->variables.collation_database;
|
||
}
|
||
$5= $5 ? $5 : $4;
|
||
if (!my_charset_same($4,$5))
|
||
{
|
||
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
|
||
$5->name, $4->csname);
|
||
YYABORT;
|
||
}
|
||
LEX *lex= Lex;
|
||
lex->create_info.table_charset=
|
||
lex->create_info.default_table_charset= $5;
|
||
lex->create_info.used_fields|= (HA_CREATE_USED_CHARSET |
|
||
HA_CREATE_USED_DEFAULT_CHARSET);
|
||
lex->alter_info.flags|= ALTER_CONVERT;
|
||
}
|
||
| create_table_options_space_separated
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.flags|= ALTER_OPTIONS;
|
||
}
|
||
| FORCE_SYM
|
||
{
|
||
Lex->alter_info.flags|= ALTER_FORCE;
|
||
}
|
||
| order_clause
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->alter_info.flags|= ALTER_ORDER;
|
||
};
|
||
|
||
opt_column:
|
||
/* empty */ {}
|
||
| COLUMN_SYM {};
|
||
|
||
opt_ignore:
|
||
/* empty */ { Lex->ignore= 0;}
|
||
| IGNORE_SYM { Lex->ignore= 1;}
|
||
;
|
||
|
||
opt_restrict:
|
||
/* empty */ { Lex->drop_mode= DROP_DEFAULT; }
|
||
| RESTRICT { Lex->drop_mode= DROP_RESTRICT; }
|
||
| CASCADE { Lex->drop_mode= DROP_CASCADE; }
|
||
;
|
||
|
||
opt_place:
|
||
/* empty */ {}
|
||
| AFTER_SYM ident { store_position_for_column($2.str); }
|
||
| FIRST_SYM { store_position_for_column(first_keyword); };
|
||
|
||
opt_to:
|
||
/* empty */ {}
|
||
| TO_SYM {}
|
||
| EQ {}
|
||
| AS {};
|
||
|
||
/*
|
||
SLAVE START and SLAVE STOP are deprecated. We keep them for compatibility.
|
||
*/
|
||
|
||
slave:
|
||
START_SYM SLAVE slave_thread_opts
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_SLAVE_START;
|
||
lex->type = 0;
|
||
/* We'll use mi structure for UNTIL options */
|
||
bzero((char*) &lex->mi, sizeof(lex->mi));
|
||
/* If you change this code don't forget to update SLAVE START too */
|
||
}
|
||
slave_until
|
||
{}
|
||
| STOP_SYM SLAVE slave_thread_opts
|
||
{
|
||
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 */
|
||
}
|
||
| SLAVE START_SYM slave_thread_opts
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_SLAVE_START;
|
||
lex->type = 0;
|
||
/* We'll use mi structure for UNTIL options */
|
||
bzero((char*) &lex->mi, sizeof(lex->mi));
|
||
}
|
||
slave_until
|
||
{}
|
||
| SLAVE STOP_SYM slave_thread_opts
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_SLAVE_STOP;
|
||
lex->type = 0;
|
||
}
|
||
;
|
||
|
||
|
||
start:
|
||
START_SYM TRANSACTION_SYM start_transaction_opts
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_BEGIN;
|
||
lex->start_transaction_opt= $3;
|
||
}
|
||
;
|
||
|
||
start_transaction_opts:
|
||
/*empty*/ { $$ = 0; }
|
||
| WITH CONSISTENT_SYM SNAPSHOT_SYM
|
||
{
|
||
$$= MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT;
|
||
}
|
||
;
|
||
|
||
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 ((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_message(ER_BAD_SLAVE_UNTIL_COND,
|
||
ER(ER_BAD_SLAVE_UNTIL_COND), MYF(0));
|
||
YYABORT;
|
||
}
|
||
|
||
}
|
||
;
|
||
|
||
slave_until_opts:
|
||
master_file_def
|
||
| slave_until_opts ',' master_file_def ;
|
||
|
||
|
||
restore:
|
||
RESTORE_SYM table_or_tables
|
||
{
|
||
Lex->sql_command = SQLCOM_RESTORE_TABLE;
|
||
WARN_DEPRECATED(yythd, "5.2", "RESTORE TABLE",
|
||
"MySQL Administrator (mysqldump, mysql)");
|
||
}
|
||
table_list FROM TEXT_STRING_sys
|
||
{
|
||
Lex->backup_dir = $6.str;
|
||
};
|
||
|
||
backup:
|
||
BACKUP_SYM table_or_tables
|
||
{
|
||
Lex->sql_command = SQLCOM_BACKUP_TABLE;
|
||
WARN_DEPRECATED(yythd, "5.2", "BACKUP TABLE",
|
||
"MySQL Administrator (mysqldump, mysql)");
|
||
}
|
||
table_list TO_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->backup_dir = $6.str;
|
||
};
|
||
|
||
checksum:
|
||
CHECKSUM_SYM table_or_tables
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_CHECKSUM;
|
||
}
|
||
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:
|
||
REPAIR opt_no_write_to_binlog table_or_tables
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_REPAIR;
|
||
lex->no_write_to_binlog= $2;
|
||
lex->check_opt.init();
|
||
}
|
||
table_list opt_mi_repair_type
|
||
{}
|
||
;
|
||
|
||
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; };
|
||
|
||
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();
|
||
}
|
||
table_list opt_mi_check_type
|
||
{}
|
||
;
|
||
|
||
binlog_base64_event:
|
||
BINLOG_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->sql_command = SQLCOM_BINLOG_BASE64_EVENT;
|
||
Lex->comment= $2;
|
||
}
|
||
;
|
||
|
||
check:
|
||
CHECK_SYM table_or_tables
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "CHECK");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_CHECK;
|
||
lex->check_opt.init();
|
||
}
|
||
table_list opt_mi_check_type
|
||
{}
|
||
;
|
||
|
||
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; };
|
||
|
||
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();
|
||
}
|
||
table_list opt_mi_check_type
|
||
{}
|
||
;
|
||
|
||
opt_no_write_to_binlog:
|
||
/* empty */ { $$= 0; }
|
||
| NO_WRITE_TO_BINLOG { $$= 1; }
|
||
| LOCAL_SYM { $$= 1; }
|
||
;
|
||
|
||
rename:
|
||
RENAME table_or_tables
|
||
{
|
||
Lex->sql_command= SQLCOM_RENAME_TABLE;
|
||
}
|
||
table_to_table_list
|
||
{}
|
||
| RENAME DATABASE
|
||
{
|
||
Lex->db_list.empty();
|
||
Lex->sql_command= SQLCOM_RENAME_DB;
|
||
}
|
||
db_to_db
|
||
{}
|
||
| RENAME USER clear_privileges rename_list
|
||
{
|
||
Lex->sql_command = SQLCOM_RENAME_USER;
|
||
}
|
||
;
|
||
|
||
rename_list:
|
||
user TO_SYM user
|
||
{
|
||
if (Lex->users_list.push_back($1) || Lex->users_list.push_back($3))
|
||
YYABORT;
|
||
}
|
||
| rename_list ',' user TO_SYM user
|
||
{
|
||
if (Lex->users_list.push_back($3) || Lex->users_list.push_back($5))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
table_to_table_list:
|
||
table_to_table
|
||
| table_to_table_list ',' table_to_table;
|
||
|
||
table_to_table:
|
||
table_ident TO_SYM table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sl= lex->current_select;
|
||
if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
|
||
TL_IGNORE) ||
|
||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
|
||
TL_IGNORE))
|
||
YYABORT;
|
||
};
|
||
|
||
db_to_db:
|
||
ident TO_SYM ident
|
||
{
|
||
LEX *lex=Lex;
|
||
if (Lex->db_list.push_back((LEX_STRING*)
|
||
sql_memdup(&$1, sizeof(LEX_STRING))) ||
|
||
Lex->db_list.push_back((LEX_STRING*)
|
||
sql_memdup(&$3, sizeof(LEX_STRING))))
|
||
YYABORT;
|
||
};
|
||
|
||
keycache:
|
||
CACHE_SYM INDEX_SYM keycache_list IN_SYM key_cache_name
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_ASSIGN_TO_KEYCACHE;
|
||
lex->ident= $5;
|
||
}
|
||
;
|
||
|
||
keycache_list:
|
||
assign_to_keycache
|
||
| keycache_list ',' assign_to_keycache;
|
||
|
||
assign_to_keycache:
|
||
table_ident cache_keys_spec
|
||
{
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sel= &lex->select_lex;
|
||
if (!sel->add_table_to_list(lex->thd, $1, NULL, 0,
|
||
TL_READ,
|
||
sel->get_use_index(),
|
||
(List<String> *)0))
|
||
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;
|
||
}
|
||
preload_list
|
||
{}
|
||
;
|
||
|
||
preload_list:
|
||
preload_keys
|
||
| preload_list ',' preload_keys;
|
||
|
||
preload_keys:
|
||
table_ident cache_keys_spec opt_ignore_leaves
|
||
{
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sel= &lex->select_lex;
|
||
if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
|
||
TL_READ,
|
||
sel->get_use_index(),
|
||
(List<String> *)0))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
cache_keys_spec:
|
||
{ Select->interval_list.empty(); }
|
||
cache_key_list_or_empty
|
||
{
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sel= &lex->select_lex;
|
||
sel->use_index= sel->interval_list;
|
||
}
|
||
;
|
||
|
||
cache_key_list_or_empty:
|
||
/* empty */ { Lex->select_lex.use_index_ptr= 0; }
|
||
| opt_key_or_index '(' key_usage_list2 ')'
|
||
{
|
||
SELECT_LEX *sel= &Lex->select_lex;
|
||
sel->use_index_ptr= &sel->use_index;
|
||
}
|
||
;
|
||
|
||
opt_ignore_leaves:
|
||
/* empty */
|
||
{ $$= 0; }
|
||
| IGNORE_SYM LEAVES { $$= TL_OPTION_IGNORE_LEAVES; }
|
||
;
|
||
|
||
/*
|
||
Select : retrieve data from table
|
||
*/
|
||
|
||
|
||
select:
|
||
select_init
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SELECT;
|
||
}
|
||
;
|
||
|
||
/* Need select_init2 for subselects. */
|
||
select_init:
|
||
SELECT_SYM select_init2
|
||
|
|
||
'(' select_paren ')' union_opt;
|
||
|
||
select_paren:
|
||
SELECT_SYM select_part2
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX * sel= lex->current_select;
|
||
if (sel->set_braces(1))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (sel->linkage == UNION_TYPE &&
|
||
!sel->master_unit()->first_select()->braces &&
|
||
sel->master_unit()->first_select()->linkage ==
|
||
UNION_TYPE)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
/* select in braces, can't contain global parameters */
|
||
if (sel->master_unit()->fake_select_lex)
|
||
sel->master_unit()->global_parameters=
|
||
sel->master_unit()->fake_select_lex;
|
||
}
|
||
| '(' select_paren ')';
|
||
|
||
select_init2:
|
||
select_part2
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX * sel= lex->current_select;
|
||
if (lex->current_select->set_braces(0))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (sel->linkage == UNION_TYPE &&
|
||
sel->master_unit()->first_select()->braces)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
union_clause
|
||
;
|
||
|
||
select_part2:
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if (sel->linkage != UNION_TYPE)
|
||
mysql_init_select(lex);
|
||
lex->current_select->parsing_place= SELECT_LIST;
|
||
}
|
||
select_options select_item_list
|
||
{
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
select_into select_lock_type;
|
||
|
||
select_into:
|
||
opt_order_clause opt_limit_clause {}
|
||
| into
|
||
| select_from
|
||
| into select_from
|
||
| select_from into;
|
||
|
||
select_from:
|
||
FROM join_table_list where_clause group_clause having_clause
|
||
opt_order_clause opt_limit_clause procedure_clause
|
||
| FROM DUAL_SYM where_clause opt_limit_clause
|
||
/* 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 (Select->options & SELECT_DISTINCT && Select->options & SELECT_ALL)
|
||
{
|
||
my_error(ER_WRONG_USAGE, MYF(0), "ALL", "DISTINCT");
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
select_option_list:
|
||
select_option_list select_option
|
||
| select_option;
|
||
|
||
select_option:
|
||
STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
|
||
| HIGH_PRIORITY
|
||
{
|
||
if (check_simple_select())
|
||
YYABORT;
|
||
Lex->lock_option= TL_READ_HIGH_PRIORITY;
|
||
}
|
||
| DISTINCT { Select->options|= SELECT_DISTINCT; }
|
||
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
|
||
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
|
||
| SQL_BUFFER_RESULT
|
||
{
|
||
if (check_simple_select())
|
||
YYABORT;
|
||
Select->options|= OPTION_BUFFER_RESULT;
|
||
}
|
||
| SQL_CALC_FOUND_ROWS
|
||
{
|
||
if (check_simple_select())
|
||
YYABORT;
|
||
Select->options|= OPTION_FOUND_ROWS;
|
||
}
|
||
| SQL_NO_CACHE_SYM
|
||
{
|
||
Lex->safe_to_cache_query=0;
|
||
Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
|
||
Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
|
||
}
|
||
| SQL_CACHE_SYM
|
||
{
|
||
/* Honor this flag only if SQL_NO_CACHE wasn't specified. */
|
||
if (Lex->select_lex.sql_cache != SELECT_LEX::SQL_NO_CACHE)
|
||
{
|
||
Lex->safe_to_cache_query=1;
|
||
Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||
Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
|
||
}
|
||
}
|
||
| ALL { Select->options|= SELECT_ALL; }
|
||
;
|
||
|
||
select_lock_type:
|
||
/* empty */
|
||
| FOR_SYM UPDATE_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->current_select->set_lock_for_tables(TL_WRITE);
|
||
lex->safe_to_cache_query=0;
|
||
}
|
||
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->current_select->
|
||
set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
|
||
lex->safe_to_cache_query=0;
|
||
}
|
||
;
|
||
|
||
select_item_list:
|
||
select_item_list ',' select_item
|
||
| select_item
|
||
| '*'
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (add_item_to_list(thd,
|
||
new Item_field(&thd->lex->current_select->
|
||
context,
|
||
NULL, NULL, "*")))
|
||
YYABORT;
|
||
(thd->lex->current_select->with_wild)++;
|
||
};
|
||
|
||
|
||
select_item:
|
||
remember_name select_item2 remember_end select_alias
|
||
{
|
||
if (add_item_to_list(YYTHD, $2))
|
||
YYABORT;
|
||
if ($4.str)
|
||
{
|
||
$2->is_autogenerated_name= FALSE;
|
||
$2->set_name($4.str, $4.length, system_charset_info);
|
||
}
|
||
else if (!$2->name) {
|
||
char *str = $1;
|
||
if (str[-1] == '`')
|
||
str--;
|
||
$2->set_name(str,(uint) ($3 - str), YYTHD->charset());
|
||
}
|
||
};
|
||
|
||
remember_name:
|
||
{ $$=(char*) Lex->tok_start; };
|
||
|
||
remember_end:
|
||
{ $$=(char*) Lex->tok_end; };
|
||
|
||
select_item2:
|
||
table_wild { $$=$1; } /* table.* */
|
||
| expr { $$=$1; };
|
||
|
||
select_alias:
|
||
/* empty */ { $$=null_lex_str;}
|
||
| AS ident { $$=$2; }
|
||
| AS TEXT_STRING_sys { $$=$2; }
|
||
| ident { $$=$1; }
|
||
| TEXT_STRING_sys { $$=$1; }
|
||
;
|
||
|
||
optional_braces:
|
||
/* empty */ {}
|
||
| '(' ')' {};
|
||
|
||
/* all possible expressions */
|
||
expr:
|
||
bool_term { Select->expr_list.push_front(new List<Item>); }
|
||
bool_or_expr
|
||
{
|
||
List<Item> *list= Select->expr_list.pop();
|
||
if (list->elements)
|
||
{
|
||
list->push_front($1);
|
||
$$= new Item_cond_or(*list);
|
||
/* optimize construction of logical OR to reduce
|
||
amount of objects for complex expressions */
|
||
}
|
||
else
|
||
$$= $1;
|
||
delete list;
|
||
}
|
||
;
|
||
|
||
bool_or_expr:
|
||
/* empty */
|
||
| bool_or_expr or bool_term
|
||
{ Select->expr_list.head()->push_back($3); }
|
||
;
|
||
|
||
bool_term:
|
||
bool_term XOR bool_term { $$= new Item_cond_xor($1,$3); }
|
||
| bool_factor { Select->expr_list.push_front(new List<Item>); }
|
||
bool_and_expr
|
||
{
|
||
List<Item> *list= Select->expr_list.pop();
|
||
if (list->elements)
|
||
{
|
||
list->push_front($1);
|
||
$$= new Item_cond_and(*list);
|
||
/* optimize construction of logical AND to reduce
|
||
amount of objects for complex expressions */
|
||
}
|
||
else
|
||
$$= $1;
|
||
delete list;
|
||
}
|
||
;
|
||
|
||
bool_and_expr:
|
||
/* empty */
|
||
| bool_and_expr and bool_factor
|
||
{ Select->expr_list.head()->push_back($3); }
|
||
;
|
||
|
||
bool_factor:
|
||
NOT_SYM bool_factor { $$= negate_expression(YYTHD, $2); }
|
||
| bool_test ;
|
||
|
||
bool_test:
|
||
bool_pri IS TRUE_SYM { $$= is_truth_value(YYTHD, $1,1,0); }
|
||
| bool_pri IS not TRUE_SYM { $$= is_truth_value(YYTHD, $1,0,0); }
|
||
| bool_pri IS FALSE_SYM { $$= is_truth_value(YYTHD, $1,0,1); }
|
||
| bool_pri IS not FALSE_SYM { $$= is_truth_value(YYTHD, $1,1,1); }
|
||
| bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
|
||
| bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
|
||
| bool_pri ;
|
||
|
||
bool_pri:
|
||
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
|
||
| bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); }
|
||
| bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); }
|
||
| bool_pri comp_op predicate %prec EQ
|
||
{ $$= (*$2)(0)->create($1,$3); }
|
||
| bool_pri comp_op all_or_any '(' subselect ')' %prec EQ
|
||
{ $$= all_any_subquery_creator($1, $2, $3, $5); }
|
||
| predicate ;
|
||
|
||
predicate:
|
||
bit_expr IN_SYM '(' subselect ')'
|
||
{ $$= new Item_in_subselect($1, $4); }
|
||
| bit_expr not IN_SYM '(' subselect ')'
|
||
{ $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
|
||
| bit_expr IN_SYM '(' expr ')'
|
||
{
|
||
$$= new Item_func_eq($1, $4);
|
||
}
|
||
| bit_expr IN_SYM '(' expr ',' expr_list ')'
|
||
{
|
||
$6->push_front($4);
|
||
$6->push_front($1);
|
||
$$= new Item_func_in(*$6);
|
||
}
|
||
| bit_expr not IN_SYM '(' expr ')'
|
||
{
|
||
$$= new Item_func_ne($1, $5);
|
||
}
|
||
| bit_expr not IN_SYM '(' expr ',' expr_list ')'
|
||
{
|
||
$7->push_front($5);
|
||
$7->push_front($1);
|
||
Item_func_in *item = new Item_func_in(*$7);
|
||
item->negate();
|
||
$$= item;
|
||
}
|
||
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
|
||
{ $$= new Item_func_between($1,$3,$5); }
|
||
| bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
|
||
{
|
||
Item_func_between *item= new Item_func_between($1,$4,$6);
|
||
item->negate();
|
||
$$= item;
|
||
}
|
||
| bit_expr SOUNDS_SYM LIKE bit_expr
|
||
{ $$= new Item_func_eq(new Item_func_soundex($1),
|
||
new Item_func_soundex($4)); }
|
||
| bit_expr LIKE simple_expr opt_escape
|
||
{ $$= new Item_func_like($1,$3,$4,Lex->escape_used); }
|
||
| bit_expr not LIKE simple_expr opt_escape
|
||
{ $$= new Item_func_not(new Item_func_like($1,$4,$5, Lex->escape_used)); }
|
||
| bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); }
|
||
| bit_expr not REGEXP bit_expr
|
||
{ $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); }
|
||
| bit_expr ;
|
||
|
||
bit_expr:
|
||
bit_expr '|' bit_term { $$= new Item_func_bit_or($1,$3); }
|
||
| bit_term ;
|
||
|
||
bit_term:
|
||
bit_term '&' bit_factor { $$= new Item_func_bit_and($1,$3); }
|
||
| bit_factor ;
|
||
|
||
bit_factor:
|
||
bit_factor SHIFT_LEFT value_expr
|
||
{ $$= new Item_func_shift_left($1,$3); }
|
||
| bit_factor SHIFT_RIGHT value_expr
|
||
{ $$= new Item_func_shift_right($1,$3); }
|
||
| value_expr ;
|
||
|
||
value_expr:
|
||
value_expr '+' term { $$= new Item_func_plus($1,$3); }
|
||
| value_expr '-' term { $$= new Item_func_minus($1,$3); }
|
||
| value_expr '+' interval_expr interval
|
||
{ $$= new Item_date_add_interval($1,$3,$4,0); }
|
||
| value_expr '-' interval_expr interval
|
||
{ $$= new Item_date_add_interval($1,$3,$4,1); }
|
||
| term ;
|
||
|
||
term:
|
||
term '*' factor { $$= new Item_func_mul($1,$3); }
|
||
| term '/' factor { $$= new Item_func_div($1,$3); }
|
||
| term '%' factor { $$= new Item_func_mod($1,$3); }
|
||
| term DIV_SYM factor { $$= new Item_func_int_div($1,$3); }
|
||
| term MOD_SYM factor { $$= new Item_func_mod($1,$3); }
|
||
| factor ;
|
||
|
||
factor:
|
||
factor '^' simple_expr { $$= new Item_func_bit_xor($1,$3); }
|
||
| simple_expr ;
|
||
|
||
or: OR_SYM | OR2_SYM;
|
||
and: AND_SYM | AND_AND_SYM;
|
||
not: NOT_SYM | NOT2_SYM;
|
||
not2: '!' | NOT2_SYM;
|
||
|
||
comp_op: EQ { $$ = &comp_eq_creator; }
|
||
| GE { $$ = &comp_ge_creator; }
|
||
| GT_SYM { $$ = &comp_gt_creator; }
|
||
| LE { $$ = &comp_le_creator; }
|
||
| LT { $$ = &comp_lt_creator; }
|
||
| NE { $$ = &comp_ne_creator; }
|
||
;
|
||
|
||
all_or_any: ALL { $$ = 1; }
|
||
| ANY_SYM { $$ = 0; }
|
||
;
|
||
|
||
interval_expr:
|
||
INTERVAL_SYM expr { $$=$2; }
|
||
;
|
||
|
||
simple_expr:
|
||
simple_ident
|
||
| function_call_keyword
|
||
| function_call_nonkeyword
|
||
| function_call_generic
|
||
| function_call_conflict
|
||
| simple_expr COLLATE_SYM ident_or_text %prec NEG
|
||
{
|
||
THD *thd= YYTHD;
|
||
Item *i1= new (thd->mem_root) Item_string($3.str,
|
||
$3.length,
|
||
thd->charset());
|
||
$$= new (thd->mem_root) Item_func_set_collation($1, i1);
|
||
}
|
||
| literal
|
||
| param_marker
|
||
| variable
|
||
| sum_expr
|
||
| simple_expr OR_OR_SYM simple_expr
|
||
{ $$= new (YYTHD->mem_root) Item_func_concat($1, $3); }
|
||
| '+' simple_expr %prec NEG { $$= $2; }
|
||
| '-' simple_expr %prec NEG
|
||
{ $$= new (YYTHD->mem_root) Item_func_neg($2); }
|
||
| '~' simple_expr %prec NEG
|
||
{ $$= new (YYTHD->mem_root) Item_func_bit_neg($2); }
|
||
| not2 simple_expr %prec NEG
|
||
{ $$= negate_expression(YYTHD, $2); }
|
||
| '(' subselect ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_singlerow_subselect($2);
|
||
}
|
||
| '(' expr ')' { $$= $2; }
|
||
| '(' expr ',' expr_list ')'
|
||
{
|
||
$4->push_front($2);
|
||
$$= new (YYTHD->mem_root) Item_row(*$4);
|
||
}
|
||
| ROW_SYM '(' expr ',' expr_list ')'
|
||
{
|
||
$5->push_front($3);
|
||
$$= new (YYTHD->mem_root) Item_row(*$5);
|
||
}
|
||
| EXISTS '(' subselect ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_exists_subselect($3);
|
||
}
|
||
| '{' ident expr '}' { $$= $3; }
|
||
| MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
|
||
{
|
||
$2->push_front($5);
|
||
Item_func_match *i1= new (YYTHD->mem_root) Item_func_match(*$2, $6);
|
||
Select->add_ftfunc_to_list(i1);
|
||
$$= i1;
|
||
}
|
||
| BINARY simple_expr %prec NEG
|
||
{
|
||
$$= create_func_cast(YYTHD, $2, ITEM_CAST_CHAR, -1, 0,
|
||
&my_charset_bin);
|
||
}
|
||
| CAST_SYM '(' expr AS cast_type ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
$$= create_func_cast(YYTHD, $3, $5,
|
||
lex->length ? atoi(lex->length) : -1,
|
||
lex->dec ? atoi(lex->dec) : 0,
|
||
lex->charset);
|
||
if (!$$)
|
||
YYABORT;
|
||
}
|
||
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
|
||
{ $$= new (YYTHD->mem_root) Item_func_case(* $4, $2, $5 ); }
|
||
| CONVERT_SYM '(' expr ',' cast_type ')'
|
||
{
|
||
$$= create_func_cast(YYTHD, $3, $5,
|
||
Lex->length ? atoi(Lex->length) : -1,
|
||
Lex->dec ? atoi(Lex->dec) : 0,
|
||
Lex->charset);
|
||
if (!$$)
|
||
YYABORT;
|
||
}
|
||
| CONVERT_SYM '(' expr USING charset_name ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_conv_charset($3,$5); }
|
||
| DEFAULT '(' simple_ident ')'
|
||
{
|
||
if ($3->is_splocal())
|
||
{
|
||
Item_splocal *il= static_cast<Item_splocal *>($3);
|
||
|
||
my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
|
||
YYABORT;
|
||
}
|
||
$$= new (YYTHD->mem_root) Item_default_value(Lex->current_context(),
|
||
$3);
|
||
}
|
||
| VALUES '(' simple_ident_nospvar ')'
|
||
{ $$= new (YYTHD->mem_root) Item_insert_value(Lex->current_context(),
|
||
$3); }
|
||
| interval_expr interval '+' expr
|
||
/* we cannot put interval before - */
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($4,$1,$2,0); }
|
||
| interval_expr
|
||
{
|
||
if ($1->type() != Item::ROW_ITEM)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
$$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1);
|
||
}
|
||
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
|
||
{
|
||
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
|
||
}
|
||
;
|
||
|
||
/*
|
||
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 (YYTHD->mem_root) Item_func_char(*$3); }
|
||
| CHAR_SYM '(' expr_list USING charset_name ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_char(*$3, $5); }
|
||
| CURRENT_USER optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_current_user(Lex->current_context());
|
||
Lex->safe_to_cache_query= 0;
|
||
}
|
||
| DATE_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_typecast($3); }
|
||
| DAY_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_dayofmonth($3); }
|
||
| HOUR_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_hour($3); }
|
||
| INSERT '(' expr ',' expr ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); }
|
||
| LEFT '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_left($3,$5); }
|
||
| MINUTE_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_minute($3); }
|
||
| MONTH_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_month($3); }
|
||
| RIGHT '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_right($3,$5); }
|
||
| SECOND_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_second($3); }
|
||
| TIME_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_time_typecast($3); }
|
||
| TIMESTAMP '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_datetime_typecast($3); }
|
||
| TIMESTAMP '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_add_time($3, $5, 1, 0); }
|
||
| TRIM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_trim($3); }
|
||
| TRIM '(' LEADING expr FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_ltrim($6,$4); }
|
||
| TRIM '(' TRAILING expr FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_rtrim($6,$4); }
|
||
| TRIM '(' BOTH expr FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_trim($6,$4); }
|
||
| TRIM '(' LEADING FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_ltrim($5); }
|
||
| TRIM '(' TRAILING FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_rtrim($5); }
|
||
| TRIM '(' BOTH FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_trim($5); }
|
||
| TRIM '(' expr FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_trim($5,$3); }
|
||
| USER '(' ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_user();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| YEAR_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_year($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:
|
||
ADDDATE_SYM '(' expr ',' expr ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_date_add_interval($3, $5,
|
||
INTERVAL_DAY, 0);
|
||
}
|
||
| ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 0); }
|
||
| CURDATE optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_curdate_local();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| CURTIME optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_curtime_local();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| CURTIME '(' expr ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_curtime_local($3);
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,0); }
|
||
| DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,1); }
|
||
| EXTRACT_SYM '(' interval FROM expr ')'
|
||
{ $$=new (YYTHD->mem_root) Item_extract( $3, $5); }
|
||
| GET_FORMAT '(' date_time_type ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_get_format($3, $5); }
|
||
| NOW_SYM optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_now_local();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| NOW_SYM '(' expr ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_now_local($3);
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| POSITION_SYM '(' bit_expr IN_SYM expr ')'
|
||
{ $$ = new (YYTHD->mem_root) Item_func_locate($5,$3); }
|
||
| SUBDATE_SYM '(' expr ',' expr ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_date_add_interval($3, $5,
|
||
INTERVAL_DAY, 1);
|
||
}
|
||
| SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3, $6, $7, 1); }
|
||
| SUBSTRING '(' expr ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); }
|
||
| SUBSTRING '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_substr($3,$5); }
|
||
| SUBSTRING '(' expr FROM expr FOR_SYM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_substr($3,$5,$7); }
|
||
| SUBSTRING '(' expr FROM expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_substr($3,$5); }
|
||
| SYSDATE optional_braces
|
||
{
|
||
if (global_system_variables.sysdate_is_now == 0)
|
||
$$= new (YYTHD->mem_root) Item_func_sysdate_local();
|
||
else
|
||
$$= new (YYTHD->mem_root) Item_func_now_local();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| SYSDATE '(' expr ')'
|
||
{
|
||
if (global_system_variables.sysdate_is_now == 0)
|
||
$$= new (YYTHD->mem_root) Item_func_sysdate_local($3);
|
||
else
|
||
$$= new (YYTHD->mem_root) Item_func_now_local($3);
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| TIMESTAMP_ADD '(' interval_time_st ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_date_add_interval($7,$5,$3,0); }
|
||
| TIMESTAMP_DIFF '(' interval_time_st ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_timestamp_diff($5,$7,$3); }
|
||
| UTC_DATE_SYM optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_curdate_utc();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| UTC_TIME_SYM optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_curtime_utc();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| UTC_TIMESTAMP_SYM optional_braces
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_now_utc();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
;
|
||
|
||
/*
|
||
Functions calls using a non reserved keywork, 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 (YYTHD->mem_root) Item_func_ascii($3); }
|
||
| CHARSET '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_charset($3); }
|
||
| COALESCE '(' expr_list ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_coalesce(* $3); }
|
||
| COLLATION_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_collation($3); }
|
||
| DATABASE '(' ')'
|
||
{
|
||
$$= new (YYTHD->mem_root) Item_func_database();
|
||
Lex->safe_to_cache_query=0;
|
||
}
|
||
| IF '(' expr ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_if($3,$5,$7); }
|
||
| MICROSECOND_SYM '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_microsecond($3); }
|
||
| MOD_SYM '(' expr ',' expr ')'
|
||
{ $$ = new (YYTHD->mem_root) Item_func_mod( $3, $5); }
|
||
| OLD_PASSWORD '(' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_old_password($3); }
|
||
| PASSWORD '(' expr ')'
|
||
{
|
||
THD *thd= YYTHD;
|
||
Item* i1;
|
||
if (thd->variables.old_passwords)
|
||
i1= new (thd->mem_root) Item_func_old_password($3);
|
||
else
|
||
i1= new (thd->mem_root) Item_func_password($3);
|
||
$$= i1;
|
||
}
|
||
| QUARTER_SYM '(' expr ')'
|
||
{ $$ = new (YYTHD->mem_root) Item_func_quarter($3); }
|
||
| REPEAT_SYM '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_repeat($3,$5); }
|
||
| REPLACE '(' expr ',' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_replace($3,$5,$7); }
|
||
| TRUNCATE_SYM '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_round($3,$5,1); }
|
||
| WEEK_SYM '(' expr ')'
|
||
{
|
||
THD *thd= YYTHD;
|
||
Item *i1= new (thd->mem_root) Item_int((char*) "0",
|
||
thd->variables.default_week_format,
|
||
1);
|
||
|
||
$$= new (thd->mem_root) Item_func_week($3, i1);
|
||
}
|
||
| WEEK_SYM '(' expr ',' expr ')'
|
||
{ $$= new (YYTHD->mem_root) Item_func_week($3,$5); }
|
||
| geometry_function
|
||
{
|
||
#ifdef HAVE_SPATIAL
|
||
$$= $1;
|
||
#else
|
||
my_error(ER_FEATURE_DISABLED, MYF(0),
|
||
sym_group_geom.name, sym_group_geom.needed_define);
|
||
YYABORT;
|
||
#endif
|
||
}
|
||
;
|
||
|
||
geometry_function:
|
||
CONTAINS_SYM '(' expr ',' expr ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_rel($3, $5,
|
||
Item_func::SP_CONTAINS_FUNC));
|
||
}
|
||
| GEOMETRYCOLLECTION '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_geometrycollection,
|
||
Geometry::wkb_point));
|
||
}
|
||
| LINESTRING '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_linestring,
|
||
Geometry::wkb_point));
|
||
}
|
||
| MULTILINESTRING '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_multilinestring,
|
||
Geometry::wkb_linestring));
|
||
}
|
||
| MULTIPOINT '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_multipoint,
|
||
Geometry::wkb_point));
|
||
}
|
||
| MULTIPOLYGON '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_multipolygon,
|
||
Geometry::wkb_polygon));
|
||
}
|
||
| POINT_SYM '(' expr ',' expr ')'
|
||
{ $$= GEOM_NEW(YYTHD, Item_func_point($3,$5)); }
|
||
| POLYGON '(' expr_list ')'
|
||
{
|
||
$$= GEOM_NEW(YYTHD,
|
||
Item_func_spatial_collection(* $3,
|
||
Geometry::wkb_polygon,
|
||
Geometry::wkb_linestring));
|
||
}
|
||
;
|
||
|
||
/*
|
||
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 (lex->current_select->inc_in_sum_expr())
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
/* Temporary placing the result of find_udf in $3 */
|
||
lex->current_select->udf_list.push_front(udf);
|
||
#endif
|
||
}
|
||
udf_expr_list ')'
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= Lex;
|
||
Create_func *builder;
|
||
Item *item= NULL;
|
||
|
||
/*
|
||
Implementation note:
|
||
names are resolved with the following order:
|
||
- MySQL native functions,
|
||
- User Defined Functions,
|
||
- Stored Functions (assuming the current <use> database)
|
||
|
||
This will be revised with WL#2128 (SQL PATH)
|
||
*/
|
||
builder= find_native_function_builder(thd, $1);
|
||
if (builder)
|
||
{
|
||
item= builder->create(thd, $1, $4);
|
||
}
|
||
else
|
||
{
|
||
#ifdef HAVE_DLOPEN
|
||
/* Retrieving the result of find_udf */
|
||
udf_func *udf;
|
||
LEX *lex= Lex;
|
||
|
||
if (NULL != (udf= lex->current_select->udf_list.pop()))
|
||
{
|
||
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(thd, $1, $4);
|
||
}
|
||
}
|
||
|
||
if (! ($$= item))
|
||
{
|
||
YYABORT;
|
||
}
|
||
}
|
||
| ident '.' ident '(' opt_expr_list ')'
|
||
{
|
||
THD *thd= YYTHD;
|
||
Create_qfunc *builder;
|
||
Item *item= NULL;
|
||
|
||
/*
|
||
The following in practice calls:
|
||
<code>Create_sp_func::create()</code>
|
||
and builds a stored function.
|
||
|
||
However, it's important to maintain the interface between the
|
||
parser and the implementation in item_create.cc clean,
|
||
since this will change with WL#2128 (SQL PATH):
|
||
- INFORMATION_SCHEMA.version() is the SQL 99 syntax for the native
|
||
funtion version(),
|
||
- MySQL.version() is the SQL 2003 syntax for the native function
|
||
version() (a vendor can specify any schema).
|
||
*/
|
||
|
||
builder= find_qualified_function_builder(thd);
|
||
DBUG_ASSERT(builder);
|
||
item= builder->create(thd, $1, $3, $5);
|
||
|
||
if (! ($$= item))
|
||
{
|
||
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; }
|
||
;
|
||
|
||
udf_expr_list:
|
||
/* empty */ { $$= NULL; }
|
||
| udf_expr_list2 { $$= $1;}
|
||
;
|
||
|
||
udf_expr_list2:
|
||
{ Select->expr_list.push_front(new List<Item>); }
|
||
udf_expr_list3
|
||
{ $$= Select->expr_list.pop(); }
|
||
;
|
||
|
||
udf_expr_list3:
|
||
udf_expr
|
||
{
|
||
Select->expr_list.head()->push_back($1);
|
||
}
|
||
| udf_expr_list3 ',' udf_expr
|
||
{
|
||
Select->expr_list.head()->push_back($3);
|
||
}
|
||
;
|
||
|
||
udf_expr:
|
||
remember_name expr remember_end select_alias
|
||
{
|
||
udf_func *udf= Select->udf_list.head();
|
||
/*
|
||
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)
|
||
{
|
||
if (!udf)
|
||
{
|
||
/*
|
||
Disallow using AS to specify explicit names for the arguments
|
||
of stored routine calls
|
||
*/
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
|
||
$2->is_autogenerated_name= FALSE;
|
||
$2->set_name($4.str, $4.length, system_charset_info);
|
||
}
|
||
else if (udf)
|
||
$2->set_name($1, (uint) ($3 - $1), YYTHD->charset());
|
||
$$= $2;
|
||
}
|
||
;
|
||
|
||
sum_expr:
|
||
AVG_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_avg($3); }
|
||
| AVG_SYM '(' DISTINCT in_sum_expr ')'
|
||
{ $$=new Item_sum_avg_distinct($4); }
|
||
| BIT_AND '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_and($3); }
|
||
| BIT_OR '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_or($3); }
|
||
| BIT_XOR '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_xor($3); }
|
||
| COUNT_SYM '(' opt_all '*' ')'
|
||
{ $$=new Item_sum_count(new Item_int((int32) 0L,1)); }
|
||
| COUNT_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_count($3); }
|
||
| COUNT_SYM '(' DISTINCT
|
||
{ Select->in_sum_expr++; }
|
||
expr_list
|
||
{ Select->in_sum_expr--; }
|
||
')'
|
||
{ $$=new Item_sum_count_distinct(* $5); }
|
||
| GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')'
|
||
{ $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); }
|
||
| MIN_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_min($3); }
|
||
/*
|
||
According to ANSI SQL, DISTINCT is allowed and has
|
||
no sence inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
|
||
is processed like an ordinary MIN | MAX()
|
||
*/
|
||
| MIN_SYM '(' DISTINCT in_sum_expr ')'
|
||
{ $$=new Item_sum_min($4); }
|
||
| MAX_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_max($3); }
|
||
| MAX_SYM '(' DISTINCT in_sum_expr ')'
|
||
{ $$=new Item_sum_max($4); }
|
||
| STD_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_std($3, 0); }
|
||
| VARIANCE_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_variance($3, 0); }
|
||
| STDDEV_SAMP_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_std($3, 1); }
|
||
| VAR_SAMP_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_variance($3, 1); }
|
||
| SUM_SYM '(' in_sum_expr ')'
|
||
{ $$=new Item_sum_sum($3); }
|
||
| SUM_SYM '(' DISTINCT in_sum_expr ')'
|
||
{ $$=new Item_sum_sum_distinct($4); }
|
||
| GROUP_CONCAT_SYM '(' opt_distinct
|
||
{ Select->in_sum_expr++; }
|
||
expr_list opt_gorder_clause
|
||
opt_gconcat_separator
|
||
')'
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->in_sum_expr--;
|
||
$$=new Item_func_group_concat(Lex->current_context(), $3, $5,
|
||
sel->gorder_list, $7);
|
||
$5->empty();
|
||
};
|
||
|
||
variable:
|
||
'@'
|
||
{
|
||
if (! Lex->parsing_options.allows_variable)
|
||
{
|
||
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
variable_aux
|
||
{
|
||
$$= $3;
|
||
}
|
||
;
|
||
|
||
variable_aux:
|
||
ident_or_text SET_VAR expr
|
||
{
|
||
$$= new Item_func_set_user_var($1, $3);
|
||
LEX *lex= Lex;
|
||
lex->uncacheable(UNCACHEABLE_RAND);
|
||
}
|
||
| ident_or_text
|
||
{
|
||
$$= new Item_func_get_user_var($1);
|
||
LEX *lex= Lex;
|
||
lex->uncacheable(UNCACHEABLE_RAND);
|
||
}
|
||
| '@' opt_var_ident_type ident_or_text opt_component
|
||
{
|
||
if ($3.str && $4.str && check_reserved_words(&$3))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (!($$= get_system_var(YYTHD, $2, $3, $4)))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
opt_distinct:
|
||
/* empty */ { $$ = 0; }
|
||
|DISTINCT { $$ = 1; };
|
||
|
||
opt_gconcat_separator:
|
||
/* empty */ { $$ = new (YYTHD->mem_root) String(",",1,default_charset_info); }
|
||
|SEPARATOR_SYM text_string { $$ = $2; };
|
||
|
||
|
||
opt_gorder_clause:
|
||
/* empty */
|
||
{
|
||
Select->gorder_list = NULL;
|
||
}
|
||
| order_clause
|
||
{
|
||
SELECT_LEX *select= Select;
|
||
select->gorder_list=
|
||
(SQL_LIST*) sql_memdup((char*) &select->order_list,
|
||
sizeof(st_sql_list));
|
||
select->order_list.empty();
|
||
};
|
||
|
||
|
||
in_sum_expr:
|
||
opt_all
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->current_select->inc_in_sum_expr())
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
expr
|
||
{
|
||
Select->in_sum_expr--;
|
||
$$= $3;
|
||
};
|
||
|
||
cast_type:
|
||
BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; }
|
||
| CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
|
||
| NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; Lex->dec=0; }
|
||
| SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
|
||
| DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
|
||
;
|
||
|
||
opt_expr_list:
|
||
/* empty */ { $$= NULL; }
|
||
| expr_list { $$= $1;}
|
||
;
|
||
|
||
expr_list:
|
||
{ Select->expr_list.push_front(new List<Item>); }
|
||
expr_list2
|
||
{ $$= Select->expr_list.pop(); };
|
||
|
||
expr_list2:
|
||
expr { Select->expr_list.head()->push_back($1); }
|
||
| expr_list2 ',' expr { Select->expr_list.head()->push_back($3); };
|
||
|
||
ident_list_arg:
|
||
ident_list { $$= $1; }
|
||
| '(' ident_list ')' { $$= $2; };
|
||
|
||
ident_list:
|
||
{ Select->expr_list.push_front(new List<Item>); }
|
||
ident_list2
|
||
{ $$= Select->expr_list.pop(); };
|
||
|
||
ident_list2:
|
||
simple_ident { Select->expr_list.head()->push_back($1); }
|
||
| ident_list2 ',' simple_ident { Select->expr_list.head()->push_back($3); };
|
||
|
||
opt_expr:
|
||
/* empty */ { $$= NULL; }
|
||
| expr { $$= $1; };
|
||
|
||
opt_else:
|
||
/* empty */ { $$= NULL; }
|
||
| ELSE expr { $$= $2; };
|
||
|
||
when_list:
|
||
{ Select->when_list.push_front(new List<Item>); }
|
||
when_list2
|
||
{ $$= Select->when_list.pop(); };
|
||
|
||
when_list2:
|
||
expr THEN_SYM expr
|
||
{
|
||
SELECT_LEX *sel=Select;
|
||
sel->when_list.head()->push_back($1);
|
||
sel->when_list.head()->push_back($3);
|
||
}
|
||
| when_list2 WHEN_SYM expr THEN_SYM expr
|
||
{
|
||
SELECT_LEX *sel=Select;
|
||
sel->when_list.head()->push_back($3);
|
||
sel->when_list.head()->push_back($5);
|
||
};
|
||
|
||
/* Warning - may return NULL in case of incomplete SELECT */
|
||
table_ref:
|
||
table_factor { $$=$1; }
|
||
| join_table
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!($$= lex->current_select->nest_last_join(lex->thd)))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
join_table_list:
|
||
derived_table_list { YYERROR_UNLESS($$=$1); }
|
||
;
|
||
|
||
/* Warning - may return NULL in case of incomplete SELECT */
|
||
derived_table_list:
|
||
table_ref { $$=$1; }
|
||
| derived_table_list ',' table_ref
|
||
{
|
||
YYERROR_UNLESS($1 && ($$=$3));
|
||
}
|
||
;
|
||
|
||
/*
|
||
Notice that JOIN is a left-associative operation, and it must be parsed
|
||
as such, that is, the parser must process first the left join operand
|
||
then the right one. Such order of processing ensures that the parser
|
||
produces correct join trees which is essential for semantic analysis
|
||
and subsequent optimization phases.
|
||
*/
|
||
join_table:
|
||
/* INNER JOIN variants */
|
||
/*
|
||
Use %prec to evaluate production 'table_ref' before 'normal_join'
|
||
so that [INNER | CROSS] JOIN is properly nested as other
|
||
left-associative joins.
|
||
*/
|
||
table_ref %prec TABLE_REF_PRIORITY normal_join table_ref
|
||
{ YYERROR_UNLESS($1 && ($$=$3)); }
|
||
| table_ref STRAIGHT_JOIN table_factor
|
||
{ YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; }
|
||
| table_ref normal_join table_ref
|
||
ON
|
||
{
|
||
YYERROR_UNLESS($1 && $3);
|
||
/* Change the current name resolution context to a local context. */
|
||
if (push_new_name_resolution_context(YYTHD, $1, $3))
|
||
YYABORT;
|
||
Select->parsing_place= IN_ON;
|
||
}
|
||
expr
|
||
{
|
||
add_join_on($3,$6);
|
||
Lex->pop_context();
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
| table_ref STRAIGHT_JOIN table_factor
|
||
ON
|
||
{
|
||
YYERROR_UNLESS($1 && $3);
|
||
/* Change the current name resolution context to a local context. */
|
||
if (push_new_name_resolution_context(YYTHD, $1, $3))
|
||
YYABORT;
|
||
Select->parsing_place= IN_ON;
|
||
}
|
||
expr
|
||
{
|
||
$3->straight=1;
|
||
add_join_on($3,$6);
|
||
Lex->pop_context();
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
| table_ref normal_join table_ref
|
||
USING
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
YYERROR_UNLESS($1 && $3);
|
||
}
|
||
'(' using_list ')'
|
||
{ add_join_natural($1,$3,$7); $$=$3; }
|
||
| table_ref NATURAL JOIN_SYM table_factor
|
||
{
|
||
YYERROR_UNLESS($1 && ($$=$4));
|
||
add_join_natural($1,$4,NULL);
|
||
}
|
||
|
||
/* LEFT JOIN variants */
|
||
| table_ref LEFT opt_outer JOIN_SYM table_ref
|
||
ON
|
||
{
|
||
YYERROR_UNLESS($1 && $5);
|
||
/* Change the current name resolution context to a local context. */
|
||
if (push_new_name_resolution_context(YYTHD, $1, $5))
|
||
YYABORT;
|
||
Select->parsing_place= IN_ON;
|
||
}
|
||
expr
|
||
{
|
||
add_join_on($5,$8);
|
||
Lex->pop_context();
|
||
$5->outer_join|=JOIN_TYPE_LEFT;
|
||
$$=$5;
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
| table_ref LEFT opt_outer JOIN_SYM table_factor
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
YYERROR_UNLESS($1 && $5);
|
||
}
|
||
USING '(' using_list ')'
|
||
{ add_join_natural($1,$5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
|
||
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
|
||
{
|
||
YYERROR_UNLESS($1 && $6);
|
||
add_join_natural($1,$6,NULL);
|
||
$6->outer_join|=JOIN_TYPE_LEFT;
|
||
$$=$6;
|
||
}
|
||
|
||
/* RIGHT JOIN variants */
|
||
| table_ref RIGHT opt_outer JOIN_SYM table_ref
|
||
ON
|
||
{
|
||
YYERROR_UNLESS($1 && $5);
|
||
/* Change the current name resolution context to a local context. */
|
||
if (push_new_name_resolution_context(YYTHD, $1, $5))
|
||
YYABORT;
|
||
Select->parsing_place= IN_ON;
|
||
}
|
||
expr
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!($$= lex->current_select->convert_right_join()))
|
||
YYABORT;
|
||
add_join_on($$, $8);
|
||
Lex->pop_context();
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
| table_ref RIGHT opt_outer JOIN_SYM table_factor
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
YYERROR_UNLESS($1 && $5);
|
||
}
|
||
USING '(' using_list ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
if (!($$= lex->current_select->convert_right_join()))
|
||
YYABORT;
|
||
add_join_natural($$,$5,$9);
|
||
}
|
||
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
|
||
{
|
||
YYERROR_UNLESS($1 && $6);
|
||
add_join_natural($6,$1,NULL);
|
||
LEX *lex= Lex;
|
||
if (!($$= lex->current_select->convert_right_join()))
|
||
YYABORT;
|
||
};
|
||
|
||
normal_join:
|
||
JOIN_SYM {}
|
||
| INNER_SYM JOIN_SYM {}
|
||
| CROSS JOIN_SYM {}
|
||
;
|
||
|
||
/* Warning - may return NULL in case of incomplete SELECT */
|
||
table_factor:
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->use_index_ptr=sel->ignore_index_ptr=0;
|
||
sel->table_join_options= 0;
|
||
}
|
||
table_ident opt_table_alias opt_key_definition
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
|
||
sel->get_table_join_options(),
|
||
lex->lock_option,
|
||
sel->get_use_index(),
|
||
sel->get_ignore_index())))
|
||
YYABORT;
|
||
sel->add_joined_table($$);
|
||
}
|
||
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
|
||
ON
|
||
{
|
||
/* Change the current name resolution context to a local context. */
|
||
if (push_new_name_resolution_context(YYTHD, $3, $7))
|
||
YYABORT;
|
||
|
||
}
|
||
expr '}'
|
||
{
|
||
LEX *lex= Lex;
|
||
YYERROR_UNLESS($3 && $7);
|
||
add_join_on($7,$10);
|
||
Lex->pop_context();
|
||
$7->outer_join|=JOIN_TYPE_LEFT;
|
||
$$=$7;
|
||
if (!($$= lex->current_select->nest_last_join(lex->thd)))
|
||
YYABORT;
|
||
}
|
||
| select_derived_init get_select_lex select_derived2
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if ($1)
|
||
{
|
||
if (sel->set_braces(1))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
/* select in braces, can't contain global parameters */
|
||
if (sel->master_unit()->fake_select_lex)
|
||
sel->master_unit()->global_parameters=
|
||
sel->master_unit()->fake_select_lex;
|
||
}
|
||
if ($2->init_nested_join(lex->thd))
|
||
YYABORT;
|
||
$$= 0;
|
||
/* incomplete derived tables return NULL, we must be
|
||
nested in select_derived rule to be here. */
|
||
}
|
||
| '(' get_select_lex select_derived union_opt ')' opt_table_alias
|
||
{
|
||
/* Use $2 instead of Lex->current_select as derived table will
|
||
alter value of Lex->current_select. */
|
||
|
||
if (!($3 || $6) && $2->embedding &&
|
||
!$2->embedding->nested_join->join_list.elements)
|
||
{
|
||
/* we have a derived table ($3 == NULL) but no alias,
|
||
Since we are nested in further parentheses so we
|
||
can pass NULL to the outer level parentheses
|
||
Permits parsing of "((((select ...))) as xyz)" */
|
||
$$= 0;
|
||
}
|
||
else
|
||
if (!$3)
|
||
{
|
||
/* Handle case of derived table, alias may be NULL if there
|
||
are no outer parentheses, add_table_to_list() will throw
|
||
error in this case */
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
SELECT_LEX_UNIT *unit= sel->master_unit();
|
||
lex->current_select= sel= unit->outer_select();
|
||
if (!($$= sel->
|
||
add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
|
||
TL_READ,(List<String> *)0,
|
||
(List<String> *)0)))
|
||
|
||
YYABORT;
|
||
sel->add_joined_table($$);
|
||
lex->pop_context();
|
||
}
|
||
else
|
||
if ($4 || $6)
|
||
{
|
||
/* simple nested joins cannot have aliases or unions */
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
else
|
||
$$= $3;
|
||
}
|
||
;
|
||
|
||
/* handle contents of parentheses in join expression */
|
||
select_derived:
|
||
get_select_lex
|
||
{
|
||
LEX *lex= Lex;
|
||
if ($1->init_nested_join(lex->thd))
|
||
YYABORT;
|
||
}
|
||
derived_table_list
|
||
{
|
||
LEX *lex= Lex;
|
||
/* for normal joins, $3 != NULL and end_nested_join() != NULL,
|
||
for derived tables, both must equal NULL */
|
||
|
||
if (!($$= $1->end_nested_join(lex->thd)) && $3)
|
||
YYABORT;
|
||
if (!$3 && $$)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
select_derived2:
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->derived_tables|= DERIVED_SUBQUERY;
|
||
if (!lex->expr_allows_subselect)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
|
||
mysql_new_select(lex, 1))
|
||
YYABORT;
|
||
mysql_init_select(lex);
|
||
lex->current_select->linkage= DERIVED_TABLE_TYPE;
|
||
lex->current_select->parsing_place= SELECT_LIST;
|
||
}
|
||
select_options select_item_list
|
||
{
|
||
Select->parsing_place= NO_MATTER;
|
||
}
|
||
opt_select_from
|
||
;
|
||
|
||
get_select_lex:
|
||
/* Empty */ { $$= Select; }
|
||
;
|
||
|
||
select_derived_init:
|
||
SELECT_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (! lex->parsing_options.allows_derived)
|
||
{
|
||
my_error(ER_VIEW_SELECT_DERIVED, MYF(0));
|
||
YYABORT;
|
||
}
|
||
|
||
SELECT_LEX *sel= lex->current_select;
|
||
TABLE_LIST *embedding;
|
||
if (!sel->embedding || sel->end_nested_join(lex->thd))
|
||
{
|
||
/* we are not in parentheses */
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
embedding= Select->embedding;
|
||
$$= embedding &&
|
||
!embedding->nested_join->join_list.elements;
|
||
/* return true if we are deeply nested */
|
||
}
|
||
;
|
||
|
||
opt_outer:
|
||
/* empty */ {}
|
||
| OUTER {};
|
||
|
||
opt_key_definition:
|
||
/* empty */ {}
|
||
| USE_SYM key_usage_list
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->use_index= *$2;
|
||
sel->use_index_ptr= &sel->use_index;
|
||
}
|
||
| FORCE_SYM key_usage_list
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->use_index= *$2;
|
||
sel->use_index_ptr= &sel->use_index;
|
||
sel->table_join_options|= TL_OPTION_FORCE_INDEX;
|
||
}
|
||
| IGNORE_SYM key_usage_list
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->ignore_index= *$2;
|
||
sel->ignore_index_ptr= &sel->ignore_index;
|
||
};
|
||
|
||
key_usage_list:
|
||
key_or_index { Select->interval_list.empty(); }
|
||
'(' key_list_or_empty ')'
|
||
{ $$= &Select->interval_list; }
|
||
;
|
||
|
||
key_list_or_empty:
|
||
/* empty */ {}
|
||
| key_usage_list2 {}
|
||
;
|
||
|
||
key_usage_list2:
|
||
key_usage_list2 ',' ident
|
||
{ Select->
|
||
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
|
||
system_charset_info)); }
|
||
| ident
|
||
{ Select->
|
||
interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
|
||
system_charset_info)); }
|
||
| PRIMARY_SYM
|
||
{ Select->
|
||
interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
|
||
system_charset_info)); };
|
||
|
||
using_list:
|
||
ident
|
||
{
|
||
if (!($$= new List<String>))
|
||
YYABORT;
|
||
$$->push_back(new (YYTHD->mem_root)
|
||
String((const char *) $1.str, $1.length,
|
||
system_charset_info));
|
||
}
|
||
| using_list ',' ident
|
||
{
|
||
$1->push_back(new (YYTHD->mem_root)
|
||
String((const char *) $3.str, $3.length,
|
||
system_charset_info));
|
||
$$= $1;
|
||
};
|
||
|
||
interval:
|
||
interval_time_st {}
|
||
| 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; }
|
||
| MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; }
|
||
| 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_st:
|
||
DAY_SYM { $$=INTERVAL_DAY; }
|
||
| WEEK_SYM { $$=INTERVAL_WEEK; }
|
||
| HOUR_SYM { $$=INTERVAL_HOUR; }
|
||
| FRAC_SECOND_SYM { $$=INTERVAL_MICROSECOND; }
|
||
| MINUTE_SYM { $$=INTERVAL_MINUTE; }
|
||
| MONTH_SYM { $$=INTERVAL_MONTH; }
|
||
| QUARTER_SYM { $$=INTERVAL_QUARTER; }
|
||
| SECOND_SYM { $$=INTERVAL_SECOND; }
|
||
| 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
|
||
| EQ;
|
||
|
||
opt_table_alias:
|
||
/* empty */ { $$=0; }
|
||
| table_alias ident
|
||
{ $$= (LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)); };
|
||
|
||
opt_all:
|
||
/* empty */
|
||
| ALL
|
||
;
|
||
|
||
where_clause:
|
||
/* empty */ { Select->where= 0; }
|
||
| WHERE
|
||
{
|
||
Select->parsing_place= IN_WHERE;
|
||
}
|
||
expr
|
||
{
|
||
SELECT_LEX *select= Select;
|
||
select->where= $3;
|
||
select->parsing_place= NO_MATTER;
|
||
if ($3)
|
||
$3->top_level_item();
|
||
}
|
||
;
|
||
|
||
having_clause:
|
||
/* empty */
|
||
| HAVING
|
||
{
|
||
Select->parsing_place= IN_HAVING;
|
||
}
|
||
expr
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->having= $3;
|
||
sel->parsing_place= NO_MATTER;
|
||
if ($3)
|
||
$3->top_level_item();
|
||
}
|
||
;
|
||
|
||
opt_escape:
|
||
ESCAPE_SYM simple_expr
|
||
{
|
||
Lex->escape_used= TRUE;
|
||
$$= $2;
|
||
}
|
||
| /* empty */
|
||
{
|
||
Lex->escape_used= FALSE;
|
||
$$= ((YYTHD->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) ?
|
||
new Item_string("", 0, &my_charset_latin1) :
|
||
new Item_string("\\", 1, &my_charset_latin1));
|
||
}
|
||
;
|
||
|
||
|
||
/*
|
||
group by statement in select
|
||
*/
|
||
|
||
group_clause:
|
||
/* empty */
|
||
| GROUP BY group_list olap_opt;
|
||
|
||
group_list:
|
||
group_list ',' order_ident order_dir
|
||
{ if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
|
||
| order_ident order_dir
|
||
{ if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
|
||
|
||
olap_opt:
|
||
/* empty */ {}
|
||
| WITH CUBE_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
|
||
{
|
||
my_error(ER_WRONG_USAGE, MYF(0), "WITH CUBE",
|
||
"global union parameters");
|
||
YYABORT;
|
||
}
|
||
lex->current_select->olap= CUBE_TYPE;
|
||
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "CUBE");
|
||
YYABORT; /* To be deleted in 5.1 */
|
||
}
|
||
| WITH ROLLUP_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
|
||
{
|
||
my_error(ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
|
||
"global union parameters");
|
||
YYABORT;
|
||
}
|
||
lex->current_select->olap= ROLLUP_TYPE;
|
||
}
|
||
;
|
||
|
||
/*
|
||
Order by statement in select
|
||
*/
|
||
|
||
opt_order_clause:
|
||
/* empty */
|
||
| order_clause;
|
||
|
||
order_clause:
|
||
ORDER_SYM BY
|
||
{
|
||
LEX *lex=Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
SELECT_LEX_UNIT *unit= sel-> master_unit();
|
||
if (sel->linkage != GLOBAL_OPTIONS_TYPE &&
|
||
sel->olap != UNSPECIFIED_OLAP_TYPE)
|
||
{
|
||
my_error(ER_WRONG_USAGE, MYF(0),
|
||
"CUBE/ROLLUP", "ORDER BY");
|
||
YYABORT;
|
||
}
|
||
if (lex->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex)
|
||
{
|
||
/*
|
||
A query of the of the form (SELECT ...) ORDER BY order_list is
|
||
executed in the same way as the query
|
||
SELECT ... ORDER BY order_list
|
||
unless the SELECT construct contains ORDER BY or LIMIT clauses.
|
||
Otherwise we create a fake SELECT_LEX if it has not been created
|
||
yet.
|
||
*/
|
||
SELECT_LEX *first_sl= unit->first_select();
|
||
if (!first_sl->next_select() &&
|
||
(first_sl->order_list.elements ||
|
||
first_sl->select_limit) &&
|
||
unit->add_fake_select_lex(lex->thd))
|
||
YYABORT;
|
||
}
|
||
} order_list;
|
||
|
||
order_list:
|
||
order_list ',' order_ident order_dir
|
||
{ if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
|
||
| order_ident order_dir
|
||
{ if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
|
||
|
||
order_dir:
|
||
/* empty */ { $$ = 1; }
|
||
| ASC { $$ =1; }
|
||
| DESC { $$ =0; };
|
||
|
||
|
||
opt_limit_clause_init:
|
||
/* empty */
|
||
{
|
||
LEX *lex= Lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
sel->offset_limit= 0;
|
||
sel->select_limit= 0;
|
||
}
|
||
| limit_clause {}
|
||
;
|
||
|
||
opt_limit_clause:
|
||
/* empty */ {}
|
||
| limit_clause {}
|
||
;
|
||
|
||
limit_clause:
|
||
LIMIT limit_options {}
|
||
;
|
||
|
||
limit_options:
|
||
limit_option
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->select_limit= $1;
|
||
sel->offset_limit= 0;
|
||
sel->explicit_limit= 1;
|
||
}
|
||
| limit_option ',' limit_option
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->select_limit= $3;
|
||
sel->offset_limit= $1;
|
||
sel->explicit_limit= 1;
|
||
}
|
||
| limit_option OFFSET_SYM limit_option
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->select_limit= $1;
|
||
sel->offset_limit= $3;
|
||
sel->explicit_limit= 1;
|
||
}
|
||
;
|
||
limit_option:
|
||
param_marker
|
||
| ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
|
||
| LONG_NUM { $$= new Item_uint($1.str, $1.length); }
|
||
| NUM { $$= new Item_uint($1.str, $1.length); }
|
||
;
|
||
|
||
delete_limit_clause:
|
||
/* empty */
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->current_select->select_limit= 0;
|
||
}
|
||
| LIMIT limit_option
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
sel->select_limit= $2;
|
||
sel->explicit_limit= 1;
|
||
};
|
||
|
||
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); }
|
||
| DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
|
||
| FLOAT_NUM { int error; $$= (ulong) my_strtoll10($1.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 { YYABORT; }
|
||
;
|
||
|
||
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); }
|
||
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
|
||
| DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
|
||
| FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($1.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); }
|
||
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
|
||
| dec_num_error { YYABORT; }
|
||
;
|
||
|
||
dec_num_error:
|
||
dec_num
|
||
{ yyerror(ER(ER_ONLY_INTEGERS_ALLOWED)); }
|
||
;
|
||
|
||
dec_num:
|
||
DECIMAL_NUM
|
||
| FLOAT_NUM
|
||
;
|
||
|
||
procedure_clause:
|
||
/* empty */
|
||
| PROCEDURE ident /* Procedure name */
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
if (! lex->parsing_options.allows_select_procedure)
|
||
{
|
||
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE");
|
||
YYABORT;
|
||
}
|
||
|
||
if (&lex->select_lex != lex->current_select)
|
||
{
|
||
my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
|
||
YYABORT;
|
||
}
|
||
lex->proc_list.elements=0;
|
||
lex->proc_list.first=0;
|
||
lex->proc_list.next= (byte**) &lex->proc_list.first;
|
||
if (add_proc_to_list(lex->thd, new Item_field(&lex->
|
||
current_select->
|
||
context,
|
||
NULL,NULL,$2.str)))
|
||
YYABORT;
|
||
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||
}
|
||
'(' procedure_list ')';
|
||
|
||
|
||
procedure_list:
|
||
/* empty */ {}
|
||
| procedure_list2 {};
|
||
|
||
procedure_list2:
|
||
procedure_list2 ',' procedure_item
|
||
| procedure_item;
|
||
|
||
procedure_item:
|
||
remember_name expr
|
||
{
|
||
LEX *lex= Lex;
|
||
if (add_proc_to_list(lex->thd, $2))
|
||
YYABORT;
|
||
if (!$2->name)
|
||
$2->set_name($1,(uint) ((char*) lex->tok_end - $1),
|
||
YYTHD->charset());
|
||
}
|
||
;
|
||
|
||
|
||
select_var_list_init:
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!lex->describe && (!(lex->result= new select_dumpvar())))
|
||
YYABORT;
|
||
}
|
||
select_var_list
|
||
{}
|
||
;
|
||
|
||
select_var_list:
|
||
select_var_list ',' select_var_ident
|
||
| select_var_ident {}
|
||
;
|
||
|
||
select_var_ident:
|
||
'@' ident_or_text
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->result)
|
||
((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0));
|
||
else
|
||
/*
|
||
The parser won't create select_result instance only
|
||
if it's an EXPLAIN.
|
||
*/
|
||
DBUG_ASSERT(lex->describe);
|
||
}
|
||
| ident_or_text
|
||
{
|
||
LEX *lex=Lex;
|
||
sp_variable_t *t;
|
||
|
||
if (!lex->spcont || !(t=lex->spcont->find_variable(&$1)))
|
||
{
|
||
my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
if (lex->result)
|
||
{
|
||
my_var *var;
|
||
((select_dumpvar *)lex->result)->
|
||
var_list.push_back(var= new my_var($1,1,t->offset,t->type));
|
||
#ifndef DBUG_OFF
|
||
if (var)
|
||
var->sp= lex->sphead;
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
The parser won't create select_result instance only
|
||
if it's an EXPLAIN.
|
||
*/
|
||
DBUG_ASSERT(lex->describe);
|
||
}
|
||
}
|
||
;
|
||
|
||
into:
|
||
INTO
|
||
{
|
||
if (! Lex->parsing_options.allows_select_into)
|
||
{
|
||
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO");
|
||
YYABORT;
|
||
}
|
||
}
|
||
into_destination
|
||
;
|
||
|
||
into_destination:
|
||
OUTFILE TEXT_STRING_filesystem
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||
if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
|
||
!(lex->result= new select_export(lex->exchange)))
|
||
YYABORT;
|
||
}
|
||
opt_field_term opt_line_term
|
||
| DUMPFILE TEXT_STRING_filesystem
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!lex->describe)
|
||
{
|
||
lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||
if (!(lex->exchange= new sql_exchange($2.str,1)))
|
||
YYABORT;
|
||
if (!(lex->result= new select_dump(lex->exchange)))
|
||
YYABORT;
|
||
}
|
||
}
|
||
| select_var_list_init
|
||
{
|
||
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||
}
|
||
;
|
||
|
||
/*
|
||
DO statement
|
||
*/
|
||
|
||
do: DO_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_DO;
|
||
mysql_init_select(lex);
|
||
}
|
||
expr_list
|
||
{
|
||
Lex->insert_list= $3;
|
||
}
|
||
;
|
||
|
||
/*
|
||
Drop : delete tables or index or user
|
||
*/
|
||
|
||
drop:
|
||
DROP opt_temporary table_or_tables if_exists table_list opt_restrict
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_DROP_TABLE;
|
||
lex->drop_temporary= $2;
|
||
lex->drop_if_exists= $4;
|
||
}
|
||
| DROP INDEX_SYM ident ON table_ident {}
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_DROP_INDEX;
|
||
lex->alter_info.drop_list.empty();
|
||
lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY,
|
||
$3.str));
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
|
||
TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
}
|
||
| DROP DATABASE if_exists ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_DROP_DB;
|
||
lex->drop_if_exists=$3;
|
||
lex->name= $4;
|
||
}
|
||
| DROP FUNCTION_SYM if_exists sp_name
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_DROP_FUNCTION;
|
||
lex->drop_if_exists= $3;
|
||
lex->spname= $4;
|
||
}
|
||
| DROP PROCEDURE if_exists sp_name
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_DROP_PROCEDURE;
|
||
lex->drop_if_exists= $3;
|
||
lex->spname= $4;
|
||
}
|
||
| DROP USER clear_privileges user_list
|
||
{
|
||
Lex->sql_command = SQLCOM_DROP_USER;
|
||
}
|
||
| DROP VIEW_SYM if_exists table_list opt_restrict
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_DROP_VIEW;
|
||
lex->drop_if_exists= $3;
|
||
}
|
||
| DROP EVENT_SYM if_exists sp_name
|
||
{
|
||
Lex->drop_if_exists= $3;
|
||
Lex->spname= $4;
|
||
Lex->sql_command = SQLCOM_DROP_EVENT;
|
||
}
|
||
| DROP TRIGGER_SYM if_exists sp_name
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_DROP_TRIGGER;
|
||
lex->drop_if_exists= $3;
|
||
lex->spname= $4;
|
||
}
|
||
| DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= DROP_TABLESPACE;
|
||
}
|
||
| DROP LOGFILE_SYM GROUP logfile_group_name opt_ts_engine opt_ts_wait
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
|
||
}
|
||
| DROP SERVER_SYM if_exists ident_or_text
|
||
{
|
||
Lex->sql_command = SQLCOM_DROP_SERVER;
|
||
Lex->drop_if_exists= $3;
|
||
Lex->server_options.server_name= $4.str;
|
||
Lex->server_options.server_name_length= $4.length;
|
||
}
|
||
;
|
||
|
||
table_list:
|
||
table_name
|
||
| table_list ',' table_name;
|
||
|
||
table_name:
|
||
table_ident
|
||
{
|
||
if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
if_exists:
|
||
/* empty */ { $$= 0; }
|
||
| IF EXISTS { $$= 1; }
|
||
;
|
||
|
||
opt_temporary:
|
||
/* empty */ { $$= 0; }
|
||
| TEMPORARY { $$= 1; }
|
||
;
|
||
/*
|
||
** Insert : add new data to table
|
||
*/
|
||
|
||
insert:
|
||
INSERT
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_INSERT;
|
||
lex->duplicates= DUP_ERROR;
|
||
mysql_init_select(lex);
|
||
/* for subselects */
|
||
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
|
||
} insert_lock_option
|
||
opt_ignore insert2
|
||
{
|
||
Select->set_lock_for_tables($3);
|
||
Lex->current_select= &Lex->select_lex;
|
||
}
|
||
insert_field_spec opt_insert_update
|
||
{}
|
||
;
|
||
|
||
replace:
|
||
REPLACE
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_REPLACE;
|
||
lex->duplicates= DUP_REPLACE;
|
||
mysql_init_select(lex);
|
||
}
|
||
replace_lock_option insert2
|
||
{
|
||
Select->set_lock_for_tables($3);
|
||
Lex->current_select= &Lex->select_lex;
|
||
}
|
||
insert_field_spec
|
||
{}
|
||
;
|
||
|
||
insert_lock_option:
|
||
/* empty */
|
||
{
|
||
#ifdef HAVE_QUERY_CACHE
|
||
/*
|
||
If it is SP we do not allow insert optimisation whan result of
|
||
insert visible only after the table unlocking but everyone can
|
||
read table.
|
||
*/
|
||
$$= (Lex->sphead ? TL_WRITE :TL_WRITE_CONCURRENT_INSERT);
|
||
#else
|
||
$$= TL_WRITE_CONCURRENT_INSERT;
|
||
#endif
|
||
}
|
||
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
|
||
| DELAYED_SYM { $$= TL_WRITE_DELAYED; }
|
||
| HIGH_PRIORITY { $$= TL_WRITE; }
|
||
;
|
||
|
||
replace_lock_option:
|
||
opt_low_priority { $$= $1; }
|
||
| DELAYED_SYM { $$= TL_WRITE_DELAYED; };
|
||
|
||
insert2:
|
||
INTO insert_table {}
|
||
| insert_table {};
|
||
|
||
insert_table:
|
||
table_name
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->field_list.empty();
|
||
lex->many_values.empty();
|
||
lex->insert_list=0;
|
||
};
|
||
|
||
insert_field_spec:
|
||
insert_values {}
|
||
| '(' ')' insert_values {}
|
||
| '(' fields ')' insert_values {}
|
||
| SET
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!(lex->insert_list = new List_item) ||
|
||
lex->many_values.push_back(lex->insert_list))
|
||
YYABORT;
|
||
}
|
||
ident_eq_list;
|
||
|
||
fields:
|
||
fields ',' insert_ident { Lex->field_list.push_back($3); }
|
||
| insert_ident { Lex->field_list.push_back($1); };
|
||
|
||
insert_values:
|
||
VALUES values_list {}
|
||
| VALUE_SYM values_list {}
|
||
| create_select { Select->set_braces(0);} union_clause {}
|
||
| '(' create_select ')' { Select->set_braces(1);} union_opt {}
|
||
;
|
||
|
||
values_list:
|
||
values_list ',' no_braces
|
||
| no_braces;
|
||
|
||
ident_eq_list:
|
||
ident_eq_list ',' ident_eq_value
|
||
|
|
||
ident_eq_value;
|
||
|
||
ident_eq_value:
|
||
simple_ident_nospvar equal expr_or_default
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->field_list.push_back($1) ||
|
||
lex->insert_list->push_back($3))
|
||
YYABORT;
|
||
};
|
||
|
||
equal: EQ {}
|
||
| SET_VAR {}
|
||
;
|
||
|
||
opt_equal:
|
||
/* empty */ {}
|
||
| equal {}
|
||
;
|
||
|
||
no_braces:
|
||
'('
|
||
{
|
||
if (!(Lex->insert_list = new List_item))
|
||
YYABORT;
|
||
}
|
||
opt_values ')'
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->many_values.push_back(lex->insert_list))
|
||
YYABORT;
|
||
};
|
||
|
||
opt_values:
|
||
/* empty */ {}
|
||
| values;
|
||
|
||
values:
|
||
values ',' expr_or_default
|
||
{
|
||
if (Lex->insert_list->push_back($3))
|
||
YYABORT;
|
||
}
|
||
| expr_or_default
|
||
{
|
||
if (Lex->insert_list->push_back($1))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
expr_or_default:
|
||
expr { $$= $1;}
|
||
| DEFAULT {$$= new Item_default_value(Lex->current_context()); }
|
||
;
|
||
|
||
opt_insert_update:
|
||
/* empty */
|
||
| ON DUPLICATE_SYM { Lex->duplicates= DUP_UPDATE; }
|
||
KEY_SYM UPDATE_SYM insert_update_list
|
||
;
|
||
|
||
/* Update rows in a table */
|
||
|
||
update:
|
||
UPDATE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
mysql_init_select(lex);
|
||
lex->sql_command= SQLCOM_UPDATE;
|
||
lex->lock_option= TL_UNLOCK; /* Will be set later */
|
||
lex->duplicates= DUP_ERROR;
|
||
}
|
||
opt_low_priority opt_ignore join_table_list
|
||
SET update_list
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->select_lex.table_list.elements > 1)
|
||
lex->sql_command= SQLCOM_UPDATE_MULTI;
|
||
else if (lex->select_lex.get_table_list()->derived)
|
||
{
|
||
/* it is single table update and it is update of derived table */
|
||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
|
||
lex->select_lex.get_table_list()->alias, "UPDATE");
|
||
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().
|
||
*/
|
||
Select->set_lock_for_tables($3);
|
||
}
|
||
where_clause opt_order_clause delete_limit_clause {}
|
||
;
|
||
|
||
update_list:
|
||
update_list ',' update_elem
|
||
| update_elem;
|
||
|
||
update_elem:
|
||
simple_ident_nospvar equal expr_or_default
|
||
{
|
||
if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
|
||
YYABORT;
|
||
};
|
||
|
||
insert_update_list:
|
||
insert_update_list ',' insert_update_elem
|
||
| insert_update_elem;
|
||
|
||
insert_update_elem:
|
||
simple_ident_nospvar equal expr_or_default
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->update_list.push_back($1) ||
|
||
lex->value_list.push_back($3))
|
||
YYABORT;
|
||
};
|
||
|
||
opt_low_priority:
|
||
/* empty */ { $$= YYTHD->update_lock_default; }
|
||
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
|
||
|
||
/* Delete rows from a table */
|
||
|
||
delete:
|
||
DELETE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_DELETE;
|
||
mysql_init_select(lex);
|
||
lex->lock_option= lex->thd->update_lock_default;
|
||
lex->ignore= 0;
|
||
lex->select_lex.init_order();
|
||
}
|
||
opt_delete_options single_multi {}
|
||
;
|
||
|
||
single_multi:
|
||
FROM table_ident
|
||
{
|
||
if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
|
||
Lex->lock_option))
|
||
YYABORT;
|
||
}
|
||
where_clause opt_order_clause
|
||
delete_limit_clause {}
|
||
| table_wild_list
|
||
{ mysql_init_multi_delete(Lex); }
|
||
FROM join_table_list where_clause
|
||
{
|
||
if (multi_delete_set_locks_and_link_aux_tables(Lex))
|
||
YYABORT;
|
||
}
|
||
| FROM table_wild_list
|
||
{ mysql_init_multi_delete(Lex); }
|
||
USING join_table_list where_clause
|
||
{
|
||
if (multi_delete_set_locks_and_link_aux_tables(Lex))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
table_wild_list:
|
||
table_wild_one {}
|
||
| table_wild_list ',' table_wild_one {};
|
||
|
||
table_wild_one:
|
||
ident opt_wild opt_table_alias
|
||
{
|
||
if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
|
||
TL_OPTION_UPDATING |
|
||
TL_OPTION_ALIAS, Lex->lock_option))
|
||
YYABORT;
|
||
}
|
||
| ident '.' ident opt_wild opt_table_alias
|
||
{
|
||
if (!Select->add_table_to_list(YYTHD,
|
||
new Table_ident(YYTHD, $1, $3, 0),
|
||
$5,
|
||
TL_OPTION_UPDATING |
|
||
TL_OPTION_ALIAS,
|
||
Lex->lock_option))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
opt_wild:
|
||
/* empty */ {}
|
||
| '.' '*' {};
|
||
|
||
|
||
opt_delete_options:
|
||
/* empty */ {}
|
||
| opt_delete_option opt_delete_options {};
|
||
|
||
opt_delete_option:
|
||
QUICK { Select->options|= OPTION_QUICK; }
|
||
| LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
|
||
| IGNORE_SYM { Lex->ignore= 1; };
|
||
|
||
truncate:
|
||
TRUNCATE_SYM opt_table_sym table_name
|
||
{
|
||
LEX* lex= Lex;
|
||
lex->sql_command= SQLCOM_TRUNCATE;
|
||
lex->select_lex.options= 0;
|
||
lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
|
||
lex->select_lex.init_order();
|
||
}
|
||
;
|
||
|
||
opt_table_sym:
|
||
/* empty */
|
||
| TABLE_SYM;
|
||
|
||
/* Show things */
|
||
|
||
show: SHOW
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->wild=0;
|
||
lex->lock_option= TL_READ;
|
||
mysql_init_select(lex);
|
||
lex->current_select->parsing_place= SELECT_LIST;
|
||
bzero((char*) &lex->create_info,sizeof(lex->create_info));
|
||
}
|
||
show_param
|
||
{}
|
||
;
|
||
|
||
show_param:
|
||
DATABASES wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_DATABASES;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
|
||
YYABORT;
|
||
}
|
||
| opt_full TABLES opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_TABLES;
|
||
lex->select_lex.db= $3;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
|
||
YYABORT;
|
||
}
|
||
| opt_full TRIGGERS_SYM opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_TRIGGERS;
|
||
lex->select_lex.db= $3;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
|
||
YYABORT;
|
||
}
|
||
| EVENTS_SYM opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_EVENTS;
|
||
lex->select_lex.db= $2;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
|
||
YYABORT;
|
||
}
|
||
| TABLE_SYM STATUS_SYM opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
|
||
lex->select_lex.db= $3;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
|
||
YYABORT;
|
||
}
|
||
| OPEN_SYM TABLES opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
|
||
lex->select_lex.db= $3;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
|
||
YYABORT;
|
||
}
|
||
| opt_full PLUGIN_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
WARN_DEPRECATED(yythd, "5.2", "SHOW PLUGIN", "'SHOW PLUGINS'");
|
||
lex->sql_command= SQLCOM_SHOW_PLUGINS;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
|
||
YYABORT;
|
||
}
|
||
| PLUGINS_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_PLUGINS;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_PLUGINS))
|
||
YYABORT;
|
||
}
|
||
| ENGINE_SYM storage_engines
|
||
{ Lex->create_info.db_type= $2; }
|
||
show_engine_param
|
||
| ENGINE_SYM ALL
|
||
{ Lex->create_info.db_type= NULL; }
|
||
show_engine_param
|
||
| opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||
if ($5)
|
||
$4->change_db($5);
|
||
if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
|
||
YYABORT;
|
||
}
|
||
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
|
||
TEXT_STRING_sys AND_SYM MASTER_LOG_POS_SYM EQ ulonglong_num
|
||
AND_SYM MASTER_SERVER_ID_SYM EQ
|
||
ulong_num
|
||
{
|
||
Lex->sql_command = SQLCOM_SHOW_NEW_MASTER;
|
||
Lex->mi.log_file_name = $8.str;
|
||
Lex->mi.pos = $12;
|
||
Lex->mi.server_id = $16;
|
||
}
|
||
| 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_limit_clause_init
|
||
| keys_or_index from_or_in table_ident opt_db where_clause
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_KEYS;
|
||
if ($4)
|
||
$3->change_db($4);
|
||
if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
|
||
YYABORT;
|
||
}
|
||
| COLUMN_SYM TYPES_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SHOW_COLUMN_TYPES;
|
||
}
|
||
| TABLE_SYM TYPES_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
|
||
WARN_DEPRECATED(yythd, "5.2", "SHOW TABLE TYPES", "'SHOW [STORAGE] ENGINES'");
|
||
}
|
||
| opt_storage ENGINES_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_ENGINES))
|
||
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
|
||
{ (void) create_select_for_variable("warning_count"); }
|
||
| COUNT_SYM '(' '*' ')' ERRORS
|
||
{ (void) create_select_for_variable("error_count"); }
|
||
| WARNINGS opt_limit_clause_init
|
||
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
|
||
| ERRORS opt_limit_clause_init
|
||
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
|
||
| opt_var_type STATUS_SYM wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_STATUS;
|
||
lex->option_type= $1;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_STATUS))
|
||
YYABORT;
|
||
}
|
||
| INNOBASE_SYM STATUS_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command = SQLCOM_SHOW_ENGINE_STATUS;
|
||
if (!(lex->create_info.db_type=
|
||
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
|
||
{
|
||
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
|
||
YYABORT;
|
||
}
|
||
WARN_DEPRECATED(yythd, "5.2", "SHOW INNODB STATUS", "'SHOW ENGINE INNODB STATUS'");
|
||
}
|
||
| MUTEX_SYM STATUS_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command = SQLCOM_SHOW_ENGINE_MUTEX;
|
||
if (!(lex->create_info.db_type=
|
||
ha_resolve_by_legacy_type(YYTHD, DB_TYPE_INNODB)))
|
||
{
|
||
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), "InnoDB");
|
||
YYABORT;
|
||
}
|
||
WARN_DEPRECATED(yythd, "5.2", "SHOW MUTEX STATUS", "'SHOW ENGINE INNODB MUTEX'");
|
||
}
|
||
| 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 (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
|
||
YYABORT;
|
||
}
|
||
| charset wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_CHARSETS;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
|
||
YYABORT;
|
||
}
|
||
| COLLATION_SYM wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_COLLATIONS;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_COLLATIONS))
|
||
YYABORT;
|
||
}
|
||
| GRANTS
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SHOW_GRANTS;
|
||
LEX_USER *curr_user;
|
||
if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user))))
|
||
YYABORT;
|
||
bzero(curr_user, sizeof(st_lex_user));
|
||
lex->grant_user= curr_user;
|
||
}
|
||
| GRANTS FOR_SYM user
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SHOW_GRANTS;
|
||
lex->grant_user=$3;
|
||
lex->grant_user->password=null_lex_str;
|
||
}
|
||
| CREATE DATABASE opt_if_not_exists ident
|
||
{
|
||
Lex->sql_command=SQLCOM_SHOW_CREATE_DB;
|
||
Lex->create_info.options=$3;
|
||
Lex->name= $4;
|
||
}
|
||
| CREATE TABLE_SYM table_ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command = SQLCOM_SHOW_CREATE;
|
||
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL,0))
|
||
YYABORT;
|
||
lex->only_view= 0;
|
||
}
|
||
| CREATE VIEW_SYM table_ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command = SQLCOM_SHOW_CREATE;
|
||
if (!lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0))
|
||
YYABORT;
|
||
lex->only_view= 1;
|
||
}
|
||
| MASTER_SYM STATUS_SYM
|
||
{
|
||
Lex->sql_command = SQLCOM_SHOW_MASTER_STAT;
|
||
}
|
||
| SLAVE STATUS_SYM
|
||
{
|
||
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
|
||
}
|
||
| CREATE PROCEDURE 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;
|
||
}
|
||
| PROCEDURE STATUS_SYM wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_STATUS_PROC;
|
||
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
|
||
YYABORT;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
|
||
YYABORT;
|
||
}
|
||
| FUNCTION_SYM STATUS_SYM wild_and_where
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_SHOW_STATUS_FUNC;
|
||
if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
|
||
YYABORT;
|
||
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
|
||
YYABORT;
|
||
}
|
||
| PROCEDURE CODE_SYM sp_name
|
||
{
|
||
#ifdef DBUG_OFF
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
#else
|
||
Lex->sql_command= SQLCOM_SHOW_PROC_CODE;
|
||
Lex->spname= $3;
|
||
#endif
|
||
}
|
||
| FUNCTION_SYM CODE_SYM sp_name
|
||
{
|
||
#ifdef DBUG_OFF
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
#else
|
||
Lex->sql_command= SQLCOM_SHOW_FUNC_CODE;
|
||
Lex->spname= $3;
|
||
#endif
|
||
}
|
||
| CREATE EVENT_SYM sp_name
|
||
{
|
||
Lex->spname= $3;
|
||
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
|
||
}
|
||
;
|
||
|
||
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 */ { $$= 0; }
|
||
| from_or_in ident { $$= $2.str; };
|
||
|
||
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 */
|
||
| LIKE TEXT_STRING_sys
|
||
{ Lex->wild= new (YYTHD->mem_root) String($2.str, $2.length,
|
||
system_charset_info); }
|
||
| WHERE expr
|
||
{
|
||
Select->where= $2;
|
||
if ($2)
|
||
$2->top_level_item();
|
||
}
|
||
;
|
||
|
||
|
||
/* A Oracle compatible synonym for show */
|
||
describe:
|
||
describe_command table_ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->lock_option= TL_READ;
|
||
mysql_init_select(lex);
|
||
lex->current_select->parsing_place= SELECT_LIST;
|
||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||
lex->select_lex.db= 0;
|
||
lex->verbose= 0;
|
||
if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS))
|
||
YYABORT;
|
||
}
|
||
opt_describe_column {}
|
||
| describe_command opt_extended_describe
|
||
{ Lex->describe|= DESCRIBE_NORMAL; }
|
||
select
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->select_lex.options|= SELECT_DESCRIBE;
|
||
}
|
||
;
|
||
|
||
describe_command:
|
||
DESC
|
||
| DESCRIBE;
|
||
|
||
opt_extended_describe:
|
||
/* empty */ {}
|
||
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
|
||
| PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
|
||
;
|
||
|
||
|
||
opt_describe_column:
|
||
/* empty */ {}
|
||
| text_string { Lex->wild= $1; }
|
||
| ident
|
||
{ Lex->wild= new (YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info); };
|
||
|
||
|
||
/* 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:
|
||
flush_options ',' flush_option
|
||
| flush_option;
|
||
|
||
flush_option:
|
||
table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list {}
|
||
| TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
|
||
| 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; }
|
||
| STATUS_SYM { Lex->type|= REFRESH_STATUS; }
|
||
| SLAVE { Lex->type|= REFRESH_SLAVE; }
|
||
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
|
||
| DES_KEY_FILE { Lex->type|= REFRESH_DES_KEY_FILE; }
|
||
| RESOURCES { Lex->type|= REFRESH_USER_RESOURCES; };
|
||
|
||
opt_table_list:
|
||
/* empty */ {;}
|
||
| table_list {;};
|
||
|
||
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; }
|
||
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
|
||
| QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;};
|
||
|
||
purge:
|
||
PURGE
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->type=0;
|
||
} purge_options
|
||
{}
|
||
;
|
||
|
||
purge_options:
|
||
master_or_binary LOGS_SYM purge_option
|
||
;
|
||
|
||
purge_option:
|
||
TO_SYM TEXT_STRING_sys
|
||
{
|
||
Lex->sql_command = SQLCOM_PURGE;
|
||
Lex->to_log = $2.str;
|
||
}
|
||
| BEFORE_SYM expr
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->value_list.empty();
|
||
lex->value_list.push_front($2);
|
||
lex->sql_command= SQLCOM_PURGE_BEFORE;
|
||
}
|
||
;
|
||
|
||
/* kill threads */
|
||
|
||
kill:
|
||
KILL_SYM kill_option expr
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->value_list.empty();
|
||
lex->value_list.push_front($3);
|
||
lex->sql_command= SQLCOM_KILL;
|
||
};
|
||
|
||
kill_option:
|
||
/* empty */ { Lex->type= 0; }
|
||
| CONNECTION_SYM { Lex->type= 0; }
|
||
| QUERY_SYM { Lex->type= ONLY_KILL_QUERY; }
|
||
;
|
||
|
||
/* change database */
|
||
|
||
use: USE_SYM ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command=SQLCOM_CHANGE_DB;
|
||
lex->select_lex.db= $2.str;
|
||
};
|
||
|
||
/* import, export of files */
|
||
|
||
load: LOAD DATA_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
|
||
YYABORT;
|
||
}
|
||
lex->fname_start= lex->ptr;
|
||
}
|
||
load_data
|
||
{}
|
||
|
|
||
LOAD TABLE_SYM table_ident FROM MASTER_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
WARN_DEPRECATED(yythd, "5.2", "LOAD TABLE FROM MASTER",
|
||
"MySQL Administrator (mysqldump, mysql)");
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD TABLE");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
|
||
if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
};
|
||
|
||
load_data:
|
||
load_data_lock opt_local INFILE TEXT_STRING_filesystem
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_LOAD;
|
||
lex->lock_option= $1;
|
||
lex->local_file= $2;
|
||
lex->duplicates= DUP_ERROR;
|
||
lex->ignore= 0;
|
||
if (!(lex->exchange= new sql_exchange($4.str, 0)))
|
||
YYABORT;
|
||
}
|
||
opt_duplicate INTO
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->fname_end= lex->ptr;
|
||
}
|
||
TABLE_SYM table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING,
|
||
lex->lock_option))
|
||
YYABORT;
|
||
lex->field_list.empty();
|
||
lex->update_list.empty();
|
||
lex->value_list.empty();
|
||
}
|
||
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
|
||
opt_load_data_set_spec
|
||
{}
|
||
|
|
||
FROM MASTER_SYM
|
||
{
|
||
Lex->sql_command = SQLCOM_LOAD_MASTER_DATA;
|
||
WARN_DEPRECATED(yythd, "5.2", "LOAD DATA FROM MASTER",
|
||
"mysqldump or future "
|
||
"BACKUP/RESTORE DATABASE facility");
|
||
};
|
||
|
||
opt_local:
|
||
/* empty */ { $$=0;}
|
||
| LOCAL_SYM { $$=1;};
|
||
|
||
load_data_lock:
|
||
/* empty */ { $$= YYTHD->update_lock_default; }
|
||
| CONCURRENT
|
||
{
|
||
#ifdef HAVE_QUERY_CACHE
|
||
/*
|
||
Ignore this option in SP to avoid problem with query cache
|
||
*/
|
||
if (Lex->sphead != 0)
|
||
$$= YYTHD->update_lock_default;
|
||
else
|
||
#endif
|
||
$$= 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_ignore_lines:
|
||
/* empty */
|
||
| IGNORE_SYM NUM LINES
|
||
{
|
||
DBUG_ASSERT(Lex->exchange != 0);
|
||
Lex->exchange->skip_lines= atol($2.str);
|
||
};
|
||
|
||
opt_field_or_var_spec:
|
||
/* empty */ { }
|
||
| '(' fields_or_vars ')' { }
|
||
| '(' ')' { };
|
||
|
||
fields_or_vars:
|
||
fields_or_vars ',' field_or_var
|
||
{ Lex->field_list.push_back($3); }
|
||
| field_or_var
|
||
{ Lex->field_list.push_back($1); }
|
||
;
|
||
|
||
field_or_var:
|
||
simple_ident_nospvar {$$= $1;}
|
||
| '@' ident_or_text
|
||
{ $$= new Item_user_var_as_out_param($2); }
|
||
;
|
||
|
||
opt_load_data_set_spec:
|
||
/* empty */ { }
|
||
| SET insert_update_list { };
|
||
|
||
|
||
/* Common definitions */
|
||
|
||
text_literal:
|
||
TEXT_STRING_literal
|
||
{
|
||
THD *thd= YYTHD;
|
||
$$ = new Item_string($1.str,$1.length,thd->variables.collation_connection);
|
||
}
|
||
| NCHAR_STRING
|
||
{ $$= new Item_string($1.str,$1.length,national_charset_info); }
|
||
| UNDERSCORE_CHARSET TEXT_STRING
|
||
{ $$ = new Item_string($2.str,$2.length,Lex->underscore_charset); }
|
||
| text_literal TEXT_STRING_literal
|
||
{ ((Item_string*) $1)->append($2.str,$2.length); }
|
||
;
|
||
|
||
text_string:
|
||
TEXT_STRING_literal
|
||
{ $$= new (YYTHD->mem_root) String($1.str,$1.length,YYTHD->variables.collation_connection); }
|
||
| HEX_NUM
|
||
{
|
||
Item *tmp= new Item_hex_string($1.str, $1.length);
|
||
/*
|
||
it is OK only emulate fix_fields, because we need only
|
||
value of constant
|
||
*/
|
||
$$= tmp ?
|
||
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
|
||
(String*) 0;
|
||
}
|
||
| BIN_NUM
|
||
{
|
||
Item *tmp= new Item_bin_string($1.str, $1.length);
|
||
/*
|
||
it is OK only emulate fix_fields, because we need only
|
||
value of constant
|
||
*/
|
||
$$= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) :
|
||
(String*) 0;
|
||
}
|
||
;
|
||
|
||
param_marker:
|
||
PARAM_MARKER
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
Item_param *item;
|
||
if (! lex->parsing_options.allows_variable)
|
||
{
|
||
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
|
||
YYABORT;
|
||
}
|
||
item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query));
|
||
if (!($$= item) || lex->param_list.push_back(item))
|
||
{
|
||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
signed_literal:
|
||
literal { $$ = $1; }
|
||
| '+' NUM_literal { $$ = $2; }
|
||
| '-' NUM_literal
|
||
{
|
||
$2->max_length++;
|
||
$$= $2->neg();
|
||
}
|
||
;
|
||
|
||
|
||
literal:
|
||
text_literal { $$ = $1; }
|
||
| NUM_literal { $$ = $1; }
|
||
| NULL_SYM { $$ = new Item_null();
|
||
Lex->next_state=MY_LEX_OPERATOR_OR_IDENT;}
|
||
| FALSE_SYM { $$= new Item_int((char*) "FALSE",0,1); }
|
||
| TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); }
|
||
| HEX_NUM { $$ = new Item_hex_string($1.str, $1.length);}
|
||
| BIN_NUM { $$= new Item_bin_string($1.str, $1.length); }
|
||
| UNDERSCORE_CHARSET HEX_NUM
|
||
{
|
||
Item *tmp= new Item_hex_string($2.str, $2.length);
|
||
/*
|
||
it is OK only emulate fix_fieds, because we need only
|
||
value of constant
|
||
*/
|
||
String *str= tmp ?
|
||
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
|
||
(String*) 0;
|
||
$$= new Item_string(str ? str->ptr() : "",
|
||
str ? str->length() : 0,
|
||
Lex->underscore_charset);
|
||
}
|
||
| UNDERSCORE_CHARSET BIN_NUM
|
||
{
|
||
Item *tmp= new Item_bin_string($2.str, $2.length);
|
||
/*
|
||
it is OK only emulate fix_fieds, because we need only
|
||
value of constant
|
||
*/
|
||
String *str= tmp ?
|
||
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
|
||
(String*) 0;
|
||
$$= new Item_string(str ? str->ptr() : "",
|
||
str ? str->length() : 0,
|
||
Lex->charset);
|
||
}
|
||
| DATE_SYM text_literal { $$ = $2; }
|
||
| TIME_SYM text_literal { $$ = $2; }
|
||
| TIMESTAMP text_literal { $$ = $2; };
|
||
|
||
NUM_literal:
|
||
NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
|
||
| LONG_NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
|
||
| ULONGLONG_NUM { $$ = new Item_uint($1.str, $1.length); }
|
||
| DECIMAL_NUM
|
||
{
|
||
$$= new Item_decimal($1.str, $1.length, YYTHD->charset());
|
||
if (YYTHD->net.report_error)
|
||
{
|
||
YYABORT;
|
||
}
|
||
}
|
||
| FLOAT_NUM
|
||
{
|
||
$$ = new Item_float($1.str, $1.length);
|
||
if (YYTHD->net.report_error)
|
||
{
|
||
YYABORT;
|
||
}
|
||
}
|
||
;
|
||
|
||
/**********************************************************************
|
||
** Creating different items.
|
||
**********************************************************************/
|
||
|
||
insert_ident:
|
||
simple_ident_nospvar { $$=$1; }
|
||
| table_wild { $$=$1; };
|
||
|
||
table_wild:
|
||
ident '.' '*'
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
$$ = new Item_field(Lex->current_context(), NullS, $1.str, "*");
|
||
sel->with_wild++;
|
||
}
|
||
| ident '.' ident '.' '*'
|
||
{
|
||
SELECT_LEX *sel= Select;
|
||
$$ = new Item_field(Lex->current_context(), (YYTHD->client_capabilities &
|
||
CLIENT_NO_SCHEMA ? NullS : $1.str),
|
||
$3.str,"*");
|
||
sel->with_wild++;
|
||
}
|
||
;
|
||
|
||
order_ident:
|
||
expr { $$=$1; };
|
||
|
||
simple_ident:
|
||
ident
|
||
{
|
||
sp_variable_t *spv;
|
||
LEX *lex = Lex;
|
||
sp_pcontext *spc = lex->spcont;
|
||
if (spc && (spv = spc->find_variable(&$1)))
|
||
{
|
||
/* We're compiling a stored procedure and found a variable */
|
||
if (! lex->parsing_options.allows_variable)
|
||
{
|
||
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
|
||
YYABORT;
|
||
}
|
||
|
||
Item_splocal *splocal;
|
||
splocal= new Item_splocal($1, spv->offset, spv->type,
|
||
lex->tok_start_prev -
|
||
lex->sphead->m_tmp_query);
|
||
#ifndef DBUG_OFF
|
||
if (splocal)
|
||
splocal->m_sp= lex->sphead;
|
||
#endif
|
||
$$ = (Item*) splocal;
|
||
lex->safe_to_cache_query=0;
|
||
}
|
||
else
|
||
{
|
||
SELECT_LEX *sel=Select;
|
||
$$= (sel->parsing_place != IN_HAVING ||
|
||
sel->get_in_sum_expr() > 0) ?
|
||
(Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) :
|
||
(Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str);
|
||
}
|
||
}
|
||
| simple_ident_q { $$= $1; }
|
||
;
|
||
|
||
simple_ident_nospvar:
|
||
ident
|
||
{
|
||
SELECT_LEX *sel=Select;
|
||
$$= (sel->parsing_place != IN_HAVING ||
|
||
sel->get_in_sum_expr() > 0) ?
|
||
(Item*) new Item_field(Lex->current_context(), NullS, NullS, $1.str) :
|
||
(Item*) new Item_ref(Lex->current_context(), NullS, NullS, $1.str);
|
||
}
|
||
| simple_ident_q { $$= $1; }
|
||
;
|
||
|
||
simple_ident_q:
|
||
ident '.' ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
|
||
/*
|
||
FIXME This will work ok in simple_ident_nospvar case because
|
||
we can't meet simple_ident_nospvar in trigger now. But it
|
||
should be changed in future.
|
||
*/
|
||
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
|
||
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
|
||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
|
||
{
|
||
Item_trigger_field *trg_fld;
|
||
bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
|
||
|
||
if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
|
||
!new_row)
|
||
{
|
||
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "OLD", "on INSERT");
|
||
YYABORT;
|
||
}
|
||
|
||
if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
|
||
new_row)
|
||
{
|
||
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0), "NEW", "on DELETE");
|
||
YYABORT;
|
||
}
|
||
|
||
DBUG_ASSERT(!new_row ||
|
||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
|
||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
|
||
const bool read_only=
|
||
!(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE);
|
||
if (!(trg_fld= new Item_trigger_field(Lex->current_context(),
|
||
new_row ?
|
||
Item_trigger_field::NEW_ROW:
|
||
Item_trigger_field::OLD_ROW,
|
||
$3.str,
|
||
SELECT_ACL,
|
||
read_only)))
|
||
YYABORT;
|
||
|
||
/*
|
||
Let us add this item to list of all Item_trigger_field objects
|
||
in trigger.
|
||
*/
|
||
lex->trg_table_fields.link_in_list((byte *)trg_fld,
|
||
(byte**)&trg_fld->next_trg_field);
|
||
|
||
$$= (Item *)trg_fld;
|
||
}
|
||
else
|
||
{
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if (sel->no_table_names_allowed)
|
||
{
|
||
my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
|
||
MYF(0), $1.str, thd->where);
|
||
}
|
||
$$= (sel->parsing_place != IN_HAVING ||
|
||
sel->get_in_sum_expr() > 0) ?
|
||
(Item*) new Item_field(Lex->current_context(), NullS, $1.str, $3.str) :
|
||
(Item*) new Item_ref(Lex->current_context(), NullS, $1.str, $3.str);
|
||
}
|
||
}
|
||
| '.' ident '.' ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if (sel->no_table_names_allowed)
|
||
{
|
||
my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
|
||
MYF(0), $2.str, thd->where);
|
||
}
|
||
$$= (sel->parsing_place != IN_HAVING ||
|
||
sel->get_in_sum_expr() > 0) ?
|
||
(Item*) new Item_field(Lex->current_context(), NullS, $2.str, $4.str) :
|
||
(Item*) new Item_ref(Lex->current_context(), NullS, $2.str, $4.str);
|
||
}
|
||
| ident '.' ident '.' ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
SELECT_LEX *sel= lex->current_select;
|
||
if (sel->no_table_names_allowed)
|
||
{
|
||
my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
|
||
MYF(0), $3.str, thd->where);
|
||
}
|
||
$$= (sel->parsing_place != IN_HAVING ||
|
||
sel->get_in_sum_expr() > 0) ?
|
||
(Item*) new Item_field(Lex->current_context(),
|
||
(YYTHD->client_capabilities &
|
||
CLIENT_NO_SCHEMA ? NullS : $1.str),
|
||
$3.str, $5.str) :
|
||
(Item*) new Item_ref(Lex->current_context(),
|
||
(YYTHD->client_capabilities &
|
||
CLIENT_NO_SCHEMA ? NullS : $1.str),
|
||
$3.str, $5.str);
|
||
};
|
||
|
||
|
||
field_ident:
|
||
ident { $$=$1;}
|
||
| ident '.' ident '.' ident
|
||
{
|
||
TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
|
||
if (my_strcasecmp(table_alias_charset, $1.str, table->db))
|
||
{
|
||
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
if (my_strcasecmp(table_alias_charset, $3.str,
|
||
table->table_name))
|
||
{
|
||
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str);
|
||
YYABORT;
|
||
}
|
||
$$=$5;
|
||
}
|
||
| ident '.' ident
|
||
{
|
||
TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
|
||
if (my_strcasecmp(table_alias_charset, $1.str, table->alias))
|
||
{
|
||
my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str);
|
||
YYABORT;
|
||
}
|
||
$$=$3;
|
||
}
|
||
| '.' ident { $$=$2;} /* For Delphi */;
|
||
|
||
table_ident:
|
||
ident { $$=new Table_ident($1); }
|
||
| ident '.' ident { $$=new Table_ident(YYTHD, $1,$3,0);}
|
||
| '.' ident { $$=new Table_ident($2);} /* For Delphi */
|
||
;
|
||
|
||
table_ident_nodb:
|
||
ident { LEX_STRING db={(char*) any_db,3}; $$=new Table_ident(YYTHD, db,$1,0); }
|
||
;
|
||
|
||
IDENT_sys:
|
||
IDENT { $$= $1; }
|
||
| IDENT_QUOTED
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (thd->charset_is_system_charset)
|
||
{
|
||
CHARSET_INFO *cs= system_charset_info;
|
||
int dummy_error;
|
||
uint wlen= cs->cset->well_formed_len(cs, $1.str,
|
||
$1.str+$1.length,
|
||
$1.length, &dummy_error);
|
||
if (wlen < $1.length)
|
||
{
|
||
my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
|
||
cs->csname, $1.str + wlen);
|
||
YYABORT;
|
||
}
|
||
$$= $1;
|
||
}
|
||
else
|
||
thd->convert_string(&$$, system_charset_info,
|
||
$1.str, $1.length, thd->charset());
|
||
}
|
||
;
|
||
|
||
TEXT_STRING_sys:
|
||
TEXT_STRING
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (thd->charset_is_system_charset)
|
||
$$= $1;
|
||
else
|
||
thd->convert_string(&$$, system_charset_info,
|
||
$1.str, $1.length, thd->charset());
|
||
}
|
||
;
|
||
|
||
TEXT_STRING_literal:
|
||
TEXT_STRING
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (thd->charset_is_collation_connection)
|
||
$$= $1;
|
||
else
|
||
thd->convert_string(&$$, thd->variables.collation_connection,
|
||
$1.str, $1.length, thd->charset());
|
||
}
|
||
;
|
||
|
||
|
||
TEXT_STRING_filesystem:
|
||
TEXT_STRING
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (thd->charset_is_character_set_filesystem)
|
||
$$= $1;
|
||
else
|
||
thd->convert_string(&$$, thd->variables.character_set_filesystem,
|
||
$1.str, $1.length, thd->charset());
|
||
}
|
||
;
|
||
|
||
ident:
|
||
IDENT_sys { $$=$1; }
|
||
| READ_ONLY_SYM
|
||
{
|
||
THD *thd= YYTHD;
|
||
$$.str= thd->strmake("read_only",9);
|
||
$$.length= 9;
|
||
}
|
||
| keyword
|
||
{
|
||
THD *thd= YYTHD;
|
||
$$.str= thd->strmake($1.str, $1.length);
|
||
$$.length= $1.length;
|
||
}
|
||
;
|
||
|
||
label_ident:
|
||
IDENT_sys { $$=$1; }
|
||
| keyword_sp
|
||
{
|
||
THD *thd= YYTHD;
|
||
$$.str= thd->strmake($1.str, $1.length);
|
||
$$.length= $1.length;
|
||
}
|
||
;
|
||
|
||
ident_or_text:
|
||
ident { $$=$1;}
|
||
| TEXT_STRING_sys { $$=$1;}
|
||
| LEX_HOSTNAME { $$=$1;};
|
||
|
||
user:
|
||
ident_or_text
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
|
||
YYABORT;
|
||
$$->user = $1;
|
||
$$->host.str= (char *) "%";
|
||
$$->host.length= 1;
|
||
|
||
if (check_string_length(&$$->user,
|
||
ER(ER_USERNAME), USERNAME_LENGTH))
|
||
YYABORT;
|
||
}
|
||
| ident_or_text '@' ident_or_text
|
||
{
|
||
THD *thd= YYTHD;
|
||
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
|
||
YYABORT;
|
||
$$->user = $1; $$->host=$3;
|
||
|
||
if (check_string_length(&$$->user,
|
||
ER(ER_USERNAME), USERNAME_LENGTH) ||
|
||
check_string_length(&$$->host,
|
||
ER(ER_HOSTNAME), HOSTNAME_LENGTH))
|
||
YYABORT;
|
||
}
|
||
| CURRENT_USER optional_braces
|
||
{
|
||
if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
|
||
YYABORT;
|
||
/*
|
||
empty LEX_USER means current_user and
|
||
will be handled in the get_current_user() function
|
||
later
|
||
*/
|
||
bzero($$, sizeof(LEX_USER));
|
||
};
|
||
|
||
/* Keyword that we allow for identifiers (except SP labels) */
|
||
keyword:
|
||
keyword_sp {}
|
||
| ASCII_SYM {}
|
||
| BACKUP_SYM {}
|
||
| BEGIN_SYM {}
|
||
| BYTE_SYM {}
|
||
| CACHE_SYM {}
|
||
| CHARSET {}
|
||
| CHECKSUM_SYM {}
|
||
| CLOSE_SYM {}
|
||
| COMMENT_SYM {}
|
||
| COMMIT_SYM {}
|
||
| CONTAINS_SYM {}
|
||
| DEALLOCATE_SYM {}
|
||
| DO_SYM {}
|
||
| END {}
|
||
| EXECUTE_SYM {}
|
||
| FLUSH_SYM {}
|
||
| HANDLER_SYM {}
|
||
| HELP_SYM {}
|
||
| HOST_SYM {}
|
||
| INSTALL_SYM {}
|
||
| LANGUAGE_SYM {}
|
||
| NO_SYM {}
|
||
| OPEN_SYM {}
|
||
| OWNER_SYM {}
|
||
| PARSER_SYM {}
|
||
| PARTITION_SYM {}
|
||
| PORT_SYM {}
|
||
| PREPARE_SYM {}
|
||
| REMOVE_SYM {}
|
||
| REPAIR {}
|
||
| RESET_SYM {}
|
||
| RESTORE_SYM {}
|
||
| ROLLBACK_SYM {}
|
||
| SAVEPOINT_SYM {}
|
||
| SECURITY_SYM {}
|
||
| SERVER_SYM {}
|
||
| SIGNED_SYM {}
|
||
| SOCKET_SYM {}
|
||
| SLAVE {}
|
||
| SONAME_SYM {}
|
||
| START_SYM {}
|
||
| STOP_SYM {}
|
||
| TRUNCATE_SYM {}
|
||
| UNICODE_SYM {}
|
||
| UNINSTALL_SYM {}
|
||
| USER {}
|
||
| WRAPPER_SYM {}
|
||
| XA_SYM {}
|
||
| UPGRADE_SYM {}
|
||
;
|
||
|
||
/*
|
||
* Keywords that we allow for labels in SPs.
|
||
* Anything that's the beginning of a statement or characteristics
|
||
* must be in keyword above, otherwise we get (harmful) shift/reduce
|
||
* conflicts.
|
||
*/
|
||
keyword_sp:
|
||
ACTION {}
|
||
| ADDDATE_SYM {}
|
||
| AFTER_SYM {}
|
||
| AGAINST {}
|
||
| AGGREGATE_SYM {}
|
||
| ALGORITHM_SYM {}
|
||
| ANY_SYM {}
|
||
| AT_SYM {}
|
||
| AUTHORS_SYM {}
|
||
| AUTO_INC {}
|
||
| AUTOEXTEND_SIZE_SYM {}
|
||
| AVG_ROW_LENGTH {}
|
||
| AVG_SYM {}
|
||
| BINLOG_SYM {}
|
||
| BIT_SYM {}
|
||
| BOOL_SYM {}
|
||
| BOOLEAN_SYM {}
|
||
| BTREE_SYM {}
|
||
| CASCADED {}
|
||
| CHAIN_SYM {}
|
||
| CHANGED {}
|
||
| CIPHER_SYM {}
|
||
| CLIENT_SYM {}
|
||
| COALESCE {}
|
||
| CODE_SYM {}
|
||
| COLLATION_SYM {}
|
||
| COLUMNS {}
|
||
| COMMITTED_SYM {}
|
||
| COMPACT_SYM {}
|
||
| COMPLETION_SYM {}
|
||
| COMPRESSED_SYM {}
|
||
| CONCURRENT {}
|
||
| CONSISTENT_SYM {}
|
||
| CONTRIBUTORS_SYM {}
|
||
| CUBE_SYM {}
|
||
| DATA_SYM {}
|
||
| DATAFILE_SYM {}
|
||
| DATETIME {}
|
||
| DATE_SYM {}
|
||
| DAY_SYM {}
|
||
| DEFINER_SYM {}
|
||
| DELAY_KEY_WRITE_SYM {}
|
||
| DES_KEY_FILE {}
|
||
| DIRECTORY_SYM {}
|
||
| DISABLE_SYM {}
|
||
| DISCARD {}
|
||
| DISK_SYM {}
|
||
| DUMPFILE {}
|
||
| DUPLICATE_SYM {}
|
||
| DYNAMIC_SYM {}
|
||
| ENDS_SYM {}
|
||
| ENUM {}
|
||
| ENGINE_SYM {}
|
||
| ENGINES_SYM {}
|
||
| ERRORS {}
|
||
| ESCAPE_SYM {}
|
||
| EVENT_SYM {}
|
||
| EVENTS_SYM {}
|
||
| EVERY_SYM {}
|
||
| EXPANSION_SYM {}
|
||
| EXTENDED_SYM {}
|
||
| EXTENT_SIZE_SYM {}
|
||
| FAST_SYM {}
|
||
| FOUND_SYM {}
|
||
| ENABLE_SYM {}
|
||
| FULL {}
|
||
| FILE_SYM {}
|
||
| FIRST_SYM {}
|
||
| FIXED_SYM {}
|
||
| FRAC_SECOND_SYM {}
|
||
| GEOMETRY_SYM {}
|
||
| GEOMETRYCOLLECTION {}
|
||
| GET_FORMAT {}
|
||
| GRANTS {}
|
||
| GLOBAL_SYM {}
|
||
| HASH_SYM {}
|
||
| HOSTS_SYM {}
|
||
| HOUR_SYM {}
|
||
| IDENTIFIED_SYM {}
|
||
| INVOKER_SYM {}
|
||
| IMPORT {}
|
||
| INDEXES {}
|
||
| INITIAL_SIZE_SYM {}
|
||
| ISOLATION {}
|
||
| ISSUER_SYM {}
|
||
| INNOBASE_SYM {}
|
||
| INSERT_METHOD {}
|
||
| KEY_BLOCK_SIZE {}
|
||
| LAST_SYM {}
|
||
| LEAVES {}
|
||
| LESS_SYM {}
|
||
| LEVEL_SYM {}
|
||
| LINESTRING {}
|
||
| LIST_SYM {}
|
||
| LOCAL_SYM {}
|
||
| LOCKS_SYM {}
|
||
| LOGFILE_SYM {}
|
||
| LOGS_SYM {}
|
||
| MAX_ROWS {}
|
||
| MASTER_SYM {}
|
||
| MASTER_HOST_SYM {}
|
||
| MASTER_PORT_SYM {}
|
||
| MASTER_LOG_FILE_SYM {}
|
||
| MASTER_LOG_POS_SYM {}
|
||
| MASTER_USER_SYM {}
|
||
| MASTER_PASSWORD_SYM {}
|
||
| MASTER_SERVER_ID_SYM {}
|
||
| MASTER_CONNECT_RETRY_SYM {}
|
||
| MASTER_SSL_SYM {}
|
||
| MASTER_SSL_CA_SYM {}
|
||
| MASTER_SSL_CAPATH_SYM {}
|
||
| MASTER_SSL_CERT_SYM {}
|
||
| MASTER_SSL_CIPHER_SYM {}
|
||
| MASTER_SSL_KEY_SYM {}
|
||
| MAX_CONNECTIONS_PER_HOUR {}
|
||
| MAX_QUERIES_PER_HOUR {}
|
||
| MAX_SIZE_SYM {}
|
||
| MAX_UPDATES_PER_HOUR {}
|
||
| MAX_USER_CONNECTIONS_SYM {}
|
||
| MAX_VALUE_SYM {}
|
||
| MEDIUM_SYM {}
|
||
| MEMORY_SYM {}
|
||
| MERGE_SYM {}
|
||
| MICROSECOND_SYM {}
|
||
| MIGRATE_SYM {}
|
||
| MINUTE_SYM {}
|
||
| MIN_ROWS {}
|
||
| MODIFY_SYM {}
|
||
| MODE_SYM {}
|
||
| MONTH_SYM {}
|
||
| MULTILINESTRING {}
|
||
| MULTIPOINT {}
|
||
| MULTIPOLYGON {}
|
||
| MUTEX_SYM {}
|
||
| NAME_SYM {}
|
||
| NAMES_SYM {}
|
||
| NATIONAL_SYM {}
|
||
| NCHAR_SYM {}
|
||
| NDBCLUSTER_SYM {}
|
||
| NEXT_SYM {}
|
||
| NEW_SYM {}
|
||
| NO_WAIT_SYM {}
|
||
| NODEGROUP_SYM {}
|
||
| NONE_SYM {}
|
||
| NVARCHAR_SYM {}
|
||
| OFFSET_SYM {}
|
||
| OLD_PASSWORD {}
|
||
| ONE_SHOT_SYM {}
|
||
| ONE_SYM {}
|
||
| PACK_KEYS_SYM {}
|
||
| PARTIAL {}
|
||
| PARTITIONING_SYM {}
|
||
| PARTITIONS_SYM {}
|
||
| PASSWORD {}
|
||
| PHASE_SYM {}
|
||
| PLUGIN_SYM {}
|
||
| PLUGINS_SYM {}
|
||
| POINT_SYM {}
|
||
| POLYGON {}
|
||
| PRESERVE_SYM {}
|
||
| PREV_SYM {}
|
||
| PRIVILEGES {}
|
||
| PROCESS {}
|
||
| PROCESSLIST_SYM {}
|
||
| QUARTER_SYM {}
|
||
| QUERY_SYM {}
|
||
| QUICK {}
|
||
| REBUILD_SYM {}
|
||
| RECOVER_SYM {}
|
||
| REDO_BUFFER_SIZE_SYM {}
|
||
| REDOFILE_SYM {}
|
||
| REDUNDANT_SYM {}
|
||
| RELAY_LOG_FILE_SYM {}
|
||
| RELAY_LOG_POS_SYM {}
|
||
| RELAY_THREAD {}
|
||
| RELOAD {}
|
||
| REORGANIZE_SYM {}
|
||
| REPEATABLE_SYM {}
|
||
| REPLICATION {}
|
||
| RESOURCES {}
|
||
| RESUME_SYM {}
|
||
| RETURNS_SYM {}
|
||
| ROLLUP_SYM {}
|
||
| ROUTINE_SYM {}
|
||
| ROWS_SYM {}
|
||
| ROW_FORMAT_SYM {}
|
||
| ROW_SYM {}
|
||
| RTREE_SYM {}
|
||
| SCHEDULE_SYM {}
|
||
| SECOND_SYM {}
|
||
| SERIAL_SYM {}
|
||
| SERIALIZABLE_SYM {}
|
||
| SESSION_SYM {}
|
||
| SIMPLE_SYM {}
|
||
| SHARE_SYM {}
|
||
| SHUTDOWN {}
|
||
| SNAPSHOT_SYM {}
|
||
| SOUNDS_SYM {}
|
||
| SQL_CACHE_SYM {}
|
||
| SQL_BUFFER_RESULT {}
|
||
| SQL_NO_CACHE_SYM {}
|
||
| SQL_THREAD {}
|
||
| STARTS_SYM {}
|
||
| STATUS_SYM {}
|
||
| STORAGE_SYM {}
|
||
| STRING_SYM {}
|
||
| SUBDATE_SYM {}
|
||
| SUBJECT_SYM {}
|
||
| SUBPARTITION_SYM {}
|
||
| SUBPARTITIONS_SYM {}
|
||
| SUPER_SYM {}
|
||
| SUSPEND_SYM {}
|
||
| TABLES {}
|
||
| TABLESPACE {}
|
||
| TEMPORARY {}
|
||
| TEMPTABLE_SYM {}
|
||
| TEXT_SYM {}
|
||
| THAN_SYM {}
|
||
| TRANSACTION_SYM {}
|
||
| TRIGGERS_SYM {}
|
||
| TIMESTAMP {}
|
||
| TIMESTAMP_ADD {}
|
||
| TIMESTAMP_DIFF {}
|
||
| TIME_SYM {}
|
||
| TYPES_SYM {}
|
||
| TYPE_SYM {}
|
||
| UDF_RETURNS_SYM {}
|
||
| FUNCTION_SYM {}
|
||
| UNCOMMITTED_SYM {}
|
||
| UNDEFINED_SYM {}
|
||
| UNDO_BUFFER_SIZE_SYM {}
|
||
| UNDOFILE_SYM {}
|
||
| UNKNOWN_SYM {}
|
||
| UNTIL_SYM {}
|
||
| USER {}
|
||
| USE_FRM {}
|
||
| VARIABLES {}
|
||
| VIEW_SYM {}
|
||
| VALUE_SYM {}
|
||
| WARNINGS {}
|
||
| WAIT_SYM {}
|
||
| WEEK_SYM {}
|
||
| WORK_SYM {}
|
||
| X509_SYM {}
|
||
| YEAR_SYM {}
|
||
;
|
||
|
||
/* Option functions */
|
||
|
||
set:
|
||
SET opt_option
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_SET_OPTION;
|
||
mysql_init_select(lex);
|
||
lex->option_type=OPT_SESSION;
|
||
lex->var_list.empty();
|
||
lex->one_shot_set= 0;
|
||
}
|
||
option_value_list
|
||
{}
|
||
;
|
||
|
||
opt_option:
|
||
/* empty */ {}
|
||
| OPTION {};
|
||
|
||
option_value_list:
|
||
option_type_value
|
||
| option_value_list ',' option_type_value;
|
||
|
||
option_type_value:
|
||
{
|
||
if (Lex->sphead)
|
||
{
|
||
/*
|
||
If we are in SP we want have own LEX for each assignment.
|
||
This is mostly because it is hard for several sp_instr_set
|
||
and sp_instr_set_trigger instructions share one LEX.
|
||
(Well, it is theoretically possible but adds some extra
|
||
overhead on preparation for execution stage and IMO less
|
||
robust).
|
||
|
||
QQ: May be we should simply prohibit group assignments in SP?
|
||
*/
|
||
LEX *lex;
|
||
Lex->sphead->reset_lex(YYTHD);
|
||
lex= Lex;
|
||
|
||
/* Set new LEX as if we at start of set rule. */
|
||
lex->sql_command= SQLCOM_SET_OPTION;
|
||
mysql_init_select(lex);
|
||
lex->option_type=OPT_SESSION;
|
||
lex->var_list.empty();
|
||
lex->one_shot_set= 0;
|
||
lex->sphead->m_tmp_query= lex->tok_start;
|
||
}
|
||
}
|
||
ext_option_value
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
sp_head *sp= lex->sphead;
|
||
|
||
if (!lex->var_list.is_empty())
|
||
{
|
||
/*
|
||
We have assignment to user or system variable or
|
||
option setting, so we should construct sp_instr_stmt
|
||
for it.
|
||
*/
|
||
LEX_STRING qbuff;
|
||
sp_instr_stmt *i;
|
||
|
||
if (!(i= new sp_instr_stmt(sp->instructions(), lex->spcont,
|
||
lex)))
|
||
YYABORT;
|
||
|
||
/*
|
||
Extract the query statement from the tokenizer. The
|
||
end is either lex->ptr, if there was no lookahead,
|
||
lex->tok_end otherwise.
|
||
*/
|
||
if (yychar == YYEMPTY)
|
||
qbuff.length= lex->ptr - sp->m_tmp_query;
|
||
else
|
||
qbuff.length= lex->tok_end - sp->m_tmp_query;
|
||
|
||
if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
|
||
YYABORT;
|
||
|
||
strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
|
||
qbuff.length);
|
||
qbuff.length+= 4;
|
||
i->m_query= qbuff;
|
||
sp->add_instr(i);
|
||
}
|
||
lex->sphead->restore_lex(YYTHD);
|
||
}
|
||
};
|
||
|
||
option_type:
|
||
option_type2 {}
|
||
| GLOBAL_SYM { $$=OPT_GLOBAL; }
|
||
| LOCAL_SYM { $$=OPT_SESSION; }
|
||
| SESSION_SYM { $$=OPT_SESSION; }
|
||
;
|
||
|
||
option_type2:
|
||
/* empty */ { $$= OPT_DEFAULT; }
|
||
| ONE_SHOT_SYM { Lex->one_shot_set= 1; $$= 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; }
|
||
;
|
||
|
||
ext_option_value:
|
||
sys_option_value
|
||
| option_type2 option_value;
|
||
|
||
sys_option_value:
|
||
option_type internal_variable_name equal set_expr_or_default
|
||
{
|
||
LEX *lex=Lex;
|
||
|
||
if ($2.var == trg_new_row_fake_var)
|
||
{
|
||
/* We are in trigger and assigning value to field of new row */
|
||
Item *it;
|
||
Item_trigger_field *trg_fld;
|
||
sp_instr_set_trigger_field *sp_fld;
|
||
LINT_INIT(sp_fld);
|
||
if ($1)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if ($4)
|
||
it= $4;
|
||
else
|
||
{
|
||
/* QQ: Shouldn't this be field's default value ? */
|
||
it= new Item_null();
|
||
}
|
||
|
||
DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
|
||
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
|
||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
|
||
if (!(trg_fld= new Item_trigger_field(Lex->current_context(),
|
||
Item_trigger_field::NEW_ROW,
|
||
$2.base_name.str,
|
||
UPDATE_ACL, FALSE)) ||
|
||
!(sp_fld= new sp_instr_set_trigger_field(lex->sphead->
|
||
instructions(),
|
||
lex->spcont,
|
||
trg_fld,
|
||
it, lex)))
|
||
YYABORT;
|
||
|
||
/*
|
||
Let us add this item to list of all Item_trigger_field
|
||
objects in trigger.
|
||
*/
|
||
lex->trg_table_fields.link_in_list((byte *)trg_fld,
|
||
(byte **)&trg_fld->next_trg_field);
|
||
|
||
lex->sphead->add_instr(sp_fld);
|
||
}
|
||
else if ($2.var)
|
||
{ /* System variable */
|
||
if ($1)
|
||
lex->option_type= $1;
|
||
lex->var_list.push_back(new set_var(lex->option_type, $2.var,
|
||
&$2.base_name, $4));
|
||
}
|
||
else
|
||
{
|
||
/* An SP local variable */
|
||
sp_pcontext *ctx= lex->spcont;
|
||
sp_variable_t *spv;
|
||
sp_instr_set *sp_set;
|
||
Item *it;
|
||
if ($1)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
|
||
spv= ctx->find_variable(&$2.base_name);
|
||
|
||
if ($4)
|
||
it= $4;
|
||
else if (spv->dflt)
|
||
it= spv->dflt;
|
||
else
|
||
it= new Item_null();
|
||
sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
|
||
spv->offset, it, spv->type, lex, TRUE);
|
||
lex->sphead->add_instr(sp_set);
|
||
}
|
||
}
|
||
| option_type TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->option_type= $1;
|
||
lex->var_list.push_back(new set_var(lex->option_type,
|
||
find_sys_var("tx_isolation"),
|
||
&null_lex_str,
|
||
new Item_int((int32) $5)));
|
||
}
|
||
;
|
||
|
||
option_value:
|
||
'@' ident_or_text equal expr
|
||
{
|
||
Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
|
||
}
|
||
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->var_list.push_back(new set_var($3, $4.var, &$4.base_name, $6));
|
||
}
|
||
| charset old_or_new_charset_name_or_default
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= Lex;
|
||
$2= $2 ? $2: global_system_variables.character_set_client;
|
||
lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2));
|
||
}
|
||
| NAMES_SYM equal expr
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
LEX_STRING names;
|
||
|
||
names.str= (char *)"names";
|
||
names.length= 5;
|
||
if (spc && spc->find_variable(&names))
|
||
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), names.str);
|
||
else
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
|
||
YYABORT;
|
||
}
|
||
| NAMES_SYM charset_name_or_default opt_collate
|
||
{
|
||
LEX *lex= Lex;
|
||
$2= $2 ? $2 : global_system_variables.character_set_client;
|
||
$3= $3 ? $3 : $2;
|
||
if (!my_charset_same($2,$3))
|
||
{
|
||
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
|
||
$3->name, $2->csname);
|
||
YYABORT;
|
||
}
|
||
lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
|
||
}
|
||
| PASSWORD equal text_or_password
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX_USER *user;
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
LEX_STRING pw;
|
||
|
||
pw.str= (char *)"password";
|
||
pw.length= 8;
|
||
if (spc && spc->find_variable(&pw))
|
||
{
|
||
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
|
||
YYABORT;
|
||
}
|
||
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
|
||
YYABORT;
|
||
user->host=null_lex_str;
|
||
user->user.str=thd->security_ctx->priv_user;
|
||
thd->lex->var_list.push_back(new set_var_password(user, $3));
|
||
}
|
||
| PASSWORD FOR_SYM user equal text_or_password
|
||
{
|
||
Lex->var_list.push_back(new set_var_password($3,$5));
|
||
}
|
||
;
|
||
|
||
internal_variable_name:
|
||
ident
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_pcontext *spc= lex->spcont;
|
||
sp_variable_t *spv;
|
||
|
||
/* We have to lookup here since local vars can shadow sysvars */
|
||
if (!spc || !(spv = spc->find_variable(&$1)))
|
||
{
|
||
/* Not an SP local variable */
|
||
sys_var *tmp=find_sys_var($1.str, $1.length);
|
||
if (!tmp)
|
||
YYABORT;
|
||
$$.var= tmp;
|
||
$$.base_name= null_lex_str;
|
||
/*
|
||
If this is time_zone variable we should open time zone
|
||
describing tables
|
||
*/
|
||
if (tmp == &sys_time_zone &&
|
||
lex->add_time_zone_tables_to_query_tables(YYTHD))
|
||
YYABORT;
|
||
else if (spc && tmp == &sys_autocommit)
|
||
{
|
||
/*
|
||
We don't allow setting AUTOCOMMIT from a stored function
|
||
or trigger.
|
||
*/
|
||
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* An SP local variable */
|
||
$$.var= NULL;
|
||
$$.base_name= $1;
|
||
}
|
||
}
|
||
| ident '.' ident
|
||
{
|
||
LEX *lex= Lex;
|
||
if (check_reserved_words(&$1))
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
|
||
(!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
|
||
!my_strcasecmp(system_charset_info, $1.str, "OLD")))
|
||
{
|
||
if ($1.str[0]=='O' || $1.str[0]=='o')
|
||
{
|
||
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "OLD", "");
|
||
YYABORT;
|
||
}
|
||
if (lex->trg_chistics.event == TRG_EVENT_DELETE)
|
||
{
|
||
my_error(ER_TRG_NO_SUCH_ROW_IN_TRG, MYF(0),
|
||
"NEW", "on DELETE");
|
||
YYABORT;
|
||
}
|
||
if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
|
||
{
|
||
my_error(ER_TRG_CANT_CHANGE_ROW, MYF(0), "NEW", "after ");
|
||
YYABORT;
|
||
}
|
||
/* This special combination will denote field of NEW row */
|
||
$$.var= trg_new_row_fake_var;
|
||
$$.base_name= $3;
|
||
}
|
||
else
|
||
{
|
||
sys_var *tmp=find_sys_var($3.str, $3.length);
|
||
if (!tmp)
|
||
YYABORT;
|
||
if (!tmp->is_struct())
|
||
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
|
||
$$.var= tmp;
|
||
$$.base_name= $1;
|
||
}
|
||
}
|
||
| DEFAULT '.' ident
|
||
{
|
||
sys_var *tmp=find_sys_var($3.str, $3.length);
|
||
if (!tmp)
|
||
YYABORT;
|
||
if (!tmp->is_struct())
|
||
my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), $3.str);
|
||
$$.var= tmp;
|
||
$$.base_name.str= (char*) "default";
|
||
$$.base_name.length= 7;
|
||
}
|
||
;
|
||
|
||
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 { $$=$1.str;}
|
||
| PASSWORD '(' TEXT_STRING ')'
|
||
{
|
||
$$= $3.length ? YYTHD->variables.old_passwords ?
|
||
Item_func_old_password::alloc(YYTHD, $3.str) :
|
||
Item_func_password::alloc(YYTHD, $3.str) :
|
||
$3.str;
|
||
}
|
||
| OLD_PASSWORD '(' TEXT_STRING ')'
|
||
{
|
||
$$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) :
|
||
$3.str;
|
||
}
|
||
;
|
||
|
||
|
||
set_expr_or_default:
|
||
expr { $$=$1; }
|
||
| DEFAULT { $$=0; }
|
||
| ON { $$=new Item_string("ON", 2, system_charset_info); }
|
||
| ALL { $$=new Item_string("ALL", 3, system_charset_info); }
|
||
| BINARY { $$=new Item_string("binary", 6, system_charset_info); }
|
||
;
|
||
|
||
|
||
/* Lock function */
|
||
|
||
lock:
|
||
LOCK_SYM table_or_tables
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOCK");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_LOCK_TABLES;
|
||
}
|
||
table_lock_list
|
||
{}
|
||
;
|
||
|
||
table_or_tables:
|
||
TABLE_SYM
|
||
| TABLES;
|
||
|
||
table_lock_list:
|
||
table_lock
|
||
| table_lock_list ',' table_lock;
|
||
|
||
table_lock:
|
||
table_ident opt_table_alias lock_option
|
||
{
|
||
if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
lock_option:
|
||
READ_SYM { $$=TL_READ_NO_INSERT; }
|
||
| WRITE_SYM { $$=YYTHD->update_lock_default; }
|
||
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
|
||
| READ_SYM LOCAL_SYM { $$= TL_READ; }
|
||
;
|
||
|
||
unlock:
|
||
UNLOCK_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "UNLOCK");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_UNLOCK_TABLES;
|
||
}
|
||
table_or_tables
|
||
{}
|
||
;
|
||
|
||
|
||
/*
|
||
** Handler: direct access to ISAM functions
|
||
*/
|
||
|
||
handler:
|
||
HANDLER_SYM table_ident OPEN_SYM opt_table_alias
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_HA_OPEN;
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
|
||
YYABORT;
|
||
}
|
||
| HANDLER_SYM table_ident_nodb CLOSE_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
|
||
YYABORT;
|
||
}
|
||
lex->sql_command = SQLCOM_HA_CLOSE;
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
|
||
YYABORT;
|
||
}
|
||
| HANDLER_SYM table_ident_nodb READ_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_BADSTATEMENT, MYF(0), "HANDLER");
|
||
YYABORT;
|
||
}
|
||
lex->expr_allows_subselect= FALSE;
|
||
lex->sql_command = SQLCOM_HA_READ;
|
||
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
|
||
lex->current_select->select_limit= new Item_int((int32) 1);
|
||
lex->current_select->offset_limit= 0;
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
|
||
YYABORT;
|
||
}
|
||
handler_read_or_scan where_clause opt_limit_clause
|
||
{
|
||
Lex->expr_allows_subselect= TRUE;
|
||
}
|
||
;
|
||
|
||
handler_read_or_scan:
|
||
handler_scan_function { Lex->ident= null_lex_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 (!(lex->insert_list = new List_item))
|
||
YYABORT;
|
||
} '(' values ')' { }
|
||
;
|
||
|
||
handler_rkey_mode:
|
||
EQ { $$=HA_READ_KEY_EXACT; }
|
||
| GE { $$=HA_READ_KEY_OR_NEXT; }
|
||
| LE { $$=HA_READ_KEY_OR_PREV; }
|
||
| GT_SYM { $$=HA_READ_AFTER_KEY; }
|
||
| LT { $$=HA_READ_BEFORE_KEY; }
|
||
;
|
||
|
||
/* GRANT / REVOKE */
|
||
|
||
revoke:
|
||
REVOKE clear_privileges revoke_command
|
||
{}
|
||
;
|
||
|
||
revoke_command:
|
||
grant_privileges ON opt_table grant_ident FROM grant_list
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_REVOKE;
|
||
lex->type= 0;
|
||
}
|
||
|
|
||
grant_privileges ON FUNCTION_SYM grant_ident FROM grant_list
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->columns.elements)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_REVOKE;
|
||
lex->type= TYPE_ENUM_FUNCTION;
|
||
|
||
}
|
||
|
|
||
grant_privileges ON PROCEDURE grant_ident FROM grant_list
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->columns.elements)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_REVOKE;
|
||
lex->type= TYPE_ENUM_PROCEDURE;
|
||
}
|
||
|
|
||
ALL opt_privileges ',' GRANT OPTION FROM grant_list
|
||
{
|
||
Lex->sql_command = SQLCOM_REVOKE_ALL;
|
||
}
|
||
;
|
||
|
||
grant:
|
||
GRANT clear_privileges grant_command
|
||
{}
|
||
;
|
||
|
||
grant_command:
|
||
grant_privileges ON opt_table grant_ident TO_SYM grant_list
|
||
require_clause grant_options
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_GRANT;
|
||
lex->type= 0;
|
||
}
|
||
|
|
||
grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
|
||
require_clause grant_options
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->columns.elements)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_GRANT;
|
||
lex->type= TYPE_ENUM_FUNCTION;
|
||
}
|
||
|
|
||
grant_privileges ON PROCEDURE grant_ident TO_SYM grant_list
|
||
require_clause grant_options
|
||
{
|
||
LEX *lex= Lex;
|
||
if (lex->columns.elements)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
lex->sql_command= SQLCOM_GRANT;
|
||
lex->type= TYPE_ENUM_PROCEDURE;
|
||
}
|
||
;
|
||
|
||
opt_table:
|
||
/* Empty */
|
||
| TABLE_SYM ;
|
||
|
||
grant_privileges:
|
||
object_privilege_list { }
|
||
| ALL opt_privileges
|
||
{
|
||
Lex->all_privileges= 1;
|
||
Lex->grant= GLOBAL_ACLS;
|
||
}
|
||
;
|
||
|
||
opt_privileges:
|
||
/* empty */
|
||
| PRIVILEGES
|
||
;
|
||
|
||
object_privilege_list:
|
||
object_privilege
|
||
| object_privilege_list ',' object_privilege;
|
||
|
||
object_privilege:
|
||
SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {}
|
||
| INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {}
|
||
| UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {}
|
||
| REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list {}
|
||
| DELETE_SYM { Lex->grant |= DELETE_ACL;}
|
||
| USAGE {}
|
||
| INDEX_SYM { Lex->grant |= INDEX_ACL;}
|
||
| ALTER { Lex->grant |= ALTER_ACL;}
|
||
| CREATE { Lex->grant |= CREATE_ACL;}
|
||
| DROP { Lex->grant |= DROP_ACL;}
|
||
| EXECUTE_SYM { Lex->grant |= EXECUTE_ACL;}
|
||
| RELOAD { Lex->grant |= RELOAD_ACL;}
|
||
| SHUTDOWN { Lex->grant |= SHUTDOWN_ACL;}
|
||
| PROCESS { Lex->grant |= PROCESS_ACL;}
|
||
| FILE_SYM { Lex->grant |= FILE_ACL;}
|
||
| GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
||
| SHOW DATABASES { Lex->grant |= SHOW_DB_ACL;}
|
||
| SUPER_SYM { Lex->grant |= SUPER_ACL;}
|
||
| CREATE TEMPORARY TABLES { Lex->grant |= CREATE_TMP_ACL;}
|
||
| LOCK_SYM TABLES { Lex->grant |= LOCK_TABLES_ACL; }
|
||
| REPLICATION SLAVE { Lex->grant |= REPL_SLAVE_ACL; }
|
||
| REPLICATION CLIENT_SYM { Lex->grant |= REPL_CLIENT_ACL; }
|
||
| CREATE VIEW_SYM { Lex->grant |= CREATE_VIEW_ACL; }
|
||
| SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; }
|
||
| CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
|
||
| ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
|
||
| CREATE USER { Lex->grant |= CREATE_USER_ACL; }
|
||
| EVENT_SYM { Lex->grant |= EVENT_ACL;}
|
||
| TRIGGER_SYM { Lex->grant |= TRIGGER_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->x509_subject)
|
||
{
|
||
my_error(ER_DUP_ARGUMENT, MYF(0), "SUBJECT");
|
||
YYABORT;
|
||
}
|
||
lex->x509_subject=$2.str;
|
||
}
|
||
| ISSUER_SYM TEXT_STRING
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->x509_issuer)
|
||
{
|
||
my_error(ER_DUP_ARGUMENT, MYF(0), "ISSUER");
|
||
YYABORT;
|
||
}
|
||
lex->x509_issuer=$2.str;
|
||
}
|
||
| CIPHER_SYM TEXT_STRING
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->ssl_cipher)
|
||
{
|
||
my_error(ER_DUP_ARGUMENT, MYF(0), "CIPHER");
|
||
YYABORT;
|
||
}
|
||
lex->ssl_cipher=$2.str;
|
||
}
|
||
;
|
||
|
||
grant_ident:
|
||
'*'
|
||
{
|
||
LEX *lex= Lex;
|
||
THD *thd= lex->thd;
|
||
uint dummy;
|
||
if (thd->copy_db_to(&lex->current_select->db, &dummy))
|
||
YYABORT;
|
||
if (lex->grant == GLOBAL_ACLS)
|
||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||
else if (lex->columns.elements)
|
||
{
|
||
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
|
||
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
| ident '.' '*'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->current_select->db = $1.str;
|
||
if (lex->grant == GLOBAL_ACLS)
|
||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||
else if (lex->columns.elements)
|
||
{
|
||
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
|
||
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
| '*' '.' '*'
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->current_select->db = NULL;
|
||
if (lex->grant == GLOBAL_ACLS)
|
||
lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
|
||
else if (lex->columns.elements)
|
||
{
|
||
my_message(ER_ILLEGAL_GRANT_FOR_TABLE,
|
||
ER(ER_ILLEGAL_GRANT_FOR_TABLE), MYF(0));
|
||
YYABORT;
|
||
}
|
||
}
|
||
| table_ident
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,0))
|
||
YYABORT;
|
||
if (lex->grant == GLOBAL_ACLS)
|
||
lex->grant = TABLE_ACLS & ~GRANT_ACL;
|
||
}
|
||
;
|
||
|
||
|
||
user_list:
|
||
user { if (Lex->users_list.push_back($1)) YYABORT;}
|
||
| user_list ',' user
|
||
{
|
||
if (Lex->users_list.push_back($3))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
|
||
grant_list:
|
||
grant_user { if (Lex->users_list.push_back($1)) YYABORT;}
|
||
| grant_list ',' grant_user
|
||
{
|
||
if (Lex->users_list.push_back($3))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
|
||
grant_user:
|
||
user IDENTIFIED_SYM BY TEXT_STRING
|
||
{
|
||
$$=$1; $1->password=$4;
|
||
if ($4.length)
|
||
{
|
||
if (YYTHD->variables.old_passwords)
|
||
{
|
||
char *buff=
|
||
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
|
||
if (buff)
|
||
make_scrambled_password_323(buff, $4.str);
|
||
$1->password.str= buff;
|
||
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
|
||
}
|
||
else
|
||
{
|
||
char *buff=
|
||
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
|
||
if (buff)
|
||
make_scrambled_password(buff, $4.str);
|
||
$1->password.str= buff;
|
||
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
|
||
}
|
||
}
|
||
}
|
||
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
|
||
{ $$= $1; $1->password= $5; }
|
||
| user
|
||
{ $$= $1; $1->password= null_lex_str; }
|
||
;
|
||
|
||
|
||
opt_column_list:
|
||
/* empty */
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->grant |= lex->which_columns;
|
||
}
|
||
| '(' column_list ')';
|
||
|
||
column_list:
|
||
column_list ',' column_list_id
|
||
| column_list_id;
|
||
|
||
column_list_id:
|
||
ident
|
||
{
|
||
String *new_str = new (YYTHD->mem_root) String((const char*) $1.str,$1.length,system_charset_info);
|
||
List_iterator <LEX_COLUMN> iter(Lex->columns);
|
||
class LEX_COLUMN *point;
|
||
LEX *lex=Lex;
|
||
while ((point=iter++))
|
||
{
|
||
if (!my_strcasecmp(system_charset_info,
|
||
point->column.ptr(), new_str->ptr()))
|
||
break;
|
||
}
|
||
lex->grant_tot_col|= lex->which_columns;
|
||
if (point)
|
||
point->rights |= lex->which_columns;
|
||
else
|
||
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
|
||
}
|
||
;
|
||
|
||
|
||
require_clause: /* empty */
|
||
| REQUIRE_SYM require_list
|
||
{
|
||
Lex->ssl_type=SSL_TYPE_SPECIFIED;
|
||
}
|
||
| REQUIRE_SYM SSL_SYM
|
||
{
|
||
Lex->ssl_type=SSL_TYPE_ANY;
|
||
}
|
||
| REQUIRE_SYM X509_SYM
|
||
{
|
||
Lex->ssl_type=SSL_TYPE_X509;
|
||
}
|
||
| REQUIRE_SYM NONE_SYM
|
||
{
|
||
Lex->ssl_type=SSL_TYPE_NONE;
|
||
}
|
||
;
|
||
|
||
grant_options:
|
||
/* empty */ {}
|
||
| WITH grant_option_list;
|
||
|
||
grant_option_list:
|
||
grant_option_list grant_option {}
|
||
| grant_option {}
|
||
;
|
||
|
||
grant_option:
|
||
GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
||
| MAX_QUERIES_PER_HOUR ulong_num
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->mqh.questions=$2;
|
||
lex->mqh.specified_limits|= USER_RESOURCES::QUERIES_PER_HOUR;
|
||
}
|
||
| MAX_UPDATES_PER_HOUR ulong_num
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->mqh.updates=$2;
|
||
lex->mqh.specified_limits|= USER_RESOURCES::UPDATES_PER_HOUR;
|
||
}
|
||
| MAX_CONNECTIONS_PER_HOUR ulong_num
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->mqh.conn_per_hour= $2;
|
||
lex->mqh.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR;
|
||
}
|
||
| MAX_USER_CONNECTIONS_SYM ulong_num
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->mqh.user_conn= $2;
|
||
lex->mqh.specified_limits|= USER_RESOURCES::USER_CONNECTIONS;
|
||
}
|
||
;
|
||
|
||
begin:
|
||
BEGIN_SYM
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command = SQLCOM_BEGIN;
|
||
lex->start_transaction_opt= 0;
|
||
}
|
||
opt_work {}
|
||
;
|
||
|
||
opt_work:
|
||
/* empty */ {}
|
||
| WORK_SYM {}
|
||
;
|
||
|
||
opt_chain:
|
||
/* empty */ { $$= (YYTHD->variables.completion_type == 1); }
|
||
| AND_SYM NO_SYM CHAIN_SYM { $$=0; }
|
||
| AND_SYM CHAIN_SYM { $$=1; }
|
||
;
|
||
|
||
opt_release:
|
||
/* empty */ { $$= (YYTHD->variables.completion_type == 2); }
|
||
| RELEASE_SYM { $$=1; }
|
||
| NO_SYM RELEASE_SYM { $$=0; }
|
||
;
|
||
|
||
opt_savepoint:
|
||
/* empty */ {}
|
||
| SAVEPOINT_SYM {}
|
||
;
|
||
|
||
commit:
|
||
COMMIT_SYM opt_work opt_chain opt_release
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_COMMIT;
|
||
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;
|
||
lex->tx_chain= $3;
|
||
lex->tx_release= $4;
|
||
}
|
||
| ROLLBACK_SYM opt_work
|
||
TO_SYM opt_savepoint ident
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->sql_command= SQLCOM_ROLLBACK_TO_SAVEPOINT;
|
||
lex->ident= $5;
|
||
}
|
||
;
|
||
|
||
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
|
||
*/
|
||
|
||
|
||
union_clause:
|
||
/* empty */ {}
|
||
| union_list
|
||
;
|
||
|
||
union_list:
|
||
UNION_SYM union_option
|
||
{
|
||
LEX *lex=Lex;
|
||
if (lex->exchange)
|
||
{
|
||
/* Only the last SELECT can have INTO...... */
|
||
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
|
||
YYABORT;
|
||
}
|
||
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
/* This counter shouldn't be incremented for UNION parts */
|
||
Lex->nest_level--;
|
||
if (mysql_new_select(lex, 0))
|
||
YYABORT;
|
||
mysql_init_select(lex);
|
||
lex->current_select->linkage=UNION_TYPE;
|
||
if ($2) /* UNION DISTINCT - remember position */
|
||
lex->current_select->master_unit()->union_distinct=
|
||
lex->current_select;
|
||
}
|
||
select_init
|
||
{
|
||
/*
|
||
Remove from the name resolution context stack the context of the
|
||
last select in the union.
|
||
*/
|
||
Lex->pop_context();
|
||
}
|
||
;
|
||
|
||
union_opt:
|
||
/* Empty */ { $$= 0; }
|
||
| union_list { $$= 1; }
|
||
| union_order_or_limit { $$= 1; }
|
||
;
|
||
|
||
union_order_or_limit:
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
|
||
SELECT_LEX *sel= lex->current_select;
|
||
SELECT_LEX_UNIT *unit= sel->master_unit();
|
||
SELECT_LEX *fake= unit->fake_select_lex;
|
||
if (fake)
|
||
{
|
||
unit->global_parameters= fake;
|
||
fake->no_table_names_allowed= 1;
|
||
lex->current_select= fake;
|
||
}
|
||
thd->where= "global ORDER clause";
|
||
}
|
||
order_or_limit
|
||
{
|
||
THD *thd= YYTHD;
|
||
thd->lex->current_select->no_table_names_allowed= 0;
|
||
thd->where= "";
|
||
}
|
||
;
|
||
|
||
order_or_limit:
|
||
order_clause opt_limit_clause_init
|
||
| limit_clause
|
||
;
|
||
|
||
union_option:
|
||
/* empty */ { $$=1; }
|
||
| DISTINCT { $$=1; }
|
||
| ALL { $$=0; }
|
||
;
|
||
|
||
subselect:
|
||
SELECT_SYM subselect_start subselect_init subselect_end
|
||
{
|
||
$$= $3;
|
||
}
|
||
| '(' subselect_start subselect ')'
|
||
{
|
||
LEX *lex= Lex;
|
||
THD *thd= YYTHD;
|
||
/*
|
||
note that a local variable can't be used for
|
||
$3 as it's used in local variable construction
|
||
and some compilers can't guarnatee the order
|
||
in which the local variables are initialized.
|
||
*/
|
||
List_iterator<Item> it($3->item_list);
|
||
Item *item;
|
||
/*
|
||
we must fill the items list for the "derived table".
|
||
*/
|
||
while ((item= it++))
|
||
add_item_to_list(thd, item);
|
||
}
|
||
union_clause subselect_end { $$= $3; };
|
||
|
||
subselect_init:
|
||
select_init2
|
||
{
|
||
$$= Lex->current_select->master_unit()->first_select();
|
||
};
|
||
|
||
subselect_start:
|
||
{
|
||
LEX *lex=Lex;
|
||
if (!lex->expr_allows_subselect)
|
||
{
|
||
yyerror(ER(ER_SYNTAX_ERROR));
|
||
YYABORT;
|
||
}
|
||
/*
|
||
we are making a "derived table" for the parenthesis
|
||
as we need to have a lex level to fit the union
|
||
after the parenthesis, e.g.
|
||
(SELECT .. ) UNION ... becomes
|
||
SELECT * FROM ((SELECT ...) UNION ...)
|
||
*/
|
||
if (mysql_new_select(Lex, 1))
|
||
YYABORT;
|
||
};
|
||
|
||
subselect_end:
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->pop_context();
|
||
SELECT_LEX *child= lex->current_select;
|
||
lex->current_select = lex->current_select->return_after_parsing();
|
||
lex->nest_level--;
|
||
lex->current_select->n_child_sum_items += child->n_sum_items;
|
||
};
|
||
|
||
/**************************************************************************
|
||
|
||
CREATE VIEW | TRIGGER | PROCEDURE statements.
|
||
|
||
**************************************************************************/
|
||
|
||
view_or_trigger_or_sp_or_event:
|
||
definer view_or_trigger_or_sp_or_event_tail
|
||
{}
|
||
| view_replace_or_algorithm definer view_tail
|
||
{}
|
||
;
|
||
|
||
view_or_trigger_or_sp_or_event_tail:
|
||
view_tail
|
||
{}
|
||
| trigger_tail
|
||
{}
|
||
| sp_tail
|
||
{}
|
||
| event_tail
|
||
{}
|
||
;
|
||
|
||
/**************************************************************************
|
||
|
||
DEFINER clause support.
|
||
|
||
**************************************************************************/
|
||
|
||
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).
|
||
*/
|
||
YYTHD->lex->definer= 0;
|
||
}
|
||
| DEFINER_SYM EQ user
|
||
{
|
||
YYTHD->lex->definer= get_current_user(YYTHD, $3);
|
||
}
|
||
;
|
||
|
||
/**************************************************************************
|
||
|
||
CREATE VIEW statement parts.
|
||
|
||
**************************************************************************/
|
||
|
||
view_replace_or_algorithm:
|
||
view_replace
|
||
{}
|
||
| view_replace view_algorithm
|
||
{}
|
||
| view_algorithm
|
||
{}
|
||
;
|
||
|
||
view_replace:
|
||
OR_SYM REPLACE
|
||
{ Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; }
|
||
;
|
||
|
||
view_algorithm:
|
||
ALGORITHM_SYM EQ UNDEFINED_SYM
|
||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
|
||
| ALGORITHM_SYM EQ MERGE_SYM
|
||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_MERGE; }
|
||
| ALGORITHM_SYM EQ TEMPTABLE_SYM
|
||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_TMPTABLE; }
|
||
;
|
||
|
||
view_algorithm_opt:
|
||
/* empty */
|
||
{ Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED; }
|
||
| view_algorithm
|
||
{}
|
||
;
|
||
|
||
view_suid:
|
||
/* empty */
|
||
{ Lex->create_view_suid= VIEW_SUID_DEFAULT; }
|
||
| SQL_SYM SECURITY_SYM DEFINER_SYM
|
||
{ Lex->create_view_suid= VIEW_SUID_DEFINER; }
|
||
| SQL_SYM SECURITY_SYM INVOKER_SYM
|
||
{ Lex->create_view_suid= VIEW_SUID_INVOKER; }
|
||
;
|
||
|
||
view_tail:
|
||
view_suid VIEW_SYM table_ident
|
||
{
|
||
THD *thd= YYTHD;
|
||
LEX *lex= thd->lex;
|
||
lex->sql_command= SQLCOM_CREATE_VIEW;
|
||
/* first table in list is target VIEW name */
|
||
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
|
||
YYABORT;
|
||
}
|
||
view_list_opt AS view_select view_check_option
|
||
{}
|
||
;
|
||
|
||
view_list_opt:
|
||
/* empty */
|
||
{}
|
||
| '(' view_list ')'
|
||
;
|
||
|
||
view_list:
|
||
ident
|
||
{
|
||
Lex->view_list.push_back((LEX_STRING*)
|
||
sql_memdup(&$1, sizeof(LEX_STRING)));
|
||
}
|
||
| view_list ',' ident
|
||
{
|
||
Lex->view_list.push_back((LEX_STRING*)
|
||
sql_memdup(&$3, sizeof(LEX_STRING)));
|
||
}
|
||
;
|
||
|
||
view_select:
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->parsing_options.allows_variable= FALSE;
|
||
lex->parsing_options.allows_select_into= FALSE;
|
||
lex->parsing_options.allows_select_procedure= FALSE;
|
||
lex->parsing_options.allows_derived= FALSE;
|
||
}
|
||
view_select_aux
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->parsing_options.allows_variable= TRUE;
|
||
lex->parsing_options.allows_select_into= TRUE;
|
||
lex->parsing_options.allows_select_procedure= TRUE;
|
||
lex->parsing_options.allows_derived= TRUE;
|
||
}
|
||
;
|
||
|
||
view_select_aux:
|
||
SELECT_SYM remember_name select_init2
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
char *stmt_beg= (lex->sphead ?
|
||
(char *)lex->sphead->m_tmp_query :
|
||
thd->query);
|
||
lex->create_view_select_start= $2 - stmt_beg;
|
||
}
|
||
| '(' remember_name select_paren ')' union_opt
|
||
{
|
||
THD *thd=YYTHD;
|
||
LEX *lex= thd->lex;
|
||
char *stmt_beg= (lex->sphead ?
|
||
(char *)lex->sphead->m_tmp_query :
|
||
thd->query);
|
||
lex->create_view_select_start= $2 - stmt_beg;
|
||
}
|
||
;
|
||
|
||
view_check_option:
|
||
/* empty */
|
||
{ Lex->create_view_check= VIEW_CHECK_NONE; }
|
||
| WITH CHECK_SYM OPTION
|
||
{ Lex->create_view_check= VIEW_CHECK_CASCADED; }
|
||
| WITH CASCADED CHECK_SYM OPTION
|
||
{ Lex->create_view_check= VIEW_CHECK_CASCADED; }
|
||
| WITH LOCAL_SYM CHECK_SYM OPTION
|
||
{ Lex->create_view_check= VIEW_CHECK_LOCAL; }
|
||
;
|
||
|
||
/**************************************************************************
|
||
|
||
CREATE TRIGGER statement parts.
|
||
|
||
**************************************************************************/
|
||
|
||
trigger_tail:
|
||
TRIGGER_SYM remember_name sp_name trg_action_time trg_event
|
||
ON remember_name table_ident FOR_SYM remember_name EACH_SYM ROW_SYM
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
|
||
YYABORT;
|
||
}
|
||
|
||
if (!(sp= new sp_head()))
|
||
YYABORT;
|
||
sp->reset_thd_mem_root(YYTHD);
|
||
sp->init(lex);
|
||
sp->init_sp_name(YYTHD, $3);
|
||
lex->stmt_definition_begin= $2;
|
||
lex->ident.str= $7;
|
||
lex->ident.length= $10 - $7;
|
||
|
||
sp->m_type= TYPE_ENUM_TRIGGER;
|
||
lex->sphead= sp;
|
||
lex->spname= $3;
|
||
/*
|
||
We have to turn of CLIENT_MULTI_QUERIES while parsing a
|
||
stored procedure, otherwise yylex will chop it into pieces
|
||
at each ';'.
|
||
*/
|
||
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
|
||
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
lex->sphead->m_chistics= &lex->sp_chistics;
|
||
lex->sphead->m_body_begin= lex->ptr;
|
||
while (my_isspace(system_charset_info, lex->sphead->m_body_begin[0]))
|
||
++lex->sphead->m_body_begin;
|
||
}
|
||
sp_proc_stmt
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
|
||
lex->sql_command= SQLCOM_CREATE_TRIGGER;
|
||
sp->init_strings(YYTHD, lex);
|
||
/* Restore flag if it was cleared above */
|
||
|
||
YYTHD->client_capabilities |= $<ulong_num>13;
|
||
sp->restore_thd_mem_root(YYTHD);
|
||
|
||
if (sp->is_not_allowed_in_function("trigger"))
|
||
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->select_lex.add_table_to_list(YYTHD, $8,
|
||
(LEX_STRING*) 0,
|
||
TL_OPTION_UPDATING,
|
||
TL_IGNORE))
|
||
YYABORT;
|
||
}
|
||
;
|
||
|
||
/**************************************************************************
|
||
|
||
CREATE FUNCTION | PROCEDURE statements parts.
|
||
|
||
**************************************************************************/
|
||
|
||
sp_tail:
|
||
udf_func_type remember_name FUNCTION_SYM sp_name
|
||
{
|
||
LEX *lex=Lex;
|
||
lex->udf.type= $1;
|
||
lex->stmt_definition_begin= $2;
|
||
lex->spname= $4;
|
||
}
|
||
create_function_tail
|
||
{}
|
||
| PROCEDURE remember_name sp_name
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp;
|
||
|
||
if (lex->sphead)
|
||
{
|
||
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
|
||
YYABORT;
|
||
}
|
||
|
||
lex->stmt_definition_begin= $2;
|
||
|
||
/* Order is important here: new - reset - init */
|
||
sp= new sp_head();
|
||
sp->reset_thd_mem_root(YYTHD);
|
||
sp->init(lex);
|
||
sp->init_sp_name(YYTHD, $3);
|
||
|
||
sp->m_type= TYPE_ENUM_PROCEDURE;
|
||
lex->sphead= sp;
|
||
/*
|
||
* We have to turn of CLIENT_MULTI_QUERIES while parsing a
|
||
* stored procedure, otherwise yylex will chop it into pieces
|
||
* at each ';'.
|
||
*/
|
||
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
|
||
}
|
||
'('
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->m_param_begin= lex->tok_start+1;
|
||
}
|
||
sp_pdparam_list
|
||
')'
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->m_param_end= lex->tok_start;
|
||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||
}
|
||
sp_c_chistics
|
||
{
|
||
LEX *lex= Lex;
|
||
|
||
lex->sphead->m_chistics= &lex->sp_chistics;
|
||
lex->sphead->m_body_begin= lex->tok_start;
|
||
}
|
||
sp_proc_stmt
|
||
{
|
||
LEX *lex= Lex;
|
||
sp_head *sp= lex->sphead;
|
||
|
||
sp->init_strings(YYTHD, lex);
|
||
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
|
||
/*
|
||
Restore flag if it was cleared above
|
||
Be careful with counting. the block where we save the value
|
||
is $4.
|
||
*/
|
||
YYTHD->client_capabilities |= $<ulong_num>4;
|
||
sp->restore_thd_mem_root(YYTHD);
|
||
}
|
||
;
|
||
|
||
/*************************************************************************/
|
||
|
||
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
|
||
{
|
||
Lex->sql_command = SQLCOM_XA_RECOVER;
|
||
}
|
||
;
|
||
|
||
xid: text_string
|
||
{
|
||
YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE);
|
||
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
|
||
YYABORT;
|
||
Lex->xid->set(1L, $1->ptr(), $1->length(), 0, 0);
|
||
}
|
||
| text_string ',' text_string
|
||
{
|
||
YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
|
||
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
|
||
YYABORT;
|
||
Lex->xid->set(1L, $1->ptr(), $1->length(), $3->ptr(), $3->length());
|
||
}
|
||
| text_string ',' text_string ',' ulong_num
|
||
{
|
||
YYERROR_UNLESS($1->length() <= MAXGTRIDSIZE && $3->length() <= MAXBQUALSIZE);
|
||
if (!(Lex->xid=(XID *)YYTHD->alloc(sizeof(XID))))
|
||
YYABORT;
|
||
Lex->xid->set($5, $1->ptr(), $1->length(), $3->ptr(), $3->length());
|
||
}
|
||
;
|
||
|
||
begin_or_start: BEGIN_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 ident SONAME_SYM TEXT_STRING_sys
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_INSTALL_PLUGIN;
|
||
lex->comment= $3;
|
||
lex->ident= $5;
|
||
};
|
||
|
||
uninstall:
|
||
UNINSTALL_SYM PLUGIN_SYM ident
|
||
{
|
||
LEX *lex= Lex;
|
||
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
|
||
lex->comment= $3;
|
||
};
|