4689 lines
96 KiB
Text
4689 lines
96 KiB
Text
|
%{
|
||
|
// 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.
|
||
|
|
||
|
// Inital 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
|
||
|
line int
|
||
|
col int
|
||
|
item interface{}
|
||
|
list []interface{}
|
||
|
}
|
||
|
|
||
|
%token <item>
|
||
|
|
||
|
/*yy:token "1.%d" */ floatLit "floating-point literal"
|
||
|
/*yy:token "%c" */ identifier "identifier"
|
||
|
/*yy:token "%d" */ intLit "integer literal"
|
||
|
/*yy:token "\"%c\"" */ stringLit "string literal"
|
||
|
/*yy:token "%x" */ hexLit "hexadecimal literal"
|
||
|
/*yy:token "%b" */ bitLit "bit literal"
|
||
|
|
||
|
|
||
|
abs "ABS"
|
||
|
add "ADD"
|
||
|
addDate "ADDDATE"
|
||
|
admin "ADMIN"
|
||
|
after "AFTER"
|
||
|
all "ALL"
|
||
|
alter "ALTER"
|
||
|
and "AND"
|
||
|
andand "&&"
|
||
|
andnot "&^"
|
||
|
any "ANY"
|
||
|
as "AS"
|
||
|
asc "ASC"
|
||
|
at "AT"
|
||
|
autoIncrement "AUTO_INCREMENT"
|
||
|
avg "AVG"
|
||
|
avgRowLength "AVG_ROW_LENGTH"
|
||
|
begin "BEGIN"
|
||
|
between "BETWEEN"
|
||
|
both "BOTH"
|
||
|
btree "BTREE"
|
||
|
by "BY"
|
||
|
byteType "BYTE"
|
||
|
caseKwd "CASE"
|
||
|
cast "CAST"
|
||
|
character "CHARACTER"
|
||
|
charsetKwd "CHARSET"
|
||
|
check "CHECK"
|
||
|
checksum "CHECKSUM"
|
||
|
coalesce "COALESCE"
|
||
|
collate "COLLATE"
|
||
|
collation "COLLATION"
|
||
|
column "COLUMN"
|
||
|
columns "COLUMNS"
|
||
|
comment "COMMENT"
|
||
|
commit "COMMIT"
|
||
|
committed "COMMITTED"
|
||
|
compact "COMPACT"
|
||
|
compressed "COMPRESSED"
|
||
|
compression "COMPRESSION"
|
||
|
concat "CONCAT"
|
||
|
concatWs "CONCAT_WS"
|
||
|
connection "CONNECTION"
|
||
|
connectionID "CONNECTION_ID"
|
||
|
constraint "CONSTRAINT"
|
||
|
convert "CONVERT"
|
||
|
count "COUNT"
|
||
|
create "CREATE"
|
||
|
cross "CROSS"
|
||
|
curDate "CURDATE"
|
||
|
currentDate "CURRENT_DATE"
|
||
|
curTime "CUR_TIME"
|
||
|
currentTime "CURRENT_TIME"
|
||
|
currentUser "CURRENT_USER"
|
||
|
database "DATABASE"
|
||
|
databases "DATABASES"
|
||
|
dateAdd "DATE_ADD"
|
||
|
dateSub "DATE_SUB"
|
||
|
day "DAY"
|
||
|
dayname "DAYNAME"
|
||
|
dayofmonth "DAYOFMONTH"
|
||
|
dayofweek "DAYOFWEEK"
|
||
|
dayofyear "DAYOFYEAR"
|
||
|
ddl "DDL"
|
||
|
deallocate "DEALLOCATE"
|
||
|
defaultKwd "DEFAULT"
|
||
|
delayed "DELAYED"
|
||
|
delayKeyWrite "DELAY_KEY_WRITE"
|
||
|
deleteKwd "DELETE"
|
||
|
desc "DESC"
|
||
|
describe "DESCRIBE"
|
||
|
distinct "DISTINCT"
|
||
|
div "DIV"
|
||
|
do "DO"
|
||
|
drop "DROP"
|
||
|
dual "DUAL"
|
||
|
duplicate "DUPLICATE"
|
||
|
dynamic "DYNAMIC"
|
||
|
elseKwd "ELSE"
|
||
|
end "END"
|
||
|
engine "ENGINE"
|
||
|
engines "ENGINES"
|
||
|
enum "ENUM"
|
||
|
eq "="
|
||
|
escape "ESCAPE"
|
||
|
execute "EXECUTE"
|
||
|
exists "EXISTS"
|
||
|
explain "EXPLAIN"
|
||
|
extract "EXTRACT"
|
||
|
falseKwd "false"
|
||
|
fields "FIELDS"
|
||
|
first "FIRST"
|
||
|
fixed "FIXED"
|
||
|
foreign "FOREIGN"
|
||
|
forKwd "FOR"
|
||
|
foundRows "FOUND_ROWS"
|
||
|
from "FROM"
|
||
|
full "FULL"
|
||
|
fulltext "FULLTEXT"
|
||
|
ge ">="
|
||
|
global "GLOBAL"
|
||
|
grant "GRANT"
|
||
|
grants "GRANTS"
|
||
|
group "GROUP"
|
||
|
groupConcat "GROUP_CONCAT"
|
||
|
hash "HASH"
|
||
|
having "HAVING"
|
||
|
highPriority "HIGH_PRIORITY"
|
||
|
hour "HOUR"
|
||
|
identified "IDENTIFIED"
|
||
|
ignore "IGNORE"
|
||
|
ifKwd "IF"
|
||
|
ifNull "IFNULL"
|
||
|
in "IN"
|
||
|
index "INDEX"
|
||
|
inner "INNER"
|
||
|
insert "INSERT"
|
||
|
interval "INTERVAL"
|
||
|
into "INTO"
|
||
|
is "IS"
|
||
|
isolation "ISOLATION"
|
||
|
join "JOIN"
|
||
|
key "KEY"
|
||
|
keyBlockSize "KEY_BLOCK_SIZE"
|
||
|
le "<="
|
||
|
leading "LEADING"
|
||
|
left "LEFT"
|
||
|
length "LENGTH"
|
||
|
level "LEVEL"
|
||
|
like "LIKE"
|
||
|
limit "LIMIT"
|
||
|
local "LOCAL"
|
||
|
locate "LOCATE"
|
||
|
lock "LOCK"
|
||
|
lower "LOWER"
|
||
|
lowPriority "LOW_PRIORITY"
|
||
|
lsh "<<"
|
||
|
max "MAX"
|
||
|
maxRows "MAX_ROWS"
|
||
|
microsecond "MICROSECOND"
|
||
|
min "MIN"
|
||
|
minute "MINUTE"
|
||
|
minRows "MIN_ROWS"
|
||
|
mod "MOD"
|
||
|
mode "MODE"
|
||
|
month "MONTH"
|
||
|
names "NAMES"
|
||
|
national "NATIONAL"
|
||
|
neq "!="
|
||
|
neqSynonym "<>"
|
||
|
not "NOT"
|
||
|
null "NULL"
|
||
|
nulleq "<=>"
|
||
|
nullIf "NULLIF"
|
||
|
offset "OFFSET"
|
||
|
on "ON"
|
||
|
only "ONLY"
|
||
|
option "OPTION"
|
||
|
or "OR"
|
||
|
order "ORDER"
|
||
|
oror "||"
|
||
|
outer "OUTER"
|
||
|
password "PASSWORD"
|
||
|
placeholder "PLACEHOLDER"
|
||
|
pow "POW"
|
||
|
power "POWER"
|
||
|
prepare "PREPARE"
|
||
|
primary "PRIMARY"
|
||
|
procedure "PROCEDURE"
|
||
|
quarter "QUARTER"
|
||
|
quick "QUICK"
|
||
|
rand "RAND"
|
||
|
read "READ"
|
||
|
redundant "REDUNDANT"
|
||
|
references "REFERENCES"
|
||
|
regexpKwd "REGEXP"
|
||
|
repeat "REPEAT"
|
||
|
repeatable "REPEATABLE"
|
||
|
replace "REPLACE"
|
||
|
right "RIGHT"
|
||
|
rlike "RLIKE"
|
||
|
rollback "ROLLBACK"
|
||
|
row "ROW"
|
||
|
rowFormat "ROW_FORMAT"
|
||
|
rsh ">>"
|
||
|
schema "SCHEMA"
|
||
|
schemas "SCHEMAS"
|
||
|
second "SECOND"
|
||
|
selectKwd "SELECT"
|
||
|
serializable "SERIALIZABLE"
|
||
|
session "SESSION"
|
||
|
set "SET"
|
||
|
share "SHARE"
|
||
|
show "SHOW"
|
||
|
signed "SIGNED"
|
||
|
some "SOME"
|
||
|
start "START"
|
||
|
status "STATUS"
|
||
|
stringType "string"
|
||
|
subDate "SUBDATE"
|
||
|
strcmp "STRCMP"
|
||
|
substring "SUBSTRING"
|
||
|
substringIndex "SUBSTRING_INDEX"
|
||
|
sum "SUM"
|
||
|
sysVar "SYS_VAR"
|
||
|
sysDate "SYSDATE"
|
||
|
tableKwd "TABLE"
|
||
|
tables "TABLES"
|
||
|
then "THEN"
|
||
|
to "TO"
|
||
|
trailing "TRAILING"
|
||
|
transaction "TRANSACTION"
|
||
|
triggers "TRIGGERS"
|
||
|
trim "TRIM"
|
||
|
trueKwd "true"
|
||
|
truncate "TRUNCATE"
|
||
|
uncommitted "UNCOMMITTED"
|
||
|
underscoreCS "UNDERSCORE_CHARSET"
|
||
|
unknown "UNKNOWN"
|
||
|
union "UNION"
|
||
|
unique "UNIQUE"
|
||
|
unlock "UNLOCK"
|
||
|
unsigned "UNSIGNED"
|
||
|
update "UPDATE"
|
||
|
upper "UPPER"
|
||
|
use "USE"
|
||
|
user "USER"
|
||
|
using "USING"
|
||
|
userVar "USER_VAR"
|
||
|
value "VALUE"
|
||
|
values "VALUES"
|
||
|
variables "VARIABLES"
|
||
|
version "VERSION"
|
||
|
warnings "WARNINGS"
|
||
|
week "WEEK"
|
||
|
weekday "WEEKDAY"
|
||
|
weekofyear "WEEKOFYEAR"
|
||
|
when "WHEN"
|
||
|
where "WHERE"
|
||
|
write "WRITE"
|
||
|
xor "XOR"
|
||
|
yearweek "YEARWEEK"
|
||
|
zerofill "ZEROFILL"
|
||
|
|
||
|
calcFoundRows "SQL_CALC_FOUND_ROWS"
|
||
|
|
||
|
currentTs "CURRENT_TIMESTAMP"
|
||
|
localTime "LOCALTIME"
|
||
|
localTs "LOCALTIMESTAMP"
|
||
|
now "NOW"
|
||
|
|
||
|
tinyIntType "TINYINT"
|
||
|
smallIntType "SMALLINT"
|
||
|
mediumIntType "MEDIUMINT"
|
||
|
intType "INT"
|
||
|
integerType "INTEGER"
|
||
|
bigIntType "BIGINT"
|
||
|
bitType "BIT"
|
||
|
|
||
|
decimalType "DECIMAL"
|
||
|
numericType "NUMERIC"
|
||
|
floatType "float"
|
||
|
doubleType "DOUBLE"
|
||
|
precisionType "PRECISION"
|
||
|
realType "REAL"
|
||
|
|
||
|
dateType "DATE"
|
||
|
timeType "TIME"
|
||
|
datetimeType "DATETIME"
|
||
|
timestampType "TIMESTAMP"
|
||
|
yearType "YEAR"
|
||
|
|
||
|
charType "CHAR"
|
||
|
varcharType "VARCHAR"
|
||
|
binaryType "BINARY"
|
||
|
varbinaryType "VARBINARY"
|
||
|
tinyblobType "TINYBLOB"
|
||
|
blobType "BLOB"
|
||
|
mediumblobType "MEDIUMBLOB"
|
||
|
longblobType "LONGBLOB"
|
||
|
tinytextType "TINYTEXT"
|
||
|
textType "TEXT"
|
||
|
mediumtextType "MEDIUMTEXT"
|
||
|
longtextType "LONGTEXT"
|
||
|
|
||
|
int16Type "int16"
|
||
|
int24Type "int24"
|
||
|
int32Type "int32"
|
||
|
int64Type "int64"
|
||
|
int8Type "int8"
|
||
|
uintType "uint"
|
||
|
uint16Type "uint16"
|
||
|
uint32Type "uint32"
|
||
|
uint64Type "uint64"
|
||
|
uint8Type "uint8",
|
||
|
float32Type "float32"
|
||
|
float64Type "float64"
|
||
|
boolType "BOOL"
|
||
|
booleanType "BOOLEAN"
|
||
|
|
||
|
parseExpression "parse expression prefix"
|
||
|
|
||
|
secondMicrosecond "SECOND_MICROSECOND"
|
||
|
minuteMicrosecond "MINUTE_MICROSECOND"
|
||
|
minuteSecond "MINUTE_SECOND"
|
||
|
hourMicrosecond "HOUR_MICROSECOND"
|
||
|
hourSecond "HOUR_SECOND"
|
||
|
hourMinute "HOUR_MINUTE"
|
||
|
dayMicrosecond "DAY_MICROSECOND"
|
||
|
daySecond "DAY_SECOND"
|
||
|
dayMinute "DAY_MINUTE"
|
||
|
dayHour "DAY_HOUR"
|
||
|
yearMonth "YEAR_MONTH"
|
||
|
|
||
|
%type <item>
|
||
|
AdminStmt "Check table statement or show ddl statement"
|
||
|
AlterTableStmt "Alter table statement"
|
||
|
AlterTableSpec "Alter table specification"
|
||
|
AlterTableSpecList "Alter table specification list"
|
||
|
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"
|
||
|
CastType "Cast function target type"
|
||
|
ColumnDef "table column definition"
|
||
|
ColumnName "column name"
|
||
|
ColumnNameList "column name list"
|
||
|
ColumnNameListOpt "column name list opt"
|
||
|
ColumnKeywordOpt "Column keyword or empty"
|
||
|
ColumnSetValue "insert statement set value by column name"
|
||
|
ColumnSetValueList "insert statement set value by column name list"
|
||
|
CommaOpt "optional comma"
|
||
|
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"
|
||
|
CrossOpt "Cross join option"
|
||
|
DateArithOpt "Date arith dateadd or datesub option"
|
||
|
DateArithMultiFormsOpt "Date arith adddate or subdate option"
|
||
|
DateArithInterval "Date arith interval part"
|
||
|
DatabaseSym "DATABASE or SCHEMA"
|
||
|
DBName "Database Name"
|
||
|
DeallocateSym "Deallocate or drop"
|
||
|
DeallocateStmt "Deallocate prepared statement"
|
||
|
Default "DEFAULT clause"
|
||
|
DefaultOpt "optional DEFAULT clause"
|
||
|
DefaultKwdOpt "optional DEFAULT keyword"
|
||
|
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"
|
||
|
EmptyStmt "empty statement"
|
||
|
EqOpt "= or empty"
|
||
|
EscapedTableRef "escaped table reference"
|
||
|
ExecuteStmt "Execute statement"
|
||
|
ExplainSym "EXPLAIN or DESCRIBE or DESC"
|
||
|
ExplainStmt "EXPLAIN statement"
|
||
|
Expression "expression"
|
||
|
ExpressionList "expression list"
|
||
|
ExpressionListOpt "expression list opt"
|
||
|
ExpressionListList "expression list list"
|
||
|
Factor "expression factor"
|
||
|
PredicateExpr "Predicate expression factor"
|
||
|
Field "field expression"
|
||
|
FieldAsName "Field alias name"
|
||
|
FieldAsNameOpt "Field alias name opt"
|
||
|
FieldList "field expression list"
|
||
|
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"
|
||
|
FunctionNameConflict "Built-in function call names which are conflict with keywords"
|
||
|
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"
|
||
|
IndexName "index name"
|
||
|
IndexOption "Index Option"
|
||
|
IndexType "index type"
|
||
|
IndexTypeOpt "Optional index type"
|
||
|
InsertIntoStmt "INSERT INTO statement"
|
||
|
InsertValues "Rest part of INSERT/REPLACE INTO statement"
|
||
|
IntoOpt "INTO or EmptyString"
|
||
|
IsolationLevel "Isolation level"
|
||
|
JoinTable "join table"
|
||
|
JoinType "join type"
|
||
|
KeyOrIndex "{KEY|INDEX}"
|
||
|
LikeEscapeOpt "like escape option"
|
||
|
LimitClause "LIMIT clause"
|
||
|
Literal "literal value"
|
||
|
LockTablesStmt "Lock tables statement"
|
||
|
LockType "Table locks type"
|
||
|
logAnd "logical and operator"
|
||
|
logOr "logical or operator"
|
||
|
LowPriorityOptional "LOW_PRIORITY or empty"
|
||
|
name "name"
|
||
|
NationalOpt "National option"
|
||
|
NotOpt "optional NOT"
|
||
|
NowSym "CURRENT_TIMESTAMP/LOCALTIME/LOCALTIMESTAMP/NOW"
|
||
|
NumLiteral "Num/Int/Float/Decimal Literal"
|
||
|
ObjectType "Grant statement object type"
|
||
|
OnDuplicateKeyUpdate "ON DUPLICATE KEY UPDATE value list"
|
||
|
Operand "operand"
|
||
|
OptFull "Full or empty"
|
||
|
OptInteger "Optional Integer keyword"
|
||
|
Order "ORDER BY clause optional collation specification"
|
||
|
OrderBy "ORDER BY clause"
|
||
|
ByItem "BY item"
|
||
|
OrderByOptional "Optional ORDER BY clause optional"
|
||
|
ByList "BY list"
|
||
|
OuterOpt "optional OUTER clause"
|
||
|
QuickOptional "QUICK 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"
|
||
|
RegexpSym "REGEXP or RLIKE"
|
||
|
ReplaceIntoStmt "REPLACE INTO statement"
|
||
|
ReplacePriority "replace statement priority"
|
||
|
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"
|
||
|
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"
|
||
|
Statement "statement"
|
||
|
StatementList "statement list"
|
||
|
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"
|
||
|
TableOption "create table option"
|
||
|
TableOptionList "create table option list"
|
||
|
TableOptionListOpt "create table option list opt"
|
||
|
TableRef "table reference"
|
||
|
TableRefs "table references"
|
||
|
TimeUnit "Time unit"
|
||
|
TransactionChar "Transaction characteristic"
|
||
|
TransactionChars "Transaction characteristic list"
|
||
|
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"
|
||
|
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"
|
||
|
ValueSym "Value or Values"
|
||
|
VariableAssignment "set variable value"
|
||
|
VariableAssignmentList "set variable value list"
|
||
|
Variable "User or system variable"
|
||
|
WhereClause "WHERE clause"
|
||
|
WhereClauseOptional "Optinal WHERE clause"
|
||
|
|
||
|
Identifier "identifier or unreserved keyword"
|
||
|
UnReservedKeyword "MySQL unreserved keywords"
|
||
|
NotKeywordToken "Tokens not mysql keyword but treated specially"
|
||
|
|
||
|
WhenClause "When clause"
|
||
|
WhenClauseList "When clause list"
|
||
|
ElseOpt "Optional else clause"
|
||
|
ExpressionOpt "Optional expression"
|
||
|
|
||
|
Type "Types"
|
||
|
|
||
|
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"
|
||
|
CharsetKw "charset or charater set"
|
||
|
OptCharset "Optional Character setting"
|
||
|
OptCollate "Optional Collate setting"
|
||
|
NUM "numbers"
|
||
|
LengthNum "Field length num(uint64)"
|
||
|
|
||
|
%token tableRefPriority
|
||
|
|
||
|
%precedence lowerThanCalcFoundRows
|
||
|
%precedence calcFoundRows
|
||
|
|
||
|
%precedence lowerThanSetKeyword
|
||
|
%precedence set
|
||
|
|
||
|
%precedence lowerThanInsertValues
|
||
|
%precedence insertValues
|
||
|
|
||
|
%left join inner cross left right full
|
||
|
/* A dummy token to force the priority of TableRef production in a join. */
|
||
|
%left tableRefPriority
|
||
|
%precedence on
|
||
|
%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 ','
|
||
|
|
||
|
%start Start
|
||
|
|
||
|
%%
|
||
|
|
||
|
Start:
|
||
|
StatementList
|
||
|
| parseExpression Expression
|
||
|
{
|
||
|
yylex.(*lexer).expr = $2.(ast.ExprNode)
|
||
|
}
|
||
|
|
||
|
/**************************************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,
|
||
|
Column: $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,
|
||
|
DropColumn: $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),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
|
||
|
/*******************************************************************************************/
|
||
|
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{}
|
||
|
}
|
||
|
|
||
|
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.(string))}
|
||
|
}
|
||
|
| Identifier '.' Identifier
|
||
|
{
|
||
|
$$ = &ast.ColumnName{Table: model.NewCIStr($1.(string)), Name: model.NewCIStr($3.(string))}
|
||
|
}
|
||
|
| Identifier '.' Identifier '.' Identifier
|
||
|
{
|
||
|
$$ = &ast.ColumnName{Schema: model.NewCIStr($1.(string)), Table: model.NewCIStr($3.(string)), Name: model.NewCIStr($5.(string))}
|
||
|
}
|
||
|
|
||
|
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{}
|
||
|
}
|
||
|
|
||
|
ColumnOption:
|
||
|
"NOT" "NULL"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNotNull}
|
||
|
}
|
||
|
| "NULL"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionNull}
|
||
|
}
|
||
|
| "AUTO_INCREMENT"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionAutoIncrement}
|
||
|
}
|
||
|
| "PRIMARY" "KEY"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionPrimaryKey}
|
||
|
}
|
||
|
| "UNIQUE"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniq}
|
||
|
}
|
||
|
| "UNIQUE" "KEY"
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionUniqKey}
|
||
|
}
|
||
|
| "DEFAULT" DefaultValueExpr
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionDefaultValue, Expr: $2.(ast.ExprNode)}
|
||
|
}
|
||
|
| "ON" "UPDATE" NowSym
|
||
|
{
|
||
|
nowFunc := &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionOnUpdate, Expr: nowFunc}
|
||
|
}
|
||
|
| "COMMENT" stringLit
|
||
|
{
|
||
|
$$ = &ast.ColumnOption{Tp: ast.ColumnOptionComment}
|
||
|
}
|
||
|
| "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" IndexTypeOpt '(' IndexColNameList ')' IndexOption
|
||
|
{
|
||
|
c := &ast.Constraint{
|
||
|
Tp: ast.ConstraintPrimaryKey,
|
||
|
Keys: $5.([]*ast.IndexColName),
|
||
|
}
|
||
|
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
|
||
|
}
|
||
|
| "FULLTEXT" "KEY" IndexName '(' IndexColNameList ')' IndexOption
|
||
|
{
|
||
|
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 ')' IndexOption
|
||
|
{
|
||
|
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 ')' IndexOption
|
||
|
{
|
||
|
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 ')' IndexOption
|
||
|
{
|
||
|
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 ')' IndexOption
|
||
|
{
|
||
|
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 ')' IndexOption
|
||
|
{
|
||
|
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 ')'
|
||
|
{
|
||
|
$$ = &ast.ReferenceDef{Table: $2.(*ast.TableName), IndexColNames: $4.([]*ast.IndexColName)}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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:
|
||
|
NowSym
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
||
|
}
|
||
|
| NowSym '(' ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP")}
|
||
|
}
|
||
|
| SignedLiteral
|
||
|
|
||
|
// TODO: Process other three keywords
|
||
|
NowSym:
|
||
|
"CURRENT_TIMESTAMP"
|
||
|
| "LOCALTIME"
|
||
|
| "LOCALTIMESTAMP"
|
||
|
| "NOW"
|
||
|
|
||
|
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
|
||
|
|
||
|
|
||
|
CreateIndexStmt:
|
||
|
"CREATE" CreateIndexStmtUnique "INDEX" Identifier "ON" TableName '(' IndexColNameList ')'
|
||
|
{
|
||
|
$$ = &ast.CreateIndexStmt{
|
||
|
Unique: $2.(bool),
|
||
|
IndexName: $4.(string),
|
||
|
Table: $6.(*ast.TableName),
|
||
|
IndexColNames: $8.([]*ast.IndexColName),
|
||
|
}
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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),
|
||
|
}
|
||
|
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBName:
|
||
|
Identifier
|
||
|
|
||
|
DatabaseOption:
|
||
|
DefaultKwdOpt CharsetKw EqOpt StringName
|
||
|
{
|
||
|
$$ = &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
|
||
|
{
|
||
|
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.(*lexer).err("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),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Default:
|
||
|
"DEFAULT" Expression
|
||
|
{
|
||
|
$$ = $2
|
||
|
}
|
||
|
|
||
|
DefaultOpt:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| Default
|
||
|
|
||
|
DefaultKwdOpt:
|
||
|
{}
|
||
|
| "DEFAULT"
|
||
|
|
||
|
/******************************************************************
|
||
|
* 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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
| "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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
| "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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DatabaseSym:
|
||
|
"DATABASE" | "SCHEMA"
|
||
|
|
||
|
DropDatabaseStmt:
|
||
|
"DROP" DatabaseSym IfExists DBName
|
||
|
{
|
||
|
$$ = &ast.DropDatabaseStmt{IfExists: $3.(bool), Name: $4.(string)}
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DropIndexStmt:
|
||
|
"DROP" "INDEX" IfExists Identifier "ON" TableName
|
||
|
{
|
||
|
$$ = &ast.DropIndexStmt{IfExists: $3.(bool), IndexName: $4.(string), Table: $6.(*ast.TableName)}
|
||
|
}
|
||
|
|
||
|
DropTableStmt:
|
||
|
"DROP" TableOrTables TableNameList
|
||
|
{
|
||
|
$$ = &ast.DropTableStmt{Tables: $3.([]*ast.TableName)}
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
| "DROP" TableOrTables "IF" "EXISTS" TableNameList
|
||
|
{
|
||
|
$$ = &ast.DropTableStmt{IfExists: true, Tables: $5.([]*ast.TableName)}
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
{
|
||
|
switch v := $1.(type) {
|
||
|
case int64:
|
||
|
$$ = uint64(v)
|
||
|
case uint64:
|
||
|
$$ = uint64(v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NUM:
|
||
|
intLit
|
||
|
|
||
|
Expression:
|
||
|
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 "IS" NotOpt trueKwd %prec is
|
||
|
{
|
||
|
$$ = &ast.IsTruthExpr{Expr:$1.(ast.ExprNode), Not: $3.(bool), True: int64(1)}
|
||
|
}
|
||
|
| Factor "IS" NotOpt falseKwd %prec is
|
||
|
{
|
||
|
$$ = &ast.IsTruthExpr{Expr:$1.(ast.ExprNode), Not: $3.(bool), True: int64(0)}
|
||
|
}
|
||
|
| Factor "IS" NotOpt "UNKNOWN" %prec is
|
||
|
{
|
||
|
/* https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_is */
|
||
|
$$ = &ast.IsNullExpr{Expr: $1.(ast.ExprNode), Not: $3.(bool)}
|
||
|
}
|
||
|
| Factor
|
||
|
|
||
|
|
||
|
logOr:
|
||
|
"||"
|
||
|
{
|
||
|
}
|
||
|
| "OR"
|
||
|
{
|
||
|
}
|
||
|
|
||
|
logAnd:
|
||
|
"&&"
|
||
|
{
|
||
|
}
|
||
|
| "AND"
|
||
|
{
|
||
|
}
|
||
|
|
||
|
name:
|
||
|
Identifier
|
||
|
|
||
|
ExpressionList:
|
||
|
Expression
|
||
|
{
|
||
|
$$ = []ast.ExprNode{$1.(ast.ExprNode)}
|
||
|
}
|
||
|
| ExpressionList ',' Expression
|
||
|
{
|
||
|
$$ = append($1.([]ast.ExprNode), $3.(ast.ExprNode))
|
||
|
}
|
||
|
|
||
|
ExpressionListOpt:
|
||
|
{
|
||
|
$$ = []ast.ExprNode{}
|
||
|
}
|
||
|
| ExpressionList
|
||
|
|
||
|
Factor:
|
||
|
Factor "IS" NotOpt "NULL" %prec is
|
||
|
{
|
||
|
$$ = &ast.IsNullExpr{Expr: $1.(ast.ExprNode), Not: $3.(bool)}
|
||
|
}
|
||
|
| Factor CompareOp PredicateExpr %prec eq
|
||
|
{
|
||
|
$$ = &ast.BinaryOperationExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: $3.(ast.ExprNode)}
|
||
|
}
|
||
|
| Factor CompareOp AnyOrAll SubSelect %prec eq
|
||
|
{
|
||
|
$$ = &ast.CompareSubqueryExpr{Op: $2.(opcode.Op), L: $1.(ast.ExprNode), R: $4.(*ast.SubqueryExpr), All: $3.(bool)}
|
||
|
}
|
||
|
| PredicateExpr
|
||
|
|
||
|
CompareOp:
|
||
|
">="
|
||
|
{
|
||
|
$$ = opcode.GE
|
||
|
}
|
||
|
| '>'
|
||
|
{
|
||
|
$$ = opcode.GT
|
||
|
}
|
||
|
| "<="
|
||
|
{
|
||
|
$$ = opcode.LE
|
||
|
}
|
||
|
| '<'
|
||
|
{
|
||
|
$$ = opcode.LT
|
||
|
}
|
||
|
| "!="
|
||
|
{
|
||
|
$$ = opcode.NE
|
||
|
}
|
||
|
| "<>"
|
||
|
{
|
||
|
$$ = opcode.NE
|
||
|
}
|
||
|
| "="
|
||
|
{
|
||
|
$$ = opcode.EQ
|
||
|
}
|
||
|
| "<=>"
|
||
|
{
|
||
|
$$ = opcode.NullEQ
|
||
|
}
|
||
|
|
||
|
AnyOrAll:
|
||
|
"ANY"
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "SOME"
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "ALL"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
PredicateExpr:
|
||
|
PrimaryFactor NotOpt "IN" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.PatternInExpr{Expr: $1.(ast.ExprNode), Not: $2.(bool), List: $5.([]ast.ExprNode)}
|
||
|
}
|
||
|
| PrimaryFactor NotOpt "IN" SubSelect
|
||
|
{
|
||
|
$$ = &ast.PatternInExpr{Expr: $1.(ast.ExprNode), Not: $2.(bool), Sel: $4.(*ast.SubqueryExpr)}
|
||
|
}
|
||
|
| PrimaryFactor NotOpt "BETWEEN" PrimaryFactor "AND" PredicateExpr
|
||
|
{
|
||
|
$$ = &ast.BetweenExpr{
|
||
|
Expr: $1.(ast.ExprNode),
|
||
|
Left: $4.(ast.ExprNode),
|
||
|
Right: $6.(ast.ExprNode),
|
||
|
Not: $2.(bool),
|
||
|
}
|
||
|
}
|
||
|
| PrimaryFactor NotOpt "LIKE" PrimaryExpression LikeEscapeOpt
|
||
|
{
|
||
|
escape := $5.(string)
|
||
|
if len(escape) > 1 {
|
||
|
yylex.(*lexer).errf("Incorrect arguments %s to ESCAPE", escape)
|
||
|
return 1
|
||
|
} else if len(escape) == 0 {
|
||
|
escape = "\\"
|
||
|
}
|
||
|
$$ = &ast.PatternLikeExpr{
|
||
|
Expr: $1.(ast.ExprNode),
|
||
|
Pattern: $4.(ast.ExprNode),
|
||
|
Not: $2.(bool),
|
||
|
Escape: escape[0],
|
||
|
}
|
||
|
}
|
||
|
| PrimaryFactor NotOpt RegexpSym PrimaryExpression
|
||
|
{
|
||
|
$$ = &ast.PatternRegexpExpr{Expr: $1.(ast.ExprNode), Pattern: $4.(ast.ExprNode), Not: $2.(bool)}
|
||
|
}
|
||
|
| PrimaryFactor
|
||
|
|
||
|
RegexpSym:
|
||
|
"REGEXP"
|
||
|
| "RLIKE"
|
||
|
|
||
|
LikeEscapeOpt:
|
||
|
%prec lowerThanEscape
|
||
|
{
|
||
|
$$ = "\\"
|
||
|
}
|
||
|
| "ESCAPE" stringLit
|
||
|
{
|
||
|
$$ = $2
|
||
|
}
|
||
|
|
||
|
NotOpt:
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "NOT"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
Field:
|
||
|
'*'
|
||
|
{
|
||
|
$$ = &ast.SelectField{WildCard: &ast.WildCardField{}}
|
||
|
}
|
||
|
| Identifier '.' '*'
|
||
|
{
|
||
|
wildCard := &ast.WildCardField{Table: model.NewCIStr($1.(string))}
|
||
|
$$ = &ast.SelectField{WildCard: wildCard}
|
||
|
}
|
||
|
| Identifier '.' Identifier '.' '*'
|
||
|
{
|
||
|
wildCard := &ast.WildCardField{Schema: model.NewCIStr($1.(string)), Table: model.NewCIStr($3.(string))}
|
||
|
$$ = &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 = yylex.(*lexer).startOffset(yyS[yypt].offset)
|
||
|
$$ = []*ast.SelectField{field}
|
||
|
}
|
||
|
| FieldList ',' Field
|
||
|
{
|
||
|
|
||
|
fl := $1.([]*ast.SelectField)
|
||
|
last := fl[len(fl)-1]
|
||
|
l := yylex.(*lexer)
|
||
|
if last.Expr != nil && last.AsName.O == "" {
|
||
|
lastEnd := l.endOffset(yyS[yypt-1].offset)
|
||
|
last.SetText(l.src[last.Offset:lastEnd])
|
||
|
}
|
||
|
newField := $3.(*ast.SelectField)
|
||
|
newField.Offset = l.startOffset(yyS[yypt].offset)
|
||
|
$$ = append(fl, newField)
|
||
|
}
|
||
|
|
||
|
GroupByClause:
|
||
|
"GROUP" "BY" ByList
|
||
|
{
|
||
|
$$ = &ast.GroupByClause{Items: $3.([]*ast.ByItem)}
|
||
|
}
|
||
|
|
||
|
HavingClause:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "HAVING" Expression
|
||
|
{
|
||
|
$$ = &ast.HavingClause{Expr: $2.(ast.ExprNode)}
|
||
|
}
|
||
|
|
||
|
IfExists:
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "IF" "EXISTS"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
IfNotExists:
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "IF" "NOT" "EXISTS"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
|
||
|
IgnoreOptional:
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "IGNORE"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
IndexName:
|
||
|
{
|
||
|
$$ = ""
|
||
|
}
|
||
|
| Identifier
|
||
|
{
|
||
|
//"index name"
|
||
|
$$ = $1.(string)
|
||
|
}
|
||
|
|
||
|
IndexOption:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "KEY_BLOCK_SIZE" EqOpt LengthNum
|
||
|
{
|
||
|
$$ = &ast.IndexOption{
|
||
|
KeyBlockSize: $1.(uint64),
|
||
|
}
|
||
|
}
|
||
|
| IndexType
|
||
|
{
|
||
|
$$ = &ast.IndexOption {
|
||
|
Tp: $1.(model.IndexType),
|
||
|
}
|
||
|
}
|
||
|
| "COMMENT" stringLit
|
||
|
{
|
||
|
$$ = &ast.IndexOption {
|
||
|
Comment: $2.(string),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IndexType:
|
||
|
"USING" "BTREE"
|
||
|
{
|
||
|
$$ = model.IndexTypeBtree
|
||
|
}
|
||
|
| "USING" "HASH"
|
||
|
{
|
||
|
$$ = model.IndexTypeHash
|
||
|
}
|
||
|
|
||
|
IndexTypeOpt:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| IndexType
|
||
|
{
|
||
|
$$ = $1
|
||
|
}
|
||
|
|
||
|
/**********************************Identifier********************************************/
|
||
|
Identifier:
|
||
|
identifier | UnReservedKeyword | NotKeywordToken
|
||
|
|
||
|
UnReservedKeyword:
|
||
|
"AUTO_INCREMENT" | "AFTER" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "CHARSET" | "COLUMNS" | "COMMIT" | "COMPACT" | "COMPRESSED"
|
||
|
| "DATE" | "DATETIME" | "DEALLOCATE" | "DO" | "DYNAMIC" | "END" | "ENGINE" | "ENGINES" | "EXECUTE" | "FIRST" | "FIXED" | "FULL" | "HASH"
|
||
|
| "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "REDUNDANT" | "ROLLBACK" | "SESSION" | "SIGNED"
|
||
|
| "START" | "STATUS" | "GLOBAL" | "TABLES"| "TEXT" | "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" | "ESCAPE" | "GRANTS" | "FIELDS" | "TRIGGERS" | "DELAY_KEY_WRITE" | "ISOLATION"
|
||
|
| "REPEATABLE" | "COMMITTED" | "UNCOMMITTED" | "ONLY" | "SERIALIZABLE" | "LEVEL" | "VARIABLES"
|
||
|
|
||
|
NotKeywordToken:
|
||
|
"ABS" | "ADDDATE" | "ADMIN" | "COALESCE" | "CONCAT" | "CONCAT_WS" | "CONNECTION_ID" | "CUR_TIME"| "COUNT" | "DAY"
|
||
|
| "DATE_ADD" | "DATE_SUB" | "DAYNAME" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "FOUND_ROWS" | "GROUP_CONCAT"| "HOUR"
|
||
|
| "IFNULL" | "LENGTH" | "LOCATE" | "MAX" | "MICROSECOND" | "MIN" | "MINUTE" | "NULLIF" | "MONTH" | "NOW" | "POW"
|
||
|
| "POWER" | "RAND" | "SECOND" | "SQL_CALC_FOUND_ROWS" | "SUBDATE" | "SUBSTRING" %prec lowerThanLeftParen
|
||
|
| "SUBSTRING_INDEX" | "SUM" | "TRIM" | "VERSION" | "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK"
|
||
|
|
||
|
/************************************************************************************
|
||
|
*
|
||
|
* Insert Statments
|
||
|
*
|
||
|
* TODO: support PARTITION
|
||
|
**********************************************************************************/
|
||
|
InsertIntoStmt:
|
||
|
"INSERT" Priority IgnoreOptional IntoOpt TableName InsertValues OnDuplicateKeyUpdate
|
||
|
{
|
||
|
x := $6.(*ast.InsertStmt)
|
||
|
x.Priority = $2.(int)
|
||
|
// 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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IntoOpt:
|
||
|
{
|
||
|
}
|
||
|
| "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:
|
||
|
'(' ')'
|
||
|
{
|
||
|
$$ = [][]ast.ExprNode{[]ast.ExprNode{}}
|
||
|
}
|
||
|
| '(' ')' ',' ExpressionListList
|
||
|
{
|
||
|
$$ = append([][]ast.ExprNode{[]ast.ExprNode{}}, $4.([][]ast.ExprNode)...)
|
||
|
}
|
||
|
| '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = [][]ast.ExprNode{$2.([]ast.ExprNode)}
|
||
|
}
|
||
|
| '(' ExpressionList ')' ',' ExpressionListList
|
||
|
{
|
||
|
$$ = append([][]ast.ExprNode{$2.([]ast.ExprNode)}, $5.([][]ast.ExprNode)...)
|
||
|
}
|
||
|
|
||
|
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 Statments END************************************/
|
||
|
|
||
|
Literal:
|
||
|
"false"
|
||
|
{
|
||
|
$$ = int64(0)
|
||
|
}
|
||
|
| "NULL"
|
||
|
| "true"
|
||
|
{
|
||
|
$$ = int64(1)
|
||
|
}
|
||
|
| floatLit
|
||
|
| intLit
|
||
|
| stringLit
|
||
|
{
|
||
|
tp := types.NewFieldType(mysql.TypeString)
|
||
|
l := yylex.(*lexer)
|
||
|
tp.Charset, tp.Collate = l.GetCharsetInfo()
|
||
|
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.(string)
|
||
|
co, err := charset.GetDefaultCollation(tp.Charset)
|
||
|
if err != nil {
|
||
|
l := yylex.(*lexer)
|
||
|
l.errf("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 ')'
|
||
|
{
|
||
|
l := yylex.(*lexer)
|
||
|
startOffset := l.startOffset(yyS[yypt-1].offset)
|
||
|
endOffset := l.endOffset(yyS[yypt].offset)
|
||
|
expr := $2.(ast.ExprNode)
|
||
|
expr.SetText(l.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" '(' Expression ',' ExpressionList ')'
|
||
|
{
|
||
|
values := append([]ast.ExprNode{$3.(ast.ExprNode)}, $5.([]ast.ExprNode)...)
|
||
|
$$ = &ast.RowExpr{Values: values}
|
||
|
}
|
||
|
| '(' Expression ',' ExpressionList ')'
|
||
|
{
|
||
|
values := append([]ast.ExprNode{$2.(ast.ExprNode)}, $4.([]ast.ExprNode)...)
|
||
|
$$ = &ast.RowExpr{Values: values}
|
||
|
}
|
||
|
| "EXISTS" SubSelect
|
||
|
{
|
||
|
$$ = &ast.ExistsSubqueryExpr{Sel: $2.(*ast.SubqueryExpr)}
|
||
|
}
|
||
|
|
||
|
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" | "REPEAT" | "CURRENT_USER" | "CURRENT_DATE" | "VERSION"
|
||
|
|
||
|
FunctionCallConflict:
|
||
|
FunctionNameConflict '(' ExpressionListOpt ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), 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.(string))}
|
||
|
}
|
||
|
| "CURRENT_DATE"
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string))}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
| "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.(string)),
|
||
|
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,
|
||
|
}
|
||
|
}
|
||
|
| "DATE" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "USER" '(' ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string))}
|
||
|
}
|
||
|
| "VALUES" '(' ColumnName ')' %prec lowerThanInsertValues
|
||
|
{
|
||
|
// TODO: support qualified identifier for column_name
|
||
|
$$ = &ast.ValuesExpr{Column: &ast.ColumnNameExpr{Name: $3.(*ast.ColumnName)}}
|
||
|
}
|
||
|
| "WEEK" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "YEAR" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName:model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
|
||
|
FunctionCallNonKeyword:
|
||
|
"COALESCE" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "CURDATE" '(' ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string))}
|
||
|
}
|
||
|
| "CUR_TIME" '(' ExpressionOpt ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{}
|
||
|
if $3 != nil {
|
||
|
args = append(args, $3.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "CURRENT_TIME" FuncDatetimePrec
|
||
|
{
|
||
|
args := []ast.ExprNode{}
|
||
|
if $2 != nil {
|
||
|
args = append(args, $2.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "CURRENT_TIMESTAMP" FuncDatetimePrec
|
||
|
{
|
||
|
args := []ast.ExprNode{}
|
||
|
if $2 != nil {
|
||
|
args = append(args, $2.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "ABS" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "CONCAT" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "CONCAT_WS" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "DAY" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "DAYNAME" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "DAYOFWEEK" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "DAYOFMONTH" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "DAYOFYEAR" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| DateArithOpt '(' Expression ',' "INTERVAL" Expression TimeUnit ')'
|
||
|
{
|
||
|
op := ast.NewValueExpr($1)
|
||
|
dateArithInterval := ast.NewValueExpr(
|
||
|
ast.DateArithInterval{
|
||
|
Unit: $7.(string),
|
||
|
Interval: $6.(ast.ExprNode),
|
||
|
},
|
||
|
)
|
||
|
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr("DATE_ARITH"),
|
||
|
Args: []ast.ExprNode{
|
||
|
op,
|
||
|
$3.(ast.ExprNode),
|
||
|
dateArithInterval,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
| DateArithMultiFormsOpt '(' Expression ',' DateArithInterval')'
|
||
|
{
|
||
|
op := ast.NewValueExpr($1)
|
||
|
dateArithInterval := ast.NewValueExpr($5)
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr("DATE_ARITH"),
|
||
|
Args: []ast.ExprNode{
|
||
|
op,
|
||
|
$3.(ast.ExprNode),
|
||
|
dateArithInterval,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
| "EXTRACT" '(' TimeUnit "FROM" Expression ')'
|
||
|
{
|
||
|
timeUnit := ast.NewValueExpr($3)
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{timeUnit, $5.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "FOUND_ROWS" '(' ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string))}
|
||
|
}
|
||
|
| "HOUR" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "IFNULL" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "LENGTH" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "LOCATE" '(' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "LOCATE" '(' Expression ',' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "LOWER" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "MICROSECOND" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "MINUTE" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "MONTH" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "NOW" '(' ExpressionOpt ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{}
|
||
|
if $3 != nil {
|
||
|
args = append(args, $3.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "NULLIF" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "POW" '(' Expression ',' Expression ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "POWER" '(' Expression ',' Expression ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "RAND" '(' ExpressionOpt ')'
|
||
|
{
|
||
|
|
||
|
args := []ast.ExprNode{}
|
||
|
if $3 != nil {
|
||
|
args = append(args, $3.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "REPLACE" '(' Expression ',' Expression ',' Expression ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "SECOND" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "STRCMP" '(' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "SUBSTRING" '(' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "SUBSTRING" '(' Expression "FROM" Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "SUBSTRING" '(' Expression ',' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "SUBSTRING" '(' Expression "FROM" Expression "FOR" Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "SUBSTRING_INDEX" '(' Expression ',' Expression ',' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "SYSDATE" '(' ExpressionOpt ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{}
|
||
|
if $3 != nil {
|
||
|
args = append(args, $3.(ast.ExprNode))
|
||
|
}
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: args}
|
||
|
}
|
||
|
| "TRIM" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$3.(ast.ExprNode)},
|
||
|
}
|
||
|
}
|
||
|
| "TRIM" '(' Expression "FROM" Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
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.(string)),
|
||
|
Args: []ast.ExprNode{$5.(ast.ExprNode), nilVal, direction},
|
||
|
}
|
||
|
}
|
||
|
| "TRIM" '(' TrimDirection Expression "FROM" Expression ')'
|
||
|
{
|
||
|
direction := ast.NewValueExpr($3)
|
||
|
$$ = &ast.FuncCallExpr{
|
||
|
FnName: model.NewCIStr($1.(string)),
|
||
|
Args: []ast.ExprNode{$6.(ast.ExprNode),$4.(ast.ExprNode), direction},
|
||
|
}
|
||
|
}
|
||
|
| "UPPER" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "WEEKDAY" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "WEEKOFYEAR" '(' Expression ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
|
||
|
}
|
||
|
| "YEARWEEK" '(' ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
|
||
|
}
|
||
|
| "CONNECTION_ID" '(' ')'
|
||
|
{
|
||
|
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string))}
|
||
|
}
|
||
|
|
||
|
DateArithOpt:
|
||
|
"DATE_ADD"
|
||
|
{
|
||
|
$$ = ast.DateAdd
|
||
|
}
|
||
|
| "DATE_SUB"
|
||
|
{
|
||
|
$$ = ast.DateSub
|
||
|
}
|
||
|
|
||
|
DateArithMultiFormsOpt:
|
||
|
"ADDDATE"
|
||
|
{
|
||
|
$$ = ast.DateAdd
|
||
|
}
|
||
|
| "SUBDATE"
|
||
|
{
|
||
|
$$ = ast.DateSub
|
||
|
}
|
||
|
|
||
|
DateArithInterval:
|
||
|
Expression
|
||
|
{
|
||
|
$$ = ast.DateArithInterval{
|
||
|
Unit: "day",
|
||
|
Interval: $1.(ast.ExprNode),
|
||
|
}
|
||
|
}
|
||
|
| "INTERVAL" Expression TimeUnit
|
||
|
{
|
||
|
$$ = ast.DateArithInterval{Unit: $3.(string), Interval: $2.(ast.ExprNode)}
|
||
|
}
|
||
|
|
||
|
TrimDirection:
|
||
|
"BOTH"
|
||
|
{
|
||
|
$$ = ast.TrimBoth
|
||
|
}
|
||
|
| "LEADING"
|
||
|
{
|
||
|
$$ = ast.TrimLeading
|
||
|
}
|
||
|
| "TRAILING"
|
||
|
{
|
||
|
$$ = ast.TrimTrailing
|
||
|
}
|
||
|
|
||
|
FunctionCallAgg:
|
||
|
"AVG" '(' DistinctOpt ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: $4.([]ast.ExprNode), Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "COUNT" '(' DistinctOpt ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: $4.([]ast.ExprNode), Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "COUNT" '(' DistinctOpt '*' ')'
|
||
|
{
|
||
|
args := []ast.ExprNode{ast.NewValueExpr(ast.UnquoteString("*"))}
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: args, Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "GROUP_CONCAT" '(' DistinctOpt ExpressionList ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: $4.([]ast.ExprNode), Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "MAX" '(' DistinctOpt Expression ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "MIN" '(' DistinctOpt Expression ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
||
|
}
|
||
|
| "SUM" '(' DistinctOpt Expression ')'
|
||
|
{
|
||
|
$$ = &ast.AggregateFuncExpr{F: $1.(string), Args: []ast.ExprNode{$4.(ast.ExprNode)}, Distinct: $3.(bool)}
|
||
|
}
|
||
|
|
||
|
FuncDatetimePrec:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| '(' ')'
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| '(' Expression ')'
|
||
|
{
|
||
|
$$ = $2
|
||
|
}
|
||
|
|
||
|
TimeUnit:
|
||
|
"MICROSECOND" | "SECOND" | "MINUTE" | "HOUR" | "DAY" | "WEEK"
|
||
|
| "MONTH" | "QUARTER" | "YEAR" | "SECOND_MICROSECOND" | "MINUTE_MICROSECOND"
|
||
|
| "MINUTE_SECOND" | "HOUR_MICROSECOND" | "HOUR_SECOND" | "HOUR_MINUTE"
|
||
|
| "DAY_MICROSECOND" | "DAY_SECOND" | "DAY_MINUTE" | "DAY_HOUR" | "YEAR_MONTH"
|
||
|
|
||
|
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)
|
||
|
if $3.(bool) {
|
||
|
x.Flag |= mysql.BinaryFlag
|
||
|
}
|
||
|
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
|
||
|
$$ = 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.(string))}
|
||
|
}
|
||
|
| Identifier '.' Identifier
|
||
|
{
|
||
|
$$ = &ast.TableName{Schema:model.NewCIStr($1.(string)), Name:model.NewCIStr($3.(string))}
|
||
|
}
|
||
|
|
||
|
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.(string),
|
||
|
SQLText: sqlText,
|
||
|
SQLVar: sqlVar,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PrepareSQL:
|
||
|
stringLit
|
||
|
| 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.(string)}
|
||
|
}
|
||
|
| "EXECUTE" Identifier "USING" UserVariableList
|
||
|
{
|
||
|
$$ = &ast.ExecuteStmt{
|
||
|
Name: $2.(string),
|
||
|
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.(string)}
|
||
|
}
|
||
|
|
||
|
DeallocateSym:
|
||
|
"DEALLOCATE" | "DROP"
|
||
|
|
||
|
/****************************Prepared Statement End*******************************/
|
||
|
|
||
|
|
||
|
RollbackStmt:
|
||
|
"ROLLBACK"
|
||
|
{
|
||
|
$$ = &ast.RollbackStmt{}
|
||
|
}
|
||
|
|
||
|
SelectStmt:
|
||
|
"SELECT" SelectStmtOpts SelectStmtFieldList SelectStmtLimit SelectLockOpt
|
||
|
{
|
||
|
st := &ast.SelectStmt {
|
||
|
Distinct: $2.(bool),
|
||
|
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 := yylex.(*lexer).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.(bool),
|
||
|
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(yylex.(*lexer).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
|
||
|
{
|
||
|
st := &ast.SelectStmt{
|
||
|
Distinct: $2.(bool),
|
||
|
Fields: $3.(*ast.FieldList),
|
||
|
From: $5.(*ast.TableRefsClause),
|
||
|
LockTp: $11.(ast.SelectLockType),
|
||
|
}
|
||
|
|
||
|
lastField := st.Fields.Fields[len(st.Fields.Fields)-1]
|
||
|
if lastField.Expr != nil && lastField.AsName.O == "" {
|
||
|
lastEnd := yyS[yypt-7].offset-1
|
||
|
lastField.SetText(yylex.(*lexer).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
|
||
|
{
|
||
|
$$ = &ast.TableSource{Source: $1.(*ast.TableName), AsName: $2.(model.CIStr)}
|
||
|
}
|
||
|
| '(' SelectStmt ')' TableAsName
|
||
|
{
|
||
|
st := $2.(*ast.SelectStmt)
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt-1].offset)
|
||
|
l.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.(string))
|
||
|
}
|
||
|
| "AS" Identifier
|
||
|
{
|
||
|
$$ = model.NewCIStr($2.(string))
|
||
|
}
|
||
|
|
||
|
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:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "OUTER"
|
||
|
|
||
|
|
||
|
CrossOpt:
|
||
|
"JOIN"
|
||
|
| "CROSS" "JOIN"
|
||
|
| "INNER" "JOIN"
|
||
|
|
||
|
|
||
|
LimitClause:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "LIMIT" LengthNum
|
||
|
{
|
||
|
$$ = &ast.Limit{Count: $2.(uint64)}
|
||
|
}
|
||
|
|
||
|
SelectStmtLimit:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "LIMIT" LengthNum
|
||
|
{
|
||
|
$$ = &ast.Limit{Count: $2.(uint64)}
|
||
|
}
|
||
|
| "LIMIT" LengthNum ',' LengthNum
|
||
|
{
|
||
|
$$ = &ast.Limit{Offset: $2.(uint64), Count: $4.(uint64)}
|
||
|
}
|
||
|
| "LIMIT" LengthNum "OFFSET" LengthNum
|
||
|
{
|
||
|
$$ = &ast.Limit{Offset: $4.(uint64), Count: $2.(uint64)}
|
||
|
}
|
||
|
|
||
|
SelectStmtDistinct:
|
||
|
/* EMPTY */
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "ALL"
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "DISTINCT"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
SelectStmtOpts:
|
||
|
SelectStmtDistinct SelectStmtCalcFoundRows
|
||
|
{
|
||
|
// TODO: return calc_found_rows opt and support more other options
|
||
|
$$ = $1
|
||
|
}
|
||
|
|
||
|
SelectStmtCalcFoundRows:
|
||
|
%prec lowerThanCalcFoundRows
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "SQL_CALC_FOUND_ROWS"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt].offset)
|
||
|
l.SetLastSelectFieldText(s, endOffset)
|
||
|
src := yylex.(*lexer).src
|
||
|
// See the implemention 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 := yylex.(*lexer).src
|
||
|
// See the implemention 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]
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt-2].offset)
|
||
|
l.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]
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt-6].offset)
|
||
|
l.SetLastSelectFieldText(lastSelect, endOffset)
|
||
|
st := $5.(*ast.SelectStmt)
|
||
|
endOffset = l.endOffset(yyS[yypt-2].offset)
|
||
|
l.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]
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt-2].offset)
|
||
|
l.SetLastSelectFieldText(lastSelect, endOffset)
|
||
|
union.SelectList.Selects = append(union.SelectList.Selects, $4.(*ast.SelectStmt))
|
||
|
$$ = union
|
||
|
}
|
||
|
|
||
|
UnionSelect:
|
||
|
SelectStmt
|
||
|
| '(' SelectStmt ')'
|
||
|
{
|
||
|
st := $2.(*ast.SelectStmt)
|
||
|
l := yylex.(*lexer)
|
||
|
endOffset := l.endOffset(yyS[yypt].offset)
|
||
|
l.SetLastSelectFieldText(st, endOffset)
|
||
|
$$ = st
|
||
|
}
|
||
|
|
||
|
UnionOpt:
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
| "ALL"
|
||
|
{
|
||
|
$$ = false
|
||
|
}
|
||
|
| "DISTINCT"
|
||
|
{
|
||
|
$$ = true
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************Set Statement*******************************/
|
||
|
SetStmt:
|
||
|
"SET" VariableAssignmentList
|
||
|
{
|
||
|
$$ = &ast.SetStmt{Variables: $2.([]*ast.VariableAssignment)}
|
||
|
}
|
||
|
| "SET" "NAMES" StringName
|
||
|
{
|
||
|
$$ = &ast.SetCharsetStmt{Charset: $3.(string)}
|
||
|
}
|
||
|
| "SET" "NAMES" StringName "COLLATE" StringName
|
||
|
{
|
||
|
$$ = &ast.SetCharsetStmt{
|
||
|
Charset: $3.(string),
|
||
|
Collate: $5.(string),
|
||
|
}
|
||
|
}
|
||
|
| "SET" CharsetKw StringName
|
||
|
{
|
||
|
$$ = &ast.SetCharsetStmt{Charset: $3.(string)}
|
||
|
}
|
||
|
| "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.(string), Value: $3.(ast.ExprNode), IsSystem: true}
|
||
|
}
|
||
|
| "GLOBAL" Identifier eq Expression
|
||
|
{
|
||
|
$$ = &ast.VariableAssignment{Name: $2.(string), Value: $4.(ast.ExprNode), IsGlobal: true, IsSystem: true}
|
||
|
}
|
||
|
| "SESSION" Identifier eq Expression
|
||
|
{
|
||
|
$$ = &ast.VariableAssignment{Name: $2.(string), Value: $4.(ast.ExprNode), IsSystem: true}
|
||
|
}
|
||
|
| "LOCAL" Identifier eq Expression
|
||
|
{
|
||
|
$$ = &ast.VariableAssignment{Name: $2.(string), 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)}
|
||
|
}
|
||
|
|
||
|
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 "AT" stringLit
|
||
|
{
|
||
|
$$ = $1.(string) + "@" + $3.(string)
|
||
|
}
|
||
|
|
||
|
PasswordOpt:
|
||
|
stringLit
|
||
|
{
|
||
|
$$ = $1.(string)
|
||
|
}
|
||
|
| "PASSWORD" '(' AuthString ')'
|
||
|
{
|
||
|
$$ = $3.(string)
|
||
|
}
|
||
|
|
||
|
AuthString:
|
||
|
stringLit
|
||
|
{
|
||
|
$$ = $1.(string)
|
||
|
}
|
||
|
|
||
|
/****************************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" "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" "INDEX" "FROM" TableName
|
||
|
{
|
||
|
$$ = &ast.ShowStmt{
|
||
|
Tp: ast.ShowIndex,
|
||
|
Table: $4.(*ast.TableName),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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),
|
||
|
}
|
||
|
}
|
||
|
| 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,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ShowLikeOrWhereOpt:
|
||
|
{
|
||
|
$$ = nil
|
||
|
}
|
||
|
| "LIKE" PrimaryExpression
|
||
|
{
|
||
|
$$ = &ast.PatternLikeExpr{Pattern: $2.(ast.ExprNode)}
|
||
|
}
|
||
|
| "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)
|
||
|
}
|
||
|
|
||
|
Statement:
|
||
|
EmptyStmt
|
||
|
| AdminStmt
|
||
|
| AlterTableStmt
|
||
|
| BeginTransactionStmt
|
||
|
| CommitStmt
|
||
|
| DeallocateStmt
|
||
|
| DeleteFromStmt
|
||
|
| ExecuteStmt
|
||
|
| ExplainStmt
|
||
|
| CreateDatabaseStmt
|
||
|
| CreateIndexStmt
|
||
|
| CreateTableStmt
|
||
|
| CreateUserStmt
|
||
|
| DoStmt
|
||
|
| DropDatabaseStmt
|
||
|
| DropIndexStmt
|
||
|
| DropTableStmt
|
||
|
| GrantStmt
|
||
|
| InsertIntoStmt
|
||
|
| PreparedStmt
|
||
|
| RollbackStmt
|
||
|
| ReplaceIntoStmt
|
||
|
| 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
|
||
|
|
||
|
StatementList:
|
||
|
Statement
|
||
|
{
|
||
|
if $1 != nil {
|
||
|
s := $1.(ast.StmtNode)
|
||
|
s.SetText(yylex.(*lexer).stmtText())
|
||
|
yylex.(*lexer).list = append(yylex.(*lexer).list, s)
|
||
|
}
|
||
|
}
|
||
|
| StatementList ';' Statement
|
||
|
{
|
||
|
if $3 != nil {
|
||
|
s := $3.(ast.StmtNode)
|
||
|
s.SetText(yylex.(*lexer).stmtText())
|
||
|
yylex.(*lexer).list = append(yylex.(*lexer).list, 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.(string)}
|
||
|
}
|
||
|
| "ENGINE" eq Identifier
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionEngine, StrValue: $3.(string)}
|
||
|
}
|
||
|
| DefaultKwdOpt CharsetKw EqOpt StringName
|
||
|
{
|
||
|
$$ = &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.(string)}
|
||
|
}
|
||
|
| "AVG_ROW_LENGTH" EqOpt LengthNum
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionAvgRowLength, UintValue: $3.(uint64)}
|
||
|
}
|
||
|
| "CONNECTION" EqOpt stringLit
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionConnection, StrValue: $3.(string)}
|
||
|
}
|
||
|
| "CHECKSUM" EqOpt LengthNum
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionCheckSum, UintValue: $3.(uint64)}
|
||
|
}
|
||
|
| "PASSWORD" EqOpt stringLit
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionPassword, StrValue: $3.(string)}
|
||
|
}
|
||
|
| "COMPRESSION" EqOpt Identifier
|
||
|
{
|
||
|
$$ = &ast.TableOption{Tp: ast.TableOptionCompression, StrValue: $3.(string)}
|
||
|
}
|
||
|
| "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)}
|
||
|
}
|
||
|
|
||
|
|
||
|
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))
|
||
|
}
|
||
|
|
||
|
|
||
|
TruncateTableStmt:
|
||
|
"TRUNCATE" "TABLE" 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
|
||
|
}
|
||
|
| "float32"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
| "float64"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
| "int64"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
| "string"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
| "uint"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
| "uint64"
|
||
|
{
|
||
|
x := types.NewFieldType($1.(byte))
|
||
|
$$ = x
|
||
|
}
|
||
|
|
||
|
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.(*lexer).errf("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.(*lexer).errf("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)
|
||
|
if $4.(bool) {
|
||
|
x.Flag |= mysql.BinaryFlag
|
||
|
}
|
||
|
$$ = x
|
||
|
}
|
||
|
| NationalOpt "CHAR" OptBinary OptCharset OptCollate
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeString)
|
||
|
if $3.(bool) {
|
||
|
x.Flag |= mysql.BinaryFlag
|
||
|
}
|
||
|
$$ = x
|
||
|
}
|
||
|
| NationalOpt "VARCHAR" FieldLen OptBinary OptCharset OptCollate
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeVarchar)
|
||
|
x.Flen = $3.(int)
|
||
|
if $4.(bool) {
|
||
|
x.Flag |= mysql.BinaryFlag
|
||
|
}
|
||
|
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
|
||
|
}
|
||
|
| "VARBINARY" FieldLen
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeVarchar)
|
||
|
x.Flen = $2.(int)
|
||
|
x.Charset = charset.CharsetBin
|
||
|
x.Collate = charset.CharsetBin
|
||
|
$$ = x
|
||
|
}
|
||
|
| BlobType
|
||
|
{
|
||
|
$$ = $1.(*types.FieldType)
|
||
|
}
|
||
|
| TextType OptBinary OptCharset OptCollate
|
||
|
{
|
||
|
x := $1.(*types.FieldType)
|
||
|
if $2.(bool) {
|
||
|
x.Flag |= mysql.BinaryFlag
|
||
|
}
|
||
|
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.Charset = charset.CharsetBin
|
||
|
x.Collate = charset.CharsetBin
|
||
|
$$ = x
|
||
|
}
|
||
|
| "BLOB" OptFieldLen
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeBlob)
|
||
|
x.Flen = $2.(int)
|
||
|
x.Charset = charset.CharsetBin
|
||
|
x.Collate = charset.CharsetBin
|
||
|
$$ = x
|
||
|
}
|
||
|
| "MEDIUMBLOB"
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeMediumBlob)
|
||
|
x.Charset = charset.CharsetBin
|
||
|
x.Collate = charset.CharsetBin
|
||
|
$$ = x
|
||
|
}
|
||
|
| "LONGBLOB"
|
||
|
{
|
||
|
x := types.NewFieldType(mysql.TypeLongBlob)
|
||
|
x.Charset = charset.CharsetBin
|
||
|
x.Collate = charset.CharsetBin
|
||
|
$$ = 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 StringName
|
||
|
{
|
||
|
$$ = $2.(string)
|
||
|
}
|
||
|
|
||
|
CharsetKw:
|
||
|
"CHARACTER" "SET"
|
||
|
| "CHARSET"
|
||
|
|
||
|
OptCollate:
|
||
|
{
|
||
|
$$ = ""
|
||
|
}
|
||
|
| "COLLATE" StringName
|
||
|
{
|
||
|
$$ = $2.(string)
|
||
|
}
|
||
|
|
||
|
StringList:
|
||
|
stringLit
|
||
|
{
|
||
|
$$ = []string{$1.(string)}
|
||
|
}
|
||
|
| StringList ',' stringLit
|
||
|
{
|
||
|
$$ = append($1.([]string), $3.(string))
|
||
|
}
|
||
|
|
||
|
StringName:
|
||
|
stringLit
|
||
|
{
|
||
|
$$ = $1.(string)
|
||
|
}
|
||
|
| Identifier
|
||
|
{
|
||
|
$$ = $1.(string)
|
||
|
}
|
||
|
|
||
|
/***********************************************************************************
|
||
|
* 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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
| "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
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UseStmt:
|
||
|
"USE" DBName
|
||
|
{
|
||
|
$$ = &ast.UseStmt{DBName: $2.(string)}
|
||
|
if yylex.(*lexer).root {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
|
||
|
/*************************************************************************************
|
||
|
* Grant statement
|
||
|
* See: https://dev.mysql.com/doc/refman/5.7/en/grant.html
|
||
|
*************************************************************************************/
|
||
|
GrantStmt:
|
||
|
"GRANT" PrivElemList "ON" ObjectType PrivLevel "TO" UserSpecList
|
||
|
{
|
||
|
$$ = &ast.GrantStmt{
|
||
|
Privs: $2.([]*ast.PrivElem),
|
||
|
ObjectType: $4.(ast.ObjectTypeType),
|
||
|
Level: $5.(*ast.GrantLevel),
|
||
|
Users: $7.([]*ast.UserSpec),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
| "ALTER"
|
||
|
{
|
||
|
$$ = mysql.AlterPriv
|
||
|
}
|
||
|
| "CREATE"
|
||
|
{
|
||
|
$$ = mysql.CreatePriv
|
||
|
}
|
||
|
| "CREATE" "USER"
|
||
|
{
|
||
|
$$ = mysql.CreateUserPriv
|
||
|
}
|
||
|
| "DELETE"
|
||
|
{
|
||
|
$$ = mysql.DeletePriv
|
||
|
}
|
||
|
| "DROP"
|
||
|
{
|
||
|
$$ = mysql.DropPriv
|
||
|
}
|
||
|
| "EXECUTE"
|
||
|
{
|
||
|
$$ = mysql.ExecutePriv
|
||
|
}
|
||
|
| "INDEX"
|
||
|
{
|
||
|
$$ = mysql.IndexPriv
|
||
|
}
|
||
|
| "INSERT"
|
||
|
{
|
||
|
$$ = mysql.InsertPriv
|
||
|
}
|
||
|
| "SELECT"
|
||
|
{
|
||
|
$$ = mysql.SelectPriv
|
||
|
}
|
||
|
| "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.(string),
|
||
|
}
|
||
|
}
|
||
|
| Identifier '.' Identifier
|
||
|
{
|
||
|
$$ = &ast.GrantLevel {
|
||
|
Level: ast.GrantLevelTable,
|
||
|
DBName: $1.(string),
|
||
|
TableName: $3.(string),
|
||
|
}
|
||
|
}
|
||
|
| Identifier
|
||
|
{
|
||
|
$$ = &ast.GrantLevel {
|
||
|
Level: ast.GrantLevelTable,
|
||
|
TableName: $1.(string),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*********************************************************************
|
||
|
* 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
|
||
|
|
||
|
%%
|