4326 lines
88 KiB
Plaintext
4326 lines
88 KiB
Plaintext
%{
|
|
// Copyright 2013 The ql Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSES/QL-LICENSE file.
|
|
|
|
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// 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 (
|
|
"fmt"
|
|
"strings"
|
|
|
|
mysql "github.com/pingcap/tidb/mysqldef"
|
|
"github.com/pingcap/tidb/parser/coldef"
|
|
"github.com/pingcap/tidb/ddl"
|
|
"github.com/pingcap/tidb/expression"
|
|
"github.com/pingcap/tidb/expression/subquery"
|
|
"github.com/pingcap/tidb/field"
|
|
"github.com/pingcap/tidb/model"
|
|
"github.com/pingcap/tidb/parser/opcode"
|
|
"github.com/pingcap/tidb/rset/rsets"
|
|
"github.com/pingcap/tidb/stmt"
|
|
"github.com/pingcap/tidb/stmt/stmts"
|
|
"github.com/pingcap/tidb/table"
|
|
"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"
|
|
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"
|
|
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"
|
|
compression "COMPRESSION"
|
|
concat "CONCAT"
|
|
concatWs "CONCAT_WS"
|
|
connection "CONNECTION"
|
|
constraint "CONSTRAINT"
|
|
convert "CONVERT"
|
|
count "COUNT"
|
|
create "CREATE"
|
|
cross "CROSS"
|
|
curDate "CURDATE"
|
|
currentDate "CURRENT_DATE"
|
|
currentUser "CURRENT_USER"
|
|
database "DATABASE"
|
|
databases "DATABASES"
|
|
day "DAY"
|
|
dayofmonth "DAYOFMONTH"
|
|
dayofweek "DAYOFWEEK"
|
|
dayofyear "DAYOFYEAR"
|
|
deallocate "DEALLOCATE"
|
|
defaultKwd "DEFAULT"
|
|
delayed "DELAYED"
|
|
deleteKwd "DELETE"
|
|
desc "DESC"
|
|
describe "DESCRIBE"
|
|
distinct "DISTINCT"
|
|
div "DIV"
|
|
do "DO"
|
|
drop "DROP"
|
|
dual "DUAL"
|
|
duplicate "DUPLICATE"
|
|
elseKwd "ELSE"
|
|
end "END"
|
|
engine "ENGINE"
|
|
engines "ENGINES"
|
|
enum "ENUM"
|
|
eq "="
|
|
escape "ESCAPE"
|
|
execute "EXECUTE"
|
|
exists "EXISTS"
|
|
explain "EXPLAIN"
|
|
extract "EXTRACT"
|
|
falseKwd "false"
|
|
first "FIRST"
|
|
foreign "FOREIGN"
|
|
forKwd "FOR"
|
|
foundRows "FOUND_ROWS"
|
|
from "FROM"
|
|
full "FULL"
|
|
fulltext "FULLTEXT"
|
|
ge ">="
|
|
global "GLOBAL"
|
|
group "GROUP"
|
|
groupConcat "GROUP_CONCAT"
|
|
having "HAVING"
|
|
highPriority "HIGH_PRIORITY"
|
|
hour "HOUR"
|
|
identified "IDENTIFIED"
|
|
ignore "IGNORE"
|
|
ifKwd "IF"
|
|
ifNull "IFNULL"
|
|
in "IN"
|
|
index "INDEX"
|
|
inner "INNER"
|
|
insert "INSERT"
|
|
into "INTO"
|
|
is "IS"
|
|
join "JOIN"
|
|
key "KEY"
|
|
keyBlockSize "KEY_BLOCK_SIZE"
|
|
le "<="
|
|
leading "LEADING"
|
|
left "LEFT"
|
|
length "LENGTH"
|
|
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"
|
|
or "OR"
|
|
order "ORDER"
|
|
oror "||"
|
|
outer "OUTER"
|
|
password "PASSWORD"
|
|
placeholder "PLACEHOLDER"
|
|
prepare "PREPARE"
|
|
primary "PRIMARY"
|
|
quarter "QUARTER"
|
|
quick "QUICK"
|
|
rand "RAND"
|
|
references "REFERENCES"
|
|
regexp "REGEXP"
|
|
repeat "REPEAT"
|
|
right "RIGHT"
|
|
rlike "RLIKE"
|
|
rollback "ROLLBACK"
|
|
row "ROW"
|
|
rsh ">>"
|
|
schema "SCHEMA"
|
|
schemas "SCHEMAS"
|
|
second "SECOND"
|
|
selectKwd "SELECT"
|
|
session "SESSION"
|
|
set "SET"
|
|
share "SHARE"
|
|
show "SHOW"
|
|
signed "SIGNED"
|
|
some "SOME"
|
|
start "START"
|
|
stringType "string"
|
|
substring "SUBSTRING"
|
|
substringIndex "SUBSTRING_INDEX"
|
|
sum "SUM"
|
|
sysVar "SYS_VAR"
|
|
sysDate "SYSDATE"
|
|
tableKwd "TABLE"
|
|
tables "TABLES"
|
|
then "THEN"
|
|
trailing "TRAILING"
|
|
transaction "TRANSACTION"
|
|
trim "TRIM"
|
|
trueKwd "true"
|
|
truncate "TRUNCATE"
|
|
unknown "UNKNOWN"
|
|
union "UNION"
|
|
unique "UNIQUE"
|
|
unsigned "UNSIGNED"
|
|
update "UPDATE"
|
|
upper "UPPER"
|
|
use "USE"
|
|
user "USER"
|
|
using "USING"
|
|
userVar "USER_VAR"
|
|
value "VALUE"
|
|
values "VALUES"
|
|
variables "VARIABLES"
|
|
warnings "WARNINGS"
|
|
week "WEEK"
|
|
weekday "WEEKDAY"
|
|
weekofyear "WEEKOFYEAR"
|
|
when "WHEN"
|
|
where "WHERE"
|
|
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>
|
|
AlterTableStmt "Alter table statement"
|
|
AlterSpecification "Alter table specification"
|
|
AlterSpecificationList "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"
|
|
CharsetName "Charset Name"
|
|
CollationName "Collation Name"
|
|
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"
|
|
Constraint "column value constraint"
|
|
ConstraintElem "table define constraint element"
|
|
ConstraintKeywordOpt "Constraint Keyword or empty"
|
|
ConstraintOpt "optional column value constraint"
|
|
ConstraintOpts "optional column value constraints"
|
|
CreateDatabaseStmt "Create Database Statement"
|
|
CreateIndexStmt "CREATE INDEX statement"
|
|
CreateIndexStmtUnique "CREATE INDEX optional UNIQUE clause"
|
|
CreateSpecification "CREATE Database specification"
|
|
CreateSpecificationList "CREATE Database specification list"
|
|
CreateSpecListOpt "CREATE Database specification list opt"
|
|
CreateTableStmt "CREATE TABLE statement"
|
|
CreateUserStmt "CREATE User statement"
|
|
CrossOpt "Cross join option"
|
|
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"
|
|
FromClause "From 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"
|
|
GroupByClause "GROUP BY clause"
|
|
GroupByList "GROUP BY list"
|
|
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"
|
|
IndexType "index type"
|
|
InsertIntoStmt "INSERT INTO statement"
|
|
InsertRest "Rest part of INSERT INTO statement"
|
|
IntoOpt "INTO or EmptyString"
|
|
JoinTable "join table"
|
|
JoinType "join type"
|
|
KeyOrIndex "{KEY|INDEX}"
|
|
LikeEscapeOpt "like escape option"
|
|
LimitClause "LIMIT clause"
|
|
Literal "literal value"
|
|
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"
|
|
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"
|
|
OrderByItem "ORDER BY list item"
|
|
OrderByOptional "Optional ORDER BY clause optional"
|
|
OrderByList "ORDER BY list"
|
|
OuterOpt "optional OUTER clause"
|
|
QualifiedIdent "qualified identifier"
|
|
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"
|
|
ReferDef "Reference definition"
|
|
RegexpSym "REGEXP or RLIKE"
|
|
RollbackStmt "ROLLBACK statement"
|
|
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"
|
|
SelectStmtOrder "SELECT statement optional ORDER BY clause"
|
|
SetStmt "Set variable statement"
|
|
ShowStmt "Show engines/databases/tables/columns/warnings statement"
|
|
ShowDatabaseNameOpt "Show tables/columns statement database name option"
|
|
ShowLikeOrWhereOpt "Show like or where condition option"
|
|
ShowTableIdentOpt "Show columns statement table name option"
|
|
SignedLiteral "Literal or NumLiteral with sign"
|
|
SimpleQualifiedIdent "Qualified identifier without *"
|
|
Statement "statement"
|
|
StatementList "statement list"
|
|
StringList "string list"
|
|
ExplainableStmt "explainable statement"
|
|
SubSelect "Sub Select"
|
|
Symbol "Constraint Symbol"
|
|
SystemVariable "System defined variable name"
|
|
TableAsOpt "table as option"
|
|
TableConstraint "table constraint definition"
|
|
TableElement "table definition element"
|
|
TableElementList "table definition element list"
|
|
TableElementListOpt "table definition element list opt"
|
|
TableFactor "table factor"
|
|
TableIdent "Table identifier"
|
|
TableIdentList "Table identifier list"
|
|
TableIdentOpt "Table identifier option"
|
|
TableOpt "create table option"
|
|
TableOptList "create table option list"
|
|
TableOptListOpt "create table option list opt"
|
|
TableRef "table reference"
|
|
TableRefs "table references"
|
|
TimeUnit "Time unit"
|
|
TrimDirection "Trim string direction"
|
|
TruncateTableStmt "TRANSACTION TABLE statement"
|
|
UnionOpt "Union Option(empty/ALL/DISTINCT)"
|
|
UnionSelect "Union select/(select)"
|
|
UnionStmt "Union statement"
|
|
UpdateStmt "UPDATE statement"
|
|
Username "Username"
|
|
UserSpecification "Username and auth option"
|
|
UserSpecificationList "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 = expression.Expr($2)
|
|
}
|
|
|
|
/**************************************AlterTableStmt***************************************
|
|
* See: https://dev.mysql.com/doc/refman/5.7/en/alter-table.html
|
|
*******************************************************************************************/
|
|
AlterTableStmt:
|
|
"ALTER" IgnoreOptional "TABLE" TableIdent AlterSpecificationList
|
|
{
|
|
$$ = &stmts.AlterTableStmt{
|
|
Ident: $4.(table.Ident),
|
|
Specs: $5.([]*ddl.AlterSpecification),
|
|
}
|
|
}
|
|
|
|
AlterSpecification:
|
|
TableOptListOpt
|
|
{
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterTableOpt,
|
|
TableOpts: $1.([]*coldef.TableOpt),
|
|
}
|
|
}
|
|
| "ADD" ColumnKeywordOpt ColumnDef ColumnPosition
|
|
{
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterAddColumn,
|
|
Column: $3.(*coldef.ColumnDef),
|
|
Position: $4.(*ddl.ColumnPosition),
|
|
}
|
|
}
|
|
| "ADD" ConstraintKeywordOpt ConstraintElem
|
|
{
|
|
constraint := $3.(*coldef.TableConstraint)
|
|
if $2 != nil {
|
|
constraint.ConstrName = $2.(string)
|
|
}
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterAddConstr,
|
|
Constraint: constraint,
|
|
}
|
|
}
|
|
| "DROP" ColumnKeywordOpt ColumnName
|
|
{
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterDropColumn,
|
|
Name: $3.(string),
|
|
}
|
|
}
|
|
| "DROP" "PRIMARY" "KEY"
|
|
{
|
|
$$ = &ddl.AlterSpecification{Action: ddl.AlterDropPrimaryKey}
|
|
}
|
|
| "DROP" KeyOrIndex IndexName
|
|
{
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterDropIndex,
|
|
Name: $3.(string),
|
|
}
|
|
}
|
|
| "DROP" "FOREIGN" "KEY" Symbol
|
|
{
|
|
$$ = &ddl.AlterSpecification{
|
|
Action: ddl.AlterDropForeignKey,
|
|
Name: $4.(string),
|
|
}
|
|
}
|
|
|
|
KeyOrIndex:
|
|
"KEY"|"INDEX"
|
|
|
|
ColumnKeywordOpt:
|
|
{}
|
|
| "COLUMN"
|
|
|
|
ColumnPosition:
|
|
{
|
|
$$ = &ddl.ColumnPosition{Type: ddl.ColumnPositionNone}
|
|
}
|
|
| "FIRST"
|
|
{
|
|
$$ = &ddl.ColumnPosition{Type: ddl.ColumnPositionFirst}
|
|
}
|
|
| "AFTER" ColumnName
|
|
{
|
|
$$ = &ddl.ColumnPosition{
|
|
Type: ddl.ColumnPositionAfter,
|
|
RelativeColumn: $2.(string),
|
|
}
|
|
}
|
|
|
|
|
|
AlterSpecificationList:
|
|
AlterSpecification
|
|
{
|
|
$$ = []*ddl.AlterSpecification{$1.(*ddl.AlterSpecification)}
|
|
}
|
|
| AlterSpecificationList ',' AlterSpecification
|
|
{
|
|
$$ = append($1.([]*ddl.AlterSpecification), $3.(*ddl.AlterSpecification))
|
|
}
|
|
|
|
ConstraintKeywordOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "CONSTRAINT"
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "CONSTRAINT" Symbol
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
Symbol:
|
|
Identifier
|
|
|
|
/*******************************************************************************************/
|
|
Assignment:
|
|
SimpleQualifiedIdent eq Expression
|
|
{
|
|
x, err := expression.NewAssignment($1.(string), $3.(expression.Expression))
|
|
if err != nil {
|
|
yylex.(*lexer).errf("Parse Assignment error: %s", $1.(string))
|
|
}
|
|
$$ = *x
|
|
}
|
|
|
|
AssignmentList:
|
|
Assignment
|
|
{
|
|
$$ = []expression.Assignment{$1.(expression.Assignment)}
|
|
}
|
|
| AssignmentList ',' Assignment
|
|
{
|
|
$$ = append($1.([]expression.Assignment), $3.(expression.Assignment))
|
|
}
|
|
|
|
AssignmentListOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []expression.Assignment{}
|
|
}
|
|
| AssignmentList
|
|
|
|
BeginTransactionStmt:
|
|
"BEGIN"
|
|
{
|
|
$$ = &stmts.BeginStmt{}
|
|
}
|
|
| "START" "TRANSACTION"
|
|
{
|
|
$$ = &stmts.BeginStmt{}
|
|
}
|
|
|
|
ColumnDef:
|
|
ColumnName Type ConstraintOpts
|
|
{
|
|
$$ = &coldef.ColumnDef{Name: $1.(string), Tp: $2.(*types.FieldType), Constraints: $3.([]*coldef.ConstraintOpt)}
|
|
}
|
|
|
|
ColumnName:
|
|
Identifier
|
|
|
|
ColumnNameList:
|
|
ColumnName
|
|
{
|
|
$$ = []string{$1.(string)}
|
|
}
|
|
| ColumnNameList ',' ColumnName
|
|
{
|
|
$$ = append($1.([]string), $3.(string))
|
|
}
|
|
|
|
ColumnNameListOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = []string{}
|
|
}
|
|
| ColumnNameList
|
|
|
|
CommitStmt:
|
|
"COMMIT"
|
|
{
|
|
$$ = &stmts.CommitStmt{}
|
|
}
|
|
|
|
Constraint:
|
|
"NOT" "NULL"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrNotNull, Bvalue: true}
|
|
}
|
|
| "NULL"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrNull, Bvalue: true}
|
|
}
|
|
| "AUTO_INCREMENT"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrAutoIncrement, Bvalue: true}
|
|
}
|
|
| "PRIMARY" "KEY"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrPrimaryKey, Bvalue: true}
|
|
}
|
|
| "UNIQUE"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrUniq, Bvalue: true}
|
|
}
|
|
| "UNIQUE" "KEY"
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrUniqKey, Bvalue: true}
|
|
}
|
|
| "DEFAULT" DefaultValueExpr
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrDefaultValue, Evalue: $2.(expression.Expression)}
|
|
}
|
|
| "ON" "UPDATE" NowSym
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrOnUpdate, Evalue: $3.(expression.Expression)}
|
|
}
|
|
| "COMMENT" stringLit
|
|
{
|
|
$$ = &coldef.ConstraintOpt{Tp: coldef.ConstrComment}
|
|
}
|
|
| "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.
|
|
$$ = nil
|
|
}
|
|
|
|
ConstraintElem:
|
|
"PRIMARY" "KEY" '(' IndexColNameList ')'
|
|
{
|
|
ce := &coldef.TableConstraint{}
|
|
ce.Tp = coldef.ConstrPrimaryKey
|
|
ce.Keys = $4.([]*coldef.IndexColName)
|
|
$$ = ce
|
|
}
|
|
| "FULLTEXT" "KEY" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrFulltext,
|
|
Keys: $5.([]*coldef.IndexColName),
|
|
ConstrName: $3.(string)}
|
|
}
|
|
| "INDEX" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrIndex,
|
|
Keys: $4.([]*coldef.IndexColName),
|
|
ConstrName: $2.(string)}
|
|
}
|
|
| "KEY" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrKey,
|
|
Keys: $4.([]*coldef.IndexColName),
|
|
ConstrName: $2.(string)}
|
|
}
|
|
| "UNIQUE" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrUniq,
|
|
Keys: $4.([]*coldef.IndexColName),
|
|
ConstrName: $2.(string)}
|
|
}
|
|
| "UNIQUE" "INDEX" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrUniqIndex,
|
|
Keys: $5.([]*coldef.IndexColName),
|
|
ConstrName: $3.(string)}
|
|
}
|
|
| "UNIQUE" "KEY" IndexName '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrUniqKey,
|
|
Keys: $5.([]*coldef.IndexColName),
|
|
ConstrName: $3.(string)}
|
|
}
|
|
| "FOREIGN" "KEY" IndexName '(' IndexColNameList ')' ReferDef
|
|
{
|
|
$$ = &coldef.TableConstraint{
|
|
Tp: coldef.ConstrForeignKey,
|
|
Keys: $5.([]*coldef.IndexColName),
|
|
ConstrName: $3.(string),
|
|
Refer: $7.(*coldef.ReferenceDef),
|
|
}
|
|
}
|
|
|
|
ReferDef:
|
|
"REFERENCES" TableIdent '(' IndexColNameList ')'
|
|
{
|
|
$$ = &coldef.ReferenceDef{TableIdent: $2.(table.Ident), IndexColNames: $4.([]*coldef.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
|
|
| SignedLiteral
|
|
|
|
// TODO: Process other three keywords
|
|
NowSym:
|
|
"CURRENT_TIMESTAMP"
|
|
{
|
|
$$ = &expression.Ident{CIStr: model.NewCIStr("CURRENT_TIMESTAMP")}
|
|
}
|
|
| "LOCALTIME"
|
|
| "LOCALTIMESTAMP"
|
|
| "NOW"
|
|
|
|
SignedLiteral:
|
|
Literal
|
|
{
|
|
$$ = expression.Value{Val: $1}
|
|
}
|
|
| '+' NumLiteral
|
|
{
|
|
n := expression.Value{Val: $2}
|
|
$$ = expression.NewUnaryOperation(opcode.Plus, n)
|
|
}
|
|
| '-' NumLiteral
|
|
{
|
|
n := expression.Value{Val: $2}
|
|
$$ = expression.NewUnaryOperation(opcode.Minus, n)
|
|
}
|
|
|
|
// TODO: support decimal literal
|
|
NumLiteral:
|
|
intLit
|
|
| floatLit
|
|
|
|
|
|
|
|
ConstraintOpt:
|
|
Constraint
|
|
|
|
ConstraintOpts:
|
|
{
|
|
$$ = []*coldef.ConstraintOpt{}
|
|
}
|
|
| ConstraintOpts ConstraintOpt
|
|
{
|
|
if $2 != nil {
|
|
$$ = append($1.([]*coldef.ConstraintOpt), $2.(*coldef.ConstraintOpt))
|
|
} else {
|
|
$$ = $1
|
|
}
|
|
}
|
|
|
|
CreateIndexStmt:
|
|
"CREATE" CreateIndexStmtUnique "INDEX" Identifier "ON" TableIdent '(' IndexColNameList ')'
|
|
{
|
|
indexName, tableIdent, colNameList := $4.(string), $6.(table.Ident), $8.([]*coldef.IndexColName)
|
|
if strings.EqualFold(indexName, tableIdent.Name.O) {
|
|
yylex.(*lexer).errf("index name collision: %s", indexName)
|
|
return 1
|
|
}
|
|
for _, colName := range colNameList {
|
|
if indexName == colName.ColumnName {
|
|
yylex.(*lexer).errf("index name collision: %s", indexName)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
$$ = &stmts.CreateIndexStmt{
|
|
Unique: $2.(bool),
|
|
IndexName: indexName,
|
|
TableIdent: tableIdent,
|
|
IndexColNames: colNameList,
|
|
}
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
CreateIndexStmtUnique:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "UNIQUE"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IndexColName:
|
|
ColumnName OptFieldLen Order
|
|
{
|
|
//Order is parsed but just ignored as MySQL did
|
|
$$ = &coldef.IndexColName{ColumnName: $1.(string), Length: $2.(int)}
|
|
}
|
|
|
|
IndexColNameList:
|
|
{
|
|
$$ = []*coldef.IndexColName{}
|
|
}
|
|
| IndexColName
|
|
{
|
|
$$ = []*coldef.IndexColName{$1.(*coldef.IndexColName)}
|
|
}
|
|
| IndexColNameList ',' IndexColName
|
|
{
|
|
$$ = append($1.([]*coldef.IndexColName), $3.(*coldef.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 CreateSpecListOpt
|
|
{
|
|
opts := $5.([]*coldef.DatabaseOpt)
|
|
//compose charset from x
|
|
var cs, co string
|
|
for _, x := range opts {
|
|
switch x.Tp {
|
|
case coldef.DBOptCharset, coldef.DBOptCollate:
|
|
cs = x.Value
|
|
}
|
|
}
|
|
|
|
ok := charset.ValidCharsetAndCollation(cs, co)
|
|
if !ok {
|
|
yylex.(*lexer).errf("Unknown character set %s or collate %s ", cs, co)
|
|
}
|
|
dbopt := &coldef.CharsetOpt{Chs: cs, Col: co}
|
|
|
|
$$ = &stmts.CreateDatabaseStmt{
|
|
IfNotExists: $3.(bool),
|
|
Name: $4.(string),
|
|
Opt: dbopt}
|
|
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
DBName:
|
|
Identifier
|
|
|
|
CreateSpecification:
|
|
DefaultKwdOpt CharsetKw EqOpt CharsetName
|
|
{
|
|
$$ = &coldef.DatabaseOpt{Tp: coldef.DBOptCollate, Value: $4.(string)}
|
|
}
|
|
| DefaultKwdOpt "COLLATE" EqOpt CollationName
|
|
{
|
|
$$ = &coldef.DatabaseOpt{Tp: coldef.DBOptCollate, Value: $4.(string)}
|
|
}
|
|
|
|
CharsetName:
|
|
Identifier
|
|
{
|
|
c := strings.ToLower($1.(string))
|
|
if charset.ValidCharsetAndCollation(c, "") {
|
|
$$ = c
|
|
} else {
|
|
yylex.(*lexer).errf("Unknown character set: '%s'", $1.(string))
|
|
return 1
|
|
}
|
|
}
|
|
| stringLit
|
|
{
|
|
c := strings.ToLower($1.(string))
|
|
if charset.ValidCharsetAndCollation(c, "") {
|
|
$$ = c
|
|
} else {
|
|
yylex.(*lexer).errf("Unknown character set: '%s'", $1.(string))
|
|
return 1
|
|
}
|
|
}
|
|
|
|
CollationName:
|
|
Identifier
|
|
|
|
CreateSpecListOpt:
|
|
{
|
|
$$ = []*coldef.DatabaseOpt{}
|
|
}
|
|
| CreateSpecificationList
|
|
|
|
CreateSpecificationList:
|
|
CreateSpecification
|
|
{
|
|
$$ = []*coldef.DatabaseOpt{$1.(*coldef.DatabaseOpt)}
|
|
}
|
|
| CreateSpecificationList CreateSpecification
|
|
{
|
|
$$ = append($1.([]*coldef.DatabaseOpt), $2.(*coldef.DatabaseOpt))
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* 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 TableIdent '(' TableElementListOpt ')' TableOptListOpt
|
|
{
|
|
tes := $6.([]interface {})
|
|
var columnDefs []*coldef.ColumnDef
|
|
var tableConstraints []*coldef.TableConstraint
|
|
for _, te := range tes {
|
|
switch te := te.(type) {
|
|
case *coldef.ColumnDef:
|
|
columnDefs = append(columnDefs, te)
|
|
case *coldef.TableConstraint:
|
|
tableConstraints = append(tableConstraints, te)
|
|
}
|
|
}
|
|
if len(columnDefs) == 0 {
|
|
yylex.(*lexer).err("Column Definition List can't be empty.")
|
|
return 1
|
|
}
|
|
|
|
opt := &coldef.TableOption{}
|
|
if $8 != nil {
|
|
for _, o := range $8.([]*coldef.TableOpt) {
|
|
switch o.Tp {
|
|
case coldef.TblOptEngine:
|
|
opt.Engine = o.StrValue
|
|
case coldef.TblOptCharset:
|
|
opt.Charset = o.StrValue
|
|
case coldef.TblOptCollate:
|
|
opt.Collate = o.StrValue
|
|
case coldef.TblOptAutoIncrement:
|
|
opt.AutoIncrement = o.UintValue
|
|
}
|
|
}
|
|
}
|
|
$$ = &stmts.CreateTableStmt{
|
|
Ident: $4.(table.Ident),
|
|
IfNotExists: $3.(bool),
|
|
Cols: columnDefs,
|
|
Constraints: tableConstraints,
|
|
Opt: opt}
|
|
}
|
|
|
|
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
|
|
{
|
|
$$ = &stmts.DoStmt {
|
|
Exprs: $2.([]expression.Expression),
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Delete Statement
|
|
*
|
|
*******************************************************************/
|
|
DeleteFromStmt:
|
|
"DELETE" LowPriorityOptional QuickOptional IgnoreOptional "FROM" TableIdent WhereClauseOptional OrderByOptional LimitClause
|
|
{
|
|
// Single Table
|
|
ts := &rsets.TableSource{Source: $6}
|
|
r := &rsets.JoinRset{Left: ts, Right: nil}
|
|
x := &stmts.DeleteStmt{
|
|
Refs: r,
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
}
|
|
if $7 != nil {
|
|
x.Where = $7.(expression.Expression)
|
|
}
|
|
|
|
if $8 != nil {
|
|
x.Order = $8.(*rsets.OrderByRset)
|
|
}
|
|
|
|
if $9 != nil {
|
|
x.Limit = $9.(*rsets.LimitRset)
|
|
}
|
|
|
|
$$ = x
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
| "DELETE" LowPriorityOptional QuickOptional IgnoreOptional TableIdentList "FROM" TableRefs WhereClauseOptional
|
|
{
|
|
// Multiple Table
|
|
x := &stmts.DeleteStmt{
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
MultiTable: true,
|
|
BeforeFrom: true,
|
|
TableIdents: $5.([]table.Ident),
|
|
Refs: $7.(*rsets.JoinRset),
|
|
}
|
|
if $8 != nil {
|
|
x.Where = $8.(expression.Expression)
|
|
}
|
|
$$ = x
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
| "DELETE" LowPriorityOptional QuickOptional IgnoreOptional "FROM" TableIdentList "USING" TableRefs WhereClauseOptional
|
|
{
|
|
// Multiple Table
|
|
x := &stmts.DeleteStmt{
|
|
LowPriority: $2.(bool),
|
|
Quick: $3.(bool),
|
|
Ignore: $4.(bool),
|
|
MultiTable: true,
|
|
TableIdents: $6.([]table.Ident),
|
|
Refs: $8.(*rsets.JoinRset),
|
|
}
|
|
if $9 != nil {
|
|
x.Where = $9.(expression.Expression)
|
|
}
|
|
$$ = x
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
DatabaseSym:
|
|
"DATABASE" | "SCHEMA"
|
|
|
|
DropDatabaseStmt:
|
|
"DROP" DatabaseSym IfExists DBName
|
|
{
|
|
$$ = &stmts.DropDatabaseStmt{IfExists: $3.(bool), Name: $4.(string)}
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
DropIndexStmt:
|
|
"DROP" "INDEX" IfExists Identifier
|
|
{
|
|
$$ = &stmts.DropIndexStmt{IfExists: $3.(bool), IndexName: $4.(string)}
|
|
}
|
|
|
|
DropTableStmt:
|
|
"DROP" "TABLE" TableIdentList
|
|
{
|
|
$$ = &stmts.DropTableStmt{TableIdents: $3.([]table.Ident)}
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
| "DROP" "TABLE" "IF" "EXISTS" TableIdentList
|
|
{
|
|
$$ = &stmts.DropTableStmt{IfExists: true, TableIdents: $5.([]table.Ident)}
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
EqOpt:
|
|
{
|
|
}
|
|
| eq
|
|
{
|
|
}
|
|
|
|
EmptyStmt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
|
|
ExplainSym:
|
|
"EXPLAIN"
|
|
| "DESCRIBE"
|
|
| "DESC"
|
|
|
|
ExplainStmt:
|
|
ExplainSym TableIdent
|
|
{
|
|
$$ = &stmts.ExplainStmt{
|
|
S:&stmts.ShowStmt{
|
|
Target: stmt.ShowColumns,
|
|
TableIdent: $2.(table.Ident)},
|
|
}
|
|
}
|
|
| ExplainSym TableIdent ColumnName
|
|
{
|
|
$$ = &stmts.ExplainStmt{
|
|
S:&stmts.ShowStmt{
|
|
Target: stmt.ShowColumns,
|
|
TableIdent: $2.(table.Ident),
|
|
ColumnName: $3.(string)},
|
|
}
|
|
}
|
|
| ExplainSym ExplainableStmt
|
|
{
|
|
$$ = &stmts.ExplainStmt{S:$2.(stmt.Statement)}
|
|
}
|
|
|
|
LengthNum:
|
|
NUM
|
|
{
|
|
switch v := $1.(type) {
|
|
case int64:
|
|
$$ = uint64(v)
|
|
case uint64:
|
|
$$ = uint64(v)
|
|
}
|
|
}
|
|
|
|
NUM:
|
|
intLit
|
|
|
|
Expression:
|
|
Expression logOr Expression %prec oror
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.OrOr, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| Expression "XOR" Expression %prec xor
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.LogicXor, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| Expression logAnd Expression %prec andand
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.AndAnd, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| "NOT" Expression %prec not
|
|
{
|
|
$$ = expression.NewUnaryOperation(opcode.Not, $2.(expression.Expression))
|
|
}
|
|
| Factor "IS" NotOpt trueKwd %prec is
|
|
{
|
|
$$ = &expression.IsTruth{Expr:$1.(expression.Expression), Not: $3.(bool), True: int64(1)}
|
|
}
|
|
| Factor "IS" NotOpt falseKwd %prec is
|
|
{
|
|
$$ = &expression.IsTruth{Expr:$1.(expression.Expression), 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 */
|
|
$$ = &expression.IsNull{Expr: $1.(expression.Expression), Not: $3.(bool)}
|
|
}
|
|
| Factor
|
|
|
|
|
|
logOr:
|
|
"||"
|
|
{
|
|
}
|
|
| "OR"
|
|
{
|
|
}
|
|
|
|
logAnd:
|
|
"&&"
|
|
{
|
|
}
|
|
| "AND"
|
|
{
|
|
}
|
|
|
|
name:
|
|
Identifier
|
|
|
|
ExpressionList:
|
|
Expression
|
|
{
|
|
$$ = []expression.Expression{expression.Expr($1)}
|
|
}
|
|
| ExpressionList ',' Expression
|
|
{
|
|
$$ = append($1.([]expression.Expression), expression.Expr($3))
|
|
}
|
|
|
|
ExpressionListOpt:
|
|
{
|
|
$$ = []expression.Expression{}
|
|
}
|
|
| ExpressionList
|
|
|
|
Factor:
|
|
Factor "IS" NotOpt "NULL" %prec is
|
|
{
|
|
$$ = &expression.IsNull{Expr: $1.(expression.Expression), Not: $3.(bool)}
|
|
}
|
|
| Factor CompareOp PredicateExpr %prec eq
|
|
{
|
|
$$ = expression.NewBinaryOperation($2.(opcode.Op), $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| Factor CompareOp AnyOrAll SubSelect %prec eq
|
|
{
|
|
$$ = expression.NewCompareSubQuery($2.(opcode.Op), $1.(expression.Expression), $4.(*subquery.SubQuery), $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 ')'
|
|
{
|
|
$$ = &expression.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), List: $5.([]expression.Expression)}
|
|
}
|
|
| PrimaryFactor NotOpt "IN" SubSelect
|
|
{
|
|
$$ = &expression.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), Sel: $4.(*subquery.SubQuery)}
|
|
}
|
|
| PrimaryFactor NotOpt "BETWEEN" PrimaryFactor "AND" PredicateExpr
|
|
{
|
|
var err error
|
|
$$, err = expression.NewBetween($1.(expression.Expression), $4.(expression.Expression), $6.(expression.Expression), $2.(bool))
|
|
if err != nil {
|
|
yylex.(*lexer).err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| 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 = "\\"
|
|
}
|
|
$$ = &expression.PatternLike{
|
|
Expr: $1.(expression.Expression),
|
|
Pattern: $4.(expression.Expression),
|
|
Not: $2.(bool),
|
|
Escape: escape[0]}
|
|
}
|
|
| PrimaryFactor NotOpt RegexpSym PrimaryExpression
|
|
{
|
|
$$ = &expression.PatternRegexp{Expr: $1.(expression.Expression), Pattern: $4.(expression.Expression), Not: $2.(bool)}
|
|
}
|
|
| PrimaryFactor
|
|
|
|
RegexpSym:
|
|
"REGEXP"
|
|
| "RLIKE"
|
|
|
|
LikeEscapeOpt:
|
|
%prec lowerThanEscape
|
|
{
|
|
$$ = "\\"
|
|
}
|
|
| "ESCAPE" stringLit
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
NotOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "NOT"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
Field:
|
|
'*'
|
|
{
|
|
$$ = &field.Field{Expr: &expression.Ident{CIStr: model.NewCIStr("*")}}
|
|
}
|
|
| Expression FieldAsNameOpt
|
|
{
|
|
expr, name := expression.Expr($1), $2.(string)
|
|
$$ = &field.Field{Expr: expr, AsName: name}
|
|
}
|
|
|
|
FieldAsNameOpt:
|
|
/* EMPTY */
|
|
{
|
|
$$ = ""
|
|
}
|
|
| FieldAsName
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
FieldAsName:
|
|
Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "AS" Identifier
|
|
{
|
|
$$ = $2
|
|
}
|
|
| stringLit
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "AS" stringLit
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
FieldList:
|
|
Field
|
|
{
|
|
$$ = []*field.Field{$1.(*field.Field)}
|
|
}
|
|
| FieldList ',' Field
|
|
{
|
|
$$ = append($1.([]*field.Field), $3.(*field.Field))
|
|
}
|
|
|
|
GroupByClause:
|
|
"GROUP" "BY" GroupByList
|
|
{
|
|
$$ = &rsets.GroupByRset{By: $3.([]expression.Expression)}
|
|
}
|
|
|
|
GroupByList:
|
|
Expression
|
|
{
|
|
$$ = []expression.Expression{$1.(expression.Expression)}
|
|
}
|
|
| GroupByList ',' Expression
|
|
{
|
|
$$ = append($1.([]expression.Expression), $3.(expression.Expression))
|
|
}
|
|
|
|
HavingClause:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "HAVING" Expression
|
|
{
|
|
$$ = &rsets.HavingRset{Expr:$2.(expression.Expression)}
|
|
}
|
|
|
|
IfExists:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IfNotExists:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IF" "NOT" "EXISTS"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
|
|
IgnoreOptional:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "IGNORE"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
IndexName:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| Identifier
|
|
{
|
|
//"index name"
|
|
$$ = $1.(string)
|
|
}
|
|
|
|
IndexType:
|
|
Identifier
|
|
{
|
|
// TODO: "index type"
|
|
$$ = $1.(string)
|
|
}
|
|
|
|
/**********************************Identifier********************************************/
|
|
Identifier:
|
|
identifier | UnReservedKeyword | NotKeywordToken
|
|
|
|
UnReservedKeyword:
|
|
"AUTO_INCREMENT" | "AFTER" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "CHARSET" | "COLUMNS" | "COMMIT"
|
|
| "DATE" | "DATETIME" | "DEALLOCATE" | "DO" | "END" | "ENGINE" | "ENGINES" | "EXECUTE" | "FIRST" | "FULL"
|
|
| "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "ROLLBACK" | "SESSION" | "SIGNED"
|
|
| "START" | "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" | "QUARTER" | "ESCAPE"
|
|
|
|
NotKeywordToken:
|
|
"ABS" | "COALESCE" | "CONCAT" | "CONCAT_WS" | "COUNT" | "DAY" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "FOUND_ROWS" | "GROUP_CONCAT"
|
|
| "HOUR" | "IFNULL" | "LENGTH" | "LOCATE" | "MAX" | "MICROSECOND" | "MIN" | "MINUTE" | "NULLIF" | "MONTH" | "NOW" | "RAND" | "SECOND" | "SQL_CALC_FOUND_ROWS"
|
|
| "SUBSTRING" %prec lowerThanLeftParen | "SUBSTRING_INDEX" | "SUM" | "TRIM" | "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK"
|
|
|
|
/************************************************************************************
|
|
*
|
|
* Insert Statments
|
|
*
|
|
* TODO: support PARTITION
|
|
**********************************************************************************/
|
|
InsertIntoStmt:
|
|
"INSERT" Priority IgnoreOptional IntoOpt TableIdent InsertRest OnDuplicateKeyUpdate
|
|
{
|
|
x := $6.(*stmts.InsertIntoStmt)
|
|
x.Priority = $2.(int)
|
|
x.TableIdent = $5.(table.Ident)
|
|
if $7 != nil {
|
|
x.OnDuplicate = $7.([]expression.Assignment)
|
|
}
|
|
$$ = x
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
IntoOpt:
|
|
{
|
|
}
|
|
| "INTO"
|
|
{
|
|
}
|
|
|
|
InsertRest:
|
|
'(' ColumnNameListOpt ')' ValueSym ExpressionListList
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{
|
|
ColNames: $2.([]string),
|
|
Lists: $5.([][]expression.Expression)}
|
|
}
|
|
| '(' ColumnNameListOpt ')' SelectStmt
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{ColNames: $2.([]string), Sel: $4.(*stmts.SelectStmt)}
|
|
}
|
|
| '(' ColumnNameListOpt ')' UnionStmt
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{ColNames: $2.([]string), Sel: $4.(*stmts.UnionStmt)}
|
|
}
|
|
| ValueSym ExpressionListList %prec insertValues
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{Lists: $2.([][]expression.Expression)}
|
|
}
|
|
| SelectStmt
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{Sel: $1.(*stmts.SelectStmt)}
|
|
}
|
|
| UnionStmt
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{Sel: $1.(*stmts.UnionStmt)}
|
|
}
|
|
| "SET" ColumnSetValueList
|
|
{
|
|
$$ = &stmts.InsertIntoStmt{Setlist: $2.([]*expression.Assignment)}
|
|
}
|
|
|
|
ValueSym:
|
|
"VALUE"
|
|
| "VALUES"
|
|
|
|
ExpressionListList:
|
|
'(' ')'
|
|
{
|
|
$$ = [][]expression.Expression{[]expression.Expression{}}
|
|
}
|
|
| '(' ')' ',' ExpressionListList
|
|
{
|
|
$$ = append([][]expression.Expression{[]expression.Expression{}}, $4.([][]expression.Expression)...)
|
|
}
|
|
| '(' ExpressionList ')'
|
|
{
|
|
$$ = [][]expression.Expression{$2.([]expression.Expression)}
|
|
}
|
|
| '(' ExpressionList ')' ',' ExpressionListList
|
|
{
|
|
$$ = append([][]expression.Expression{$2.([]expression.Expression)}, $5.([][]expression.Expression)...)
|
|
}
|
|
|
|
ColumnSetValue:
|
|
ColumnName eq Expression
|
|
{
|
|
$$ = &expression.Assignment{
|
|
ColName: $1.(string),
|
|
Expr: expression.Expr($3)}
|
|
}
|
|
|
|
ColumnSetValueList:
|
|
{
|
|
$$ = []*expression.Assignment{}
|
|
}
|
|
| ColumnSetValue
|
|
{
|
|
$$ = []*expression.Assignment{$1.(*expression.Assignment)}
|
|
}
|
|
| ColumnSetValueList ',' ColumnSetValue
|
|
{
|
|
$$ = append($1.([]*expression.Assignment), $3.(*expression.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 Statments END************************************/
|
|
|
|
Literal:
|
|
"false"
|
|
{
|
|
$$ = int64(0)
|
|
}
|
|
| "NULL"
|
|
| "true"
|
|
{
|
|
$$ = int64(1)
|
|
}
|
|
| floatLit
|
|
| intLit
|
|
| stringLit
|
|
| hexLit
|
|
| bitLit
|
|
|
|
Operand:
|
|
Literal
|
|
{
|
|
$$ = expression.Value{Val: $1}
|
|
}
|
|
| QualifiedIdent
|
|
{
|
|
$$ = &expression.Ident{CIStr: model.NewCIStr($1.(string))}
|
|
}
|
|
| '(' Expression ')'
|
|
{
|
|
$$ = &expression.PExpr{Expr: expression.Expr($2)}
|
|
}
|
|
| "DEFAULT" %prec lowerThanLeftParen
|
|
{
|
|
$$ = &expression.Default{}
|
|
}
|
|
| "DEFAULT" '(' ColumnName ')'
|
|
{
|
|
$$ = &expression.Default{Name: $3.(string)}
|
|
}
|
|
| Variable
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "PLACEHOLDER"
|
|
{
|
|
l := yylex.(*lexer)
|
|
if !l.prepare {
|
|
l.err("Can not accept placeholder when not parsing prepare sql")
|
|
}
|
|
pm := &expression.ParamMarker{}
|
|
l.ParamList = append(l.ParamList, pm)
|
|
$$ = pm
|
|
}
|
|
| "ROW" '(' Expression ',' ExpressionList ')'
|
|
{
|
|
values := append([]expression.Expression{$3.(expression.Expression)}, $5.([]expression.Expression)...)
|
|
$$ = &expression.Row{Values: values}
|
|
}
|
|
| '(' Expression ',' ExpressionList ')'
|
|
{
|
|
values := append([]expression.Expression{$2.(expression.Expression)}, $4.([]expression.Expression)...)
|
|
$$ = &expression.Row{Values: values}
|
|
}
|
|
| "EXISTS" SubSelect
|
|
{
|
|
$$ = &expression.ExistsSubQuery{Sel: $2.(*subquery.SubQuery)}
|
|
}
|
|
|
|
OrderBy:
|
|
"ORDER" "BY" OrderByList
|
|
{
|
|
$$ = &rsets.OrderByRset{By: $3.([]rsets.OrderByItem)}
|
|
}
|
|
|
|
OrderByList:
|
|
OrderByItem
|
|
{
|
|
$$ = []rsets.OrderByItem{$1.(rsets.OrderByItem)}
|
|
}
|
|
| OrderByList ',' OrderByItem
|
|
{
|
|
$$ = append($1.([]rsets.OrderByItem), $3.(rsets.OrderByItem))
|
|
}
|
|
|
|
OrderByItem:
|
|
Expression Order
|
|
{
|
|
$$ = rsets.OrderByItem{Expr: $1.(expression.Expression), Asc: $2.(bool)}
|
|
}
|
|
|
|
Order:
|
|
/* EMPTY */
|
|
{
|
|
$$ = true // ASC by default
|
|
}
|
|
| "ASC"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "DESC"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
OrderByOptional:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| OrderBy
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
PrimaryExpression:
|
|
Operand
|
|
| Function
|
|
| SubSelect
|
|
| '!' PrimaryExpression %prec neg
|
|
{
|
|
$$ = expression.NewUnaryOperation(opcode.Not, $2.(expression.Expression))
|
|
}
|
|
| '~' PrimaryExpression %prec neg
|
|
{
|
|
$$ = expression.NewUnaryOperation(opcode.BitNeg, $2.(expression.Expression))
|
|
}
|
|
| '-' PrimaryExpression %prec neg
|
|
{
|
|
$$ = expression.NewUnaryOperation(opcode.Minus, $2.(expression.Expression))
|
|
}
|
|
| '+' PrimaryExpression %prec neg
|
|
{
|
|
$$ = expression.NewUnaryOperation(opcode.Plus, $2.(expression.Expression))
|
|
}
|
|
| "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
|
|
$$ = &expression.FunctionCast{
|
|
Expr: $2.(expression.Expression),
|
|
Tp: x,
|
|
FunctionType: expression.BinaryOperator,
|
|
}
|
|
}
|
|
| PrimaryExpression "COLLATE" CollationName %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"
|
|
|
|
FunctionCallConflict:
|
|
FunctionNameConflict '(' ExpressionListOpt ')'
|
|
{
|
|
x := yylex.(*lexer)
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
x.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CURRENT_USER"
|
|
{
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_current-user
|
|
x := yylex.(*lexer)
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), []expression.Expression{}, false)
|
|
if err != nil {
|
|
x.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CURRENT_DATE"
|
|
{
|
|
x := yylex.(*lexer)
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), []expression.Expression{}, false)
|
|
if err != nil {
|
|
x.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
DistinctOpt:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "DISTINCT" "ALL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
FunctionCallKeyword:
|
|
"AVG" '(' DistinctOpt ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $4.([]expression.Expression), $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CAST" '(' Expression "AS" CastType ')'
|
|
{
|
|
/* See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast */
|
|
$$ = &expression.FunctionCast{
|
|
Expr: $3.(expression.Expression),
|
|
Tp: $5.(*types.FieldType),
|
|
FunctionType: expression.CastFunction,
|
|
}
|
|
}
|
|
| "CASE" ExpressionOpt WhenClauseList ElseOpt "END"
|
|
{
|
|
x := &expression.FunctionCase{WhenClauses: $3.([]*expression.WhenClause)}
|
|
if $2 != nil {
|
|
x.Value = $2.(expression.Expression)
|
|
}
|
|
if $4 != nil {
|
|
x.ElseClause = $4.(expression.Expression)
|
|
}
|
|
$$ = x
|
|
}
|
|
| "CONVERT" '(' Expression "USING" CharsetName ')'
|
|
{
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
|
|
$$ = &expression.FunctionConvert{
|
|
Expr: $3.(expression.Expression),
|
|
Charset: $5.(string),
|
|
}
|
|
}
|
|
| "CONVERT" '(' Expression ',' CastType ')'
|
|
{
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
|
|
$$ = &expression.FunctionCast{
|
|
Expr: $3.(expression.Expression),
|
|
Tp: $5.(*types.FieldType),
|
|
FunctionType: expression.ConvertFunction,
|
|
}
|
|
}
|
|
| "DATE" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "USER" '(' ')'
|
|
{
|
|
args := []expression.Expression{}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "VALUES" '(' Identifier ')' %prec lowerThanInsertValues
|
|
{
|
|
// TODO: support qualified identifier for column_name
|
|
$$ = &expression.Values{CIStr: model.NewCIStr($3.(string))}
|
|
}
|
|
| "WEEK" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "YEAR" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
FunctionCallNonKeyword:
|
|
"COALESCE" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CURDATE" '(' ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), []expression.Expression{}, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CURRENT_TIMESTAMP" FuncDatetimePrec
|
|
{
|
|
args := []expression.Expression{}
|
|
if $2 != nil {
|
|
args = append(args, $2.(expression.Expression))
|
|
}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "ABS" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CONCAT" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "CONCAT_WS" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "DAY" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "DAYOFWEEK" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "DAYOFMONTH" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "DAYOFYEAR" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "EXTRACT" '(' TimeUnit "FROM" Expression ')'
|
|
{
|
|
$$ = &expression.Extract{
|
|
Unit: $3.(string),
|
|
Date: $5.(expression.Expression),
|
|
}
|
|
}
|
|
| "FOUND_ROWS" '(' ')'
|
|
{
|
|
args := []expression.Expression{}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "HOUR" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "IFNULL" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "LENGTH" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "LOCATE" '(' Expression ',' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionLocate{
|
|
SubStr: $3.(expression.Expression),
|
|
Str: $5.(expression.Expression),
|
|
}
|
|
}
|
|
| "LOCATE" '(' Expression ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionLocate{
|
|
SubStr: $3.(expression.Expression),
|
|
Str: $5.(expression.Expression),
|
|
Pos: $7.(expression.Expression),
|
|
}
|
|
}
|
|
| "LOWER" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "MICROSECOND" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "MINUTE" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "MONTH" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "NOW" '(' ExpressionOpt ')'
|
|
{
|
|
args := []expression.Expression{}
|
|
if $3 != nil {
|
|
args = append(args, $3.(expression.Expression))
|
|
}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "NULLIF" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression), false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "RAND" '(' ExpressionOpt ')'
|
|
{
|
|
|
|
args := []expression.Expression{}
|
|
if $3 != nil {
|
|
args = append(args, $3.(expression.Expression))
|
|
}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "SECOND" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression ',' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionSubstring{
|
|
StrExpr: $3.(expression.Expression),
|
|
Pos: $5.(expression.Expression),
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression "FROM" Expression ')'
|
|
{
|
|
$$ = &expression.FunctionSubstring{
|
|
StrExpr: $3.(expression.Expression),
|
|
Pos: $5.(expression.Expression),
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionSubstring{
|
|
StrExpr: $3.(expression.Expression),
|
|
Pos: $5.(expression.Expression),
|
|
Len: $7.(expression.Expression),
|
|
}
|
|
}
|
|
| "SUBSTRING" '(' Expression "FROM" Expression "FOR" Expression ')'
|
|
{
|
|
$$ = &expression.FunctionSubstring{
|
|
StrExpr: $3.(expression.Expression),
|
|
Pos: $5.(expression.Expression),
|
|
Len: $7.(expression.Expression),
|
|
}
|
|
}
|
|
| "SUBSTRING_INDEX" '(' Expression ',' Expression ',' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionSubstringIndex{
|
|
StrExpr: $3.(expression.Expression),
|
|
Delim: $5.(expression.Expression),
|
|
Count: $7.(expression.Expression),
|
|
}
|
|
}
|
|
| "SYSDATE" '(' ExpressionOpt ')'
|
|
{
|
|
args := []expression.Expression{}
|
|
if $3 != nil {
|
|
args = append(args, $3.(expression.Expression))
|
|
}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "TRIM" '(' Expression ')'
|
|
{
|
|
$$ = &expression.FunctionTrim{
|
|
Str: $3.(expression.Expression),
|
|
}
|
|
}
|
|
| "TRIM" '(' Expression "FROM" Expression ')'
|
|
{
|
|
$$ = &expression.FunctionTrim{
|
|
Str: $5.(expression.Expression),
|
|
RemStr: $3.(expression.Expression),
|
|
}
|
|
}
|
|
| "TRIM" '(' TrimDirection "FROM" Expression ')'
|
|
{
|
|
$$ = &expression.FunctionTrim{
|
|
Str: $5.(expression.Expression),
|
|
Direction: $3.(int),
|
|
}
|
|
}
|
|
| "TRIM" '(' TrimDirection Expression "FROM" Expression ')'
|
|
{
|
|
$$ = &expression.FunctionTrim{
|
|
Str: $6.(expression.Expression),
|
|
RemStr: $4.(expression.Expression),
|
|
Direction: $3.(int),
|
|
}
|
|
}
|
|
| "UPPER" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "WEEKDAY" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "WEEKOFYEAR" '(' Expression ')'
|
|
{
|
|
args := []expression.Expression{$3.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "YEARWEEK" '(' ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $3.([]expression.Expression),false)
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
TrimDirection:
|
|
"BOTH"
|
|
{
|
|
$$ = expression.TrimBoth
|
|
}
|
|
| "LEADING"
|
|
{
|
|
$$ = expression.TrimLeading
|
|
}
|
|
| "TRAILING"
|
|
{
|
|
$$ = expression.TrimTrailing
|
|
}
|
|
|
|
FunctionCallAgg:
|
|
"COUNT" '(' DistinctOpt ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $4.([]expression.Expression), $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "COUNT" '(' DistinctOpt '*' ')'
|
|
{
|
|
var err error
|
|
args := []expression.Expression{ expression.Value{Val: expression.TypeStar("*")} }
|
|
$$, err = expression.NewCall($1.(string), args, $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "GROUP_CONCAT" '(' DistinctOpt ExpressionList ')'
|
|
{
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), $4.([]expression.Expression),$3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "MAX" '(' DistinctOpt Expression ')'
|
|
{
|
|
args := []expression.Expression{$4.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "MIN" '(' DistinctOpt Expression ')'
|
|
{
|
|
args := []expression.Expression{$4.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
| "SUM" '(' DistinctOpt Expression ')'
|
|
{
|
|
args := []expression.Expression{$4.(expression.Expression)}
|
|
var err error
|
|
$$, err = expression.NewCall($1.(string), args, $3.(bool))
|
|
if err != nil {
|
|
l := yylex.(*lexer)
|
|
l.err(err)
|
|
return 1
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
$$ = []*expression.WhenClause{$1.(*expression.WhenClause)}
|
|
}
|
|
| WhenClauseList WhenClause
|
|
{
|
|
$$ = append($1.([]*expression.WhenClause), $2.(*expression.WhenClause))
|
|
}
|
|
|
|
WhenClause:
|
|
"WHEN" Expression "THEN" Expression
|
|
{
|
|
$$ = &expression.WhenClause{
|
|
Expr: $2.(expression.Expression),
|
|
Result: $4.(expression.Expression),
|
|
}
|
|
}
|
|
|
|
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.(*coldef.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 '|'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Or, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '&' PrimaryFactor %prec '&'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.And, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor "<<" PrimaryFactor %prec lsh
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.LeftShift, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor ">>" PrimaryFactor %prec rsh
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.RightShift, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '+' PrimaryFactor %prec '+'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Plus, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '-' PrimaryFactor %prec '-'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Minus, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '*' PrimaryFactor %prec '*'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Mul, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '/' PrimaryFactor %prec '/'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Div, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '%' PrimaryFactor %prec '%'
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Mod, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor "DIV" PrimaryFactor %prec div
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.IntDiv, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor "MOD" PrimaryFactor %prec mod
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Mod, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryFactor '^' PrimaryFactor
|
|
{
|
|
$$ = expression.NewBinaryOperation(opcode.Xor, $1.(expression.Expression), $3.(expression.Expression))
|
|
}
|
|
| PrimaryExpression
|
|
|
|
|
|
Priority:
|
|
{
|
|
$$ = stmts.NoPriority
|
|
}
|
|
| "LOW_PRIORITY"
|
|
{
|
|
$$ = stmts.LowPriority
|
|
}
|
|
| "HIGH_PRIORITY"
|
|
{
|
|
$$ = stmts.HighPriority
|
|
}
|
|
| "DELAYED"
|
|
{
|
|
$$ = stmts.DelayedPriority
|
|
}
|
|
|
|
LowPriorityOptional:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "LOW_PRIORITY"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
QualifiedIdent:
|
|
Identifier
|
|
| Identifier '.' '*'
|
|
{
|
|
$$ = fmt.Sprintf("%s.*", $1.(string))
|
|
}
|
|
| Identifier '.' Identifier
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s", $1.(string), $3.(string))
|
|
}
|
|
| Identifier '.' Identifier '.' Identifier
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s.%s", $1.(string), $3.(string), $5.(string))
|
|
}
|
|
| Identifier '.' Identifier '.' '*'
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s.*", $1.(string), $3.(string))
|
|
}
|
|
|
|
SimpleQualifiedIdent:
|
|
Identifier
|
|
| Identifier '.' Identifier
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s", $1.(string), $3.(string))
|
|
}
|
|
| Identifier '.' Identifier '.' Identifier
|
|
{
|
|
$$ = fmt.Sprintf("%s.%s.%s", $1.(string), $3.(string), $5.(string))
|
|
}
|
|
|
|
TableIdent:
|
|
Identifier
|
|
{
|
|
$$ = table.Ident{Name:model.NewCIStr($1.(string))}
|
|
}
|
|
| Identifier '.' Identifier
|
|
{
|
|
$$ = table.Ident{Schema:model.NewCIStr($1.(string)), Name:model.NewCIStr($3.(string))}
|
|
}
|
|
|
|
TableIdentList:
|
|
TableIdent
|
|
{
|
|
tbl := []table.Ident{$1.(table.Ident)}
|
|
$$ = tbl
|
|
}
|
|
| TableIdentList ',' TableIdent
|
|
{
|
|
$$ = append($1.([]table.Ident), $3.(table.Ident))
|
|
}
|
|
|
|
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 *expression.Variable
|
|
switch $4.(type) {
|
|
case string:
|
|
sqlText = $4.(string)
|
|
case *expression.Variable:
|
|
sqlVar = $4.(*expression.Variable)
|
|
}
|
|
$$ = &stmts.PreparedStmt{
|
|
InPrepare: true,
|
|
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
|
|
{
|
|
$$ = &stmts.ExecuteStmt{Name: $2.(string)}
|
|
}
|
|
| "EXECUTE" Identifier "USING" UserVariableList
|
|
{
|
|
$$ = &stmts.ExecuteStmt{
|
|
Name: $2.(string),
|
|
UsingVars: $4.([]expression.Expression),
|
|
}
|
|
}
|
|
|
|
UserVariableList:
|
|
UserVariable
|
|
{
|
|
$$ = []expression.Expression{$1.(expression.Expression)}
|
|
}
|
|
| UserVariableList ',' UserVariable
|
|
{
|
|
$$ = append($1.([]expression.Expression), $3.(expression.Expression))
|
|
}
|
|
|
|
/*
|
|
* See: https://dev.mysql.com/doc/refman/5.0/en/deallocate-prepare.html
|
|
*/
|
|
|
|
DeallocateStmt:
|
|
DeallocateSym "PREPARE" Identifier
|
|
{
|
|
$$ = &stmts.DeallocateStmt{Name: $3.(string)}
|
|
}
|
|
|
|
DeallocateSym:
|
|
"DEALLOCATE" | "DROP"
|
|
|
|
/****************************Prepared Statement End*******************************/
|
|
|
|
|
|
RollbackStmt:
|
|
"ROLLBACK"
|
|
{
|
|
$$ = &stmts.RollbackStmt{}
|
|
}
|
|
|
|
SelectStmt:
|
|
"SELECT" SelectStmtOpts SelectStmtFieldList FromDual SelectStmtLimit SelectLockOpt
|
|
{
|
|
$$ = &stmts.SelectStmt {
|
|
Distinct: $2.(bool),
|
|
Fields: $3.([]*field.Field),
|
|
From: nil,
|
|
Lock: $6.(coldef.LockType),
|
|
}
|
|
}
|
|
| "SELECT" SelectStmtOpts SelectStmtFieldList "FROM"
|
|
FromClause WhereClauseOptional SelectStmtGroup HavingClause SelectStmtOrder
|
|
SelectStmtLimit SelectLockOpt
|
|
{
|
|
st := &stmts.SelectStmt{
|
|
Distinct: $2.(bool),
|
|
Fields: $3.([]*field.Field),
|
|
From: $5.(*rsets.JoinRset),
|
|
Lock: $11.(coldef.LockType),
|
|
}
|
|
|
|
if $6 != nil {
|
|
st.Where = &rsets.WhereRset{Expr: $6.(expression.Expression)}
|
|
}
|
|
|
|
if $7 != nil {
|
|
st.GroupBy = $7.(*rsets.GroupByRset)
|
|
}
|
|
|
|
if $8 != nil {
|
|
st.Having = $8.(*rsets.HavingRset)
|
|
}
|
|
|
|
if $9 != nil {
|
|
st.OrderBy = $9.(*rsets.OrderByRset)
|
|
}
|
|
|
|
if $10 != nil {
|
|
ay := $10.([]interface{})
|
|
st.Limit = ay[0].(*rsets.LimitRset)
|
|
st.Offset = ay[1].(*rsets.OffsetRset)
|
|
}
|
|
|
|
$$ = st
|
|
}
|
|
|
|
FromDual:
|
|
/* Empty */
|
|
| "FROM" "DUAL"
|
|
|
|
|
|
FromClause:
|
|
TableRefs
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
TableRefs:
|
|
EscapedTableRef
|
|
{
|
|
r := &rsets.JoinRset{Left: $1, Right: nil}
|
|
if j, ok := $1.(*rsets.JoinRset); ok {
|
|
// if $1 is JoinRset, use it directly
|
|
r = j
|
|
}
|
|
$$ = r
|
|
}
|
|
| TableRefs ',' EscapedTableRef
|
|
{
|
|
/* from a, b is default cross join */
|
|
$$ = &rsets.JoinRset{Left: $1, Right: $3, Type: rsets.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:
|
|
TableIdent TableIdentOpt
|
|
{
|
|
$$ = &rsets.TableSource{Source: $1, Name: $2.(string)}
|
|
}
|
|
| '(' SelectStmt ')' TableAsOpt
|
|
{
|
|
$$ = &rsets.TableSource{Source: $2, Name: $4.(string)}
|
|
}
|
|
| '(' UnionStmt ')' TableAsOpt
|
|
{
|
|
$$ = &rsets.TableSource{Source: $2, Name: $4.(string)}
|
|
}
|
|
| '(' TableRefs ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
TableIdentOpt:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| TableAsOpt
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
TableAsOpt:
|
|
Identifier
|
|
{
|
|
$$ = $1
|
|
}
|
|
| "AS" Identifier
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
JoinTable:
|
|
/* Use %prec to evaluate production TableRef before cross join */
|
|
TableRef CrossOpt TableRef %prec tableRefPriority
|
|
{
|
|
$$ = &rsets.JoinRset{Left: $1, Right: $3, Type: rsets.CrossJoin}
|
|
}
|
|
| TableRef CrossOpt TableRef "ON" Expression
|
|
{
|
|
$$ = &rsets.JoinRset{Left: $1, Right: $3, Type: rsets.CrossJoin, On: $5.(expression.Expression)}
|
|
}
|
|
| TableRef JoinType OuterOpt "JOIN" TableRef "ON" Expression
|
|
{
|
|
$$ = &rsets.JoinRset{Left: $1, Right: $5, Type: $2.(rsets.JoinType), On: $7.(expression.Expression)}
|
|
}
|
|
/* Support Using */
|
|
|
|
JoinType:
|
|
"LEFT"
|
|
{
|
|
$$ = rsets.LeftJoin
|
|
}
|
|
| "RIGHT"
|
|
{
|
|
$$ = rsets.RightJoin
|
|
}
|
|
|
|
OuterOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "OUTER"
|
|
|
|
|
|
CrossOpt:
|
|
"JOIN"
|
|
| "CROSS" "JOIN"
|
|
| "INNER" "JOIN"
|
|
|
|
|
|
LimitClause:
|
|
{
|
|
$$ = (*rsets.LimitRset)(nil)
|
|
}
|
|
| "LIMIT" LengthNum
|
|
{
|
|
$$ = &rsets.LimitRset{Count: $2.(uint64)}
|
|
}
|
|
|
|
SelectStmtLimit:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LIMIT" LengthNum
|
|
{
|
|
$$ = []interface{}{
|
|
&rsets.LimitRset{Count: $2.(uint64)},
|
|
(*rsets.OffsetRset)(nil)}
|
|
}
|
|
| "LIMIT" LengthNum ',' LengthNum
|
|
{
|
|
$$ = []interface{}{
|
|
&rsets.LimitRset{Count: $4.(uint64)},
|
|
&rsets.OffsetRset{Count: $2.(uint64)}}
|
|
}
|
|
| "LIMIT" LengthNum "OFFSET" LengthNum
|
|
{
|
|
$$ = []interface{}{
|
|
&rsets.LimitRset{Count: $2.(uint64)},
|
|
&rsets.OffsetRset{Count: $4.(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
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
SelectStmtGroup:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| GroupByClause
|
|
|
|
SelectStmtOrder:
|
|
/* EMPTY */
|
|
{
|
|
$$ = nil
|
|
}
|
|
| OrderBy
|
|
|
|
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/subqueries.html
|
|
SubSelect:
|
|
'(' SelectStmt ')'
|
|
{
|
|
s := $2.(*stmts.SelectStmt)
|
|
src := yylex.(*lexer).src
|
|
// See the implemention of yyParse function
|
|
s.SetText(src[yyS[yypt-1].offset-1:yyS[yypt].offset-1])
|
|
$$ = &subquery.SubQuery{Stmt: s}
|
|
}
|
|
| '(' UnionStmt ')'
|
|
{
|
|
s := $2.(*stmts.UnionStmt)
|
|
src := yylex.(*lexer).src
|
|
// See the implemention of yyParse function
|
|
s.SetText(src[yyS[yypt-1].offset-1:yyS[yypt].offset-1])
|
|
$$ = &subquery.SubQuery{Stmt: s}
|
|
}
|
|
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
|
|
SelectLockOpt:
|
|
/* empty */
|
|
{
|
|
$$ = coldef.SelectLockNone
|
|
}
|
|
| "FOR" "UPDATE"
|
|
{
|
|
$$ = coldef.SelectLockForUpdate
|
|
}
|
|
| "LOCK" "IN" "SHARE" "MODE"
|
|
{
|
|
$$ = coldef.SelectLockInShareMode
|
|
}
|
|
|
|
/********************Set Statement*******************************/
|
|
SetStmt:
|
|
"SET" VariableAssignmentList
|
|
{
|
|
$$ = &stmts.SetStmt{Variables: $2.([]*stmts.VariableAssignment)}
|
|
}
|
|
| "SET" "NAMES" CharsetName
|
|
{
|
|
$$ = &stmts.SetCharsetStmt{Charset: $3.(string)}
|
|
}
|
|
| "SET" "NAMES" CharsetName "COLLATE" CollationName
|
|
{
|
|
$$ = &stmts.SetCharsetStmt{
|
|
Charset: $3.(string),
|
|
Collate: $5.(string),
|
|
}
|
|
}
|
|
| "SET" CharsetKw CharsetName
|
|
{
|
|
$$ = &stmts.SetCharsetStmt{Charset: $3.(string)}
|
|
}
|
|
| "SET" "PASSWORD" eq PasswordOpt
|
|
{
|
|
$$ = &stmts.SetPwdStmt{Password: $4.(string)}
|
|
}
|
|
| "SET" "PASSWORD" "FOR" Username eq PasswordOpt
|
|
{
|
|
$$ = &stmts.SetPwdStmt{User: $4.(string), Password: $6.(string)}
|
|
}
|
|
|
|
VariableAssignment:
|
|
Identifier eq Expression
|
|
{
|
|
$$ = &stmts.VariableAssignment{Name: $1.(string), Value: $3.(expression.Expression), IsSystem: true}
|
|
}
|
|
| "GLOBAL" Identifier eq Expression
|
|
{
|
|
$$ = &stmts.VariableAssignment{Name: $2.(string), Value: $4.(expression.Expression), IsGlobal: true, IsSystem: true}
|
|
}
|
|
| "SESSION" Identifier eq Expression
|
|
{
|
|
$$ = &stmts.VariableAssignment{Name: $2.(string), Value: $4.(expression.Expression), IsSystem: true}
|
|
}
|
|
| "LOCAL" Identifier eq Expression
|
|
{
|
|
$$ = &stmts.VariableAssignment{Name: $2.(string), Value: $4.(expression.Expression), 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, "@@")
|
|
}
|
|
$$ = &stmts.VariableAssignment{Name: v, Value: $3.(expression.Expression), IsGlobal: isGlobal, IsSystem: true}
|
|
}
|
|
| "USER_VAR" eq Expression
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &stmts.VariableAssignment{Name: v, Value: $3.(expression.Expression)}
|
|
}
|
|
|
|
VariableAssignmentList:
|
|
{
|
|
$$ = []*stmts.VariableAssignment{}
|
|
}
|
|
| VariableAssignment
|
|
{
|
|
$$ = []*stmts.VariableAssignment{$1.(*stmts.VariableAssignment)}
|
|
}
|
|
| VariableAssignmentList ',' VariableAssignment
|
|
{
|
|
$$ = append($1.([]*stmts.VariableAssignment), $3.(*stmts.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, "@@")
|
|
}
|
|
$$ = &expression.Variable{Name: v, IsGlobal: isGlobal, IsSystem: true}
|
|
}
|
|
|
|
UserVariable:
|
|
"USER_VAR"
|
|
{
|
|
v := $1.(string)
|
|
v = strings.TrimPrefix(v, "@")
|
|
$$ = &expression.Variable{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)
|
|
}
|
|
|
|
/****************************Show Statement*******************************/
|
|
ShowStmt:
|
|
"SHOW" "ENGINES"
|
|
{
|
|
$$ = &stmts.ShowStmt{Target: stmt.ShowEngines}
|
|
}
|
|
| "SHOW" "DATABASES"
|
|
{
|
|
$$ = &stmts.ShowStmt{Target: stmt.ShowDatabases}
|
|
}
|
|
| "SHOW" "SCHEMAS"
|
|
{
|
|
$$ = &stmts.ShowStmt{Target: stmt.ShowDatabases}
|
|
}
|
|
| "SHOW" "CHARACTER" "SET"
|
|
{
|
|
$$ = &stmts.ShowStmt{Target: stmt.ShowCharset}
|
|
}
|
|
| "SHOW" OptFull "TABLES" ShowDatabaseNameOpt ShowLikeOrWhereOpt
|
|
{
|
|
stmt := &stmts.ShowStmt{
|
|
Target: stmt.ShowTables,
|
|
DBName: $4.(string),
|
|
Full: $2.(bool),
|
|
}
|
|
stmt.SetCondition($5)
|
|
$$ = stmt
|
|
}
|
|
| "SHOW" OptFull "COLUMNS" ShowTableIdentOpt ShowDatabaseNameOpt
|
|
{
|
|
$$ = &stmts.ShowStmt{
|
|
Target: stmt.ShowColumns,
|
|
TableIdent: $4.(table.Ident),
|
|
DBName: $5.(string),
|
|
Full: $2.(bool),
|
|
}
|
|
}
|
|
| "SHOW" "WARNINGS"
|
|
{
|
|
$$ = &stmts.ShowStmt{Target: stmt.ShowWarnings}
|
|
}
|
|
| "SHOW" GlobalScope "VARIABLES" ShowLikeOrWhereOpt
|
|
{
|
|
stmt := &stmts.ShowStmt{
|
|
Target: stmt.ShowVariables,
|
|
GlobalScope: $2.(bool),
|
|
}
|
|
stmt.SetCondition($4)
|
|
$$ = stmt
|
|
}
|
|
| "SHOW" "COLLATION" ShowLikeOrWhereOpt
|
|
{
|
|
stmt := &stmts.ShowStmt{
|
|
Target: stmt.ShowCollation,
|
|
}
|
|
stmt.SetCondition($3)
|
|
$$ = stmt
|
|
}
|
|
| "SHOW" "CREATE" "TABLE" TableIdent
|
|
{
|
|
$$ = &stmts.ShowStmt{
|
|
Target: stmt.ShowCreateTable,
|
|
TableIdent: $4.(table.Ident),
|
|
}
|
|
}
|
|
|
|
ShowLikeOrWhereOpt:
|
|
{
|
|
$$ = nil
|
|
}
|
|
| "LIKE" PrimaryExpression
|
|
{
|
|
$$ = &expression.PatternLike{Pattern: $2.(expression.Expression)}
|
|
}
|
|
| "WHERE" Expression
|
|
{
|
|
$$ = expression.Expr($2)
|
|
}
|
|
|
|
GlobalScope:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "GLOBAL"
|
|
{
|
|
$$ = true
|
|
}
|
|
| "SESSION"
|
|
{
|
|
$$ = false
|
|
}
|
|
|
|
OptFull:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "FULL"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
ShowDatabaseNameOpt:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "FROM" DBName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
| "IN" DBName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
ShowTableIdentOpt:
|
|
"FROM" TableIdent
|
|
{
|
|
$$ = $2.(table.Ident)
|
|
}
|
|
| "IN" TableIdent
|
|
{
|
|
$$ = $2.(table.Ident)
|
|
}
|
|
|
|
Statement:
|
|
EmptyStmt
|
|
| AlterTableStmt
|
|
| BeginTransactionStmt
|
|
| CommitStmt
|
|
| DeallocateStmt
|
|
| DeleteFromStmt
|
|
| ExecuteStmt
|
|
| ExplainStmt
|
|
| CreateDatabaseStmt
|
|
| CreateIndexStmt
|
|
| CreateTableStmt
|
|
| CreateUserStmt
|
|
| DoStmt
|
|
| DropDatabaseStmt
|
|
| DropIndexStmt
|
|
| DropTableStmt
|
|
| InsertIntoStmt
|
|
| PreparedStmt
|
|
| RollbackStmt
|
|
| SelectStmt
|
|
| SetStmt
|
|
| ShowStmt
|
|
| TruncateTableStmt
|
|
| UnionStmt
|
|
| 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.(*subquery.SubQuery).Stmt
|
|
}
|
|
|
|
ExplainableStmt:
|
|
SelectStmt
|
|
| DeleteFromStmt
|
|
| UpdateStmt
|
|
| InsertIntoStmt
|
|
|
|
StatementList:
|
|
Statement
|
|
{
|
|
if $1 != nil {
|
|
s := $1.(stmt.Statement)
|
|
s.SetText(yylex.(*lexer).stmtText())
|
|
yylex.(*lexer).list = []stmt.Statement{ s }
|
|
}
|
|
}
|
|
| StatementList ';' Statement
|
|
{
|
|
if $3 != nil {
|
|
s := $3.(stmt.Statement)
|
|
s.SetText(yylex.(*lexer).stmtText())
|
|
yylex.(*lexer).list = append(yylex.(*lexer).list, s)
|
|
}
|
|
}
|
|
|
|
TableConstraint:
|
|
"CONSTRAINT" name ConstraintElem
|
|
{
|
|
cst := $3.(*coldef.TableConstraint)
|
|
cst.ConstrName = $2.(string)
|
|
$$ = cst
|
|
}
|
|
| ConstraintElem
|
|
{
|
|
$$ = $1
|
|
}
|
|
|
|
TableElement:
|
|
ColumnDef
|
|
{
|
|
$$ = $1.(*coldef.ColumnDef)
|
|
}
|
|
| TableConstraint
|
|
{
|
|
$$ = $1.(*coldef.TableConstraint)
|
|
}
|
|
| "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
|
|
}
|
|
}
|
|
|
|
TableElementListOpt:
|
|
{
|
|
$$ = []interface{}{}
|
|
}
|
|
| TableElementList
|
|
|
|
TableOpt:
|
|
"ENGINE" Identifier
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptEngine, StrValue: $2.(string)}
|
|
}
|
|
| "ENGINE" eq Identifier
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptEngine, StrValue: $3.(string)}
|
|
}
|
|
| DefaultKwdOpt CharsetKw EqOpt CharsetName
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptCharset, StrValue: $4.(string)}
|
|
}
|
|
| DefaultKwdOpt "COLLATE" EqOpt CollationName
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptCollate, StrValue: $4.(string)}
|
|
}
|
|
| "AUTO_INCREMENT" eq LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptAutoIncrement, UintValue: $3.(uint64)}
|
|
}
|
|
| "COMMENT" EqOpt stringLit
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptComment, StrValue: $3.(string)}
|
|
}
|
|
| "AVG_ROW_LENGTH" EqOpt LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptAvgRowLength, UintValue: $3.(uint64)}
|
|
}
|
|
| "CONNECTION" EqOpt stringLit
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptConnection, StrValue: $3.(string)}
|
|
}
|
|
| "CHECKSUM" EqOpt LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptCheckSum, UintValue: $3.(uint64)}
|
|
}
|
|
| "PASSWORD" EqOpt stringLit
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptPassword, StrValue: $3.(string)}
|
|
}
|
|
| "COMPRESSION" EqOpt Identifier
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptCompression, StrValue: $3.(string)}
|
|
}
|
|
| "KEY_BLOCK_SIZE" EqOpt LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptKeyBlockSize, UintValue: $3.(uint64)}
|
|
}
|
|
| "MAX_ROWS" EqOpt LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptMaxRows, UintValue: $3.(uint64)}
|
|
}
|
|
| "MIN_ROWS" EqOpt LengthNum
|
|
{
|
|
$$ = &coldef.TableOpt{Tp: coldef.TblOptMinRows, UintValue: $3.(uint64)}
|
|
}
|
|
|
|
|
|
TableOptListOpt:
|
|
{
|
|
$$ = []*coldef.TableOpt{}
|
|
}
|
|
| TableOptList %prec lowerThanComma
|
|
|
|
TableOptList:
|
|
TableOpt
|
|
{
|
|
$$ = []*coldef.TableOpt{$1.(*coldef.TableOpt)}
|
|
}
|
|
| TableOptList TableOpt
|
|
{
|
|
$$ = append($1.([]*coldef.TableOpt), $2.(*coldef.TableOpt))
|
|
}
|
|
| TableOptList ',' TableOpt
|
|
{
|
|
$$ = append($1.([]*coldef.TableOpt), $3.(*coldef.TableOpt))
|
|
}
|
|
|
|
|
|
TruncateTableStmt:
|
|
"TRUNCATE" "TABLE" TableIdent
|
|
{
|
|
$$ = &stmts.TruncateTableStmt{TableIdent: $3.(table.Ident)}
|
|
}
|
|
|
|
/*************************************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.([]*field.Opt) {
|
|
if o.IsUnsigned {
|
|
x.Flag |= mysql.UnsignedFlag
|
|
}
|
|
if o.IsZerofill {
|
|
x.Flag |= mysql.ZerofillFlag
|
|
}
|
|
}
|
|
$$ = x
|
|
}
|
|
| FixedPointType FloatOpt FieldOpts
|
|
{
|
|
fopt := $2.(*coldef.FloatOpt)
|
|
x := types.NewFieldType($1.(byte))
|
|
x.Flen = fopt.Flen
|
|
x.Decimal = fopt.Decimal
|
|
for _, o := range $3.([]*field.Opt) {
|
|
if o.IsUnsigned {
|
|
x.Flag |= mysql.UnsignedFlag
|
|
}
|
|
if o.IsZerofill {
|
|
x.Flag |= mysql.ZerofillFlag
|
|
}
|
|
}
|
|
$$ = x
|
|
}
|
|
| FloatingPointType FloatOpt FieldOpts
|
|
{
|
|
fopt := $2.(*coldef.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.([]*field.Opt) {
|
|
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
|
|
{
|
|
x := types.NewFieldType(mysql.TypeString)
|
|
x.Flen = $3.(int)
|
|
if $4.(bool) {
|
|
x.Flag |= mysql.BinaryFlag
|
|
}
|
|
$$ = x
|
|
}
|
|
| NationalOpt "CHAR" OptBinary
|
|
{
|
|
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"
|
|
{
|
|
$$ = &field.Opt{IsUnsigned: true}
|
|
}
|
|
| "ZEROFILL"
|
|
{
|
|
$$ = &field.Opt{IsZerofill: true, IsUnsigned: true}
|
|
}
|
|
|
|
FieldOpts:
|
|
{
|
|
$$ = []*field.Opt{}
|
|
}
|
|
| FieldOpts FieldOpt
|
|
{
|
|
$$ = append($1.([]*field.Opt), $2.(*field.Opt))
|
|
}
|
|
|
|
FloatOpt:
|
|
{
|
|
$$ = &coldef.FloatOpt{Flen: types.UnspecifiedLength, Decimal: types.UnspecifiedLength}
|
|
}
|
|
| FieldLen
|
|
{
|
|
$$ = &coldef.FloatOpt{Flen: $1.(int), Decimal: types.UnspecifiedLength}
|
|
}
|
|
| Precision
|
|
{
|
|
$$ = $1.(*coldef.FloatOpt)
|
|
}
|
|
|
|
Precision:
|
|
'(' LengthNum ',' LengthNum ')'
|
|
{
|
|
$$ = &coldef.FloatOpt{Flen: int($2.(uint64)), Decimal: int($4.(uint64))}
|
|
}
|
|
|
|
OptBinary:
|
|
{
|
|
$$ = false
|
|
}
|
|
| "BINARY"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
OptCharset:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| CharsetKw CharsetName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
CharsetKw:
|
|
"CHARACTER" "SET"
|
|
| "CHARSET"
|
|
|
|
OptCollate:
|
|
{
|
|
$$ = ""
|
|
}
|
|
| "COLLATE" CollationName
|
|
{
|
|
$$ = $2.(string)
|
|
}
|
|
|
|
StringList:
|
|
stringLit
|
|
{
|
|
$$ = []string{$1.(string)}
|
|
}
|
|
| StringList ',' stringLit
|
|
{
|
|
$$ = append($1.([]string), $3.(string))
|
|
}
|
|
|
|
/************************************************************************************
|
|
* Union statement
|
|
* See: https://dev.mysql.com/doc/refman/5.7/en/union.html
|
|
***********************************************************************************/
|
|
UnionStmt:
|
|
UnionSelect "UNION" UnionOpt SelectStmt
|
|
{
|
|
ds := []bool {$3.(bool)}
|
|
ss := []*stmts.SelectStmt{$1.(*stmts.SelectStmt), $4.(*stmts.SelectStmt)}
|
|
$$ = &stmts.UnionStmt{
|
|
Distincts: ds,
|
|
Selects: ss,
|
|
}
|
|
}
|
|
| UnionSelect "UNION" UnionOpt '(' SelectStmt ')' SelectStmtOrder SelectStmtLimit
|
|
{
|
|
ds := []bool {$3.(bool)}
|
|
ss := []*stmts.SelectStmt{$1.(*stmts.SelectStmt), $5.(*stmts.SelectStmt)}
|
|
st := &stmts.UnionStmt{
|
|
Distincts: ds,
|
|
Selects: ss,
|
|
}
|
|
if $7 != nil {
|
|
st.OrderBy = $7.(*rsets.OrderByRset)
|
|
}
|
|
|
|
if $8 != nil {
|
|
ay := $8.([]interface{})
|
|
st.Limit = ay[0].(*rsets.LimitRset)
|
|
st.Offset = ay[1].(*rsets.OffsetRset)
|
|
}
|
|
$$ = st
|
|
}
|
|
| UnionSelect "UNION" UnionOpt UnionStmt
|
|
{
|
|
s := $4.(*stmts.UnionStmt)
|
|
s.Distincts = append([]bool {$3.(bool)}, s.Distincts...)
|
|
s.Selects = append([]*stmts.SelectStmt{$1.(*stmts.SelectStmt)}, s.Selects...)
|
|
$$ = s
|
|
}
|
|
|
|
UnionSelect:
|
|
SelectStmt
|
|
{
|
|
$$ = $1
|
|
}
|
|
| '(' SelectStmt ')'
|
|
{
|
|
$$ = $2
|
|
}
|
|
|
|
|
|
UnionOpt:
|
|
{
|
|
$$ = true
|
|
}
|
|
| "ALL"
|
|
{
|
|
$$ = false
|
|
}
|
|
| "DISTINCT"
|
|
{
|
|
$$ = true
|
|
}
|
|
|
|
|
|
/***********************************************************************************
|
|
* Update Statement
|
|
* See: https://dev.mysql.com/doc/refman/5.7/en/update.html
|
|
***********************************************************************************/
|
|
UpdateStmt:
|
|
"UPDATE" LowPriorityOptional IgnoreOptional TableRef "SET" AssignmentList WhereClauseOptional OrderByOptional LimitClause
|
|
{
|
|
// Single-table syntax
|
|
r := &rsets.JoinRset{Left: $4, Right: nil}
|
|
st := &stmts.UpdateStmt{
|
|
LowPriority: $2.(bool),
|
|
TableRefs: r,
|
|
List: $6.([]expression.Assignment),
|
|
}
|
|
if $7 != nil {
|
|
st.Where = $7.(expression.Expression)
|
|
}
|
|
if $8 != nil {
|
|
st.Order = $8.(*rsets.OrderByRset)
|
|
}
|
|
if $9 != nil {
|
|
st.Limit = $9.(*rsets.LimitRset)
|
|
}
|
|
$$ = st
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
| "UPDATE" LowPriorityOptional IgnoreOptional TableRefs "SET" AssignmentList WhereClauseOptional
|
|
{
|
|
// Multiple-table syntax
|
|
st := &stmts.UpdateStmt{
|
|
LowPriority: $2.(bool),
|
|
TableRefs: $4.(*rsets.JoinRset),
|
|
List: $6.([]expression.Assignment),
|
|
MultipleTable: true,
|
|
}
|
|
if $7 != nil {
|
|
st.Where = $7.(expression.Expression)
|
|
}
|
|
$$ = st
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
UseStmt:
|
|
"USE" DBName
|
|
{
|
|
$$ = &stmts.UseStmt{DBName: $2.(string)}
|
|
if yylex.(*lexer).root {
|
|
break
|
|
}
|
|
}
|
|
|
|
WhereClause:
|
|
"WHERE" Expression
|
|
{
|
|
$$ = expression.Expr($2)
|
|
}
|
|
|
|
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 UserSpecificationList
|
|
{
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/create-user.html
|
|
$$ = &stmts.CreateUserStmt{
|
|
IfNotExists: $3.(bool),
|
|
Specs: $4.([]*coldef.UserSpecification),
|
|
}
|
|
}
|
|
|
|
UserSpecification:
|
|
Username AuthOption
|
|
{
|
|
$$ = &coldef.UserSpecification{
|
|
User: $1.(string),
|
|
AuthOpt: $2.(*coldef.AuthOption),
|
|
}
|
|
}
|
|
|
|
UserSpecificationList:
|
|
UserSpecification
|
|
{
|
|
$$ = []*coldef.UserSpecification{$1.(*coldef.UserSpecification)}
|
|
}
|
|
| UserSpecificationList ',' UserSpecification
|
|
{
|
|
$$ = append($1.([]*coldef.UserSpecification), $3.(*coldef.UserSpecification))
|
|
}
|
|
|
|
AuthOption:
|
|
{}
|
|
| "IDENTIFIED" "BY" AuthString
|
|
{
|
|
$$ = &coldef.AuthOption {
|
|
AuthString: $3.(string),
|
|
ByAuthString: true,
|
|
}
|
|
}
|
|
| "IDENTIFIED" "BY" "PASSWORD" HashString
|
|
{
|
|
$$ = &coldef.AuthOption {
|
|
HashString: $4.(string),
|
|
}
|
|
}
|
|
|
|
HashString:
|
|
stringLit
|
|
%%
|
|
|