6412 lines
139 KiB
Plaintext
6412 lines
139 KiB
Plaintext
%{
|
|
// Copyright 2013 The ql Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSES/QL-LICENSE file.
|
|
|
|
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Initial yacc source generated by ebnf2y[1]
|
|
// at 2013-10-04 23:10:47.861401015 +0200 CEST
|
|
//
|
|
// $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _
|
|
//
|
|
// [1]: http://github.com/cznic/ebnf2y
|
|
|
|
package parser
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pingcap/tidb/mysql"
|
|
"github.com/pingcap/tidb/ast"
|
|
"github.com/pingcap/tidb/model"
|
|
"github.com/pingcap/tidb/parser/opcode"
|
|
"github.com/pingcap/tidb/util/charset"
|
|
"github.com/pingcap/tidb/util/types"
|
|
)
|
|
|
|
%}
|
|
|
|
%union {
|
|
offset int // offset
|
|
item interface{}
|
|
ident string
|
|
}
|
|
|
|
%token <ident>
|
|
/*yy:token "%c" */ identifier "identifier"
|
|
/*yy:token "\"%c\"" */ stringLit "string literal"
|
|
invalid "a special token never used by parser, used by lexer to indicate error"
|
|
hintBegin "hintBegin is a virtual token for optimizer hint grammar"
|
|
hintEnd "hintEnd is a virtual token for optimizer hint grammar"
|
|
andand "&&"
|
|
oror "||"
|
|
|
|
/* the following tokens belong to ReservedKeyword*/
|
|
add "ADD"
|
|
all "ALL"
|
|
alter "ALTER"
|
|
analyze "ANALYZE"
|
|
and "AND"
|
|
as "AS"
|
|
asc "ASC"
|
|
between "BETWEEN"
|
|
bigIntType "BIGINT"
|
|
binaryType "BINARY"
|
|
blobType "BLOB"
|
|
both "BOTH"
|
|
by "BY"
|
|
cascade "CASCADE"
|
|
caseKwd "CASE"
|
|
change "CHANGE"
|
|
character "CHARACTER"
|
|
charType "CHAR"
|
|
check "CHECK"
|
|
collate "COLLATE"
|
|
column "COLUMN"
|
|
constraint "CONSTRAINT"
|
|
convert "CONVERT"
|
|
create "CREATE"
|
|
cross "CROSS"
|
|
currentDate "CURRENT_DATE"
|
|
currentTime "CURRENT_TIME"
|
|
currentTs "CURRENT_TIMESTAMP"
|
|
currentUser "CURRENT_USER"
|
|
database "DATABASE"
|
|
databases "DATABASES"
|
|
dayHour "DAY_HOUR"
|
|
dayMicrosecond "DAY_MICROSECOND"
|
|
dayMinute "DAY_MINUTE"
|
|
daySecond "DAY_SECOND"
|
|
decimalType "DECIMAL"
|
|
defaultKwd "DEFAULT"
|
|
delayed "DELAYED"
|
|
deleteKwd "DELETE"
|
|
desc "DESC"
|
|
describe "DESCRIBE"
|
|
distinct "DISTINCT"
|
|
tidbSMJ "TIDB_SMJ"
|
|
tidbINLJ "TIDB_INLJ"
|
|
div "DIV"
|
|
doubleType "DOUBLE"
|
|
drop "DROP"
|
|
dual "DUAL"
|
|
elseKwd "ELSE"
|
|
enclosed "ENCLOSED"
|
|
escaped "ESCAPED"
|
|
exists "EXISTS"
|
|
explain "EXPLAIN"
|
|
falseKwd "FALSE"
|
|
floatType "FLOAT"
|
|
forKwd "FOR"
|
|
force "FORCE"
|
|
foreign "FOREIGN"
|
|
from "FROM"
|
|
fulltext "FULLTEXT"
|
|
grants "GRANTS"
|
|
group "GROUP"
|
|
having "HAVING"
|
|
highPriority "HIGH_PRIORITY"
|
|
hourMicrosecond "HOUR_MICROSECOND"
|
|
hourMinute "HOUR_MINUTE"
|
|
hourSecond "HOUR_SECOND"
|
|
ifKwd "IF"
|
|
ignore "IGNORE"
|
|
in "IN"
|
|
index "INDEX"
|
|
infile "INFILE"
|
|
inner "INNER"
|
|
integerType "INTEGER"
|
|
interval "INTERVAL"
|
|
into "INTO"
|
|
is "IS"
|
|
insert "INSERT"
|
|
intType "INT"
|
|
join "JOIN"
|
|
key "KEY"
|
|
keys "KEYS"
|
|
leading "LEADING"
|
|
left "LEFT"
|
|
like "LIKE"
|
|
limit "LIMIT"
|
|
lines "LINES"
|
|
load "LOAD"
|
|
localTime "LOCALTIME"
|
|
localTs "LOCALTIMESTAMP"
|
|
lock "LOCK"
|
|
longblobType "LONGBLOB"
|
|
longtextType "LONGTEXT"
|
|
lowPriority "LOW_PRIORITY"
|
|
makeSet "MAKE_SET"
|
|
maxValue "MAXVALUE"
|
|
mediumblobType "MEDIUMBLOB"
|
|
mediumIntType "MEDIUMINT"
|
|
mediumtextType "MEDIUMTEXT"
|
|
mid "MID"
|
|
minuteMicrosecond "MINUTE_MICROSECOND"
|
|
minuteSecond "MINUTE_SECOND"
|
|
mod "MOD"
|
|
not "NOT"
|
|
noWriteToBinLog "NO_WRITE_TO_BINLOG"
|
|
null "NULL"
|
|
numericType "NUMERIC"
|
|
oct "OCT"
|
|
octetLength "OCTET_LENGTH"
|
|
on "ON"
|
|
option "OPTION"
|
|
or "OR"
|
|
ord "ORD"
|
|
order "ORDER"
|
|
outer "OUTER"
|
|
partition "PARTITION"
|
|
partitions "PARTITIONS"
|
|
position "POSITION"
|
|
precisionType "PRECISION"
|
|
primary "PRIMARY"
|
|
procedure "PROCEDURE"
|
|
quote "QUOTE"
|
|
rangeKwd "RANGE"
|
|
read "READ"
|
|
realType "REAL"
|
|
references "REFERENCES"
|
|
regexpKwd "REGEXP"
|
|
rename "RENAME"
|
|
repeat "REPEAT"
|
|
replace "REPLACE"
|
|
restrict "RESTRICT"
|
|
revoke "REVOKE"
|
|
right "RIGHT"
|
|
rlike "RLIKE"
|
|
schema "SCHEMA"
|
|
schemas "SCHEMAS"
|
|
secondMicrosecond "SECOND_MICROSECOND"
|
|
selectKwd "SELECT"
|
|
set "SET"
|
|
show "SHOW"
|
|
smallIntType "SMALLINT"
|
|
starting "STARTING"
|
|
tableKwd "TABLE"
|
|
terminated "TERMINATED"
|
|
then "THEN"
|
|
tinyblobType "TINYBLOB"
|
|
tinyIntType "TINYINT"
|
|
tinytextType "TINYTEXT"
|
|
to "TO"
|
|
trailing "TRAILING"
|
|
trueKwd "TRUE"
|
|
unique "UNIQUE"
|
|
union "UNION"
|
|
unlock "UNLOCK"
|
|
unsigned "UNSIGNED"
|
|
update "UPDATE"
|
|
use "USE"
|
|
using "USING"
|
|
utcDate "UTC_DATE"
|
|
utcTimestamp "UTC_TIMESTAMP"
|
|
values "VALUES"
|
|
varcharType "VARCHAR"
|
|
varbinaryType "VARBINARY"
|
|
when "WHEN"
|
|
where "WHERE"
|
|
write "WRITE"
|
|
with "WITH"
|
|
xor "XOR"
|
|
yearMonth "YEAR_MONTH"
|
|
zerofill "ZEROFILL"
|
|
|
|
/* the following tokens belong to NotKeywordToken*/
|
|
abs "ABS"
|
|
acos "ACOS"
|
|
addDate "ADDDATE"
|
|
addTime "ADDTIME"
|
|
admin "ADMIN"
|
|
aesDecrypt "AES_DECRYPT"
|
|
benchmark "BENCHMARK"
|
|
aesEncrypt "AES_ENCRYPT"
|
|
asin "ASIN"
|
|
atan "ATAN"
|
|
atan2 "ATAN2"
|
|
bin "BIN"
|
|
ceil "CEIL"
|
|
ceiling "CEILING"
|
|
coalesce "COALESCE"
|
|
coercibility "COERCIBILITY"
|
|
concat "CONCAT"
|
|
concatWs "CONCAT_WS"
|
|
connectionID "CONNECTION_ID"
|
|
convertTz "CONVERT_TZ"
|
|
curTime "CUR_TIME"
|
|
cos "COS"
|
|
cot "COT"
|
|
count "COUNT"
|
|
day "DAY"
|
|
datediff "DATEDIFF"
|
|
dateAdd "DATE_ADD"
|
|
dateFormat "DATE_FORMAT"
|
|
dateSub "DATE_SUB"
|
|
dayname "DAYNAME"
|
|
dayofmonth "DAYOFMONTH"
|
|
dayofweek "DAYOFWEEK"
|
|
dayofyear "DAYOFYEAR"
|
|
degrees "DEGREES"
|
|
fromDays "FROM_DAYS"
|
|
events "EVENTS"
|
|
exp "EXP"
|
|
elt "ELT"
|
|
exportSet "EXPORT_SET"
|
|
fieldKwd "FIELD_KWD"
|
|
findInSet "FIND_IN_SET"
|
|
floor "FLOOR"
|
|
format "FORMAT"
|
|
foundRows "FOUND_ROWS"
|
|
fromUnixTime "FROM_UNIXTIME"
|
|
fromBase64 "FROM_BASE64"
|
|
getFormat "GET_FORMAT"
|
|
grant "GRANT"
|
|
groupConcat "GROUP_CONCAT"
|
|
greatest "GREATEST"
|
|
hour "HOUR"
|
|
hex "HEX"
|
|
unhex "UNHEX"
|
|
ifNull "IFNULL"
|
|
insertFunc "INSERT_FUNC"
|
|
instr "INSTR"
|
|
isNull "ISNULL"
|
|
kill "KILL"
|
|
lastInsertID "LAST_INSERT_ID"
|
|
lcase "LCASE"
|
|
length "LENGTH"
|
|
least "LEAST"
|
|
ln "LN"
|
|
loadFile "LOAD_FILE"
|
|
locate "LOCATE"
|
|
log "LOG"
|
|
log2 "LOG2"
|
|
log10 "LOG10"
|
|
lower "LOWER"
|
|
lpad "LPAD"
|
|
ltrim "LTRIM"
|
|
makeDate "MAKEDATE"
|
|
makeTime "MAKETIME"
|
|
max "MAX"
|
|
microsecond "MICROSECOND"
|
|
min "MIN"
|
|
minute "MINUTE"
|
|
nullIf "NULLIF"
|
|
month "MONTH"
|
|
monthname "MONTHNAME"
|
|
now "NOW"
|
|
periodAdd "PERIOD_ADD"
|
|
periodDiff "PERIOD_DIFF"
|
|
pi "PI"
|
|
pow "POW"
|
|
power "POWER"
|
|
process "PROCESS"
|
|
query "QUERY"
|
|
rand "RAND"
|
|
radians "RADIANS"
|
|
rowCount "ROW_COUNT"
|
|
secToTime "SEC_TO_TIME"
|
|
second "SECOND"
|
|
sessionUser "SESSION_USER"
|
|
systemUser "SYSTEM_USER"
|
|
sign "SIGN"
|
|
sin "SIN"
|
|
subTime "SUBTIME"
|
|
sleep "SLEEP"
|
|
sqrt "SQRT"
|
|
calcFoundRows "SQL_CALC_FOUND_ROWS"
|
|
strcmp "STRCMP"
|
|
strToDate "STR_TO_DATE"
|
|
subDate "SUBDATE"
|
|
substring "SUBSTRING"
|
|
substringIndex "SUBSTRING_INDEX"
|
|
sum "SUM"
|
|
sysDate "SYSDATE"
|
|
tan "TAN"
|
|
timediff "TIMEDIFF"
|
|
timeFormat "TIME_FORMAT"
|
|
timeToSec "TIME_TO_SEC"
|
|
timestampAdd "TIMESTAMPADD"
|
|
trim "TRIM"
|
|
rtrim "RTRIM"
|
|
ucase "UCASE"
|
|
unixTimestamp "UNIX_TIMESTAMP"
|
|
upper "UPPER"
|
|
version "VERSION"
|
|
weekday "WEEKDAY"
|
|
weekofyear "WEEKOFYEAR"
|
|
yearweek "YEARWEEK"
|
|
round "ROUND"
|
|
statsPersistent "STATS_PERSISTENT"
|
|
toBase64 "TO_BASE64"
|
|
toDays "TO_DAYS"
|
|
toSeconds "TO_SECONDS"
|
|
getLock "GET_LOCK"
|
|
releaseLock "RELEASE_LOCK"
|
|
rpad "RPAD"
|
|
utcTime "UTC_TIME"
|
|
bitCount "BIT_COUNT"
|
|
bitLength "BIT_LENGTH"
|
|
charFunc "CHAR_FUNC"
|
|
charLength "CHAR_LENGTH"
|
|
characterLength "CHARACTER_LENGTH"
|
|
conv "CONV"
|
|
bitXor "BIT_XOR"
|
|
crc32 "CRC32"
|
|
compress "COMPRESS"
|
|
decode "DECODE"
|
|
desDecrypt "DES_DECRYPT"
|
|
desEncrypt "DES_ENCRYPT"
|
|
encode "ENCODE"
|
|
encrypt "ENCRYPT"
|
|
md5 "MD5"
|
|
oldPassword "OLD_PASSWORD"
|
|
randomBytes "RANDOM_BYTES"
|
|
sha1 "SHA1"
|
|
sha "SHA"
|
|
sha2 "SHA2"
|
|
uncompress "UNCOMPRESS"
|
|
uncompressedLength "UNCOMPRESSED_LENGTH"
|
|
validatePasswordStrength "VALIDATE_PASSWORD_STRENGTH"
|
|
anyValue "ANY_VALUE"
|
|
inetAton "INET_ATON"
|
|
inetNtoa "INET_NTOA"
|
|
inet6Aton "INET6_ATON"
|
|
inet6Ntoa "INET6_NTOA"
|
|
isFreeLock "IS_FREE_LOCK"
|
|
isIPv4 "IS_IPV4"
|
|
isIPv4Compat "IS_IPV4_COMPAT"
|
|
isIPv4Mapped "IS_IPV4_MAPPED"
|
|
isIPv6 "IS_IPV6"
|
|
isUsedLock "IS_USED_LOCK"
|
|
masterPosWait "MASTER_POS_WAIT"
|
|
nameConst "NAME_CONST"
|
|
releaseAllLocks "RELEASE_ALL_LOCKS"
|
|
uuid "UUID"
|
|
uuidShort "UUID_SHORT"
|
|
underscoreCS "UNDERSCORE_CHARSET"
|
|
|
|
/* the following tokens belong to UnReservedKeyword*/
|
|
action "ACTION"
|
|
after "AFTER"
|
|
any "ANY"
|
|
ascii "ASCII"
|
|
at "AT"
|
|
autoIncrement "AUTO_INCREMENT"
|
|
avgRowLength "AVG_ROW_LENGTH"
|
|
avg "AVG"
|
|
begin "BEGIN"
|
|
binlog "BINLOG"
|
|
bitType "BIT"
|
|
booleanType "BOOLEAN"
|
|
boolType "BOOL"
|
|
btree "BTREE"
|
|
byteType "BYTE"
|
|
charsetKwd "CHARSET"
|
|
checksum "CHECKSUM"
|
|
collation "COLLATION"
|
|
columns "COLUMNS"
|
|
comment "COMMENT"
|
|
commit "COMMIT"
|
|
committed "COMMITTED"
|
|
compact "COMPACT"
|
|
compressed "COMPRESSED"
|
|
compression "COMPRESSION"
|
|
connection "CONNECTION"
|
|
consistent "CONSISTENT"
|
|
data "DATA"
|
|
dateType "DATE"
|
|
datetimeType "DATETIME"
|
|
deallocate "DEALLOCATE"
|
|
delayKeyWrite "DELAY_KEY_WRITE"
|
|
disable "DISABLE"
|
|
do "DO"
|
|
duplicate "DUPLICATE"
|
|
dynamic "DYNAMIC"
|
|
enable "ENABLE"
|
|
end "END"
|
|
engine "ENGINE"
|
|
engines "ENGINES"
|
|
escape "ESCAPE"
|
|
execute "EXECUTE"
|
|
fields "FIELDS"
|
|
first "FIRST"
|
|
fixed "FIXED"
|
|
flush "FLUSH"
|
|
full "FULL"
|
|
function "FUNCTION"
|
|
hash "HASH"
|
|
identified "IDENTIFIED"
|
|
isolation "ISOLATION"
|
|
indexes "INDEXES"
|
|
keyBlockSize "KEY_BLOCK_SIZE"
|
|
local "LOCAL"
|
|
less "LESS"
|
|
level "LEVEL"
|
|
mode "MODE"
|
|
modify "MODIFY"
|
|
maxRows "MAX_ROWS"
|
|
minRows "MIN_ROWS"
|
|
names "NAMES"
|
|
national "NATIONAL"
|
|
no "NO"
|
|
none "NONE"
|
|
offset "OFFSET"
|
|
only "ONLY"
|
|
password "PASSWORD"
|
|
prepare "PREPARE"
|
|
privileges "PRIVILEGES"
|
|
processlist "PROCESSLIST"
|
|
quarter "QUARTER"
|
|
quick "QUICK"
|
|
redundant "REDUNDANT"
|
|
repeatable "REPEATABLE"
|
|
reverse "REVERSE"
|
|
rollback "ROLLBACK"
|
|
row "ROW"
|
|
rowFormat "ROW_FORMAT"
|
|
serializable "SERIALIZABLE"
|
|
session "SESSION"
|
|
share "SHARE"
|
|
signed "SIGNED"
|
|
snapshot "SNAPSHOT"
|
|
space "SPACE"
|
|
sqlCache "SQL_CACHE"
|
|
sqlNoCache "SQL_NO_CACHE"
|
|
start "START"
|
|
status "STATUS"
|
|
super "SUPER"
|
|
some "SOME"
|
|
global "GLOBAL"
|
|
tables "TABLES"
|
|
textType "TEXT"
|
|
than "THAN"
|
|
tidb "TIDB"
|
|
timeType "TIME"
|
|
timestampType "TIMESTAMP"
|
|
timestampDiff "TIMESTAMPDIFF"
|
|
transaction "TRANSACTION"
|
|
trigger "TRIGGER"
|
|
triggers "TRIGGERS"
|
|
truncate "TRUNCATE"
|
|
uncommitted "UNCOMMITTED"
|
|
unknown "UNKNOWN"
|
|
user "USER"
|
|
value "VALUE"
|
|
variables "VARIABLES"
|
|
view "VIEW"
|
|
warnings "WARNINGS"
|
|
week "WEEK"
|
|
yearType "YEAR"
|
|
|
|
%token <item>
|
|
|
|
/*yy:token "1.%d" */ floatLit "floating-point literal"
|
|
/*yy:token "1.%d" */ decLit "decimal literal"
|
|
/*yy:token "%d" */ intLit "integer literal"
|
|
/*yy:token "%x" */ hexLit "hexadecimal literal"
|
|
/*yy:token "%b" */ bitLit "bit literal"
|
|
|
|
andnot "&^"
|
|
assignmentEq ":="
|
|
cast "CAST"
|
|
curDate "CURDATE"
|
|
ddl "DDL"
|
|
enum "ENUM"
|
|
eq "="
|
|
extract "EXTRACT"
|
|
|
|
ge ">="
|
|
le "<="
|
|
lsh "<<"
|
|
neq "!="
|
|
neqSynonym "<>"
|
|
nulleq "<=>"
|
|
placeholder "PLACEHOLDER"
|
|
rsh ">>"
|
|
sysVar "SYS_VAR"
|
|
userVar "USER_VAR"
|
|
|
|
%type <item>
|
|
AdminStmt "Check table statement or show ddl statement"
|
|
AlterTableStmt "Alter table statement"
|
|
AlterTableSpec "Alter table specification"
|
|
AlterTableSpecList "Alter table specification list"
|
|
AlterUserStmt "Alter user statement"
|
|
AnalyzeTableStmt "Analyze table statement"
|
|
AnyOrAll "Any or All for subquery"
|
|
Assignment "assignment"
|
|
AssignmentList "assignment list"
|
|
AssignmentListOpt "assignment list opt"
|
|
AuthOption "User auth option"
|
|
AuthString "Password string value"
|
|
BeginTransactionStmt "BEGIN TRANSACTION statement"
|
|
BinlogStmt "Binlog base64 statement"
|
|
CastType "Cast function target type"
|
|
CharsetName "Character set name"
|
|
ColumnDef "table column definition"
|
|
ColumnName "column name"
|
|
ColumnNameList "column name list"
|
|
ColumnNameListOpt "column name list opt"
|
|
ColumnSetValue "insert statement set value by column name"
|
|
ColumnSetValueList "insert statement set value by column name list"
|
|
CommitStmt "COMMIT statement"
|
|
CompareOp "Compare opcode"
|
|
ColumnOption "column definition option"
|
|
ColumnOptionList "column definition option list"
|
|
ColumnOptionListOpt "optional column definition option list"
|
|
Constraint "table constraint"
|
|
ConstraintElem "table constraint element"
|
|
ConstraintKeywordOpt "Constraint Keyword or empty"
|
|
CreateDatabaseStmt "Create Database Statement"
|
|
CreateIndexStmt "CREATE INDEX statement"
|
|
CreateIndexStmtUnique "CREATE INDEX optional UNIQUE clause"
|
|
DatabaseOption "CREATE Database specification"
|
|
DatabaseOptionList "CREATE Database specification list"
|
|
DatabaseOptionListOpt "CREATE Database specification list opt"
|
|
CreateTableStmt "CREATE TABLE statement"
|
|
CreateUserStmt "CREATE User statement"
|
|
DBName "Database Name"
|
|
DeallocateStmt "Deallocate prepared statement"
|
|
DefaultValueExpr "DefaultValueExpr(Now or Signed Literal)"
|
|
DeleteFromStmt "DELETE FROM statement"
|
|
DistinctOpt "Distinct option"
|
|
DoStmt "Do statement"
|
|
DropDatabaseStmt "DROP DATABASE statement"
|
|
DropIndexStmt "DROP INDEX statement"
|
|
DropTableStmt "DROP TABLE statement"
|
|
DropUserStmt "DROP USER"
|
|
DropViewStmt "DROP VIEW statement"
|
|
EmptyStmt "empty statement"
|
|
Enclosed "Enclosed by"
|
|
EqOpt "= or empty"
|
|
EscapedTableRef "escaped table reference"
|
|
Escaped "Escaped by"
|
|
ExecuteStmt "Execute statement"
|
|
ExplainStmt "EXPLAIN statement"
|
|
Expression "expression"
|
|
ExpressionList "expression list"
|
|
ExpressionListOpt "expression list opt"
|
|
ExpressionListList "expression list list"
|
|
ExpressionListListItem "expression list list item"
|
|
Factor "expression factor"
|
|
PredicateExpr "Predicate expression factor"
|
|
Field "field expression"
|
|
Fields "Fields clause"
|
|
FieldsTerminated "Fields terminated by"
|
|
FieldAsName "Field alias name"
|
|
FieldAsNameOpt "Field alias name opt"
|
|
FieldList "field expression list"
|
|
FlushStmt "Flush statement"
|
|
FlushOption "Flush option"
|
|
TableRefsClause "Table references clause"
|
|
Function "function expr"
|
|
FunctionCallAgg "Function call on aggregate data"
|
|
FunctionCallConflict "Function call with reserved keyword as function name"
|
|
FunctionCallKeyword "Function call with keyword as function name"
|
|
FunctionCallNonKeyword "Function call with nonkeyword as function name"
|
|
FuncDatetimePrec "Function datetime precision"
|
|
GlobalScope "The scope of variable"
|
|
GrantStmt "Grant statement"
|
|
GroupByClause "GROUP BY clause"
|
|
HashString "Hashed string"
|
|
HavingClause "HAVING clause"
|
|
IfExists "If Exists"
|
|
IfNotExists "If Not Exists"
|
|
IgnoreOptional "IGNORE or empty"
|
|
IndexColName "Index column name"
|
|
IndexColNameList "List of index column name"
|
|
IndexHint "index hint"
|
|
IndexHintList "index hint list"
|
|
IndexHintListOpt "index hint list opt"
|
|
IndexHintScope "index hint scope"
|
|
IndexHintType "index hint type"
|
|
IndexName "index name"
|
|
IndexNameList "index name list"
|
|
IndexOption "Index Option"
|
|
IndexOptionList "Index Option List or empty"
|
|
IndexType "index type"
|
|
IndexTypeOpt "Optional index type"
|
|
InsertIntoStmt "INSERT INTO statement"
|
|
InsertValues "Rest part of INSERT/REPLACE INTO statement"
|
|
JoinTable "join table"
|
|
JoinType "join type"
|
|
KillStmt "Kill statement"
|
|
KillOrKillTiDB "Kill or Kill TiDB"
|
|
LikeEscapeOpt "like escape option"
|
|
LimitClause "LIMIT clause"
|
|
LimitOption "Limit option could be integer or parameter marker."
|
|
Lines "Lines clause"
|
|
LinesTerminated "Lines terminated by"
|
|
Literal "literal value"
|
|
LoadDataStmt "Load data statement"
|
|
LocalOpt "Local opt"
|
|
LockTablesStmt "Lock tables statement"
|
|
LowPriorityOptional "LOW_PRIORITY or empty"
|
|
NumLiteral "Num/Int/Float/Decimal Literal"
|
|
NoWriteToBinLogAliasOpt "NO_WRITE_TO_BINLOG alias LOCAL or empty"
|
|
NowSymOptionFraction "NowSym with optional fraction part"
|
|
ObjectType "Grant statement object type"
|
|
OnDuplicateKeyUpdate "ON DUPLICATE KEY UPDATE value list"
|
|
Operand "operand"
|
|
OptFull "Full or empty"
|
|
Order "ORDER BY clause optional collation specification"
|
|
OrderBy "ORDER BY clause"
|
|
ByItem "BY item"
|
|
OrderByOptional "Optional ORDER BY clause optional"
|
|
ByList "BY list"
|
|
QuickOptional "QUICK or empty"
|
|
PartitionDefinition "Partition definition"
|
|
PartitionDefinitionList "Partition definition list"
|
|
PartitionDefinitionListOpt "Partition definition list option"
|
|
PartitionOpt "Partition option"
|
|
PartitionNumOpt "PARTITION NUM option"
|
|
PartDefValuesOpt "VALUES {LESS THAN {(expr | value_list) | MAXVALUE} | IN {value_list}"
|
|
PartDefStorageOpt "ENGINE = xxx or empty"
|
|
PasswordOpt "Password option"
|
|
ColumnPosition "Column position [First|After ColumnName]"
|
|
PreparedStmt "PreparedStmt"
|
|
PrepareSQL "Prepare statement sql string"
|
|
PrimaryExpression "primary expression"
|
|
PrimaryFactor "primary expression factor"
|
|
Priority "insert statement priority"
|
|
PrivElem "Privilege element"
|
|
PrivElemList "Privilege element list"
|
|
PrivLevel "Privilege scope"
|
|
PrivType "Privilege type"
|
|
ReferDef "Reference definition"
|
|
OnDeleteOpt "optional ON DELETE clause"
|
|
OnUpdateOpt "optional ON UPDATE clause"
|
|
ReferOpt "reference option"
|
|
RenameTableStmt "rename table statement"
|
|
ReplaceIntoStmt "REPLACE INTO statement"
|
|
ReplacePriority "replace statement priority"
|
|
RevokeStmt "Revoke statement"
|
|
RollbackStmt "ROLLBACK statement"
|
|
RowFormat "Row format option"
|
|
SelectLockOpt "FOR UPDATE or LOCK IN SHARE MODE,"
|
|
SelectStmt "SELECT statement"
|
|
SelectStmtCalcFoundRows "SELECT statement optional SQL_CALC_FOUND_ROWS"
|
|
SelectStmtSQLCache "SELECT statement optional SQL_CAHCE/SQL_NO_CACHE"
|
|
SelectStmtDistinct "SELECT statement optional DISTINCT clause"
|
|
SelectStmtFieldList "SELECT statement field list"
|
|
SelectStmtLimit "SELECT statement optional LIMIT clause"
|
|
SelectStmtOpts "Select statement options"
|
|
SelectStmtGroup "SELECT statement optional GROUP BY clause"
|
|
SetStmt "Set variable statement"
|
|
ShowStmt "Show engines/databases/tables/columns/warnings/status statement"
|
|
ShowTargetFilterable "Show target that can be filtered by WHERE or LIKE"
|
|
ShowDatabaseNameOpt "Show tables/columns statement database name option"
|
|
ShowTableAliasOpt "Show table alias option"
|
|
ShowLikeOrWhereOpt "Show like or where clause option"
|
|
SignedLiteral "Literal or NumLiteral with sign"
|
|
Starting "Starting by"
|
|
Statement "statement"
|
|
StatementList "statement list"
|
|
StatsPersistentVal "stats_persistent value"
|
|
StringName "string literal or identifier"
|
|
StringList "string list"
|
|
ExplainableStmt "explainable statement"
|
|
SubSelect "Sub Select"
|
|
Symbol "Constraint Symbol"
|
|
SystemVariable "System defined variable name"
|
|
TableAsName "table alias name"
|
|
TableAsNameOpt "table alias name optional"
|
|
TableElement "table definition element"
|
|
TableElementList "table definition element list"
|
|
TableFactor "table factor"
|
|
TableLock "Table name and lock type"
|
|
TableLockList "Table lock list"
|
|
TableName "Table name"
|
|
TableNameList "Table name list"
|
|
TableNameListOpt "Table name list opt"
|
|
TableOption "create table option"
|
|
TableOptionList "create table option list"
|
|
TableOptionListOpt "create table option list opt"
|
|
TableRef "table reference"
|
|
TableRefs "table references"
|
|
TrimDirection "Trim string direction"
|
|
TruncateTableStmt "TRANSACTION TABLE statement"
|
|
UnionOpt "Union Option(empty/ALL/DISTINCT)"
|
|
UnionStmt "Union select state ment"
|
|
UnionClauseList "Union select clause list"
|
|
UnionSelect "Union (select) item"
|
|
UnlockTablesStmt "Unlock tables statement"
|
|
UpdateStmt "UPDATE statement"
|
|
Username "Username"
|
|
UsernameList "UsernameList"
|
|
UserSpec "Username and auth option"
|
|
UserSpecList "Username and auth option list"
|
|
UserVariable "User defined variable name"
|
|
UserVariableList "User defined variable name list"
|
|
UseStmt "USE statement"
|
|
VariableAssignment "set variable value"
|
|
VariableAssignmentList "set variable value list"
|
|
Variable "User or system variable"
|
|
WhereClause "WHERE clause"
|
|
WhereClauseOptional "Optional WHERE clause"
|
|
WhenClause "When clause"
|
|
WhenClauseList "When clause list"
|
|
WithReadLockOpt "With Read Lock opt"
|
|
WithGrantOptionOpt "With Grant Option opt"
|
|
ElseOpt "Optional else clause"
|
|
ExpressionOpt "Optional expression"
|
|
Type "Types"
|
|
|
|
BetweenOrNotOp "Between predicate"
|
|
IsOrNotOp "Is predicate"
|
|
InOrNotOp "In predicate"
|
|
LikeOrNotOp "Like predicate"
|
|
RegexpOrNotOp "Regexp predicate"
|
|
|
|
NumericType "Numeric types"
|
|
IntegerType "Integer Types types"
|
|
FixedPointType "Exact value types"
|
|
FloatingPointType "Approximate value types"
|
|
BitValueType "bit value types"
|
|
StringType "String types"
|
|
BlobType "Blob types"
|
|
TextType "Text types"
|
|
DateAndTimeType "Date and Time types"
|
|
|
|
OptFieldLen "Field length or empty"
|
|
FieldLen "Field length"
|
|
FieldOpts "Field type definition option list"
|
|
FieldOpt "Field type definition option"
|
|
FloatOpt "Floating-point type option"
|
|
Precision "Floating-point precision option"
|
|
OptBinary "Optional BINARY"
|
|
OptCharset "Optional Character setting"
|
|
OptCollate "Optional Collate setting"
|
|
NUM "numbers"
|
|
LengthNum "Field length num(uint64)"
|
|
HintTableList "Table list in optimizer hint"
|
|
TableOptimizerHintOpt "Table level optimizer hint"
|
|
TableOptimizerHints "Table level optimizer hints"
|
|
TableOptimizerHintList "Table level optimizer hint list"
|
|
|
|
%type <ident>
|
|
KeyOrIndex "{KEY|INDEX}"
|
|
ColumnKeywordOpt "Column keyword or empty"
|
|
PrimaryOpt "Optional primary keyword"
|
|
NowSym "CURRENT_TIMESTAMP/LOCALTIME/LOCALTIMESTAMP"
|
|
NowSymFunc "CURRENT_TIMESTAMP/LOCALTIME/LOCALTIMESTAMP/NOW"
|
|
DefaultKwdOpt "optional DEFAULT keyword"
|
|
DatabaseSym "DATABASE or SCHEMA"
|
|
ExplainSym "EXPLAIN or DESCRIBE or DESC"
|
|
RegexpSym "REGEXP or RLIKE"
|
|
IntoOpt "INTO or EmptyString"
|
|
ValueSym "Value or Values"
|
|
TimeUnit "Time unit for 'DATE_ADD', 'DATE_SUB', 'ADDDATE', 'SUBDATE', 'EXTRACT'"
|
|
TimestampUnit "Time unit for 'TIMESTAMPADD' and 'TIMESTAMPDIFF'"
|
|
DeallocateSym "Deallocate or drop"
|
|
OuterOpt "optional OUTER clause"
|
|
CrossOpt "Cross join option"
|
|
TransactionChar "Transaction characteristic"
|
|
TransactionChars "Transaction characteristic list"
|
|
IsolationLevel "Isolation level"
|
|
ShowIndexKwd "Show index/indexs/key keyword"
|
|
FromOrIn "From or In"
|
|
OptTable "Optional table keyword"
|
|
OptInteger "Optional Integer keyword"
|
|
NationalOpt "National option"
|
|
CharsetKw "charset or charater set"
|
|
CommaOpt "optional comma"
|
|
LockType "Table locks type"
|
|
logAnd "logical and operator"
|
|
logOr "logical or operator"
|
|
FieldsOrColumns "Fields or columns"
|
|
GetFormatSelector "{DATE|DATETIME|TIME}"
|
|
|
|
%type <ident>
|
|
Identifier "identifier or unreserved keyword"
|
|
IdentifierOrReservedKeyword "Identifier or ReservedKeyword"
|
|
NotKeywordToken "Tokens not mysql keyword but treated specially"
|
|
UnReservedKeyword "MySQL unreserved keywords"
|
|
ReservedKeyword "MySQL reserved keywords"
|
|
FunctionNameConflict "Built-in function call names which are conflict with keywords"
|
|
FunctionNameDateArith "Date arith function call names (date_add or date_sub)"
|
|
FunctionNameDateArithMultiForms "Date arith function call names (adddate or subdate)"
|
|
|
|
%precedence lowestOpt
|
|
%token tableRefPriority
|
|
|
|
%precedence lowerThanCalcFoundRows
|
|
%precedence calcFoundRows
|
|
|
|
%precedence lowerThanSQLCache
|
|
%precedence sqlCache sqlNoCache
|
|
|
|
%precedence lowerThanIntervalKeyword
|
|
%precedence interval
|
|
|
|
%precedence lowerThanSetKeyword
|
|
%precedence set
|
|
|
|
%precedence lowerThanInsertValues
|
|
%precedence insertValues
|
|
|
|
%precedence lowerThanKey
|
|
%precedence key
|
|
|
|
%left join inner cross left right full
|
|
/* A dummy token to force the priority of TableRef production in a join. */
|
|
%left tableRefPriority
|
|
%precedence lowerThanOn
|
|
%precedence on
|
|
%right assignmentEq
|
|
%left oror or
|
|
%left xor
|
|
%left andand and
|
|
%left between
|
|
%precedence lowerThanEq
|
|
%left eq ge le neq neqSynonym '>' '<' is like in
|
|
%left '|'
|
|
%left '&'
|
|
%left rsh lsh
|
|
%left '-' '+'
|
|
%left '*' '/' '%' div mod
|
|
%left '^'
|
|
%left '~' neg
|
|
%right not
|
|
%right collate
|
|
|
|
%precedence lowerThanLeftParen
|
|
%precedence '('
|
|
%precedence lowerThanQuick
|
|
%precedence quick
|
|
%precedence lowerThanEscape
|
|
%precedence escape
|
|
%precedence lowerThanComma
|
|
%precedence ','
|
|
%precedence lowerThanWith
|
|
%precedence with
|
|
%precedence lowerThanInto
|
|
%precedence into
|
|
%precedence lowerThanIf
|
|
%precedence ifKwd
|
|
%precedence lowerThanIgnore
|
|
%precedence ignore
|
|
%precedence tableKwd
|
|
|
|
%start Start
|
|
|
|
%%
|
|
|
|
Start:
|
|
StatementList
|
|
|
|
/**************************************AlterTableStmt***************************************
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
|
|
*******************************************************************************************/
|
|
AlterTableStmt:
|
|
"ALTER" IgnoreOptional "TABLE" TableName AlterTableSpecList
|
|
{
|
|
$$ = &ast.AlterTableStmt{
|
|
Table: $4.(*ast.TableName),
|
|
Specs: $5.([]*ast.AlterTableSpec),
|
|
}
|
|
}
|
|
|
|
AlterTableSpec:
|
|
TableOptionListOpt
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableOption,
|
|
Options:$1.([]*ast.TableOption),
|
|
}
|
|
}
|
|
| "ADD" ColumnKeywordOpt ColumnDef ColumnPosition
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableAddColumn,
|
|
NewColumn: $3.(*ast.ColumnDef),
|
|
Position: $4.(*ast.ColumnPosition),
|
|
}
|
|
}
|
|
| "ADD" Constraint
|
|
{
|
|
constraint := $2.(*ast.Constraint)
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableAddConstraint,
|
|
Constraint: constraint,
|
|
}
|
|
}
|
|
| "DROP" ColumnKeywordOpt ColumnName
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableDropColumn,
|
|
OldColumnName: $3.(*ast.ColumnName),
|
|
}
|
|
}
|
|
| "DROP" "PRIMARY" "KEY"
|
|
{
|
|
$$ = &ast.AlterTableSpec{Tp: ast.AlterTableDropPrimaryKey}
|
|
}
|
|
| "DROP" KeyOrIndex IndexName
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableDropIndex,
|
|
Name: $3.(string),
|
|
}
|
|
}
|
|
| "DROP" "FOREIGN" "KEY" Symbol
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableDropForeignKey,
|
|
Name: $4.(string),
|
|
}
|
|
}
|
|
| "DISABLE" "KEYS"
|
|
{
|
|
$$ = &ast.AlterTableSpec{}
|
|
}
|
|
| "ENABLE" "KEYS"
|
|
{
|
|
$$ = &ast.AlterTableSpec{}
|
|
}
|
|
| "MODIFY" ColumnKeywordOpt ColumnDef ColumnPosition
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableModifyColumn,
|
|
NewColumn: $3.(*ast.ColumnDef),
|
|
Position: $4.(*ast.ColumnPosition),
|
|
}
|
|
}
|
|
| "CHANGE" ColumnKeywordOpt ColumnName ColumnDef
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableChangeColumn,
|
|
OldColumnName: $3.(*ast.ColumnName),
|
|
NewColumn: $4.(*ast.ColumnDef),
|
|
}
|
|
}
|
|
| "ALTER" ColumnKeywordOpt ColumnName "SET" "DEFAULT" SignedLiteral
|
|
{
|
|
option := &ast.ColumnOption{Expr: $6.(ast.ExprNode)}
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableAlterColumn,
|
|
NewColumn: &ast.ColumnDef{
|
|
Name: $3.(*ast.ColumnName),
|
|
Options: []*ast.ColumnOption{option},
|
|
},
|
|
}
|
|
}
|
|
| "ALTER" ColumnKeywordOpt ColumnName "DROP" "DEFAULT"
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableAlterColumn,
|
|
NewColumn: &ast.ColumnDef{
|
|
Name: $3.(*ast.ColumnName),
|
|
},
|
|
}
|
|
}
|
|
| "RENAME" "TO" TableName
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableRenameTable,
|
|
NewTable: $3.(*ast.TableName),
|
|
}
|
|
}
|
|
| "RENAME" "AS" TableName
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableRenameTable,
|
|
NewTable: $3.(*ast.TableName),
|
|
}
|
|
}
|
|
| "LOCK" eq "NONE"
|
|
{
|
|
$$ = &ast.AlterTableSpec{
|
|
Tp: ast.AlterTableLock,
|
|
}
|
|
}
|
|
|
|
|
|
KeyOrIndex: "KEY" | "INDEX"
|
|
|
|
ColumnKeywordOpt:
|
|
{}
|
|
| "COLUMN"
|
|
|
|
ColumnPosition:
|
|
{
|
|
$$ = &ast.ColumnPosition{Tp: ast.ColumnPositionNone}
|
|
}
|
|
| "FIRST"
|
|
{
|
|
$$ = &ast.ColumnPosition{Tp: ast.ColumnPositionFirst}
|
|
}
|
|
| "AFTER" ColumnName
|
|
{
|
|
$$ = &ast.ColumnPosition{
|
|
Tp: ast.ColumnPositionAfter,
|
|
RelativeColumn: $2.(*ast.ColumnName),
|
|
}
|
|
}
|
|
|
|
AlterTableSpecList:
|
|
AlterTableSpec
|
|
{
|
|
$$ = []*ast.AlterTableSpec{$1.(*ast.AlterTableSpec)}
|
|
}
|
|
| AlterTableSpecList ',' AlterTableSpec
|
|
{
|
|
$$ = append($1.([]*ast.AlterTableSpec), $3.(*ast.AlterTableSpec))
|
|
}
|
|
|
|
ConstraintKeywordOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "CONSTRAINT"
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "CONSTRAINT" Symbol
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
Symbol:
|
|
Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
/**************************************RenameTableStmt***************************************
|
|
* See http://dev.mysql.com/doc/refman/5.7/en/rename-table.html
|
|
*******************************************************************************************/
|
|
RenameTableStmt:
|
|
"RENAME" "TABLE" TableName "TO" TableName
|
|
{
|
|
$$ = &ast.RenameTableStmt{
|
|
OldTable: $3.(*ast.TableName),
|
|
NewTable: $5.(*ast.TableName),
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************************/
|
|
|
|
AnalyzeTableStmt:
|
|
"ANALYZE" "TABLE" TableNameList
|
|
{
|
|
$$ = &ast.AnalyzeTableStmt{TableNames: $3.([]*ast.TableName)}
|
|
}
|
|
| "ANALYZE" "TABLE" TableName "INDEX" IndexNameList
|
|
{
|
|
$$ = &ast.AnalyzeTableStmt{TableNames: []*ast.TableName{$3.(*ast.TableName)}, IndexNames: $5.([]model.CIStr)}
|
|
}
|
|
|
|
/*******************************************************************************************/
|
|
Assignment:
|
|
ColumnName eq Expression
|
|
{
|
|
$$ = &ast.Assignment{Column: $1.(*ast.ColumnName), Expr:$3.(ast.ExprNode)}
|
|
}
|
|
|
|
AssignmentList:
|
|
Assignment
|
|
{
|
|
$$ = []*ast.Assignment{$1.(*ast.Assignment)}
|
|
}
|
|
| AssignmentList ',' Assignment
|
|
{
|
|
$$ = append($1.([]*ast.Assignment), $3.(*ast.Assignment))
|
|
}
|
|
|
|
AssignmentListOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []*ast.Assignment{}
|
|
}
|
|
| AssignmentList
|
|
|
|
BeginTransactionStmt:
|
|
"BEGIN"
|
|
{
|
|
$$ = &ast.BeginStmt{}
|
|
}
|
|
| "START" "TRANSACTION"
|
|
{
|
|
$$ = &ast.BeginStmt{}
|
|
}
|
|
| "START" "TRANSACTION" "WITH" "CONSISTENT" "SNAPSHOT"
|
|
{
|
|
$$ = &ast.BeginStmt{}
|
|
}
|
|
|
|
BinlogStmt:
|
|
"BINLOG" stringLit
|
|
{
|
|
$$ = &ast.BinlogStmt{Str: $2}
|
|
}
|
|
|
|
ColumnDef:
|
|
ColumnName Type ColumnOptionListOpt
|
|
{
|
|
$$ = &ast.ColumnDef{Name: $1.(*ast.ColumnName), Tp: $2.(*types.FieldType), Options: $3.([]*ast.ColumnOption)}
|
|
}
|
|
|
|
ColumnName:
|
|
Identifier
|
|
{
|
|
$$ = &ast.ColumnName{Name: model.NewCIStr($1)}
|
|
}
|
|
| Identifier '.' IdentifierOrReservedKeyword
|
|
{
|
|
$$ = &ast.ColumnName{Table: model.NewCIStr($1), Name: model.NewCIStr($3)}
|
|
}
|
|
| Identifier '.' Identifier '.' IdentifierOrReservedKeyword
|
|
{
|
|
$$ = &ast.ColumnName{Schema: model.NewCIStr($1), Table: model.NewCIStr($3), Name: model.NewCIStr($5)}
|
|
}
|
|
|
|
ColumnNameList:
|
|
ColumnName
|
|
{
|
|
$$ = []*ast.ColumnName{$1.(*ast.ColumnName)}
|
|
}
|
|
| ColumnNameList ',' ColumnName
|
|
{
|
|
$$ = append($1.([]*ast.ColumnName), $3.(*ast.ColumnName))
|
|
}
|
|
|
|
ColumnNameListOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []*ast.ColumnName{}
|
|
}
|
|
| ColumnNameList
|
|
{
|
|
$$ = $1.([]*ast.ColumnName)
|
|
}
|
|
|
|
CommitStmt:
|
|
"COMMIT"
|
|
{
|
|
$$ = &ast.CommitStmt{}
|
|
}
|
|
|
|
PrimaryOpt:
|
|
{}
|
|
| "PRIMARY"
|
|
|
|
ColumnOption:
|
|
"NOT" "NULL"
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNotNull}
|
|
}
|
|
| "NULL"
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNull}
|
|
}
|
|
| "AUTO_INCREMENT"
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionAutoIncrement}
|
|
}
|
|
| PrimaryOpt "KEY"
|
|
{
|
|
// KEY is normally a synonym for INDEX. The key attribute PRIMARY KEY
|
|
// can also be specified as just KEY when given in a column definition.
|
|
// See http://dev.mysql.com/doc/refman/5.7/en/create-table.html
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionPrimaryKey}
|
|
}
|
|
| "UNIQUE" %prec lowerThanKey
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}
|
|
}
|
|
| "UNIQUE" "KEY"
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}
|
|
}
|
|
| "DEFAULT" DefaultValueExpr
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionDefaultValue, Expr: $2.(ast.ExprNode)}
|
|
}
|
|
| "ON" "UPDATE" NowSymOptionFraction
|
|
{
|
|
nowFunc := &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionOnUpdate, Expr: nowFunc}
|
|
}
|
|
| "COMMENT" stringLit
|
|
{
|
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr($2)}
|
|
}
|
|
| "CHECK" '(' Expression ')'
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/create-table.html
|
|
// The CHECK clause is parsed but ignored by all storage engines.
|
|
$$ = &ast.ColumnOption{}
|
|
}
|
|
|
|
ColumnOptionList:
|
|
ColumnOption
|
|
{
|
|
$$ = []*ast.ColumnOption{$1.(*ast.ColumnOption)}
|
|
}
|
|
| ColumnOptionList ColumnOption
|
|
{
|
|
$$ = append($1.([]*ast.ColumnOption), $2.(*ast.ColumnOption))
|
|
}
|
|
|
|
ColumnOptionListOpt:
|
|
{
|
|
$$ = []*ast.ColumnOption{}
|
|
}
|
|
| ColumnOptionList
|
|
{
|
|
$$ = $1.([]*ast.ColumnOption)
|
|
}
|
|
|
|
ConstraintElem:
|
|
"PRIMARY" "KEY" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintPrimaryKey,
|
|
Keys: $6.([]*ast.IndexColName),
|
|
}
|
|
if $8 != nil {
|
|
c.Option = $8.(*ast.IndexOption)
|
|
}
|
|
if $4 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $4.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "FULLTEXT" "KEY" IndexName '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintFulltext,
|
|
Keys: $5.([]*ast.IndexColName),
|
|
Name: $3.(string),
|
|
}
|
|
if $7 != nil {
|
|
c.Option = $7.(*ast.IndexOption)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "INDEX" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintIndex,
|
|
Keys: $5.([]*ast.IndexColName),
|
|
Name: $2.(string),
|
|
}
|
|
if $7 != nil {
|
|
c.Option = $7.(*ast.IndexOption)
|
|
}
|
|
if $3 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $3.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "KEY" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintKey,
|
|
Keys: $5.([]*ast.IndexColName),
|
|
Name: $2.(string),
|
|
}
|
|
if $7 != nil {
|
|
c.Option = $7.(*ast.IndexOption)
|
|
}
|
|
if $3 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $3.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "UNIQUE" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintUniq,
|
|
Keys: $5.([]*ast.IndexColName),
|
|
Name: $2.(string),
|
|
}
|
|
if $7 != nil {
|
|
c.Option = $7.(*ast.IndexOption)
|
|
}
|
|
if $3 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $3.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "UNIQUE" "INDEX" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintUniqIndex,
|
|
Keys: $6.([]*ast.IndexColName),
|
|
Name: $3.(string),
|
|
}
|
|
if $8 != nil {
|
|
c.Option = $8.(*ast.IndexOption)
|
|
}
|
|
if $4 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $4.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "UNIQUE" "KEY" IndexName IndexTypeOpt '(' IndexColNameList ')' IndexOptionList
|
|
{
|
|
c := &ast.Constraint{
|
|
Tp: ast.ConstraintUniqKey,
|
|
Keys: $6.([]*ast.IndexColName),
|
|
Name: $3.(string),
|
|
}
|
|
if $8 != nil {
|
|
c.Option = $8.(*ast.IndexOption)
|
|
}
|
|
if $4 != nil {
|
|
if c.Option == nil {
|
|
c.Option = &ast.IndexOption{}
|
|
}
|
|
c.Option.Tp = $4.(model.IndexType)
|
|
}
|
|
$$ = c
|
|
}
|
|
| "FOREIGN" "KEY" IndexName '(' IndexColNameList ')' ReferDef
|
|
{
|
|
$$ = &ast.Constraint{
|
|
Tp: ast.ConstraintForeignKey,
|
|
Keys: $5.([]*ast.IndexColName),
|
|
Name: $3.(string),
|
|
Refer: $7.(*ast.ReferenceDef),
|
|
}
|
|
}
|
|
|
|
ReferDef:
|
|
"REFERENCES" TableName '(' IndexColNameList ')' OnDeleteOpt OnUpdateOpt
|
|
{
|
|
var onDeleteOpt *ast.OnDeleteOpt
|
|
if $6 != nil {
|
|
onDeleteOpt = $6.(*ast.OnDeleteOpt)
|
|
}
|
|
var onUpdateOpt *ast.OnUpdateOpt
|
|
if $7 != nil {
|
|
onUpdateOpt = $7.(*ast.OnUpdateOpt)
|
|
}
|
|
$$ = &ast.ReferenceDef{
|
|
Table: $2.(*ast.TableName),
|
|
IndexColNames: $4.([]*ast.IndexColName),
|
|
OnDelete: onDeleteOpt,
|
|
OnUpdate: onUpdateOpt,
|
|
}
|
|
}
|
|
|
|
OnDeleteOpt:
|
|
{
|
|
$$ = &ast.OnDeleteOpt{}
|
|
} %prec lowerThanOn
|
|
| "ON" "DELETE" ReferOpt
|
|
{
|
|
$$ = &ast.OnDeleteOpt{ReferOpt: $3.(ast.ReferOptionType)}
|
|
}
|
|
|
|
OnUpdateOpt:
|
|
{
|
|
$$ = &ast.OnUpdateOpt{}
|
|
} %prec lowerThanOn
|
|
| "ON" "UPDATE" ReferOpt
|
|
{
|
|
$$ = &ast.OnUpdateOpt{ReferOpt: $3.(ast.ReferOptionType)}
|
|
}
|
|
|
|
ReferOpt:
|
|
"RESTRICT"
|
|
{
|
|
$$ = ast.ReferOptionRestrict
|
|
}
|
|
| "CASCADE"
|
|
{
|
|
$$ = ast.ReferOptionCascade
|
|
}
|
|
| "SET" "NULL"
|
|
{
|
|
$$ = ast.ReferOptionSetNull
|
|
}
|
|
| "NO" "ACTION"
|
|
{
|
|
$$ = ast.ReferOptionNoAction
|
|
}
|
|
|
|
/*
|
|
* The DEFAULT clause specifies a default value for a column.
|
|
* With one exception, the default value must be a constant;
|
|
* it cannot be a function or an expression. This means, for example,
|
|
* that you cannot set the default for a date column to be the value of
|
|
* a function such as NOW() or CURRENT_DATE. The exception is that you
|
|
* can specify CURRENT_TIMESTAMP as the default for a TIMESTAMP or DATETIME column.
|
|
*
|
|
* See http://dev.mysql.com/doc/refman/5.7/en/create-table.html
|
|
* https://github.com/mysql/mysql-server/blob/5.7/sql/sql_yacc.yy#L6832
|
|
*/
|
|
DefaultValueExpr:
|
|
NowSymOptionFraction | SignedLiteral
|
|
|
|
NowSymOptionFraction:
|
|
NowSym
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
|
}
|
|
| NowSymFunc '(' ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
|
}
|
|
| NowSymFunc '(' NUM ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
|
}
|
|
|
|
/*
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_localtime
|
|
* TODO: Process other three keywords
|
|
*/
|
|
NowSymFunc:
|
|
"CURRENT_TIMESTAMP" | "LOCALTIME" | "LOCALTIMESTAMP" | "NOW"
|
|
NowSym:
|
|
"CURRENT_TIMESTAMP" | "LOCALTIME" | "LOCALTIMESTAMP"
|
|
|
|
|
|
SignedLiteral:
|
|
Literal
|
|
{
|
|
$$ = ast.NewValueExpr($1)
|
|
}
|
|
| '+' NumLiteral
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr($2)}
|
|
}
|
|
| '-' NumLiteral
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr($2)}
|
|
}
|
|
|
|
// TODO: support decimal literal
|
|
NumLiteral:
|
|
intLit
|
|
| floatLit
|
|
| decLit
|
|
|
|
|
|
CreateIndexStmt:
|
|
"CREATE" CreateIndexStmtUnique "INDEX" Identifier "ON" TableName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &ast.CreateIndexStmt{
|
|
Unique: $2.(bool),
|
|
IndexName: $4,
|
|
Table: $6.(*ast.TableName),
|
|
IndexColNames: $8.([]*ast.IndexColName),
|
|
}
|
|
}
|
|
|
|
CreateIndexStmtUnique:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "UNIQUE"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IndexColName:
|
|
ColumnName OptFieldLen Order
|
|
{
|
|
//Order is parsed but just ignored as MySQL did
|
|
$$ = &ast.IndexColName{Column: $1.(*ast.ColumnName), Length: $2.(int)}
|
|
}
|
|
|
|
IndexColNameList:
|
|
{
|
|
$$ = []*ast.IndexColName{}
|
|
}
|
|
| IndexColName
|
|
{
|
|
$$ = []*ast.IndexColName{$1.(*ast.IndexColName)}
|
|
}
|
|
| IndexColNameList ',' IndexColName
|
|
{
|
|
$$ = append($1.([]*ast.IndexColName), $3.(*ast.IndexColName))
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Create Database Statement
|
|
* CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
|
|
* [create_specification] ...
|
|
*
|
|
* create_specification:
|
|
* [DEFAULT] CHARACTER SET [=] charset_name
|
|
* | [DEFAULT] COLLATE [=] collation_name
|
|
*******************************************************************/
|
|
CreateDatabaseStmt:
|
|
"CREATE" DatabaseSym IfNotExists DBName DatabaseOptionListOpt
|
|
{
|
|
$$ = &ast.CreateDatabaseStmt{
|
|
IfNotExists: $3.(bool),
|
|
Name: $4.(string),
|
|
Options: $5.([]*ast.DatabaseOption),
|
|
}
|
|
}
|
|
|
|
DBName:
|
|
Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
DatabaseOption:
|
|
DefaultKwdOpt CharsetKw EqOpt CharsetName
|
|
{
|
|
$$ = &ast.DatabaseOption{Tp: ast.DatabaseOptionCharset, Value: $4.(string)}
|
|
}
|
|
| DefaultKwdOpt "COLLATE" EqOpt StringName
|
|
{
|
|
$$ = &ast.DatabaseOption{Tp: ast.DatabaseOptionCollate, Value: $4.(string)}
|
|
}
|
|
|
|
DatabaseOptionListOpt:
|
|
{
|
|
$$ = []*ast.DatabaseOption{}
|
|
}
|
|
| DatabaseOptionList
|
|
|
|
DatabaseOptionList:
|
|
DatabaseOption
|
|
{
|
|
$$ = []*ast.DatabaseOption{$1.(*ast.DatabaseOption)}
|
|
}
|
|
| DatabaseOptionList DatabaseOption
|
|
{
|
|
$$ = append($1.([]*ast.DatabaseOption), $2.(*ast.DatabaseOption))
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Create Table Statement
|
|
*
|
|
* Example:
|
|
* CREATE TABLE Persons
|
|
* (
|
|
* P_Id int NOT NULL,
|
|
* LastName varchar(255) NOT NULL,
|
|
* FirstName varchar(255),
|
|
* Address varchar(255),
|
|
* City varchar(255),
|
|
* PRIMARY KEY (P_Id)
|
|
* )
|
|
*******************************************************************/
|
|
CreateTableStmt:
|
|
"CREATE" "TABLE" IfNotExists TableName '(' TableElementList ')' TableOptionListOpt PartitionOpt
|
|
{
|
|
tes := $6.([]interface {})
|
|
var columnDefs []*ast.ColumnDef
|
|
var constraints []*ast.Constraint
|
|
for _, te := range tes {
|
|
switch te := te.(type) {
|
|
case *ast.ColumnDef:
|
|
columnDefs = append(columnDefs, te)
|
|
case *ast.Constraint:
|
|
constraints = append(constraints, te)
|
|
}
|
|
}
|
|
if len(columnDefs) == 0 {
|
|
yylex.Errorf("Column Definition List can't be empty.")
|
|
return 1
|
|
}
|
|
$$ = &ast.CreateTableStmt{
|
|
Table: $4.(*ast.TableName),
|
|
IfNotExists: $3.(bool),
|
|
Cols: columnDefs,
|
|
Constraints: constraints,
|
|
Options: $8.([]*ast.TableOption),
|
|
}
|
|
}
|
|
| "CREATE" "TABLE" IfNotExists TableName "LIKE" TableName
|
|
{
|
|
$$ = &ast.CreateTableStmt{
|
|
Table: $4.(*ast.TableName),
|
|
ReferTable: $6.(*ast.TableName),
|
|
IfNotExists: $3.(bool),
|
|
}
|
|
}
|
|
|
|
DefaultKwdOpt:
|
|
{}
|
|
| "DEFAULT"
|
|
|
|
PartitionOpt:
|
|
{}
|
|
| "PARTITION" "BY" "HASH" '(' Expression ')' PartitionNumOpt PartitionDefinitionListOpt
|
|
{}
|
|
| "PARTITION" "BY" "RANGE" '(' Expression ')' PartitionNumOpt PartitionDefinitionListOpt
|
|
{}
|
|
|
|
PartitionNumOpt:
|
|
{}
|
|
| "PARTITIONS" NUM
|
|
{}
|
|
|
|
PartitionDefinitionListOpt:
|
|
{}
|
|
| '(' PartitionDefinitionList ')'
|
|
{}
|
|
|
|
PartitionDefinitionList:
|
|
PartitionDefinition
|
|
{}
|
|
| PartitionDefinitionList ',' PartitionDefinition
|
|
{}
|
|
|
|
PartitionDefinition:
|
|
"PARTITION" Identifier PartDefValuesOpt PartDefStorageOpt
|
|
{}
|
|
|
|
PartDefValuesOpt:
|
|
{}
|
|
| "VALUES" "LESS" "THAN" "MAXVALUE"
|
|
{}
|
|
| "VALUES" "LESS" "THAN" '(' ExpressionList ')'
|
|
{}
|
|
|
|
PartDefStorageOpt:
|
|
{}
|
|
| "ENGINE" eq Identifier
|
|
{}
|
|
|
|
/******************************************************************
|
|
* Do statement
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/do.html
|
|
******************************************************************/
|
|
DoStmt:
|
|
"DO" ExpressionList
|
|
{
|
|
$$ = &ast.DoStmt {
|
|
Exprs: $2.([]ast.ExprNode),
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Delete Statement
|
|
*
|
|
*******************************************************************/
|
|
DeleteFromStmt:
|
|
"DELETE" LowPriorityOptional QuickOptional IgnoreOptional "FROM" TableName WhereClauseOptional OrderByOptional LimitClause
|
|
{
|
|
// Single Table
|
|
join := &ast.Join{Left: &ast.TableSource{Source: $6.(ast.ResultSetNode)}, Right: nil}
|
|
x := &ast.DeleteStmt{
|
|
TableRefs: &ast.TableRefsClause{TableRefs: join},
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
}
|
|
if $7 != nil {
|
|
x.Where = $7.(ast.ExprNode)
|
|
}
|
|
if $8 != nil {
|
|
x.Order = $8.(*ast.OrderByClause)
|
|
}
|
|
if $9 != nil {
|
|
x.Limit = $9.(*ast.Limit)
|
|
}
|
|
|
|
$$ = x
|
|
}
|
|
| "DELETE" LowPriorityOptional QuickOptional IgnoreOptional TableNameList "FROM" TableRefs WhereClauseOptional
|
|
{
|
|
// Multiple Table
|
|
x := &ast.DeleteStmt{
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
IsMultiTable: true,
|
|
BeforeFrom: true,
|
|
Tables: &ast.DeleteTableList{Tables: $5.([]*ast.TableName)},
|
|
TableRefs: &ast.TableRefsClause{TableRefs: $7.(*ast.Join)},
|
|
}
|
|
if $8 != nil {
|
|
x.Where = $8.(ast.ExprNode)
|
|
}
|
|
$$ = x
|
|
}
|
|
| "DELETE" LowPriorityOptional QuickOptional IgnoreOptional "FROM" TableNameList "USING" TableRefs WhereClauseOptional
|
|
{
|
|
// Multiple Table
|
|
x := &ast.DeleteStmt{
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
IsMultiTable: true,
|
|
Tables: &ast.DeleteTableList{Tables: $6.([]*ast.TableName)},
|
|
TableRefs: &ast.TableRefsClause{TableRefs: $8.(*ast.Join)},
|
|
}
|
|
if $9 != nil {
|
|
x.Where = $9.(ast.ExprNode)
|
|
}
|
|
$$ = x
|
|
}
|
|
|
|
DatabaseSym:
|
|
"DATABASE" | "SCHEMA"
|
|
|
|
DropDatabaseStmt:
|
|
"DROP" DatabaseSym IfExists DBName
|
|
{
|
|
$$ = &ast.DropDatabaseStmt{IfExists: $3.(bool), Name: $4.(string)}
|
|
}
|
|
|
|
DropIndexStmt:
|
|
"DROP" "INDEX" IfExists Identifier "ON" TableName
|
|
{
|
|
$$ = &ast.DropIndexStmt{IfExists: $3.(bool), IndexName: $4, Table: $6.(*ast.TableName)}
|
|
}
|
|
|
|
DropTableStmt:
|
|
"DROP" TableOrTables TableNameList
|
|
{
|
|
$$ = &ast.DropTableStmt{Tables: $3.([]*ast.TableName)}
|
|
}
|
|
| "DROP" TableOrTables "IF" "EXISTS" TableNameList
|
|
{
|
|
$$ = &ast.DropTableStmt{IfExists: true, Tables: $5.([]*ast.TableName)}
|
|
}
|
|
|
|
DropViewStmt:
|
|
"DROP" "VIEW" "IF" "EXISTS" TableNameList
|
|
{
|
|
$$ = &ast.DoStmt{}
|
|
}
|
|
|
|
DropUserStmt:
|
|
"DROP" "USER" UsernameList
|
|
{
|
|
$$ = &ast.DropUserStmt{IfExists: false, UserList: $3.([]string)}
|
|
}
|
|
| "DROP" "USER" "IF" "EXISTS" UsernameList
|
|
{
|
|
$$ = &ast.DropUserStmt{IfExists: true, UserList: $5.([]string)}
|
|
}
|
|
|
|
TableOrTables:
|
|
"TABLE"
|
|
| "TABLES"
|
|
|
|
EqOpt:
|
|
{}
|
|
| eq
|
|
|
|
EmptyStmt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
|
|
ExplainSym:
|
|
"EXPLAIN" | "DESCRIBE" | "DESC"
|
|
|
|
ExplainStmt:
|
|
ExplainSym TableName
|
|
{
|
|
$$ = &ast.ExplainStmt{
|
|
Stmt: &ast.ShowStmt{
|
|
Tp: ast.ShowColumns,
|
|
Table: $2.(*ast.TableName),
|
|
},
|
|
}
|
|
}
|
|
| ExplainSym TableName ColumnName
|
|
{
|
|
$$ = &ast.ExplainStmt{
|
|
Stmt: &ast.ShowStmt{
|
|
Tp: ast.ShowColumns,
|
|
Table: $2.(*ast.TableName),
|
|
Column: $3.(*ast.ColumnName),
|
|
},
|
|
}
|
|
}
|
|
| ExplainSym ExplainableStmt
|
|
{
|
|
$$ = &ast.ExplainStmt{Stmt: $2.(ast.StmtNode)}
|
|
}
|
|
|
|
LengthNum:
|
|
NUM
|
|
{
|
|
$$ = getUint64FromNUM($1)
|
|
}
|
|
|
|
NUM:
|
|
intLit
|
|
|
|
Expression:
|
|
"USER_VAR" assignmentEq Expression %prec assignmentEq
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &ast.VariableExpr{
|
|
Name: v,
|
|
IsGlobal: false,
|
|
IsSystem: false,
|
|
Value: $3.(ast.ExprNode),
|
|
}
|
|
}
|
|
| Expression logOr Expression %prec oror
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.OrOr, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| Expression "XOR" Expression %prec xor
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.LogicXor, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| Expression logAnd Expression %prec andand
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.AndAnd, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| "NOT" Expression %prec not
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Not, V: $2.(ast.ExprNode)}
|
|
}
|
|
| Factor IsOrNotOp trueKwd %prec is
|
|
{
|
|
$$ = &ast.IsTruthExpr{Expr:$1.(ast.ExprNode), Not: !$2.(bool), True: int64(1)}
|
|
}
|
|
| Factor IsOrNotOp falseKwd %prec is
|
|
{
|
|
$$ = &ast.IsTruthExpr{Expr:$1.(ast.ExprNode), Not: !$2.(bool), True: int64(0)}
|
|
}
|
|
| Factor IsOrNotOp "UNKNOWN" %prec is
|
|
{
|
|
/* https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_is */
|
|
$$ = &ast.IsNullExpr{Expr: $1.(ast.ExprNode), Not: !$2.(bool)}
|
|
}
|
|
| Factor
|
|
|
|
|
|
logOr:
|
|
"||" | "OR"
|
|
|
|
logAnd:
|
|
"&&" | "AND"
|
|
|
|
ExpressionList:
|
|
Expression
|
|
{
|
|
$$ = []ast.ExprNode{$1.(ast.ExprNode)}
|
|
}
|
|
| ExpressionList ',' Expression
|
|
{
|
|
$$ = append($1.([]ast.ExprNode), $3.(ast.ExprNode))
|
|
}
|
|
|
|
ExpressionListOpt:
|
|
{
|
|
$$ = []ast.ExprNode{}
|
|
}
|
|
| ExpressionList
|
|
|
|
Factor:
|
|
Factor IsOrNotOp "NULL" %prec is
|
|
{
|
|
$$ = &ast.IsNullExpr{Expr: $1.(ast.ExprNode), Not: !$2.(bool)}
|
|
}
|
|
| Factor CompareOp PredicateExpr %prec eq
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| Factor CompareOp "USER_VAR" assignmentEq PredicateExpr %prec assignmentEq
|
|
{
|
|
v := $3.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
variable := &ast.VariableExpr{
|
|
Name: v,
|
|
IsGlobal: false,
|
|
IsSystem: false,
|
|
Value: $5.(ast.ExprNode),
|
|
}
|
|
$$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: variable}
|
|
}
|
|
| Factor CompareOp AnyOrAll SubSelect %prec eq
|
|
{
|
|
sq := $4.(*ast.SubqueryExpr)
|
|
sq.MultiRows = true
|
|
$$ = &ast.CompareSubqueryExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: sq, All: $3.(bool)}
|
|
}
|
|
| PredicateExpr
|
|
|
|
CompareOp:
|
|
">="
|
|
{
|
|
$$ = opcode.GE
|
|
}
|
|
| '>'
|
|
{
|
|
$$ = opcode.GT
|
|
}
|
|
| "<="
|
|
{
|
|
$$ = opcode.LE
|
|
}
|
|
| '<'
|
|
{
|
|
$$ = opcode.LT
|
|
}
|
|
| "!="
|
|
{
|
|
$$ = opcode.NE
|
|
}
|
|
| "<>"
|
|
{
|
|
$$ = opcode.NE
|
|
}
|
|
| "="
|
|
{
|
|
$$ = opcode.EQ
|
|
}
|
|
| "<=>"
|
|
{
|
|
$$ = opcode.NullEQ
|
|
}
|
|
|
|
BetweenOrNotOp:
|
|
"BETWEEN"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "NOT" "BETWEEN"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
IsOrNotOp:
|
|
"IS"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "IS" "NOT"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
InOrNotOp:
|
|
"IN"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "NOT" "IN"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
LikeOrNotOp:
|
|
"LIKE"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "NOT" "LIKE"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
RegexpOrNotOp:
|
|
RegexpSym
|
|
{
|
|
$$ = true
|
|
}
|
|
| "NOT" RegexpSym
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
AnyOrAll:
|
|
"ANY"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "SOME"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
PredicateExpr:
|
|
PrimaryFactor InOrNotOp '(' ExpressionList ')'
|
|
{
|
|
$$ = &ast.PatternInExpr{Expr: $1.(ast.ExprNode), Not: !$2.(bool), List: $4.([]ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor InOrNotOp SubSelect
|
|
{
|
|
sq := $3.(*ast.SubqueryExpr)
|
|
sq.MultiRows = true
|
|
$$ = &ast.PatternInExpr{Expr: $1.(ast.ExprNode), Not: !$2.(bool), Sel: sq}
|
|
}
|
|
| PrimaryFactor BetweenOrNotOp PrimaryFactor "AND" PredicateExpr
|
|
{
|
|
$$ = &ast.BetweenExpr{
|
|
Expr: $1.(ast.ExprNode),
|
|
Left: $3.(ast.ExprNode),
|
|
Right: $5.(ast.ExprNode),
|
|
Not: !$2.(bool),
|
|
}
|
|
}
|
|
| PrimaryFactor LikeOrNotOp PrimaryExpression LikeEscapeOpt
|
|
{
|
|
escape := $4.(string)
|
|
if len(escape) > 1 {
|
|
yylex.Errorf("Incorrect arguments %s to ESCAPE", escape)
|
|
return 1
|
|
} else if len(escape) == 0 {
|
|
escape = "\\"
|
|
}
|
|
$$ = &ast.PatternLikeExpr{
|
|
Expr: $1.(ast.ExprNode),
|
|
Pattern: $3.(ast.ExprNode),
|
|
Not: !$2.(bool),
|
|
Escape: escape[0],
|
|
}
|
|
}
|
|
| PrimaryFactor RegexpOrNotOp PrimaryExpression
|
|
{
|
|
$$ = &ast.PatternRegexpExpr{Expr: $1.(ast.ExprNode), Pattern: $3.(ast.ExprNode), Not: !$2.(bool)}
|
|
}
|
|
| PrimaryFactor
|
|
|
|
RegexpSym:
|
|
"REGEXP" | "RLIKE"
|
|
|
|
LikeEscapeOpt:
|
|
%prec lowerThanEscape
|
|
{
|
|
$$ = "\\"
|
|
}
|
|
| "ESCAPE" stringLit
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
Field:
|
|
'*'
|
|
{
|
|
$$ = &ast.SelectField{WildCard: &ast.WildCardField{}}
|
|
}
|
|
| Identifier '.' '*'
|
|
{
|
|
wildCard := &ast.WildCardField{Table: model.NewCIStr($1)}
|
|
$$ = &ast.SelectField{WildCard: wildCard}
|
|
}
|
|
| Identifier '.' Identifier '.' '*'
|
|
{
|
|
wildCard := &ast.WildCardField{Schema: model.NewCIStr($1), Table: model.NewCIStr($3)}
|
|
$$ = &ast.SelectField{WildCard: wildCard}
|
|
}
|
|
| Expression FieldAsNameOpt
|
|
{
|
|
expr := $1.(ast.ExprNode)
|
|
asName := $2.(string)
|
|
$$ = &ast.SelectField{Expr: expr, AsName: model.NewCIStr(asName)}
|
|
}
|
|
|
|
FieldAsNameOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = ""
|
|
}
|
|
| FieldAsName
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
FieldAsName:
|
|
Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "AS" Identifier
|
|
{
|
|
$$ = $2
|
|
}
|
|
| stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "AS" stringLit
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
FieldList:
|
|
Field
|
|
{
|
|
field := $1.(*ast.SelectField)
|
|
field.Offset = parser.startOffset(&yyS[yypt])
|
|
$$ = []*ast.SelectField{field}
|
|
}
|
|
| FieldList ',' Field
|
|
{
|
|
|
|
fl := $1.([]*ast.SelectField)
|
|
last := fl[len(fl)-1]
|
|
if last.Expr != nil && last.AsName.O == "" {
|
|
lastEnd := parser.endOffset(&yyS[yypt-1])
|
|
last.SetText(parser.src[last.Offset:lastEnd])
|
|
}
|
|
newField := $3.(*ast.SelectField)
|
|
newField.Offset = parser.startOffset(&yyS[yypt])
|
|
$$ = append(fl, newField)
|
|
}
|
|
|
|
GroupByClause:
|
|
"GROUP" "BY" ByList
|
|
{
|
|
$$ = &ast.GroupByClause{Items: $3.([]*ast.ByItem)}
|
|
}
|
|
|
|
HavingClause:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "HAVING" Expression
|
|
{
|
|
$$ = &ast.HavingClause{Expr: $2.(ast.ExprNode)}
|
|
}
|
|
|
|
IfExists:
|
|
%prec lowestOpt
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IfNotExists:
|
|
%prec lowestOpt
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "NOT" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
|
|
IgnoreOptional:
|
|
%prec lowerThanIgnore
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IGNORE"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IndexName:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| Identifier
|
|
{
|
|
//"index name"
|
|
$$ = $1
|
|
}
|
|
|
|
IndexOptionList:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| IndexOptionList IndexOption
|
|
{
|
|
// Merge the options
|
|
if $1 == nil {
|
|
$$ = $2
|
|
} else {
|
|
opt1 := $1.(*ast.IndexOption)
|
|
opt2 := $2.(*ast.IndexOption)
|
|
if len(opt2.Comment) > 0 {
|
|
opt1.Comment = opt2.Comment
|
|
} else if opt2.Tp != 0 {
|
|
opt1.Tp = opt2.Tp
|
|
}
|
|
$$ = opt1
|
|
}
|
|
}
|
|
|
|
|
|
IndexOption:
|
|
"KEY_BLOCK_SIZE" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.IndexOption{
|
|
// TODO bug should be fix here!
|
|
// KeyBlockSize: $1.(uint64),
|
|
}
|
|
}
|
|
| IndexType
|
|
{
|
|
$$ = &ast.IndexOption {
|
|
Tp: $1.(model.IndexType),
|
|
}
|
|
}
|
|
| "COMMENT" stringLit
|
|
{
|
|
$$ = &ast.IndexOption {
|
|
Comment: $2,
|
|
}
|
|
}
|
|
|
|
IndexType:
|
|
"USING" "BTREE"
|
|
{
|
|
$$ = model.IndexTypeBtree
|
|
}
|
|
| "USING" "HASH"
|
|
{
|
|
$$ = model.IndexTypeHash
|
|
}
|
|
|
|
IndexTypeOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| IndexType
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
/**********************************Identifier********************************************/
|
|
Identifier:
|
|
identifier | UnReservedKeyword | NotKeywordToken
|
|
|
|
IdentifierOrReservedKeyword:
|
|
Identifier | ReservedKeyword
|
|
|
|
UnReservedKeyword:
|
|
"ACTION" | "ASCII" | "AUTO_INCREMENT" | "AFTER" | "AT" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "CHARSET"
|
|
| "COLUMNS" | "COMMIT" | "COMPACT" | "COMPRESSED" | "CONSISTENT" | "DATA" | "DATE" | "DATETIME" | "DEALLOCATE" | "DO"
|
|
| "DYNAMIC"| "END" | "ENGINE" | "ENGINES" | "ESCAPE" | "EXECUTE" | "FIELDS" | "FIRST" | "FIXED" | "FORMAT" | "FULL" |"GLOBAL"
|
|
| "HASH" | "LESS" | "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "REDUNDANT"
|
|
| "ROLLBACK" | "SESSION" | "SIGNED" | "SNAPSHOT" | "START" | "STATUS" | "TABLES" | "TEXT" | "THAN" | "TIDB" | "TIME" | "TIMESTAMP"
|
|
| "TRANSACTION" | "TRUNCATE" | "UNKNOWN" | "VALUE" | "WARNINGS" | "YEAR" | "MODE" | "WEEK" | "ANY" | "SOME" | "USER" | "IDENTIFIED"
|
|
| "COLLATION" | "COMMENT" | "AVG_ROW_LENGTH" | "CONNECTION" | "CHECKSUM" | "COMPRESSION" | "KEY_BLOCK_SIZE" | "MAX_ROWS"
|
|
| "MIN_ROWS" | "NATIONAL" | "ROW" | "ROW_FORMAT" | "QUARTER" | "GRANTS" | "TRIGGERS" | "DELAY_KEY_WRITE" | "ISOLATION"
|
|
| "REPEATABLE" | "COMMITTED" | "UNCOMMITTED" | "ONLY" | "SERIALIZABLE" | "LEVEL" | "VARIABLES" | "SQL_CACHE" | "INDEXES" | "PROCESSLIST"
|
|
| "SQL_NO_CACHE" | "DISABLE" | "ENABLE" | "REVERSE" | "SPACE" | "PRIVILEGES" | "NO" | "BINLOG" | "FUNCTION" | "VIEW" | "MODIFY" | "EVENTS" | "PARTITIONS"
|
|
| "TIMESTAMPDIFF" | "NONE" | "SUPER"
|
|
|
|
ReservedKeyword:
|
|
"ADD" | "ALL" | "ALTER" | "ANALYZE" | "AND" | "AS" | "ASC" | "BETWEEN" | "BIGINT"
|
|
| "BINARY" | "BLOB" | "BOTH" | "BY" | "CASCADE" | "CASE" | "CHANGE" | "CHARACTER" | "CHECK" | "COLLATE"
|
|
| "COLUMN" | "CONSTRAINT" | "CONVERT" | "CREATE" | "CROSS" | "CURRENT_DATE" | "CURRENT_TIME"
|
|
| "CURRENT_TIMESTAMP" | "CURRENT_USER" | "DATABASE" | "DATABASES" | "DAY_HOUR" | "DAY_MICROSECOND"
|
|
| "DAY_MINUTE" | "DAY_SECOND" | "DECIMAL" | "DEFAULT" | "DELETE" | "DESC" | "DESCRIBE"
|
|
| "DISTINCT" | "DIV" | "DOUBLE" | "DROP" | "DUAL" | "ELSE" | "ENCLOSED" | "ESCAPED"
|
|
| "EXISTS" | "EXPLAIN" | "FALSE" | "FLOAT" | "FOR" | "FORCE" | "FOREIGN" | "FROM"
|
|
| "FULLTEXT" | "GRANT" | "GROUP" | "HAVING" | "HOUR_MICROSECOND" | "HOUR_MINUTE"
|
|
| "HOUR_SECOND" | "IF" | "IGNORE" | "IN" | "INDEX" | "INFILE" | "INNER" | "INSERT" | "INT" | "INTO" | "INTEGER"
|
|
| "INTERVAL" | "IS" | "JOIN" | "KEY" | "KEYS" | "KILL" | "LEADING" | "LEFT" | "LIKE" | "LIMIT" | "LINES" | "LOAD"
|
|
| "LOCALTIME" | "LOCALTIMESTAMP" | "LOCK" | "LONGBLOB" | "LONGTEXT" | "MAXVALUE" | "MEDIUMBLOB" | "MEDIUMINT" | "MEDIUMTEXT"
|
|
| "MINUTE_MICROSECOND" | "MINUTE_SECOND" | "MOD" | "NOT" | "NO_WRITE_TO_BINLOG" | "NULL" | "NUMERIC"
|
|
| "ON" | "OPTION" | "OR" | "ORDER" | "OUTER" | "PARTITION" | "PRECISION" | "PRIMARY" | "PROCEDURE" | "RANGE" | "READ"
|
|
| "REAL" | "REFERENCES" | "REGEXP" | "RENAME" | "REPEAT" | "REPLACE" | "RESTRICT" | "REVOKE" | "RIGHT" | "RLIKE"
|
|
| "SCHEMA" | "SCHEMAS" | "SECOND_MICROSECOND" | "SELECT" | "SET" | "SHOW" | "SMALLINT"
|
|
| "STARTING" | "TABLE" | "TERMINATED" | "THEN" | "TINYBLOB" | "TINYINT" | "TINYTEXT" | "TO"
|
|
| "TRAILING" | "TRIGGER" | "TRUE" | "UNION" | "UNIQUE" | "UNLOCK" | "UNSIGNED"
|
|
| "UPDATE" | "USE" | "USING" | "UTC_DATE" | "UTC_TIMESTAMP" | "VALUES" | "VARBINARY" | "VARCHAR"
|
|
| "WHEN" | "WHERE" | "WRITE" | "XOR" | "YEAR_MONTH" | "ZEROFILL"
|
|
/*
|
|
| "DELAYED" | "HIGH_PRIORITY" | "LOW_PRIORITY"| "WITH"
|
|
*/
|
|
|
|
|
|
NotKeywordToken:
|
|
"ABS" | "ACOS" | "ADDTIME" | "ADDDATE" | "ADMIN" | "ASIN" | "ATAN" | "ATAN2" | "BENCHMARK" | "BIN" | "BIT_COUNT" | "BIT_LENGTH" | "COALESCE" | "COERCIBILITY" | "CONCAT" | "CONCAT_WS" | "CONNECTION_ID" | "CONVERT_TZ" | "CUR_TIME"| "COS" | "COT" | "COUNT" | "DAY"
|
|
| "DATEDIFF" | "DATE_ADD" | "DATE_FORMAT" | "DATE_SUB" | "DAYNAME" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "DEGREES" | "ELT" | "EXP" | "EXPORT_SET" | "FROM_DAYS" | "FROM_BASE64" | "FIND_IN_SET" | "FOUND_ROWS"
|
|
| "GET_FORMAT" | "GROUP_CONCAT" | "GREATEST" | "LEAST" | "HOUR" | "HEX" | "UNHEX" | "IFNULL" | "INSTR" | "ISNULL" | "LAST_INSERT_ID" | "LCASE" | "LENGTH" | "LOAD_FILE" | "LOCATE" | "LOWER" | "LPAD" | "LTRIM"
|
|
| "MAKE_SET" | "MAX" | "MAKEDATE" | "MAKETIME" | "MICROSECOND" | "MID" | "MIN" | "MINUTE" | "NULLIF" | "MONTH" | "MONTHNAME" | "NOW" | "OCT" | "OCTET_LENGTH" | "ORD" | "POSITION" | "PERIOD_ADD" | "PERIOD_DIFF" | "PI" | "POW" | "POWER" | "RAND" | "RADIANS" | "ROW_COUNT"
|
|
"QUOTE" | "SEC_TO_TIME" | "SECOND" | "SIGN" | "SIN" | "SLEEP" | "SQRT" | "SQL_CALC_FOUND_ROWS" | "STR_TO_DATE" | "SUBTIME" | "SUBDATE" | "SUBSTRING" %prec lowerThanLeftParen |
|
|
"SESSION_USER" | "SUBSTRING_INDEX" | "SUM" | "SYSTEM_USER" | "TAN" | "TIME_FORMAT" | "TIME_TO_SEC" | "TIMESTAMPADD" | "TO_BASE64" | "TO_DAYS" | "TO_SECONDS" | "TRIM" | "RTRIM" | "UCASE" | "UTC_TIME" | "UPPER" | "VERSION" | "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK" | "ROUND"
|
|
| "STATS_PERSISTENT" | "GET_LOCK" | "RELEASE_LOCK" | "CEIL" | "CEILING" | "FLOOR" | "FROM_UNIXTIME" | "TIMEDIFF" | "LN" | "LOG" | "LOG2" | "LOG10" | "FIELD_KWD"
|
|
| "AES_DECRYPT" | "AES_ENCRYPT" | "QUOTE"
|
|
| "ANY_VALUE" | "INET_ATON" | "INET_NTOA" | "INET6_ATON" | "INET6_NTOA" | "IS_FREE_LOCK" | "IS_IPV4" | "IS_IPV4_COMPAT" | "IS_IPV4_MAPPED" | "IS_IPV6" | "IS_USED_LOCK" | "MASTER_POS_WAIT" | "NAME_CONST" | "RELEASE_ALL_LOCKS" | "UUID" | "UUID_SHORT"
|
|
| "COMPRESS" | "DECODE" | "DES_DECRYPT" | "DES_ENCRYPT" | "ENCODE" | "ENCRYPT" | "MD5" | "OLD_PASSWORD" | "RANDOM_BYTES" | "SHA1" | "SHA" | "SHA2" | "UNCOMPRESS" | "UNCOMPRESSED_LENGTH" | "VALIDATE_PASSWORD_STRENGTH"
|
|
|
|
/************************************************************************************
|
|
*
|
|
* Insert Statements
|
|
*
|
|
* TODO: support PARTITION
|
|
**********************************************************************************/
|
|
InsertIntoStmt:
|
|
"INSERT" Priority IgnoreOptional IntoOpt TableName InsertValues OnDuplicateKeyUpdate
|
|
{
|
|
x := $6.(*ast.InsertStmt)
|
|
x.Priority = $2.(int)
|
|
x.Ignore = $3.(bool)
|
|
// Wraps many layers here so that it can be processed the same way as select statement.
|
|
ts := &ast.TableSource{Source: $5.(*ast.TableName)}
|
|
x.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}
|
|
if $7 != nil {
|
|
x.OnDuplicate = $7.([]*ast.Assignment)
|
|
}
|
|
$$ = x
|
|
}
|
|
|
|
IntoOpt:
|
|
%prec lowerThanInto
|
|
{}
|
|
| "INTO"
|
|
|
|
InsertValues:
|
|
'(' ColumnNameListOpt ')' ValueSym ExpressionListList
|
|
{
|
|
$$ = &ast.InsertStmt{
|
|
Columns: $2.([]*ast.ColumnName),
|
|
Lists: $5.([][]ast.ExprNode),
|
|
}
|
|
}
|
|
| '(' ColumnNameListOpt ')' SelectStmt
|
|
{
|
|
$$ = &ast.InsertStmt{Columns: $2.([]*ast.ColumnName), Select: $4.(*ast.SelectStmt)}
|
|
}
|
|
| '(' ColumnNameListOpt ')' UnionStmt
|
|
{
|
|
$$ = &ast.InsertStmt{Columns: $2.([]*ast.ColumnName), Select: $4.(*ast.UnionStmt)}
|
|
}
|
|
| ValueSym ExpressionListList %prec insertValues
|
|
{
|
|
$$ = &ast.InsertStmt{Lists: $2.([][]ast.ExprNode)}
|
|
}
|
|
| SelectStmt
|
|
{
|
|
$$ = &ast.InsertStmt{Select: $1.(*ast.SelectStmt)}
|
|
}
|
|
| UnionStmt
|
|
{
|
|
$$ = &ast.InsertStmt{Select: $1.(*ast.UnionStmt)}
|
|
}
|
|
| "SET" ColumnSetValueList
|
|
{
|
|
$$ = &ast.InsertStmt{Setlist: $2.([]*ast.Assignment)}
|
|
}
|
|
|
|
ValueSym:
|
|
"VALUE" | "VALUES"
|
|
|
|
ExpressionListList:
|
|
ExpressionListListItem
|
|
{
|
|
$$ = [][]ast.ExprNode{$1.([]ast.ExprNode)}
|
|
}
|
|
| ExpressionListList ',' ExpressionListListItem
|
|
{
|
|
$$ = append($1.([][]ast.ExprNode), $3.([]ast.ExprNode))
|
|
}
|
|
|
|
ExpressionListListItem:
|
|
'(' ExpressionListOpt ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
ColumnSetValue:
|
|
ColumnName eq Expression
|
|
{
|
|
$$ = &ast.Assignment{
|
|
Column: $1.(*ast.ColumnName),
|
|
Expr: $3.(ast.ExprNode),
|
|
}
|
|
}
|
|
|
|
ColumnSetValueList:
|
|
{
|
|
$$ = []*ast.Assignment{}
|
|
}
|
|
| ColumnSetValue
|
|
{
|
|
$$ = []*ast.Assignment{$1.(*ast.Assignment)}
|
|
}
|
|
| ColumnSetValueList ',' ColumnSetValue
|
|
{
|
|
$$ = append($1.([]*ast.Assignment), $3.(*ast.Assignment))
|
|
}
|
|
|
|
/*
|
|
* ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ...
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
|
|
*/
|
|
OnDuplicateKeyUpdate:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "ON" "DUPLICATE" "KEY" "UPDATE" AssignmentList
|
|
{
|
|
$$ = $5
|
|
}
|
|
|
|
/***********************************Insert Statements END************************************/
|
|
|
|
/************************************************************************************
|
|
* Replace Statements
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/replace.html
|
|
*
|
|
* TODO: support PARTITION
|
|
**********************************************************************************/
|
|
ReplaceIntoStmt:
|
|
"REPLACE" ReplacePriority IntoOpt TableName InsertValues
|
|
{
|
|
x := $5.(*ast.InsertStmt)
|
|
x.IsReplace = true
|
|
x.Priority = $2.(int)
|
|
ts := &ast.TableSource{Source: $4.(*ast.TableName)}
|
|
x.Table = &ast.TableRefsClause{TableRefs: &ast.Join{Left: ts}}
|
|
$$ = x
|
|
}
|
|
|
|
ReplacePriority:
|
|
{
|
|
$$ = ast.NoPriority
|
|
}
|
|
| "LOW_PRIORITY"
|
|
{
|
|
$$ = ast.LowPriority
|
|
}
|
|
| "DELAYED"
|
|
{
|
|
$$ = ast.DelayedPriority
|
|
}
|
|
|
|
/***********************************Replace Statements END************************************/
|
|
|
|
Literal:
|
|
"FALSE"
|
|
{
|
|
$$ = int64(0)
|
|
}
|
|
| "NULL"
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "TRUE"
|
|
{
|
|
$$ = int64(1)
|
|
}
|
|
| floatLit
|
|
| decLit
|
|
| intLit
|
|
| stringLit
|
|
{
|
|
tp := types.NewFieldType(mysql.TypeString)
|
|
tp.Charset, tp.Collate = parser.charset, parser.collation
|
|
expr := ast.NewValueExpr($1)
|
|
expr.SetType(tp)
|
|
$$ = expr
|
|
}
|
|
| "UNDERSCORE_CHARSET" stringLit
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/charset-literal.html
|
|
tp := types.NewFieldType(mysql.TypeString)
|
|
tp.Charset = $1
|
|
co, err := charset.GetDefaultCollation(tp.Charset)
|
|
if err != nil {
|
|
yylex.Errorf("Get collation error for charset: %s", tp.Charset)
|
|
return 1
|
|
}
|
|
tp.Collate = co
|
|
expr := ast.NewValueExpr($2)
|
|
expr.SetType(tp)
|
|
$$ = expr
|
|
}
|
|
| hexLit
|
|
| bitLit
|
|
|
|
Operand:
|
|
Literal
|
|
{
|
|
$$ = ast.NewValueExpr($1)
|
|
}
|
|
| ColumnName
|
|
{
|
|
$$ = &ast.ColumnNameExpr{Name: $1.(*ast.ColumnName)}
|
|
}
|
|
| '(' Expression ')'
|
|
{
|
|
startOffset := parser.startOffset(&yyS[yypt-1])
|
|
endOffset := parser.endOffset(&yyS[yypt])
|
|
expr := $2.(ast.ExprNode)
|
|
expr.SetText(parser.src[startOffset:endOffset])
|
|
$$ = &ast.ParenthesesExpr{Expr: expr}
|
|
}
|
|
| "DEFAULT" %prec lowerThanLeftParen
|
|
{
|
|
$$ = &ast.DefaultExpr{}
|
|
}
|
|
| "DEFAULT" '(' ColumnName ')'
|
|
{
|
|
$$ = &ast.DefaultExpr{Name: $3.(*ast.ColumnName)}
|
|
}
|
|
| Variable
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "PLACEHOLDER"
|
|
{
|
|
$$ = &ast.ParamMarkerExpr{
|
|
Offset: yyS[yypt].offset,
|
|
}
|
|
}
|
|
| "ROW" '(' ExpressionList ',' Expression ')'
|
|
{
|
|
values := append($3.([]ast.ExprNode), $5.(ast.ExprNode))
|
|
$$ = &ast.RowExpr{Values: values}
|
|
}
|
|
| '(' ExpressionList ',' Expression ')'
|
|
{
|
|
values := append($2.([]ast.ExprNode), $4.(ast.ExprNode))
|
|
$$ = &ast.RowExpr{Values: values}
|
|
}
|
|
| "EXISTS" SubSelect
|
|
{
|
|
sq := $2.(*ast.SubqueryExpr)
|
|
sq.Exists = true
|
|
$$ = &ast.ExistsSubqueryExpr{Sel: sq}
|
|
}
|
|
|
|
OrderBy:
|
|
"ORDER" "BY" ByList
|
|
{
|
|
$$ = &ast.OrderByClause{Items: $3.([]*ast.ByItem)}
|
|
}
|
|
|
|
ByList:
|
|
ByItem
|
|
{
|
|
$$ = []*ast.ByItem{$1.(*ast.ByItem)}
|
|
}
|
|
| ByList ',' ByItem
|
|
{
|
|
$$ = append($1.([]*ast.ByItem), $3.(*ast.ByItem))
|
|
}
|
|
|
|
ByItem:
|
|
Expression Order
|
|
{
|
|
expr := $1
|
|
valueExpr, ok := expr.(*ast.ValueExpr)
|
|
if ok {
|
|
position, isPosition := valueExpr.GetValue().(int64)
|
|
if isPosition {
|
|
expr = &ast.PositionExpr{N: int(position)}
|
|
}
|
|
}
|
|
$$ = &ast.ByItem{Expr: expr.(ast.ExprNode), Desc: $2.(bool)}
|
|
}
|
|
|
|
Order:
|
|
/* EMPTY */
|
|
{
|
|
$$ = false // ASC by default
|
|
}
|
|
| "ASC"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DESC"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
OrderByOptional:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| OrderBy
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
PrimaryExpression:
|
|
Operand
|
|
| Function
|
|
| SubSelect
|
|
| '!' PrimaryExpression %prec neg
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Not, V: $2.(ast.ExprNode)}
|
|
}
|
|
| '~' PrimaryExpression %prec neg
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.BitNeg, V: $2.(ast.ExprNode)}
|
|
}
|
|
| '-' PrimaryExpression %prec neg
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: $2.(ast.ExprNode)}
|
|
}
|
|
| '+' PrimaryExpression %prec neg
|
|
{
|
|
$$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: $2.(ast.ExprNode)}
|
|
}
|
|
| "BINARY" PrimaryExpression %prec neg
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#operator_binary
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Charset = charset.CharsetBin
|
|
x.Collate = charset.CharsetBin
|
|
$$ = &ast.FuncCastExpr{
|
|
Expr: $2.(ast.ExprNode),
|
|
Tp: x,
|
|
FunctionType: ast.CastBinaryOperator,
|
|
}
|
|
}
|
|
| PrimaryExpression "COLLATE" StringName %prec neg
|
|
{
|
|
// TODO: Create a builtin function hold expr and collation. When do evaluation, convert expr result using the collation.
|
|
$$ = $1
|
|
}
|
|
|
|
Function:
|
|
FunctionCallKeyword
|
|
| FunctionCallNonKeyword
|
|
| FunctionCallConflict
|
|
| FunctionCallAgg
|
|
|
|
FunctionNameConflict:
|
|
"DATABASE"
|
|
| "SCHEMA"
|
|
| "IF"
|
|
| "LEFT"
|
|
| "RIGHT"
|
|
| "REPEAT"
|
|
| "CURRENT_USER"
|
|
| "UTC_DATE"
|
|
| "CURRENT_DATE"
|
|
| "VERSION"
|
|
| "INTERVAL" %prec lowerThanIntervalKeyword
|
|
|
|
FunctionCallConflict:
|
|
FunctionNameConflict '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CURRENT_USER"
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_current-user
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}
|
|
}
|
|
| "CURRENT_DATE"
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}
|
|
}
|
|
| "UTC_DATE"
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}
|
|
}
|
|
| "MOD" '(' PrimaryFactor ',' PrimaryFactor ')'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Mod, L: $3.(ast.ExprNode), R: $5.(ast.ExprNode)}
|
|
}
|
|
|
|
DistinctOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "DISTINCT" "ALL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
FunctionCallKeyword:
|
|
"CAST" '(' Expression "AS" CastType ')'
|
|
{
|
|
/* See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast */
|
|
$$ = &ast.FuncCastExpr{
|
|
Expr: $3.(ast.ExprNode),
|
|
Tp: $5.(*types.FieldType),
|
|
FunctionType: ast.CastFunction,
|
|
}
|
|
}
|
|
| "CASE" ExpressionOpt WhenClauseList ElseOpt "END"
|
|
{
|
|
x := &ast.CaseExpr{WhenClauses: $3.([]*ast.WhenClause)}
|
|
if $2 != nil {
|
|
x.Value = $2.(ast.ExprNode)
|
|
}
|
|
if $4 != nil {
|
|
x.ElseClause = $4.(ast.ExprNode)
|
|
}
|
|
$$ = x
|
|
}
|
|
| "CHARSET" '(' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
|
}
|
|
| "COLLATION" '(' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
|
}
|
|
| "CONVERT" '(' Expression "USING" StringName ')'
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
|
|
charset := ast.NewValueExpr($5)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), charset},
|
|
}
|
|
}
|
|
| "CONVERT" '(' Expression ',' CastType ')'
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
|
|
$$ = &ast.FuncCastExpr{
|
|
Expr: $3.(ast.ExprNode),
|
|
Tp: $5.(*types.FieldType),
|
|
FunctionType: ast.CastConvertFunction,
|
|
}
|
|
}
|
|
| "ASCII" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "USER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "VALUES" '(' ColumnName ')' %prec lowerThanInsertValues
|
|
{
|
|
// TODO: support qualified identifier for column_name
|
|
$$ = &ast.ValuesExpr{Column: &ast.ColumnNameExpr{Name: $3.(*ast.ColumnName)}}
|
|
}
|
|
| "WEEK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "YEAR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FORMAT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INSERT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr(ast.InsertFunc), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOCALTIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOCALTIMESTAMP" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "QUARTER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "PASSWORD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr(ast.PasswordFunc), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
|
|
FunctionCallNonKeyword:
|
|
"ABS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ADDTIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ACOS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "AES_DECRYPT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "AES_ENCRYPT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ASIN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ATAN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ATAN2" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "BENCHMARK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "BIN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "COALESCE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CONVERT_TZ" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "COS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "COT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "COERCIBILITY" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CURDATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CUR_TIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CURRENT_TIME" FuncDatetimePrec
|
|
{
|
|
args := []ast.ExprNode{}
|
|
if $2 != nil {
|
|
args = append(args, $2.(ast.ExprNode))
|
|
}
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: args}
|
|
}
|
|
| "CURRENT_TIMESTAMP" FuncDatetimePrec
|
|
{
|
|
args := []ast.ExprNode{}
|
|
if $2 != nil {
|
|
args = append(args, $2.(ast.ExprNode))
|
|
}
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: args}
|
|
}
|
|
| "CONCAT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CONCAT_WS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CEIL" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CEILING" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DATEDIFF" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DAY" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DAYNAME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DAYOFWEEK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DAYOFMONTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DAYOFYEAR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DEGREES" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ELT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "EXP" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "EXPORT_SET" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FLOOR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FIELD_KWD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| FunctionNameDateArithMultiForms '(' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{
|
|
$3.(ast.ExprNode),
|
|
$5.(ast.ExprNode),
|
|
ast.NewValueExpr("DAY"),
|
|
},
|
|
}
|
|
}
|
|
| FunctionNameDateArithMultiForms '(' Expression ',' "INTERVAL" Expression TimeUnit ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{
|
|
$3.(ast.ExprNode),
|
|
$6.(ast.ExprNode),
|
|
ast.NewValueExpr($7),
|
|
},
|
|
}
|
|
}
|
|
| FunctionNameDateArith '(' Expression ',' "INTERVAL" Expression TimeUnit ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{
|
|
$3.(ast.ExprNode),
|
|
$6.(ast.ExprNode),
|
|
ast.NewValueExpr($7),
|
|
},
|
|
}
|
|
}
|
|
| "DATE_FORMAT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FROM_BASE64" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FROM_DAYS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "EXTRACT" '(' TimeUnit "FROM" Expression ')'
|
|
{
|
|
timeUnit := ast.NewValueExpr($3)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1.(string)),
|
|
Args: []ast.ExprNode{timeUnit, $5.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "FIND_IN_SET" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FOUND_ROWS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "FROM_UNIXTIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "GET_FORMAT" '(' GetFormatSelector ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{ast.NewValueExpr($3), $5.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "GREATEST" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LEAST" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "HOUR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "HEX" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UNHEX" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IFNULL" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INSTR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ISNULL" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LAST_INSERT_ID" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOAD_FILE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOCATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOG" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOG2" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOG10" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LOWER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LPAD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LCASE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "LTRIM" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MAKEDATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MAKETIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MAKE_SET" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MID" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MICROSECOND" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MINUTE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MONTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MONTHNAME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "NOW" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "NULLIF" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "PERIOD_ADD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "PERIOD_DIFF" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "PI" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "OCT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "OCTET_LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ORD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "POSITION" '(' PrimaryFactor "IN" Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}}
|
|
}
|
|
| "POW" '(' ExpressionList ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "POWER" '(' ExpressionList ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RADIANS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "QUOTE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RAND" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "REPLACE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "REVERSE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RTRIM" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ROW_COUNT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SEC_TO_TIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SECOND" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SESSION_USER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SIGN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SIN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SQRT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SLEEP" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SPACE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "STRCMP" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "STR_TO_DATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SUBSTRING" '(' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression "FROM" Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression "FROM" Expression "FOR" Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "SUBSTRING_INDEX" '(' Expression ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "SUBTIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SYSDATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TAN" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SYSTEM_USER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TIMEDIFF" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TIME_FORMAT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TIME_TO_SEC" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TIMESTAMPADD" '(' TimestampUnit ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{ast.NewValueExpr($3), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "TIMESTAMPDIFF" '(' TimestampUnit ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{ast.NewValueExpr($3), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "TIMESTAMP" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TO_BASE64" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TO_DAYS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TO_SECONDS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "TRIM" '(' Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$3.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "TRIM" '(' Expression "FROM" Expression ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$5.(ast.ExprNode), $3.(ast.ExprNode)},
|
|
}
|
|
}
|
|
| "TRIM" '(' TrimDirection "FROM" Expression ')'
|
|
{
|
|
nilVal := ast.NewValueExpr(nil)
|
|
direction := ast.NewValueExpr($3)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$5.(ast.ExprNode), nilVal, direction},
|
|
}
|
|
}
|
|
| "TRIM" '(' TrimDirection Expression "FROM" Expression ')'
|
|
{
|
|
direction := ast.NewValueExpr($3)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr($1),
|
|
Args: []ast.ExprNode{$6.(ast.ExprNode),$4.(ast.ExprNode), direction},
|
|
}
|
|
}
|
|
| "TRUNCATE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UPPER" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UTC_TIME" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UCASE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UNIX_TIMESTAMP" '(' ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1)}
|
|
}
|
|
| "UNIX_TIMESTAMP" '(' ExpressionList ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UTC_TIMESTAMP" FuncDatetimePrec
|
|
{
|
|
args := []ast.ExprNode{}
|
|
if $2 != nil {
|
|
args = append(args, $2.(ast.ExprNode))
|
|
}
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: args}
|
|
}
|
|
| "WEEKDAY" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "WEEKOFYEAR" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "YEARWEEK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CONNECTION_ID" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ROUND" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "GET_LOCK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RELEASE_LOCK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RPAD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "BIT_COUNT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "BIT_LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CHAR" '(' ExpressionList ')'
|
|
{
|
|
nilVal := ast.NewValueExpr(nil)
|
|
args := $3.([]ast.ExprNode)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr(ast.CharFunc),
|
|
Args: append(args, nilVal),
|
|
}
|
|
}
|
|
| "CHAR" '(' ExpressionList "USING" StringName ')'
|
|
{
|
|
charset := ast.NewValueExpr($5)
|
|
args := $3.([]ast.ExprNode)
|
|
$$ = &ast.FuncCallExpr{
|
|
FnName: model.NewCIStr(ast.CharFunc),
|
|
Args: append(args, charset),
|
|
}
|
|
}
|
|
| "CHAR_LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CHARACTER_LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CONV" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "CRC32" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ANY_VALUE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INET_ATON" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INET_NTOA" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INET6_ATON" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "COMPRESS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "INET6_NTOA" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_FREE_LOCK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_IPV4" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DECODE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DES_DECRYPT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_IPV4_COMPAT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "DES_ENCRYPT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_IPV4_MAPPED" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ENCODE" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "ENCRYPT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_IPV6" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MD5" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "IS_USED_LOCK" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "OLD_PASSWORD" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "MASTER_POS_WAIT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "NAME_CONST" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RANDOM_BYTES" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SHA1" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SHA" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "SHA2" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "RELEASE_ALL_LOCKS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UUID" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UUID_SHORT" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UNCOMPRESS" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "UNCOMPRESSED_LENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
| "VALIDATE_PASSWORD_STRENGTH" '(' ExpressionListOpt ')'
|
|
{
|
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
|
|
}
|
|
|
|
GetFormatSelector:
|
|
"DATE"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DATETIME"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "TIME"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
|
|
FunctionNameDateArith:
|
|
"DATE_ADD"
|
|
| "DATE_SUB"
|
|
|
|
|
|
FunctionNameDateArithMultiForms:
|
|
"ADDDATE"
|
|
| "SUBDATE"
|
|
|
|
|
|
TrimDirection:
|
|
"BOTH"
|
|
{
|
|
$$ = ast.TrimBoth
|
|
}
|
|
| "LEADING"
|
|
{
|
|
$$ = ast.TrimLeading
|
|
}
|
|
| "TRAILING"
|
|
{
|
|
$$ = ast.TrimTrailing
|
|
}
|
|
|
|
FunctionCallAgg:
|
|
"AVG" '(' DistinctOpt Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
|
}
|
|
| "BIT_XOR" '(' Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
|
}
|
|
| "COUNT" '(' "DISTINCT" ExpressionList ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: $4.([]ast.ExprNode), Distinct: true}
|
|
}
|
|
| "COUNT" '(' "ALL" Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}}
|
|
}
|
|
| "COUNT" '(' Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
|
}
|
|
| "COUNT" '(' '*' ')'
|
|
{
|
|
args := []ast.ExprNode{ast.NewValueExpr(1)}
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: args}
|
|
}
|
|
| "GROUP_CONCAT" '(' DistinctOpt ExpressionList ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: $4.([]ast.ExprNode), Distinct: $3.(bool)}
|
|
}
|
|
| "MAX" '(' DistinctOpt Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
|
}
|
|
| "MIN" '(' DistinctOpt Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
|
}
|
|
| "SUM" '(' DistinctOpt Expression ')'
|
|
{
|
|
$$ = &ast.AggregateFuncExpr{F: $1, Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
|
}
|
|
|
|
FuncDatetimePrec:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| '(' ')'
|
|
{
|
|
$$ = nil
|
|
}
|
|
| '(' Expression ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
TimeUnit:
|
|
"MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "SECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MINUTE"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "HOUR"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "WEEK"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MONTH"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "QUARTER"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "YEAR"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "SECOND_MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MINUTE_MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MINUTE_SECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "HOUR_MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "HOUR_SECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "HOUR_MINUTE"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY_MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY_SECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY_MINUTE"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY_HOUR"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "YEAR_MONTH"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
|
|
TimestampUnit:
|
|
"MICROSECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "SECOND"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MINUTE"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "HOUR"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "DAY"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "WEEK"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "MONTH"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "QUARTER"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
| "YEAR"
|
|
{
|
|
$$ = strings.ToUpper($1)
|
|
}
|
|
|
|
ExpressionOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| Expression
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
WhenClauseList:
|
|
WhenClause
|
|
{
|
|
$$ = []*ast.WhenClause{$1.(*ast.WhenClause)}
|
|
}
|
|
| WhenClauseList WhenClause
|
|
{
|
|
$$ = append($1.([]*ast.WhenClause), $2.(*ast.WhenClause))
|
|
}
|
|
|
|
WhenClause:
|
|
"WHEN" Expression "THEN" Expression
|
|
{
|
|
$$ = &ast.WhenClause{
|
|
Expr: $2.(ast.ExprNode),
|
|
Result: $4.(ast.ExprNode),
|
|
}
|
|
}
|
|
|
|
ElseOpt:
|
|
/* empty */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "ELSE" Expression
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
CastType:
|
|
"BINARY" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Flen = $2.(int)
|
|
x.Charset = charset.CharsetBin
|
|
x.Collate = charset.CharsetBin
|
|
$$ = x
|
|
}
|
|
| "CHAR" OptFieldLen OptBinary OptCharset
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Flen = $2.(int)
|
|
x.Charset = $4.(string)
|
|
$$ = x
|
|
}
|
|
| "DATE"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDate)
|
|
$$ = x
|
|
}
|
|
| "DATETIME" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDatetime)
|
|
x.Decimal = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "DECIMAL" FloatOpt
|
|
{
|
|
fopt := $2.(*ast.FloatOpt)
|
|
x := types.NewFieldType(mysql.TypeNewDecimal)
|
|
x.Flen = fopt.Flen
|
|
x.Decimal = fopt.Decimal
|
|
if fopt.Flen == types.UnspecifiedLength {
|
|
x.Flen = mysql.GetDefaultFieldLength(mysql.TypeNewDecimal)
|
|
x.Decimal = mysql.GetDefaultDecimal(mysql.TypeNewDecimal)
|
|
}
|
|
$$ = x
|
|
}
|
|
| "TIME" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDuration)
|
|
x.Decimal = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "SIGNED" OptInteger
|
|
{
|
|
x := types.NewFieldType(mysql.TypeLonglong)
|
|
$$ = x
|
|
}
|
|
| "UNSIGNED" OptInteger
|
|
{
|
|
x := types.NewFieldType(mysql.TypeLonglong)
|
|
x.Flag |= mysql.UnsignedFlag
|
|
$$ = x
|
|
}
|
|
|
|
|
|
PrimaryFactor:
|
|
PrimaryFactor '|' PrimaryFactor %prec '|'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Or, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '&' PrimaryFactor %prec '&'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.And, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor "<<" PrimaryFactor %prec lsh
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.LeftShift, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor ">>" PrimaryFactor %prec rsh
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.RightShift, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '+' PrimaryFactor %prec '+'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Plus, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '-' PrimaryFactor %prec '-'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Minus, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '*' PrimaryFactor %prec '*'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Mul, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '/' PrimaryFactor %prec '/'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Div, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '%' PrimaryFactor %prec '%'
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Mod, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor "DIV" PrimaryFactor %prec div
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.IntDiv, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor "MOD" PrimaryFactor %prec mod
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Mod, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryFactor '^' PrimaryFactor
|
|
{
|
|
$$ = &ast.BinaryOperationExpr{Op: opcode.Xor, L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
|
}
|
|
| PrimaryExpression
|
|
|
|
|
|
Priority:
|
|
{
|
|
$$ = ast.NoPriority
|
|
}
|
|
| "LOW_PRIORITY"
|
|
{
|
|
$$ = ast.LowPriority
|
|
}
|
|
| "HIGH_PRIORITY"
|
|
{
|
|
$$ = ast.HighPriority
|
|
}
|
|
| "DELAYED"
|
|
{
|
|
$$ = ast.DelayedPriority
|
|
}
|
|
|
|
LowPriorityOptional:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "LOW_PRIORITY"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
TableName:
|
|
Identifier
|
|
{
|
|
$$ = &ast.TableName{Name:model.NewCIStr($1)}
|
|
}
|
|
| IdentifierOrReservedKeyword '.' IdentifierOrReservedKeyword
|
|
{
|
|
$$ = &ast.TableName{Schema:model.NewCIStr($1), Name:model.NewCIStr($3)}
|
|
}
|
|
|
|
TableNameList:
|
|
TableName
|
|
{
|
|
tbl := []*ast.TableName{$1.(*ast.TableName)}
|
|
$$ = tbl
|
|
}
|
|
| TableNameList ',' TableName
|
|
{
|
|
$$ = append($1.([]*ast.TableName), $3.(*ast.TableName))
|
|
}
|
|
|
|
QuickOptional:
|
|
%prec lowerThanQuick
|
|
{
|
|
$$ = false
|
|
}
|
|
| "QUICK"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
/***************************Prepared Statement Start******************************
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/prepare.html
|
|
* Example:
|
|
* PREPARE stmt_name FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
|
|
* OR
|
|
* SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
|
|
* PREPARE stmt_name FROM @s;
|
|
*/
|
|
|
|
PreparedStmt:
|
|
"PREPARE" Identifier "FROM" PrepareSQL
|
|
{
|
|
var sqlText string
|
|
var sqlVar *ast.VariableExpr
|
|
switch $4.(type) {
|
|
case string:
|
|
sqlText = $4.(string)
|
|
case *ast.VariableExpr:
|
|
sqlVar = $4.(*ast.VariableExpr)
|
|
}
|
|
$$ = &ast.PrepareStmt{
|
|
Name: $2,
|
|
SQLText: sqlText,
|
|
SQLVar: sqlVar,
|
|
}
|
|
}
|
|
|
|
PrepareSQL:
|
|
stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
| UserVariable
|
|
|
|
|
|
/*
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/execute.html
|
|
* Example:
|
|
* EXECUTE stmt1 USING @a, @b;
|
|
* OR
|
|
* EXECUTE stmt1;
|
|
*/
|
|
ExecuteStmt:
|
|
"EXECUTE" Identifier
|
|
{
|
|
$$ = &ast.ExecuteStmt{Name: $2}
|
|
}
|
|
| "EXECUTE" Identifier "USING" UserVariableList
|
|
{
|
|
$$ = &ast.ExecuteStmt{
|
|
Name: $2,
|
|
UsingVars: $4.([]ast.ExprNode),
|
|
}
|
|
}
|
|
|
|
UserVariableList:
|
|
UserVariable
|
|
{
|
|
$$ = []ast.ExprNode{$1.(ast.ExprNode)}
|
|
}
|
|
| UserVariableList ',' UserVariable
|
|
{
|
|
$$ = append($1.([]ast.ExprNode), $3.(ast.ExprNode))
|
|
}
|
|
|
|
/*
|
|
* See https://dev.mysql.com/doc/refman/5.0/en/deallocate-prepare.html
|
|
*/
|
|
|
|
DeallocateStmt:
|
|
DeallocateSym "PREPARE" Identifier
|
|
{
|
|
$$ = &ast.DeallocateStmt{Name: $3}
|
|
}
|
|
|
|
DeallocateSym:
|
|
"DEALLOCATE" | "DROP"
|
|
|
|
/****************************Prepared Statement End*******************************/
|
|
|
|
|
|
RollbackStmt:
|
|
"ROLLBACK"
|
|
{
|
|
$$ = &ast.RollbackStmt{}
|
|
}
|
|
|
|
SelectStmt:
|
|
"SELECT" SelectStmtOpts SelectStmtFieldList SelectStmtLimit SelectLockOpt
|
|
{
|
|
st := &ast.SelectStmt {
|
|
Distinct: $2.(*ast.SelectStmtOpts).Distinct,
|
|
Fields: $3.(*ast.FieldList),
|
|
LockTp: $5.(ast.SelectLockType),
|
|
}
|
|
lastField := st.Fields.Fields[len(st.Fields.Fields)-1]
|
|
if lastField.Expr != nil && lastField.AsName.O == "" {
|
|
src := parser.src
|
|
var lastEnd int
|
|
if $4 != nil {
|
|
lastEnd = yyS[yypt-1].offset-1
|
|
} else if $5 != ast.SelectLockNone {
|
|
lastEnd = yyS[yypt].offset-1
|
|
} else {
|
|
lastEnd = len(src)
|
|
if src[lastEnd-1] == ';' {
|
|
lastEnd--
|
|
}
|
|
}
|
|
lastField.SetText(src[lastField.Offset:lastEnd])
|
|
}
|
|
if $4 != nil {
|
|
st.Limit = $4.(*ast.Limit)
|
|
}
|
|
$$ = st
|
|
}
|
|
| "SELECT" SelectStmtOpts SelectStmtFieldList FromDual WhereClauseOptional SelectStmtLimit SelectLockOpt
|
|
{
|
|
st := &ast.SelectStmt {
|
|
Distinct: $2.(*ast.SelectStmtOpts).Distinct,
|
|
Fields: $3.(*ast.FieldList),
|
|
LockTp: $7.(ast.SelectLockType),
|
|
}
|
|
lastField := st.Fields.Fields[len(st.Fields.Fields)-1]
|
|
if lastField.Expr != nil && lastField.AsName.O == "" {
|
|
lastEnd := yyS[yypt-3].offset-1
|
|
lastField.SetText(parser.src[lastField.Offset:lastEnd])
|
|
}
|
|
if $5 != nil {
|
|
st.Where = $5.(ast.ExprNode)
|
|
}
|
|
if $6 != nil {
|
|
st.Limit = $6.(*ast.Limit)
|
|
}
|
|
$$ = st
|
|
}
|
|
| "SELECT" SelectStmtOpts SelectStmtFieldList "FROM"
|
|
TableRefsClause WhereClauseOptional SelectStmtGroup HavingClause OrderByOptional
|
|
SelectStmtLimit SelectLockOpt
|
|
{
|
|
opts := $2.(*ast.SelectStmtOpts)
|
|
st := &ast.SelectStmt{
|
|
Distinct: opts.Distinct,
|
|
Fields: $3.(*ast.FieldList),
|
|
From: $5.(*ast.TableRefsClause),
|
|
LockTp: $11.(ast.SelectLockType),
|
|
}
|
|
if opts.TableHints != nil {
|
|
st.TableHints = opts.TableHints
|
|
}
|
|
|
|
lastField := st.Fields.Fields[len(st.Fields.Fields)-1]
|
|
if lastField.Expr != nil && lastField.AsName.O == "" {
|
|
lastEnd := parser.endOffset(&yyS[yypt-7])
|
|
lastField.SetText(parser.src[lastField.Offset:lastEnd])
|
|
}
|
|
|
|
if $6 != nil {
|
|
st.Where = $6.(ast.ExprNode)
|
|
}
|
|
|
|
if $7 != nil {
|
|
st.GroupBy = $7.(*ast.GroupByClause)
|
|
}
|
|
|
|
if $8 != nil {
|
|
st.Having = $8.(*ast.HavingClause)
|
|
}
|
|
|
|
if $9 != nil {
|
|
st.OrderBy = $9.(*ast.OrderByClause)
|
|
}
|
|
|
|
if $10 != nil {
|
|
st.Limit = $10.(*ast.Limit)
|
|
}
|
|
|
|
$$ = st
|
|
}
|
|
|
|
FromDual:
|
|
"FROM" "DUAL"
|
|
|
|
|
|
TableRefsClause:
|
|
TableRefs
|
|
{
|
|
$$ = &ast.TableRefsClause{TableRefs: $1.(*ast.Join)}
|
|
}
|
|
|
|
TableRefs:
|
|
EscapedTableRef
|
|
{
|
|
if j, ok := $1.(*ast.Join); ok {
|
|
// if $1 is Join, use it directly
|
|
$$ = j
|
|
} else {
|
|
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: nil}
|
|
}
|
|
}
|
|
| TableRefs ',' EscapedTableRef
|
|
{
|
|
/* from a, b is default cross join */
|
|
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
|
|
}
|
|
|
|
EscapedTableRef:
|
|
TableRef %prec lowerThanSetKeyword
|
|
{
|
|
$$ = $1
|
|
}
|
|
| '{' Identifier TableRef '}'
|
|
{
|
|
/*
|
|
* ODBC escape syntax for outer join is { OJ join_table }
|
|
* Use an Identifier for OJ
|
|
*/
|
|
$$ = $3
|
|
}
|
|
|
|
TableRef:
|
|
TableFactor
|
|
{
|
|
$$ = $1
|
|
}
|
|
| JoinTable
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
TableFactor:
|
|
TableName TableAsNameOpt IndexHintListOpt
|
|
{
|
|
tn := $1.(*ast.TableName)
|
|
tn.IndexHints = $3.([]*ast.IndexHint)
|
|
$$ = &ast.TableSource{Source: tn, AsName: $2.(model.CIStr)}
|
|
}
|
|
| '(' SelectStmt ')' TableAsName
|
|
{
|
|
st := $2.(*ast.SelectStmt)
|
|
endOffset := parser.endOffset(&yyS[yypt-1])
|
|
parser.setLastSelectFieldText(st, endOffset)
|
|
$$ = &ast.TableSource{Source: $2.(*ast.SelectStmt), AsName: $4.(model.CIStr)}
|
|
}
|
|
| '(' UnionStmt ')' TableAsName
|
|
{
|
|
$$ = &ast.TableSource{Source: $2.(*ast.UnionStmt), AsName: $4.(model.CIStr)}
|
|
}
|
|
| '(' TableRefs ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
TableAsNameOpt:
|
|
{
|
|
$$ = model.CIStr{}
|
|
}
|
|
| TableAsName
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
TableAsName:
|
|
Identifier
|
|
{
|
|
$$ = model.NewCIStr($1)
|
|
}
|
|
| "AS" Identifier
|
|
{
|
|
$$ = model.NewCIStr($2)
|
|
}
|
|
|
|
IndexHintType:
|
|
"USE" KeyOrIndex
|
|
{
|
|
$$ = ast.HintUse
|
|
}
|
|
| "IGNORE" KeyOrIndex
|
|
{
|
|
$$ = ast.HintIgnore
|
|
}
|
|
| "FORCE" KeyOrIndex
|
|
{
|
|
$$ = ast.HintForce
|
|
}
|
|
|
|
IndexHintScope:
|
|
{
|
|
$$ = ast.HintForScan
|
|
}
|
|
| "FOR" "JOIN"
|
|
{
|
|
$$ = ast.HintForJoin
|
|
}
|
|
| "FOR" "ORDER" "BY"
|
|
{
|
|
$$ = ast.HintForOrderBy
|
|
}
|
|
| "FOR" "GROUP" "BY"
|
|
{
|
|
$$ = ast.HintForGroupBy
|
|
}
|
|
|
|
|
|
IndexHint:
|
|
IndexHintType IndexHintScope '(' IndexNameList ')'
|
|
{
|
|
$$ = &ast.IndexHint{
|
|
IndexNames: $4.([]model.CIStr),
|
|
HintType: $1.(ast.IndexHintType),
|
|
HintScope: $2.(ast.IndexHintScope),
|
|
}
|
|
}
|
|
|
|
IndexNameList:
|
|
{
|
|
var nameList []model.CIStr
|
|
$$ = nameList
|
|
}
|
|
| Identifier
|
|
{
|
|
$$ = []model.CIStr{model.NewCIStr($1)}
|
|
}
|
|
| IndexNameList ',' Identifier
|
|
{
|
|
$$ = append($1.([]model.CIStr), model.NewCIStr($3))
|
|
}
|
|
|
|
|
|
IndexHintList:
|
|
IndexHint
|
|
{
|
|
$$ = []*ast.IndexHint{$1.(*ast.IndexHint)}
|
|
}
|
|
| IndexHintList IndexHint
|
|
{
|
|
$$ = append($1.([]*ast.IndexHint), $2.(*ast.IndexHint))
|
|
}
|
|
|
|
IndexHintListOpt:
|
|
{
|
|
var hintList []*ast.IndexHint
|
|
$$ = hintList
|
|
}
|
|
| IndexHintList
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
JoinTable:
|
|
/* Use %prec to evaluate production TableRef before cross join */
|
|
TableRef CrossOpt TableRef %prec tableRefPriority
|
|
{
|
|
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin}
|
|
}
|
|
| TableRef CrossOpt TableRef "ON" Expression
|
|
{
|
|
on := &ast.OnCondition{Expr: $5.(ast.ExprNode)}
|
|
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $3.(ast.ResultSetNode), Tp: ast.CrossJoin, On: on}
|
|
}
|
|
| TableRef JoinType OuterOpt "JOIN" TableRef "ON" Expression
|
|
{
|
|
on := &ast.OnCondition{Expr: $7.(ast.ExprNode)}
|
|
$$ = &ast.Join{Left: $1.(ast.ResultSetNode), Right: $5.(ast.ResultSetNode), Tp: $2.(ast.JoinType), On: on}
|
|
}
|
|
/* Support Using */
|
|
|
|
JoinType:
|
|
"LEFT"
|
|
{
|
|
$$ = ast.LeftJoin
|
|
}
|
|
| "RIGHT"
|
|
{
|
|
$$ = ast.RightJoin
|
|
}
|
|
|
|
OuterOpt:
|
|
{}
|
|
| "OUTER"
|
|
|
|
CrossOpt:
|
|
"JOIN"
|
|
| "CROSS" "JOIN"
|
|
| "INNER" "JOIN"
|
|
|
|
LimitClause:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LIMIT" LimitOption
|
|
{
|
|
$$ = &ast.Limit{Count: $2.(ast.ExprNode)}
|
|
}
|
|
|
|
LimitOption:
|
|
LengthNum
|
|
{
|
|
$$ = ast.NewValueExpr($1)
|
|
}
|
|
| "PLACEHOLDER"
|
|
{
|
|
$$ = &ast.ParamMarkerExpr{
|
|
Offset: yyS[yypt].offset,
|
|
}
|
|
}
|
|
|
|
SelectStmtLimit:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LIMIT" LimitOption
|
|
{
|
|
$$ = &ast.Limit{Count: $2.(ast.ExprNode)}
|
|
}
|
|
| "LIMIT" LimitOption ',' LimitOption
|
|
{
|
|
$$ = &ast.Limit{Offset: $2.(ast.ExprNode), Count: $4.(ast.ExprNode)}
|
|
}
|
|
| "LIMIT" LimitOption "OFFSET" LimitOption
|
|
{
|
|
$$ = &ast.Limit{Offset: $4.(ast.ExprNode), Count: $2.(ast.ExprNode)}
|
|
}
|
|
|
|
SelectStmtDistinct:
|
|
/* EMPTY */
|
|
{
|
|
$$ = false
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
SelectStmtOpts:
|
|
TableOptimizerHints SelectStmtDistinct SelectStmtSQLCache SelectStmtCalcFoundRows
|
|
{
|
|
opt := &ast.SelectStmtOpts{}
|
|
if $1 != nil {
|
|
opt.TableHints = $1.([]*ast.TableOptimizerHint)
|
|
}
|
|
if $2 != nil {
|
|
opt.Distinct = $2.(bool)
|
|
}
|
|
if $3 != nil {
|
|
opt.SQLCache = $3.(bool)
|
|
}
|
|
if $4 != nil {
|
|
opt.CalcFoundRows = $4.(bool)
|
|
}
|
|
|
|
$$ = opt
|
|
}
|
|
|
|
TableOptimizerHints:
|
|
/* empty */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| hintBegin TableOptimizerHintList hintEnd
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
HintTableList:
|
|
Identifier
|
|
{
|
|
$$ = []model.CIStr{model.NewCIStr($1)}
|
|
}
|
|
| HintTableList ',' Identifier
|
|
{
|
|
$$ = append($1.([]model.CIStr), model.NewCIStr($3))
|
|
}
|
|
|
|
TableOptimizerHintList:
|
|
TableOptimizerHintOpt
|
|
{
|
|
$$ = []*ast.TableOptimizerHint{$1.(*ast.TableOptimizerHint)}
|
|
}
|
|
| TableOptimizerHintList TableOptimizerHintOpt
|
|
{
|
|
$$ = append($1.([]*ast.TableOptimizerHint), $2.(*ast.TableOptimizerHint))
|
|
}
|
|
|
|
TableOptimizerHintOpt:
|
|
tidbSMJ '(' HintTableList ')'
|
|
{
|
|
$$ = &ast.TableOptimizerHint{HintName: model.NewCIStr($1), Tables: $3.([]model.CIStr)}
|
|
}
|
|
| tidbINLJ '(' HintTableList ')'
|
|
{
|
|
$$ = &ast.TableOptimizerHint{HintName: model.NewCIStr($1), Tables: $3.([]model.CIStr)}
|
|
}
|
|
|
|
SelectStmtCalcFoundRows:
|
|
%prec lowerThanCalcFoundRows
|
|
{
|
|
$$ = false
|
|
}
|
|
| "SQL_CALC_FOUND_ROWS"
|
|
{
|
|
$$ = true
|
|
}
|
|
SelectStmtSQLCache:
|
|
%prec lowerThanSQLCache
|
|
{
|
|
$$ = false
|
|
}
|
|
| "SQL_CACHE"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "SQL_NO_CACHE"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
SelectStmtFieldList:
|
|
FieldList
|
|
{
|
|
$$ = &ast.FieldList{Fields: $1.([]*ast.SelectField)}
|
|
}
|
|
|
|
SelectStmtGroup:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| GroupByClause
|
|
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/subqueries.html
|
|
SubSelect:
|
|
'(' SelectStmt ')'
|
|
{
|
|
s := $2.(*ast.SelectStmt)
|
|
endOffset := parser.endOffset(&yyS[yypt])
|
|
parser.setLastSelectFieldText(s, endOffset)
|
|
src := parser.src
|
|
// See the implementation of yyParse function
|
|
s.SetText(src[yyS[yypt-1].offset-1:yyS[yypt].offset-1])
|
|
$$ = &ast.SubqueryExpr{Query: s}
|
|
}
|
|
| '(' UnionStmt ')'
|
|
{
|
|
s := $2.(*ast.UnionStmt)
|
|
src := parser.src
|
|
// See the implementation of yyParse function
|
|
s.SetText(src[yyS[yypt-1].offset-1:yyS[yypt].offset-1])
|
|
$$ = &ast.SubqueryExpr{Query: s}
|
|
}
|
|
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
|
|
SelectLockOpt:
|
|
/* empty */
|
|
{
|
|
$$ = ast.SelectLockNone
|
|
}
|
|
| "FOR" "UPDATE"
|
|
{
|
|
$$ = ast.SelectLockForUpdate
|
|
}
|
|
| "LOCK" "IN" "SHARE" "MODE"
|
|
{
|
|
$$ = ast.SelectLockInShareMode
|
|
}
|
|
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/union.html
|
|
UnionStmt:
|
|
UnionClauseList "UNION" UnionOpt SelectStmt
|
|
{
|
|
union := $1.(*ast.UnionStmt)
|
|
union.Distinct = union.Distinct || $3.(bool)
|
|
lastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]
|
|
endOffset := parser.endOffset(&yyS[yypt-2])
|
|
parser.setLastSelectFieldText(lastSelect, endOffset)
|
|
union.SelectList.Selects = append(union.SelectList.Selects, $4.(*ast.SelectStmt))
|
|
$$ = union
|
|
}
|
|
| UnionClauseList "UNION" UnionOpt '(' SelectStmt ')' OrderByOptional SelectStmtLimit
|
|
{
|
|
union := $1.(*ast.UnionStmt)
|
|
union.Distinct = union.Distinct || $3.(bool)
|
|
lastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]
|
|
endOffset := parser.endOffset(&yyS[yypt-6])
|
|
parser.setLastSelectFieldText(lastSelect, endOffset)
|
|
st := $5.(*ast.SelectStmt)
|
|
endOffset = parser.endOffset(&yyS[yypt-2])
|
|
parser.setLastSelectFieldText(st, endOffset)
|
|
union.SelectList.Selects = append(union.SelectList.Selects, st)
|
|
if $7 != nil {
|
|
union.OrderBy = $7.(*ast.OrderByClause)
|
|
}
|
|
if $8 != nil {
|
|
union.Limit = $8.(*ast.Limit)
|
|
}
|
|
$$ = union
|
|
}
|
|
|
|
UnionClauseList:
|
|
UnionSelect
|
|
{
|
|
selectList := &ast.UnionSelectList{Selects: []*ast.SelectStmt{$1.(*ast.SelectStmt)}}
|
|
$$ = &ast.UnionStmt{
|
|
SelectList: selectList,
|
|
}
|
|
}
|
|
| UnionClauseList "UNION" UnionOpt UnionSelect
|
|
{
|
|
union := $1.(*ast.UnionStmt)
|
|
union.Distinct = union.Distinct || $3.(bool)
|
|
lastSelect := union.SelectList.Selects[len(union.SelectList.Selects)-1]
|
|
endOffset := parser.endOffset(&yyS[yypt-2])
|
|
parser.setLastSelectFieldText(lastSelect, endOffset)
|
|
union.SelectList.Selects = append(union.SelectList.Selects, $4.(*ast.SelectStmt))
|
|
$$ = union
|
|
}
|
|
|
|
UnionSelect:
|
|
SelectStmt
|
|
| '(' SelectStmt ')'
|
|
{
|
|
st := $2.(*ast.SelectStmt)
|
|
endOffset := parser.endOffset(&yyS[yypt])
|
|
parser.setLastSelectFieldText(st, endOffset)
|
|
$$ = st
|
|
}
|
|
|
|
UnionOpt:
|
|
{
|
|
$$ = true
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
|
|
/********************Set Statement*******************************/
|
|
SetStmt:
|
|
"SET" VariableAssignmentList
|
|
{
|
|
$$ = &ast.SetStmt{Variables: $2.([]*ast.VariableAssignment)}
|
|
}
|
|
| "SET" "PASSWORD" eq PasswordOpt
|
|
{
|
|
$$ = &ast.SetPwdStmt{Password: $4.(string)}
|
|
}
|
|
| "SET" "PASSWORD" "FOR" Username eq PasswordOpt
|
|
{
|
|
$$ = &ast.SetPwdStmt{User: $4.(string), Password: $6.(string)}
|
|
}
|
|
| "SET" "GLOBAL" "TRANSACTION" TransactionChars
|
|
{
|
|
// Parsed but ignored
|
|
}
|
|
| "SET" "SESSION" "TRANSACTION" TransactionChars
|
|
{
|
|
// Parsed but ignored
|
|
}
|
|
|
|
TransactionChars:
|
|
TransactionChar
|
|
| TransactionChars ',' TransactionChar
|
|
|
|
TransactionChar:
|
|
"ISOLATION" "LEVEL" IsolationLevel
|
|
| "READ" "WRITE"
|
|
| "READ" "ONLY"
|
|
|
|
IsolationLevel:
|
|
"REPEATABLE" "READ"
|
|
| "READ" "COMMITTED"
|
|
| "READ" "UNCOMMITTED"
|
|
| "SERIALIZABLE"
|
|
|
|
VariableAssignment:
|
|
Identifier eq Expression
|
|
{
|
|
$$ = &ast.VariableAssignment{Name: $1, Value: $3.(ast.ExprNode), IsSystem: true}
|
|
}
|
|
| "GLOBAL" Identifier eq Expression
|
|
{
|
|
$$ = &ast.VariableAssignment{Name: $2, Value: $4.(ast.ExprNode), IsGlobal: true, IsSystem: true}
|
|
}
|
|
| "SESSION" Identifier eq Expression
|
|
{
|
|
$$ = &ast.VariableAssignment{Name: $2, Value: $4.(ast.ExprNode), IsSystem: true}
|
|
}
|
|
| "LOCAL" Identifier eq Expression
|
|
{
|
|
$$ = &ast.VariableAssignment{Name: $2, Value: $4.(ast.ExprNode), IsSystem: true}
|
|
}
|
|
| "SYS_VAR" eq Expression
|
|
{
|
|
v := strings.ToLower($1.(string))
|
|
var isGlobal bool
|
|
if strings.HasPrefix(v, "@@global.") {
|
|
isGlobal = true
|
|
v = strings.TrimPrefix(v, "@@global.")
|
|
} else if strings.HasPrefix(v, "@@session.") {
|
|
v = strings.TrimPrefix(v, "@@session.")
|
|
} else if strings.HasPrefix(v, "@@local.") {
|
|
v = strings.TrimPrefix(v, "@@local.")
|
|
} else if strings.HasPrefix(v, "@@") {
|
|
v = strings.TrimPrefix(v, "@@")
|
|
}
|
|
$$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode), IsGlobal: isGlobal, IsSystem: true}
|
|
}
|
|
| "USER_VAR" eq Expression
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode)}
|
|
}
|
|
| "USER_VAR" assignmentEq Expression
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &ast.VariableAssignment{Name: v, Value: $3.(ast.ExprNode)}
|
|
}
|
|
| "NAMES" CharsetName
|
|
{
|
|
$$ = &ast.VariableAssignment{
|
|
Name: ast.SetNames,
|
|
Value: ast.NewValueExpr($2.(string)),
|
|
}
|
|
}
|
|
| "NAMES" CharsetName "COLLATE" StringName
|
|
{
|
|
$$ = &ast.VariableAssignment{
|
|
Name: ast.SetNames,
|
|
Value: ast.NewValueExpr($2.(string)),
|
|
ExtendValue: ast.NewValueExpr($4.(string)),
|
|
}
|
|
}
|
|
| CharsetKw CharsetName
|
|
{
|
|
$$ = &ast.VariableAssignment{
|
|
Name: ast.SetNames,
|
|
Value: ast.NewValueExpr($2.(string)),
|
|
}
|
|
}
|
|
|
|
CharsetName:
|
|
StringName
|
|
{
|
|
$$ = $1
|
|
}
|
|
| binaryType
|
|
{
|
|
$$ = charset.CharsetBin
|
|
}
|
|
|
|
VariableAssignmentList:
|
|
{
|
|
$$ = []*ast.VariableAssignment{}
|
|
}
|
|
| VariableAssignment
|
|
{
|
|
$$ = []*ast.VariableAssignment{$1.(*ast.VariableAssignment)}
|
|
}
|
|
| VariableAssignmentList ',' VariableAssignment
|
|
{
|
|
$$ = append($1.([]*ast.VariableAssignment), $3.(*ast.VariableAssignment))
|
|
}
|
|
|
|
Variable:
|
|
SystemVariable | UserVariable
|
|
|
|
SystemVariable:
|
|
"SYS_VAR"
|
|
{
|
|
v := strings.ToLower($1.(string))
|
|
var isGlobal bool
|
|
if strings.HasPrefix(v, "@@global.") {
|
|
isGlobal = true
|
|
v = strings.TrimPrefix(v, "@@global.")
|
|
} else if strings.HasPrefix(v, "@@session.") {
|
|
v = strings.TrimPrefix(v, "@@session.")
|
|
} else if strings.HasPrefix(v, "@@local.") {
|
|
v = strings.TrimPrefix(v, "@@local.")
|
|
} else if strings.HasPrefix(v, "@@") {
|
|
v = strings.TrimPrefix(v, "@@")
|
|
}
|
|
$$ = &ast.VariableExpr{Name: v, IsGlobal: isGlobal, IsSystem: true}
|
|
}
|
|
|
|
UserVariable:
|
|
"USER_VAR"
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &ast.VariableExpr{Name: v, IsGlobal: false, IsSystem: false}
|
|
}
|
|
|
|
Username:
|
|
stringLit
|
|
{
|
|
$$ = $1 + "@%"
|
|
}
|
|
| stringLit "AT" stringLit
|
|
{
|
|
$$ = $1 + "@" + $3
|
|
}
|
|
|
|
UsernameList:
|
|
Username
|
|
{
|
|
$$ = []string{$1.(string)}
|
|
}
|
|
| UsernameList ',' Username
|
|
|
|
{
|
|
$$ = append($1.([]string), $3.(string))
|
|
}
|
|
|
|
PasswordOpt:
|
|
stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "PASSWORD" '(' AuthString ')'
|
|
{
|
|
$$ = $3.(string)
|
|
}
|
|
|
|
AuthString:
|
|
stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
/****************************Admin Statement*******************************/
|
|
AdminStmt:
|
|
"ADMIN" "SHOW" "DDL"
|
|
{
|
|
$$ = &ast.AdminStmt{Tp: ast.AdminShowDDL}
|
|
}
|
|
| "ADMIN" "CHECK" "TABLE" TableNameList
|
|
{
|
|
$$ = &ast.AdminStmt{
|
|
Tp: ast.AdminCheckTable,
|
|
Tables: $4.([]*ast.TableName),
|
|
}
|
|
}
|
|
|
|
/****************************Show Statement*******************************/
|
|
ShowStmt:
|
|
"SHOW" ShowTargetFilterable ShowLikeOrWhereOpt
|
|
{
|
|
stmt := $2.(*ast.ShowStmt)
|
|
if $3 != nil {
|
|
if x, ok := $3.(*ast.PatternLikeExpr); ok {
|
|
stmt.Pattern = x
|
|
} else {
|
|
stmt.Where = $3.(ast.ExprNode)
|
|
}
|
|
}
|
|
$$ = stmt
|
|
}
|
|
| "SHOW" "CREATE" "TABLE" TableName
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowCreateTable,
|
|
Table: $4.(*ast.TableName),
|
|
}
|
|
}
|
|
| "SHOW" "CREATE" "DATABASE" DBName
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowCreateDatabase,
|
|
DBName: $4.(string),
|
|
}
|
|
}
|
|
| "SHOW" "GRANTS"
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowGrants}
|
|
}
|
|
| "SHOW" "GRANTS" "FOR" Username
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/show-grants.html
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowGrants,
|
|
User: $4.(string),
|
|
}
|
|
}
|
|
| "SHOW" "PROCESSLIST"
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowProcessList,
|
|
}
|
|
}
|
|
|
|
ShowIndexKwd:
|
|
"INDEX"
|
|
| "INDEXES"
|
|
| "KEYS"
|
|
|
|
FromOrIn:
|
|
"FROM" | "IN"
|
|
|
|
ShowTargetFilterable:
|
|
"ENGINES"
|
|
{
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowEngines}
|
|
}
|
|
| "DATABASES"
|
|
{
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowDatabases}
|
|
}
|
|
| "SCHEMAS"
|
|
{
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowDatabases}
|
|
}
|
|
| "CHARACTER" "SET"
|
|
{
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowCharset}
|
|
}
|
|
| OptFull "TABLES" ShowDatabaseNameOpt
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowTables,
|
|
DBName: $3.(string),
|
|
Full: $1.(bool),
|
|
}
|
|
}
|
|
| "TABLE" "STATUS" ShowDatabaseNameOpt
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowTableStatus,
|
|
DBName: $3.(string),
|
|
}
|
|
}
|
|
| ShowIndexKwd FromOrIn TableName
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowIndex,
|
|
Table: $3.(*ast.TableName),
|
|
}
|
|
}
|
|
| ShowIndexKwd FromOrIn Identifier FromOrIn Identifier
|
|
{
|
|
show := &ast.ShowStmt{
|
|
Tp: ast.ShowIndex,
|
|
Table: &ast.TableName{Name:model.NewCIStr($3), Schema: model.NewCIStr($5)},
|
|
}
|
|
$$ = show
|
|
}
|
|
| OptFull "COLUMNS" ShowTableAliasOpt ShowDatabaseNameOpt
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowColumns,
|
|
Table: $3.(*ast.TableName),
|
|
DBName: $4.(string),
|
|
Full: $1.(bool),
|
|
}
|
|
}
|
|
| OptFull "FIELDS" ShowTableAliasOpt ShowDatabaseNameOpt
|
|
{
|
|
// SHOW FIELDS is a synonym for SHOW COLUMNS.
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowColumns,
|
|
Table: $3.(*ast.TableName),
|
|
DBName: $4.(string),
|
|
Full: $1.(bool),
|
|
}
|
|
}
|
|
| "WARNINGS"
|
|
{
|
|
$$ = &ast.ShowStmt{Tp: ast.ShowWarnings}
|
|
}
|
|
| GlobalScope "VARIABLES"
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowVariables,
|
|
GlobalScope: $1.(bool),
|
|
}
|
|
}
|
|
| GlobalScope "STATUS"
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowStatus,
|
|
GlobalScope: $1.(bool),
|
|
}
|
|
}
|
|
| "COLLATION"
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowCollation,
|
|
}
|
|
}
|
|
| "TRIGGERS" ShowDatabaseNameOpt
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowTriggers,
|
|
DBName: $2.(string),
|
|
}
|
|
}
|
|
| "PROCEDURE" "STATUS"
|
|
{
|
|
$$ = &ast.ShowStmt {
|
|
Tp: ast.ShowProcedureStatus,
|
|
}
|
|
}
|
|
| "FUNCTION" "STATUS"
|
|
{
|
|
// This statement is similar to SHOW PROCEDURE STATUS but for stored functions.
|
|
// See http://dev.mysql.com/doc/refman/5.7/en/show-function-status.html
|
|
// We do not support neither stored functions nor stored procedures.
|
|
// So we reuse show procedure status process logic.
|
|
$$ = &ast.ShowStmt {
|
|
Tp: ast.ShowProcedureStatus,
|
|
}
|
|
}
|
|
| "EVENTS" ShowDatabaseNameOpt
|
|
{
|
|
$$ = &ast.ShowStmt{
|
|
Tp: ast.ShowEvents,
|
|
DBName: $2.(string),
|
|
}
|
|
}
|
|
ShowLikeOrWhereOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LIKE" PrimaryExpression
|
|
{
|
|
$$ = &ast.PatternLikeExpr{
|
|
Pattern: $2.(ast.ExprNode),
|
|
Escape: '\\',
|
|
}
|
|
}
|
|
| "WHERE" Expression
|
|
{
|
|
$$ = $2.(ast.ExprNode)
|
|
}
|
|
|
|
GlobalScope:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "GLOBAL"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "SESSION"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
OptFull:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "FULL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
ShowDatabaseNameOpt:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "FROM" DBName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
| "IN" DBName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
ShowTableAliasOpt:
|
|
"FROM" TableName
|
|
{
|
|
$$ = $2.(*ast.TableName)
|
|
}
|
|
| "IN" TableName
|
|
{
|
|
$$ = $2.(*ast.TableName)
|
|
}
|
|
|
|
FlushStmt:
|
|
"FLUSH" NoWriteToBinLogAliasOpt FlushOption
|
|
{
|
|
tmp := $3.(*ast.FlushStmt)
|
|
tmp.NoWriteToBinLog = $2.(bool)
|
|
$$ = tmp
|
|
}
|
|
|
|
FlushOption:
|
|
"PRIVILEGES"
|
|
{
|
|
$$ = &ast.FlushStmt{
|
|
Tp: ast.FlushPrivileges,
|
|
}
|
|
}
|
|
| TableOrTables TableNameListOpt WithReadLockOpt
|
|
{
|
|
$$ = &ast.FlushStmt{
|
|
Tp: ast.FlushTables,
|
|
Tables: $2.([]*ast.TableName),
|
|
ReadLock: $3.(bool),
|
|
}
|
|
}
|
|
|
|
NoWriteToBinLogAliasOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "NO_WRITE_TO_BINLOG"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "LOCAL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
TableNameListOpt:
|
|
{
|
|
$$ = []*ast.TableName{}
|
|
}
|
|
| TableNameList
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
WithReadLockOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "WITH" "READ" "LOCK"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
Statement:
|
|
EmptyStmt
|
|
| AdminStmt
|
|
| AlterTableStmt
|
|
| AlterUserStmt
|
|
| AnalyzeTableStmt
|
|
| BeginTransactionStmt
|
|
| BinlogStmt
|
|
| CommitStmt
|
|
| DeallocateStmt
|
|
| DeleteFromStmt
|
|
| ExecuteStmt
|
|
| ExplainStmt
|
|
| CreateDatabaseStmt
|
|
| CreateIndexStmt
|
|
| CreateTableStmt
|
|
| CreateUserStmt
|
|
| DoStmt
|
|
| DropDatabaseStmt
|
|
| DropIndexStmt
|
|
| DropTableStmt
|
|
| DropViewStmt
|
|
| DropUserStmt
|
|
| FlushStmt
|
|
| GrantStmt
|
|
| InsertIntoStmt
|
|
| KillStmt
|
|
| LoadDataStmt
|
|
| PreparedStmt
|
|
| RollbackStmt
|
|
| RenameTableStmt
|
|
| ReplaceIntoStmt
|
|
| RevokeStmt
|
|
| SelectStmt
|
|
| UnionStmt
|
|
| SetStmt
|
|
| ShowStmt
|
|
| TruncateTableStmt
|
|
| UpdateStmt
|
|
| UseStmt
|
|
| SubSelect
|
|
{
|
|
// `(select 1)`; is a valid select statement
|
|
// TODO: This is used to fix issue #320. There may be a better solution.
|
|
$$ = $1.(*ast.SubqueryExpr).Query
|
|
}
|
|
| UnlockTablesStmt
|
|
| LockTablesStmt
|
|
|
|
ExplainableStmt:
|
|
SelectStmt
|
|
| DeleteFromStmt
|
|
| UpdateStmt
|
|
| InsertIntoStmt
|
|
| ReplaceIntoStmt
|
|
| UnionStmt
|
|
|
|
StatementList:
|
|
Statement
|
|
{
|
|
if $1 != nil {
|
|
s := $1.(ast.StmtNode)
|
|
if lexer, ok := yylex.(stmtTexter); ok {
|
|
s.SetText(lexer.stmtText())
|
|
}
|
|
parser.result = append(parser.result, s)
|
|
}
|
|
}
|
|
| StatementList ';' Statement
|
|
{
|
|
if $3 != nil {
|
|
s := $3.(ast.StmtNode)
|
|
if lexer, ok := yylex.(stmtTexter); ok {
|
|
s.SetText(lexer.stmtText())
|
|
}
|
|
parser.result = append(parser.result, s)
|
|
}
|
|
}
|
|
|
|
Constraint:
|
|
ConstraintKeywordOpt ConstraintElem
|
|
{
|
|
cst := $2.(*ast.Constraint)
|
|
if $1 != nil {
|
|
cst.Name = $1.(string)
|
|
}
|
|
$$ = cst
|
|
}
|
|
|
|
TableElement:
|
|
ColumnDef
|
|
{
|
|
$$ = $1.(*ast.ColumnDef)
|
|
}
|
|
| Constraint
|
|
{
|
|
$$ = $1.(*ast.Constraint)
|
|
}
|
|
| "CHECK" '(' Expression ')'
|
|
{
|
|
/* Nothing to do now */
|
|
$$ = nil
|
|
}
|
|
|
|
TableElementList:
|
|
TableElement
|
|
{
|
|
if $1 != nil {
|
|
$$ = []interface{}{$1.(interface{})}
|
|
} else {
|
|
$$ = []interface{}{}
|
|
}
|
|
}
|
|
| TableElementList ',' TableElement
|
|
{
|
|
if $3 != nil {
|
|
$$ = append($1.([]interface{}), $3)
|
|
} else {
|
|
$$ = $1
|
|
}
|
|
}
|
|
|
|
TableOption:
|
|
"ENGINE" Identifier
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: $2}
|
|
}
|
|
| "ENGINE" eq Identifier
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: $3}
|
|
}
|
|
| DefaultKwdOpt CharsetKw EqOpt CharsetName
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionCharset, StrValue: $4.(string)}
|
|
}
|
|
| DefaultKwdOpt "COLLATE" EqOpt StringName
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionCollate, StrValue: $4.(string)}
|
|
}
|
|
| "AUTO_INCREMENT" eq LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionAutoIncrement, UintValue: $3.(uint64)}
|
|
}
|
|
| "COMMENT" EqOpt stringLit
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionComment, StrValue: $3}
|
|
}
|
|
| "AVG_ROW_LENGTH" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionAvgRowLength, UintValue: $3.(uint64)}
|
|
}
|
|
| "CONNECTION" EqOpt stringLit
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionConnection, StrValue: $3}
|
|
}
|
|
| "CHECKSUM" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionCheckSum, UintValue: $3.(uint64)}
|
|
}
|
|
| "PASSWORD" EqOpt stringLit
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionPassword, StrValue: $3}
|
|
}
|
|
| "COMPRESSION" EqOpt Identifier
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionCompression, StrValue: $3}
|
|
}
|
|
| "KEY_BLOCK_SIZE" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionKeyBlockSize, UintValue: $3.(uint64)}
|
|
}
|
|
| "MAX_ROWS" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionMaxRows, UintValue: $3.(uint64)}
|
|
}
|
|
| "MIN_ROWS" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionMinRows, UintValue: $3.(uint64)}
|
|
}
|
|
| "DELAY_KEY_WRITE" EqOpt LengthNum
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionDelayKeyWrite, UintValue: $3.(uint64)}
|
|
}
|
|
| RowFormat
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionRowFormat, UintValue: $1.(uint64)}
|
|
}
|
|
| "STATS_PERSISTENT" EqOpt StatsPersistentVal
|
|
{
|
|
$$ = &ast.TableOption{Tp: ast.TableOptionStatsPersistent}
|
|
}
|
|
|
|
StatsPersistentVal:
|
|
"DEFAULT"
|
|
{}
|
|
| LengthNum
|
|
{}
|
|
|
|
TableOptionListOpt:
|
|
{
|
|
$$ = []*ast.TableOption{}
|
|
}
|
|
| TableOptionList %prec lowerThanComma
|
|
|
|
TableOptionList:
|
|
TableOption
|
|
{
|
|
$$ = []*ast.TableOption{$1.(*ast.TableOption)}
|
|
}
|
|
| TableOptionList TableOption
|
|
{
|
|
$$ = append($1.([]*ast.TableOption), $2.(*ast.TableOption))
|
|
}
|
|
| TableOptionList ',' TableOption
|
|
{
|
|
$$ = append($1.([]*ast.TableOption), $3.(*ast.TableOption))
|
|
}
|
|
|
|
OptTable:
|
|
%prec lowestOpt
|
|
{}
|
|
| "TABLE"
|
|
|
|
TruncateTableStmt:
|
|
"TRUNCATE" OptTable TableName
|
|
{
|
|
$$ = &ast.TruncateTableStmt{Table: $3.(*ast.TableName)}
|
|
}
|
|
|
|
RowFormat:
|
|
"ROW_FORMAT" EqOpt "DEFAULT"
|
|
{
|
|
$$ = ast.RowFormatDefault
|
|
}
|
|
| "ROW_FORMAT" EqOpt "DYNAMIC"
|
|
{
|
|
$$ = ast.RowFormatDynamic
|
|
}
|
|
| "ROW_FORMAT" EqOpt "FIXED"
|
|
{
|
|
$$ = ast.RowFormatFixed
|
|
}
|
|
| "ROW_FORMAT" EqOpt "COMPRESSED"
|
|
{
|
|
$$ = ast.RowFormatCompressed
|
|
}
|
|
| "ROW_FORMAT" EqOpt "REDUNDANT"
|
|
{
|
|
$$ = ast.RowFormatRedundant
|
|
}
|
|
| "ROW_FORMAT" EqOpt "COMPACT"
|
|
{
|
|
$$ = ast.RowFormatCompact
|
|
}
|
|
|
|
/*************************************Type Begin***************************************/
|
|
Type:
|
|
NumericType
|
|
{
|
|
$$ = $1
|
|
}
|
|
| StringType
|
|
{
|
|
$$ = $1
|
|
}
|
|
| DateAndTimeType
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
NumericType:
|
|
IntegerType OptFieldLen FieldOpts
|
|
{
|
|
// TODO: check flen 0
|
|
x := types.NewFieldType($1.(byte))
|
|
x.Flen = $2.(int)
|
|
for _, o := range $3.([]*ast.TypeOpt) {
|
|
if o.IsUnsigned {
|
|
x.Flag |= mysql.UnsignedFlag
|
|
}
|
|
if o.IsZerofill {
|
|
x.Flag |= mysql.ZerofillFlag
|
|
}
|
|
}
|
|
$$ = x
|
|
}
|
|
| FixedPointType FloatOpt FieldOpts
|
|
{
|
|
fopt := $2.(*ast.FloatOpt)
|
|
x := types.NewFieldType($1.(byte))
|
|
x.Flen = fopt.Flen
|
|
x.Decimal = fopt.Decimal
|
|
for _, o := range $3.([]*ast.TypeOpt) {
|
|
if o.IsUnsigned {
|
|
x.Flag |= mysql.UnsignedFlag
|
|
}
|
|
if o.IsZerofill {
|
|
x.Flag |= mysql.ZerofillFlag
|
|
}
|
|
}
|
|
$$ = x
|
|
}
|
|
| FloatingPointType FloatOpt FieldOpts
|
|
{
|
|
fopt := $2.(*ast.FloatOpt)
|
|
x := types.NewFieldType($1.(byte))
|
|
x.Flen = fopt.Flen
|
|
if x.Tp == mysql.TypeFloat {
|
|
// Fix issue #312
|
|
if x.Flen > 53 {
|
|
yylex.Errorf("Float len(%d) should not be greater than 53", x.Flen)
|
|
return 1
|
|
}
|
|
if x.Flen > 24 {
|
|
x.Tp = mysql.TypeDouble
|
|
}
|
|
}
|
|
x.Decimal =fopt.Decimal
|
|
for _, o := range $3.([]*ast.TypeOpt) {
|
|
if o.IsUnsigned {
|
|
x.Flag |= mysql.UnsignedFlag
|
|
}
|
|
if o.IsZerofill {
|
|
x.Flag |= mysql.ZerofillFlag
|
|
}
|
|
}
|
|
$$ = x
|
|
}
|
|
| BitValueType OptFieldLen
|
|
{
|
|
x := types.NewFieldType($1.(byte))
|
|
x.Flen = $2.(int)
|
|
if x.Flen == -1 || x.Flen == 0 {
|
|
x.Flen = 1
|
|
} else if x.Flen > 64 {
|
|
yylex.Errorf("invalid field length %d for bit type, must in [1, 64]", x.Flen)
|
|
}
|
|
$$ = x
|
|
}
|
|
|
|
IntegerType:
|
|
"TINYINT"
|
|
{
|
|
$$ = mysql.TypeTiny
|
|
}
|
|
| "SMALLINT"
|
|
{
|
|
$$ = mysql.TypeShort
|
|
}
|
|
| "MEDIUMINT"
|
|
{
|
|
$$ = mysql.TypeInt24
|
|
}
|
|
| "INT"
|
|
{
|
|
$$ = mysql.TypeLong
|
|
}
|
|
| "INTEGER"
|
|
{
|
|
$$ = mysql.TypeLong
|
|
}
|
|
| "BIGINT"
|
|
{
|
|
$$ = mysql.TypeLonglong
|
|
}
|
|
| "BOOL"
|
|
{
|
|
$$ = mysql.TypeTiny
|
|
}
|
|
| "BOOLEAN"
|
|
{
|
|
$$ = mysql.TypeTiny
|
|
}
|
|
|
|
OptInteger:
|
|
{}
|
|
| "INTEGER"
|
|
|
|
FixedPointType:
|
|
"DECIMAL"
|
|
{
|
|
$$ = mysql.TypeNewDecimal
|
|
}
|
|
| "NUMERIC"
|
|
{
|
|
$$ = mysql.TypeNewDecimal
|
|
}
|
|
|
|
FloatingPointType:
|
|
"FLOAT"
|
|
{
|
|
$$ = mysql.TypeFloat
|
|
}
|
|
| "REAL"
|
|
{
|
|
$$ = mysql.TypeDouble
|
|
}
|
|
| "DOUBLE"
|
|
{
|
|
$$ = mysql.TypeDouble
|
|
}
|
|
| "DOUBLE" "PRECISION"
|
|
{
|
|
$$ = mysql.TypeDouble
|
|
}
|
|
|
|
BitValueType:
|
|
"BIT"
|
|
{
|
|
$$ = mysql.TypeBit
|
|
}
|
|
|
|
StringType:
|
|
NationalOpt "CHAR" FieldLen OptBinary OptCharset OptCollate
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Flen = $3.(int)
|
|
x.Charset = $5.(string)
|
|
x.Collate = $6.(string)
|
|
$$ = x
|
|
}
|
|
| NationalOpt "CHAR" OptBinary OptCharset OptCollate
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Charset = $4.(string)
|
|
x.Collate = $5.(string)
|
|
$$ = x
|
|
}
|
|
| NationalOpt "VARCHAR" FieldLen OptBinary OptCharset OptCollate
|
|
{
|
|
x := types.NewFieldType(mysql.TypeVarchar)
|
|
x.Flen = $3.(int)
|
|
x.Charset = $5.(string)
|
|
x.Collate = $6.(string)
|
|
$$ = x
|
|
}
|
|
| "BINARY" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Flen = $2.(int)
|
|
x.Charset = charset.CharsetBin
|
|
x.Collate = charset.CharsetBin
|
|
x.Flag |= mysql.BinaryFlag
|
|
$$ = x
|
|
}
|
|
| "VARBINARY" FieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeVarchar)
|
|
x.Flen = $2.(int)
|
|
x.Charset = charset.CharsetBin
|
|
x.Collate = charset.CharsetBin
|
|
x.Flag |= mysql.BinaryFlag
|
|
$$ = x
|
|
}
|
|
| BlobType
|
|
{
|
|
x := $1.(*types.FieldType)
|
|
x.Charset = charset.CharsetBin
|
|
x.Collate = charset.CharsetBin
|
|
x.Flag |= mysql.BinaryFlag
|
|
$$ = $1.(*types.FieldType)
|
|
}
|
|
| TextType OptBinary OptCharset OptCollate
|
|
{
|
|
x := $1.(*types.FieldType)
|
|
x.Charset = $3.(string)
|
|
x.Collate = $4.(string)
|
|
$$ = x
|
|
}
|
|
| "ENUM" '(' StringList ')' OptCharset OptCollate
|
|
{
|
|
x := types.NewFieldType(mysql.TypeEnum)
|
|
x.Elems = $3.([]string)
|
|
x.Charset = $5.(string)
|
|
x.Collate = $6.(string)
|
|
$$ = x
|
|
}
|
|
| "SET" '(' StringList ')' OptCharset OptCollate
|
|
{
|
|
x := types.NewFieldType(mysql.TypeSet)
|
|
x.Elems = $3.([]string)
|
|
x.Charset = $5.(string)
|
|
x.Collate = $6.(string)
|
|
$$ = x
|
|
}
|
|
|
|
NationalOpt:
|
|
{}
|
|
| "NATIONAL"
|
|
|
|
BlobType:
|
|
"TINYBLOB"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeTinyBlob)
|
|
$$ = x
|
|
}
|
|
| "BLOB" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeBlob)
|
|
x.Flen = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "MEDIUMBLOB"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeMediumBlob)
|
|
$$ = x
|
|
}
|
|
| "LONGBLOB"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeLongBlob)
|
|
$$ = x
|
|
}
|
|
|
|
TextType:
|
|
"TINYTEXT"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeTinyBlob)
|
|
$$ = x
|
|
|
|
}
|
|
| "TEXT" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeBlob)
|
|
x.Flen = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "MEDIUMTEXT"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeMediumBlob)
|
|
$$ = x
|
|
}
|
|
| "LONGTEXT"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeLongBlob)
|
|
$$ = x
|
|
}
|
|
|
|
|
|
DateAndTimeType:
|
|
"DATE"
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDate)
|
|
$$ = x
|
|
}
|
|
| "DATETIME" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDatetime)
|
|
x.Decimal = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "TIMESTAMP" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeTimestamp)
|
|
x.Decimal = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "TIME" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeDuration)
|
|
x.Decimal = $2.(int)
|
|
$$ = x
|
|
}
|
|
| "YEAR" OptFieldLen
|
|
{
|
|
x := types.NewFieldType(mysql.TypeYear)
|
|
x.Flen = $2.(int)
|
|
$$ = x
|
|
}
|
|
|
|
FieldLen:
|
|
'(' LengthNum ')'
|
|
{
|
|
$$ = int($2.(uint64))
|
|
}
|
|
|
|
OptFieldLen:
|
|
{
|
|
/* -1 means unspecified field length*/
|
|
$$ = types.UnspecifiedLength
|
|
}
|
|
| FieldLen
|
|
{
|
|
$$ = $1.(int)
|
|
}
|
|
|
|
FieldOpt:
|
|
"UNSIGNED"
|
|
{
|
|
$$ = &ast.TypeOpt{IsUnsigned: true}
|
|
}
|
|
| "ZEROFILL"
|
|
{
|
|
$$ = &ast.TypeOpt{IsZerofill: true, IsUnsigned: true}
|
|
}
|
|
|
|
FieldOpts:
|
|
{
|
|
$$ = []*ast.TypeOpt{}
|
|
}
|
|
| FieldOpts FieldOpt
|
|
{
|
|
$$ = append($1.([]*ast.TypeOpt), $2.(*ast.TypeOpt))
|
|
}
|
|
|
|
FloatOpt:
|
|
{
|
|
$$ = &ast.FloatOpt{Flen: types.UnspecifiedLength, Decimal: types.UnspecifiedLength}
|
|
}
|
|
| FieldLen
|
|
{
|
|
$$ = &ast.FloatOpt{Flen: $1.(int), Decimal: types.UnspecifiedLength}
|
|
}
|
|
| Precision
|
|
{
|
|
$$ = $1.(*ast.FloatOpt)
|
|
}
|
|
|
|
Precision:
|
|
'(' LengthNum ',' LengthNum ')'
|
|
{
|
|
$$ = &ast.FloatOpt{Flen: int($2.(uint64)), Decimal: int($4.(uint64))}
|
|
}
|
|
|
|
OptBinary:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "BINARY"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
OptCharset:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| CharsetKw CharsetName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
CharsetKw:
|
|
"CHARACTER" "SET"
|
|
| "CHARSET"
|
|
|
|
OptCollate:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "COLLATE" StringName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
StringList:
|
|
stringLit
|
|
{
|
|
$$ = []string{$1}
|
|
}
|
|
| StringList ',' stringLit
|
|
{
|
|
$$ = append($1.([]string), $3)
|
|
}
|
|
|
|
StringName:
|
|
stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
| Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
/***********************************************************************************
|
|
* Update Statement
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/update.html
|
|
***********************************************************************************/
|
|
UpdateStmt:
|
|
"UPDATE" LowPriorityOptional IgnoreOptional TableRef "SET" AssignmentList WhereClauseOptional OrderByOptional LimitClause
|
|
{
|
|
var refs *ast.Join
|
|
if x, ok := $4.(*ast.Join); ok {
|
|
refs = x
|
|
} else {
|
|
refs = &ast.Join{Left: $4.(ast.ResultSetNode)}
|
|
}
|
|
st := &ast.UpdateStmt{
|
|
LowPriority: $2.(bool),
|
|
TableRefs: &ast.TableRefsClause{TableRefs: refs},
|
|
List: $6.([]*ast.Assignment),
|
|
}
|
|
if $7 != nil {
|
|
st.Where = $7.(ast.ExprNode)
|
|
}
|
|
if $8 != nil {
|
|
st.Order = $8.(*ast.OrderByClause)
|
|
}
|
|
if $9 != nil {
|
|
st.Limit = $9.(*ast.Limit)
|
|
}
|
|
$$ = st
|
|
}
|
|
| "UPDATE" LowPriorityOptional IgnoreOptional TableRefs "SET" AssignmentList WhereClauseOptional
|
|
{
|
|
st := &ast.UpdateStmt{
|
|
LowPriority: $2.(bool),
|
|
TableRefs: &ast.TableRefsClause{TableRefs: $4.(*ast.Join)},
|
|
List: $6.([]*ast.Assignment),
|
|
}
|
|
if $7 != nil {
|
|
st.Where = $7.(ast.ExprNode)
|
|
}
|
|
$$ = st
|
|
}
|
|
|
|
UseStmt:
|
|
"USE" DBName
|
|
{
|
|
$$ = &ast.UseStmt{DBName: $2.(string)}
|
|
}
|
|
|
|
WhereClause:
|
|
"WHERE" Expression
|
|
{
|
|
$$ = $2.(ast.ExprNode)
|
|
}
|
|
|
|
WhereClauseOptional:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| WhereClause
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
CommaOpt:
|
|
{}
|
|
| ','
|
|
{}
|
|
|
|
/************************************************************************************
|
|
* Account Management Statements
|
|
* https://dev.mysql.com/doc/refman/5.7/en/account-management-sql.html
|
|
************************************************************************************/
|
|
CreateUserStmt:
|
|
"CREATE" "USER" IfNotExists UserSpecList
|
|
{
|
|
// See https://dev.mysql.com/doc/refman/5.7/en/create-user.html
|
|
$$ = &ast.CreateUserStmt{
|
|
IfNotExists: $3.(bool),
|
|
Specs: $4.([]*ast.UserSpec),
|
|
}
|
|
}
|
|
|
|
/* See http://dev.mysql.com/doc/refman/5.7/en/alter-user.html */
|
|
AlterUserStmt:
|
|
"ALTER" "USER" IfExists UserSpecList
|
|
{
|
|
$$ = &ast.AlterUserStmt{
|
|
IfExists: $3.(bool),
|
|
Specs: $4.([]*ast.UserSpec),
|
|
}
|
|
}
|
|
| "ALTER" "USER" IfExists "USER" '(' ')' "IDENTIFIED" "BY" AuthString
|
|
{
|
|
auth := &ast.AuthOption {
|
|
AuthString: $9.(string),
|
|
ByAuthString: true,
|
|
}
|
|
$$ = &ast.AlterUserStmt{
|
|
IfExists: $3.(bool),
|
|
CurrentAuth: auth,
|
|
}
|
|
}
|
|
|
|
UserSpec:
|
|
Username AuthOption
|
|
{
|
|
userSpec := &ast.UserSpec{
|
|
User: $1.(string),
|
|
}
|
|
if $2 != nil {
|
|
userSpec.AuthOpt = $2.(*ast.AuthOption)
|
|
}
|
|
$$ = userSpec
|
|
}
|
|
|
|
UserSpecList:
|
|
UserSpec
|
|
{
|
|
$$ = []*ast.UserSpec{$1.(*ast.UserSpec)}
|
|
}
|
|
| UserSpecList ',' UserSpec
|
|
{
|
|
$$ = append($1.([]*ast.UserSpec), $3.(*ast.UserSpec))
|
|
}
|
|
|
|
AuthOption:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "IDENTIFIED" "BY" AuthString
|
|
{
|
|
$$ = &ast.AuthOption {
|
|
AuthString: $3.(string),
|
|
ByAuthString: true,
|
|
}
|
|
}
|
|
| "IDENTIFIED" "BY" "PASSWORD" HashString
|
|
{
|
|
$$ = &ast.AuthOption{
|
|
HashString: $4.(string),
|
|
}
|
|
}
|
|
|
|
HashString:
|
|
stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
/*************************************************************************************
|
|
* Grant statement
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/grant.html
|
|
*************************************************************************************/
|
|
GrantStmt:
|
|
"GRANT" PrivElemList "ON" ObjectType PrivLevel "TO" UserSpecList WithGrantOptionOpt
|
|
{
|
|
$$ = &ast.GrantStmt{
|
|
Privs: $2.([]*ast.PrivElem),
|
|
ObjectType: $4.(ast.ObjectTypeType),
|
|
Level: $5.(*ast.GrantLevel),
|
|
Users: $7.([]*ast.UserSpec),
|
|
WithGrant: $8.(bool),
|
|
}
|
|
}
|
|
|
|
WithGrantOptionOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "WITH" "GRANT" "OPTION"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
PrivElem:
|
|
PrivType
|
|
{
|
|
$$ = &ast.PrivElem{
|
|
Priv: $1.(mysql.PrivilegeType),
|
|
}
|
|
}
|
|
| PrivType '(' ColumnNameList ')'
|
|
{
|
|
$$ = &ast.PrivElem{
|
|
Priv: $1.(mysql.PrivilegeType),
|
|
Cols: $3.([]*ast.ColumnName),
|
|
}
|
|
}
|
|
|
|
PrivElemList:
|
|
PrivElem
|
|
{
|
|
$$ = []*ast.PrivElem{$1.(*ast.PrivElem)}
|
|
}
|
|
| PrivElemList ',' PrivElem
|
|
{
|
|
$$ = append($1.([]*ast.PrivElem), $3.(*ast.PrivElem))
|
|
}
|
|
|
|
PrivType:
|
|
"ALL"
|
|
{
|
|
$$ = mysql.AllPriv
|
|
}
|
|
| "ALL" "PRIVILEGES"
|
|
{
|
|
$$ = mysql.AllPriv
|
|
}
|
|
| "ALTER"
|
|
{
|
|
$$ = mysql.AlterPriv
|
|
}
|
|
| "CREATE"
|
|
{
|
|
$$ = mysql.CreatePriv
|
|
}
|
|
| "CREATE" "USER"
|
|
{
|
|
$$ = mysql.CreateUserPriv
|
|
}
|
|
| "TRIGGER"
|
|
{
|
|
$$ = mysql.TriggerPriv
|
|
}
|
|
| "DELETE"
|
|
{
|
|
$$ = mysql.DeletePriv
|
|
}
|
|
| "DROP"
|
|
{
|
|
$$ = mysql.DropPriv
|
|
}
|
|
| "PROCESS"
|
|
{
|
|
$$ = mysql.ProcessPriv
|
|
}
|
|
| "EXECUTE"
|
|
{
|
|
$$ = mysql.ExecutePriv
|
|
}
|
|
| "INDEX"
|
|
{
|
|
$$ = mysql.IndexPriv
|
|
}
|
|
| "INSERT"
|
|
{
|
|
$$ = mysql.InsertPriv
|
|
}
|
|
| "SELECT"
|
|
{
|
|
$$ = mysql.SelectPriv
|
|
}
|
|
| "SUPER"
|
|
{
|
|
$$ = mysql.SuperPriv
|
|
}
|
|
| "SHOW" "DATABASES"
|
|
{
|
|
$$ = mysql.ShowDBPriv
|
|
}
|
|
| "UPDATE"
|
|
{
|
|
$$ = mysql.UpdatePriv
|
|
}
|
|
| "GRANT" "OPTION"
|
|
{
|
|
$$ = mysql.GrantPriv
|
|
}
|
|
|
|
ObjectType:
|
|
{
|
|
$$ = ast.ObjectTypeNone
|
|
}
|
|
| "TABLE"
|
|
{
|
|
$$ = ast.ObjectTypeTable
|
|
}
|
|
|
|
PrivLevel:
|
|
'*'
|
|
{
|
|
$$ = &ast.GrantLevel {
|
|
Level: ast.GrantLevelDB,
|
|
}
|
|
}
|
|
| '*' '.' '*'
|
|
{
|
|
$$ = &ast.GrantLevel {
|
|
Level: ast.GrantLevelGlobal,
|
|
}
|
|
}
|
|
| Identifier '.' '*'
|
|
{
|
|
$$ = &ast.GrantLevel {
|
|
Level: ast.GrantLevelDB,
|
|
DBName: $1,
|
|
}
|
|
}
|
|
| Identifier '.' Identifier
|
|
{
|
|
$$ = &ast.GrantLevel {
|
|
Level: ast.GrantLevelTable,
|
|
DBName: $1,
|
|
TableName: $3,
|
|
}
|
|
}
|
|
| Identifier
|
|
{
|
|
$$ = &ast.GrantLevel {
|
|
Level: ast.GrantLevelTable,
|
|
TableName: $1,
|
|
}
|
|
}
|
|
|
|
/**************************************RevokeStmt*******************************************
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/revoke.html
|
|
*******************************************************************************************/
|
|
RevokeStmt:
|
|
"REVOKE" PrivElemList "ON" ObjectType PrivLevel "FROM" UserSpecList
|
|
{
|
|
$$ = &ast.RevokeStmt{
|
|
Privs: $2.([]*ast.PrivElem),
|
|
ObjectType: $4.(ast.ObjectTypeType),
|
|
Level: $5.(*ast.GrantLevel),
|
|
Users: $7.([]*ast.UserSpec),
|
|
}
|
|
}
|
|
|
|
/**************************************LoadDataStmt*****************************************
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/load-data.html
|
|
*******************************************************************************************/
|
|
LoadDataStmt:
|
|
"LOAD" "DATA" LocalOpt "INFILE" stringLit "INTO" "TABLE" TableName Fields Lines
|
|
{
|
|
x := &ast.LoadDataStmt{
|
|
Path: $5,
|
|
Table: $8.(*ast.TableName),
|
|
}
|
|
if $3 != nil {
|
|
x.IsLocal = true
|
|
}
|
|
if $9 != nil {
|
|
x.FieldsInfo = $9.(*ast.FieldsClause)
|
|
}
|
|
if $10 != nil {
|
|
x.LinesInfo = $10.(*ast.LinesClause)
|
|
}
|
|
$$ = x
|
|
}
|
|
|
|
LocalOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LOCAL"
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
Fields:
|
|
{
|
|
escape := "\\"
|
|
$$ = &ast.FieldsClause{
|
|
Terminated: "\t",
|
|
Escaped: escape[0],
|
|
}
|
|
}
|
|
| FieldsOrColumns FieldsTerminated Enclosed Escaped
|
|
{
|
|
escape := $4.(string)
|
|
if escape != "\\" && len(escape) > 1 {
|
|
yylex.Errorf("Incorrect arguments %s to ESCAPE", escape)
|
|
return 1
|
|
}
|
|
var enclosed byte
|
|
str := $3.(string)
|
|
if len(str) > 1 {
|
|
yylex.Errorf("Incorrect arguments %s to ENCLOSED", escape)
|
|
return 1
|
|
}else if len(str) != 0 {
|
|
enclosed = str[0]
|
|
}
|
|
$$ = &ast.FieldsClause{
|
|
Terminated: $2.(string),
|
|
Enclosed: enclosed,
|
|
Escaped: escape[0],
|
|
}
|
|
}
|
|
|
|
FieldsOrColumns:
|
|
"FIELDS" | "COLUMNS"
|
|
|
|
FieldsTerminated:
|
|
{
|
|
$$ = "\t"
|
|
}
|
|
| "TERMINATED" "BY" stringLit
|
|
{
|
|
$$ = $3
|
|
}
|
|
|
|
Enclosed:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "ENCLOSED" "BY" stringLit
|
|
{
|
|
$$ = $3
|
|
}
|
|
|
|
Escaped:
|
|
{
|
|
$$ = "\\"
|
|
}
|
|
| "ESCAPED" "BY" stringLit
|
|
{
|
|
$$ = $3
|
|
}
|
|
|
|
Lines:
|
|
{
|
|
$$ = &ast.LinesClause{Terminated: "\n"}
|
|
}
|
|
| "LINES" Starting LinesTerminated
|
|
{
|
|
$$ = &ast.LinesClause{Starting: $2.(string), Terminated: $3.(string)}
|
|
}
|
|
|
|
Starting:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "STARTING" "BY" stringLit
|
|
{
|
|
$$ = $3
|
|
}
|
|
|
|
LinesTerminated:
|
|
{
|
|
$$ = "\n"
|
|
}
|
|
| "TERMINATED" "BY" stringLit
|
|
{
|
|
$$ = $3
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* Lock/Unlock Tables
|
|
* See http://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
|
|
* All the statement leaves empty. This is used to prevent mysqldump error.
|
|
*********************************************************************/
|
|
|
|
UnlockTablesStmt:
|
|
"UNLOCK" "TABLES"
|
|
{}
|
|
|
|
LockTablesStmt:
|
|
"LOCK" "TABLES" TableLockList
|
|
{}
|
|
|
|
TableLock:
|
|
TableName LockType
|
|
|
|
LockType:
|
|
"READ"
|
|
| "READ" "LOCAL"
|
|
| "WRITE"
|
|
|
|
TableLockList:
|
|
TableLock
|
|
| TableLockList ',' TableLock
|
|
|
|
|
|
/********************************************************************
|
|
* Kill Statement
|
|
* See https://dev.mysql.com/doc/refman/5.7/en/kill.html
|
|
*******************************************************************/
|
|
|
|
KillStmt:
|
|
KillOrKillTiDB NUM
|
|
{
|
|
$$ = &ast.KillStmt{
|
|
ConnectionID: getUint64FromNUM($2),
|
|
TiDBExtension: $1.(bool),
|
|
}
|
|
}
|
|
| KillOrKillTiDB "CONNECTION" NUM
|
|
{
|
|
$$ = &ast.KillStmt{
|
|
ConnectionID: getUint64FromNUM($3),
|
|
TiDBExtension: $1.(bool),
|
|
}
|
|
}
|
|
| KillOrKillTiDB "QUERY" NUM
|
|
{
|
|
$$ = &ast.KillStmt{
|
|
ConnectionID: getUint64FromNUM($3),
|
|
Query: true,
|
|
TiDBExtension: $1.(bool),
|
|
}
|
|
}
|
|
|
|
KillOrKillTiDB:
|
|
"KILL"
|
|
{
|
|
$$ = false
|
|
}
|
|
/* KILL TIDB is a special grammar extension in TiDB, it can be used only when
|
|
the client connect to TiDB directly, not proxied under LVS. */
|
|
| "KILL" "TIDB"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
%%
|