Files
tidb/parser/parser.y
shenli ced00cc547 *: Remove conversion function
It is useless in MySQL and will cause conflict with
year/time/datetime/date function.
2015-09-06 18:07:17 +08:00

3308 lines
65 KiB
Plaintext

%{
// 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/expressions"
"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 {
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 "%di" */ imaginaryLit "imaginary literal"
/*yy:token "%d" */ intLit "integer literal"
/*yy:token "\"%c\"" */ stringLit "string literal"
add "ADD"
after "AFTER"
all "ALL"
alter "ALTER"
and "AND"
andand "&&"
andnot "&^"
as "AS"
asc "ASC"
autoIncrement "AUTO_INCREMENT"
begin "BEGIN"
between "BETWEEN"
by "BY"
byteType "BYTE"
caseKwd "CASE"
cast "CAST"
character "CHARACTER"
charsetKwd "CHARSET"
collation "COLLATE"
column "COLUMN"
columns "COLUMNS"
commit "COMMIT"
constraint "CONSTRAINT"
convert "CONVERT"
create "CREATE"
cross "CROSS"
database "DATABASE"
databases "DATABASES"
deallocate "DEALLOCATE"
defaultKwd "DEFAULT"
delayed "DELAYED"
deleteKwd "DELETE"
desc "DESC"
describe "DESCRIBE"
distinct "DISTINCT"
div "DIV"
do "DO"
drop "DROP"
duplicate "DUPLICATE"
durationType "duration"
elseKwd "ELSE"
end "END"
engine "ENGINE"
engines "ENGINES"
eq "="
execute "EXECUTE"
exists "EXISTS"
explain "EXPLAIN"
falseKwd "false"
first "FIRST"
foreign "FOREIGN"
forKwd "FOR"
from "FROM"
full "FULL"
fulltext "FULLTEXT"
ge ">="
global "GLOBAL"
group "GROUP"
having "HAVING"
highPriority "HIGH_PRIORITY"
ignore "IGNORE"
ifKwd "IF"
in "IN"
index "INDEX"
inner "INNER"
insert "INSERT"
into "INTO"
is "IS"
join "JOIN"
key "KEY"
le "<="
left "LEFT"
like "LIKE"
limit "LIMIT"
local "LOCAL"
lock "LOCK"
lowPriority "LOW_PRIORITY"
lsh "<<"
mod "MOD"
mode "MODE"
names "NAMES"
neq "!="
neqSynonym "<>"
not "NOT"
null "NULL"
offset "OFFSET"
on "ON"
or "OR"
order "ORDER"
oror "||"
outer "OUTER"
password "PASSWORD"
placeholder "PLACEHOLDER"
prepare "PREPARE"
primary "PRIMARY"
quick "QUICK"
references "REFERENCES"
regexp "REGEXP"
right "RIGHT"
rlike "RLIKE"
rollback "ROLLBACK"
rsh ">>"
runeType "rune"
schema "SCHEMA"
schemas "SCHEMAS"
selectKwd "SELECT"
session "SESSION"
set "SET"
share "SHARE"
show "SHOW"
signed "SIGNED"
start "START"
stringType "string"
substring "SUBSTRING"
sysVar "SYS_VAR"
tableKwd "TABLE"
tables "TABLES"
then "THEN"
transaction "TRANSACTION"
trueKwd "true"
truncate "TRUNCATE"
unknown "UNKNOWN"
union "UNION"
unique "UNIQUE"
unsigned "UNSIGNED"
update "UPDATE"
use "USE"
using "USING"
userVar "USER_VAR"
value "VALUE"
values "VALUES"
warnings "WARNINGS"
when "WHEN"
where "WHERE"
xor "XOR"
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"
bigRatType "bigrat"
boolType "BOOL"
booleanType "BOOLEAN"
parseExpression "parse expression prefix"
%type <item>
AggAllOpt "All option in aggregate function"
AlterTableStmt "Alter table statement"
AlterSpecification "Alter table specification"
AlterSpecificationList "Alter table specification list"
AsOpt "as optional"
Assignment "assignment"
AssignmentList "assignment list"
AssignmentList1 "assignment list optional trailing comma"
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"
ColumnNameList1 "column name list with optional trailing comma"
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"
Constraint "column value constraint"
ConstraintElem "table define constraint element"
ConstraintKeywordOpt "Constraint Keyword or empty"
ConstraintOpt "optional column value constraint"
ConstraintOpts "optional column value constraints"
CreateDatabase "Create {DATABASE | SCHEMA}"
CreateDatabaseStmt "Create Database Statement"
CreateIndexStmt "CREATE INDEX statement"
CreateIndexStmtUnique "CREATE INDEX optional UNIQUE clause"
CreateSpecification "CREATE Database specification"
CreateSpecificationList "CREATE Database specification list"
CreateTableStmt "CREATE TABLE statement"
CrossOpt "Cross join option"
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"
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"
ExpressionListList "expression list list"
ExpressionList1 "expression list expression"
Factor "expression factor"
Factor1 "binary expression factor"
Field "field expression"
Field1 "field expression optional AS clause"
FieldList "field expression list"
ForUserOpt "Set password for user option"
FromClause "From clause"
Function "function expr"
FunctionCall "function call post part"
FunctionCallArgList "function call optional argument list"
GroupByClause "GROUP BY clause"
GroupByList "GROUP BY list"
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}"
LimitClause "LIMIT clause"
Literal "literal value"
logAnd "logical and operator"
logOr "logical or operator"
LowPriorityOptional "LOW_PRIORITY or empty"
name "name"
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"
SelectStmtWhere "SELECT statement optional WHERE clause"
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"
ShowTableIdentOpt "Show columns statement table name option"
SignedLiteral "Literal or NumLiteral with sign"
Statement "statement"
StatementList "statement list"
SubSelect "Sub Select"
Symbol "Constraint Symbol"
SystemVariable "System defined variable name"
TableConstraint "table constraint definition"
TableElement "table definition element"
TableElementList "table definition element list"
TableFactor "table factor"
TableIdent "Table identifier"
TableIdentList "Table identifier list"
TableIdentOpt "Table identifier option"
TableOpt "create table option"
TableOpts "create table option list"
TableRef "table reference"
TableRefs "table references"
TruncateTableStmt "TRANSACTION TABLE statement"
UnionOpt "Union Option(empty/ALL/DISTINCT)"
UnionStmt "Union statement"
UpdateStmt "UPDATE statement"
Username "Username"
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"
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)"
FunctionNameConflict "Built-in function call names which are conflict with keywords"
%token tableRefPriority
%left join inner cross left right full
/* A dummy token to force the priority of TableRef production in a join. */
%left tableRefPriority
%left oror or
%left xor
%left andand and
%left between
%left eq ge le neq neqSynonym '>' '<' is like in
%left '|'
%left '&'
%left rsh lsh
%left '-' '+'
%left '*' '/' '%' div mod
%left '^'
%left '~' neg
%right not
%start Start
%%
Start:
StatementList
| parseExpression Expression
{
yylex.(*lexer).expr = expressions.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:
TableOpts
{
$$ = &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:
{
$$ = []*ddl.AlterSpecification{}
}
| 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:
ColumnName eq Expression
{
$$ = expressions.Assignment{ColName: $1.(string), Expr: expressions.Expr($3)}
}
AssignmentList:
Assignment AssignmentList1 CommaOpt
{
$$ = append([]expressions.Assignment{$1.(expressions.Assignment)}, $2.([]expressions.Assignment)...)
}
AssignmentList1:
/* EMPTY */
{
$$ = []expressions.Assignment{}
}
| AssignmentList1 ',' Assignment
{
$$ = append($1.([]expressions.Assignment), $3.(expressions.Assignment))
}
BeginTransactionStmt:
"BEGIN"
{
$$ = &stmts.BeginStmt{}
}
| "START" "TRANSACTION"
{
$$ = &stmts.BeginStmt{}
}
FunctionCall:
'(' AggAllOpt FunctionCallArgList ')'
{
$$ = []interface{}{false, $3}
}
| '(' "DISTINCT" AggAllOpt ExpressionList')'
{
/* Distinct must have expression list, can not empty and '*' */
$$ = []interface{}{true, $4}
}
AggAllOpt:
{
}
| "ALL"
{
/* TODO: not all functions support ALL, so later we will distinguish to handle them */
/* ALL has nothing to do. */
}
FunctionCallArgList:
/* EMPTY */
{
$$ = []expression.Expression{}
}
/* select count(*) from table */
| '*'
{
$$ = []expression.Expression{ expressions.Value{expressions.TypeStar("*")} }
}
| ExpressionList
ColumnDef:
ColumnName Type ConstraintOpts
{
$$ = &coldef.ColumnDef{Name: $1.(string), Tp: $2.(*types.FieldType), Constraints: $3.([]*coldef.ConstraintOpt)}
}
ColumnName:
Identifier
ColumnNameList:
ColumnName ColumnNameList1 CommaOpt
{
$$ = append([]string{$1.(string)}, $2.([]string)...)
}
ColumnNameList1:
/* EMPTY */
{
$$ = []string{}
}
| ColumnNameList1 ',' ColumnName
{
$$ = append($1.([]string), $3.(string))
}
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)}
}
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"
{
$$ = &expressions.Ident{model.NewCIStr("CURRENT_TIMESTAMP")}
}
| "LOCALTIME"
| "LOCALTIMESTAMP"
| "NOW"
SignedLiteral:
Literal
{
$$ = expressions.Value{$1}
}
| '+' NumLiteral
{
n := expressions.Value{$2}
$$ = expressions.NewUnaryOperation(opcode.Plus, n)
}
| '-' NumLiteral
{
n := expressions.Value{$2}
$$ = expressions.NewUnaryOperation(opcode.Minus, n)
}
// TODO: support decimal literal
NumLiteral:
intLit
| floatLit
ConstraintOpt:
Constraint
ConstraintOpts:
{
$$ = []*coldef.ConstraintOpt{}
}
| ConstraintOpt
{
$$ = []*coldef.ConstraintOpt{$1.(*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).err("index name collision: %s", indexName)
return 1
}
for _, colName := range colNameList {
if indexName == colName.ColumnName {
yylex.(*lexer).err("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:
CreateDatabase IfNotExists DBName CreateSpecificationList
{
opts := $4.([]*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 {
//TODO: return error
fmt.Println("get charset error")
}
dbopt := &coldef.CharsetOpt{Chs: cs, Col: co}
$$ = &stmts.CreateDatabaseStmt{
IfNotExists: $2.(bool),
Name: $3.(string),
Opt: dbopt}
if yylex.(*lexer).root {
break
}
}
CreateDatabase:
"CREATE" "DATABASE"
{
}
| "CREATE" "SCHEMA"
{
}
DBName:
Identifier
CreateSpecification:
DefaultOpt CharsetKw EqOpt CharsetName
{
$$ = &coldef.DatabaseOpt{Tp: coldef.DBOptCollate, Value: $4.(string)}
}
| DefaultOpt "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).err(fmt.Sprintf("Unknown character set: '%s'", $1.(string)))
return 1
}
}
CollationName:
Identifier
CreateSpecificationList:
{
$$ = []*coldef.DatabaseOpt{}
}
| 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 '(' TableElementList ')' TableOpts CommaOpt
{
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
x := &stmts.DeleteStmt{
TableIdent: $6.(table.Ident),
LowPriority: $2.(bool),
Quick: $3.(bool),
Ignore: $4.(bool)}
if $7 != nil {
x.Where = $7.(*rsets.WhereRset).Expr
}
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.(*rsets.WhereRset).Expr
}
$$ = 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.(*rsets.WhereRset).Expr
}
$$ = x
if yylex.(*lexer).root {
break
}
}
DropDatabaseStmt:
"DROP" "DATABASE" IfExists Identifier
{
$$ = &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 Statement
{
$$ = &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
{
$$ = expressions.NewBinaryOperation(opcode.OrOr, $1.(expression.Expression), $3.(expression.Expression))
}
| Expression "XOR" Expression %prec xor
{
$$ = expressions.NewBinaryOperation(opcode.LogicXor, $1.(expression.Expression), $3.(expression.Expression))
}
| Expression logAnd Expression %prec andand
{
$$ = expressions.NewBinaryOperation(opcode.AndAnd, $1.(expression.Expression), $3.(expression.Expression))
}
| "NOT" Expression %prec not
{
$$ = expressions.NewUnaryOperation(opcode.Not, $2.(expression.Expression))
}
| Factor "IS" NotOpt trueKwd %prec is
{
$$ = &expressions.IsTruth{Expr:$1.(expression.Expression), Not: $3.(bool), True: int8(1)}
}
| Factor "IS" NotOpt falseKwd %prec is
{
$$ = &expressions.IsTruth{Expr:$1.(expression.Expression), Not: $3.(bool), True: int8(0)}
}
| Factor "IS" NotOpt "UNKNOWN" %prec is
{
/* https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_is */
$$ = &expressions.IsNull{Expr: $1.(expression.Expression), Not: $3.(bool)}
}
| Factor
logOr:
"||"
{
}
| "OR"
{
}
logAnd:
"&&"
{
}
| "AND"
{
}
name:
Identifier
ExpressionList:
Expression ExpressionList1 CommaOpt
{
$$ = append([]expression.Expression{expressions.Expr($1)}, $2.([]expression.Expression)...)
}
ExpressionList1:
/* EMPTY */
{
$$ = []expression.Expression(nil)
}
| ExpressionList1 ',' Expression
{
$$ = append($1.([]expression.Expression), expressions.Expr($3))
}
Factor:
Factor "IS" NotOpt "NULL" %prec is
{
$$ = &expressions.IsNull{Expr: $1.(expression.Expression), Not: $3.(bool)}
}
| Factor ">=" Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.GE, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor '>' Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.GT, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor "<=" Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.LE, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor '<' Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.LT, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor "!=" Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.NE, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor "<>" Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.NE, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor "=" Factor1 %prec eq
{
$$ = expressions.NewBinaryOperation(opcode.EQ, $1.(expression.Expression), $3.(expression.Expression))
}
| Factor1
Factor1:
PrimaryFactor NotOpt "IN" '(' ExpressionList ')'
{
$$ = &expressions.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), List: $5.([]expression.Expression)}
}
| PrimaryFactor NotOpt "IN" '(' SelectStmt semiOpt ')'
{
$$ = &expressions.PatternIn{Expr: $1.(expression.Expression), Not: $2.(bool), Sel: $5.(*stmts.SelectStmt)}
}
| PrimaryFactor NotOpt "BETWEEN" PrimaryFactor "AND" Factor1
{
var err error
$$, err = expressions.NewBetween($1.(expression.Expression), $4.(expression.Expression), $6.(expression.Expression), $2.(bool))
if err != nil {
yylex.(*lexer).err("%v", err)
return 1
}
}
| PrimaryFactor NotOpt "LIKE" PrimaryExpression
{
$$ = &expressions.PatternLike{Expr: $1.(expression.Expression), Pattern: $4.(expression.Expression), Not: $2.(bool)}
}
| PrimaryFactor NotOpt RegexpSym PrimaryExpression
{
$$ = &expressions.PatternRegexp{Expr: $1.(expression.Expression), Pattern: $4.(expression.Expression), Not: $2.(bool)}
}
| PrimaryFactor
RegexpSym:
"REGEXP"
| "RLIKE"
NotOpt:
{
$$ = false
}
| "NOT"
{
$$ = true
}
Field:
'*'
{
$$ = &field.Field{Expr: &expressions.Ident{CIStr: model.NewCIStr("*")}}
}
| Expression Field1
{
expr, name := expressions.Expr($1), $2.(string)
if name == "" {
name = expr.String()
}
$$ = &field.Field{Expr: expr, Name: name}
}
Field1:
/* EMPTY */
{
$$ = ""
}
| AsOpt
{
$$ = $1
}
AsOpt:
identifier
{
// TODO: check potential bug
$$ = $1
}
| "AS" Identifier
{
$$ = $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
// TODO: Add Data Type UnReserved Keywords
UnReservedKeyword:
"AUTO_INCREMENT" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "CHARSET" | "COLUMN" | "COLUMNS" | "DATE" | "DATETIME"
| "ENGINE" | "FULL" | "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" | "QUICK" | "ROLLBACK" | "SESSION" | "GLOBAL"
| "TABLES"| "TEXT" | "TIME" | "TIMESTAMP" | "TRANSACTION" | "TRUNCATE" | "VALUE" | "WARNINGS" | "YEAR" | "NOW"
| "SUBSTRING"
/************************************************************************************
*
* 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.([]expressions.Assignment)
}
$$ = x
if yylex.(*lexer).root {
break
}
}
IntoOpt:
{
}
| "INTO"
{
}
InsertRest:
'(' ColumnNameList ')' ValueSym ExpressionListList
{
$$ = &stmts.InsertIntoStmt{
ColNames: $2.([]string),
Lists: $5.([][]expression.Expression)}
}
| '(' ColumnNameList ')' SelectStmt
{
$$ = &stmts.InsertIntoStmt{ColNames: $2.([]string), Sel: $4.(*stmts.SelectStmt)}
}
| ValueSym ExpressionListList
{
$$ = &stmts.InsertIntoStmt{Lists: $2.([][]expression.Expression)}
}
| SelectStmt
{
$$ = &stmts.InsertIntoStmt{Sel: $1.(*stmts.SelectStmt)}
}
| "SET" ColumnSetValueList
{
$$ = &stmts.InsertIntoStmt{Setlist: $2.([]*expressions.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 "DEFAULT"
{
//set columnname = DEFAULT
$$ = &expressions.Assignment{
ColName: $1.(string),
Expr: expressions.Expr($3)}
}
| ColumnName eq Expression
{
$$ = &expressions.Assignment{
ColName: $1.(string),
Expr: expressions.Expr($3)}
}
ColumnSetValueList:
{
$$ = []*expressions.Assignment{}
}
| ColumnSetValue
{
$$ = []*expressions.Assignment{$1.(*expressions.Assignment)}
}
| ColumnSetValueList ',' ColumnSetValue
{
$$ = append($1.([]*expressions.Assignment), $3.(*expressions.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"
{
$$ = int8(0)
}
| "NULL"
| "true"
{
$$ = int8(1)
}
| floatLit
| imaginaryLit
| intLit
| stringLit
Operand:
Literal
{
$$ = expressions.Value{$1}
}
| QualifiedIdent
{
$$ = &expressions.Ident{model.NewCIStr($1.(string))}
}
| '(' Expression ')'
{
$$ = &expressions.PExpr{Expr: expressions.Expr($2)}
}
| "DEFAULT"
{
$$ = &expressions.Default{}
}
| "DEFAULT" '(' ColumnName ')'
{
$$ = &expressions.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 := &expressions.ParamMarker{}
l.ParamList = append(l.ParamList, pm)
$$ = pm
}
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
{
$$ = expressions.NewUnaryOperation(opcode.Not, $2.(expression.Expression))
}
| '~' PrimaryExpression %prec neg
{
$$ = expressions.NewUnaryOperation(opcode.BitNeg, $2.(expression.Expression))
}
| '-' PrimaryExpression %prec neg
{
$$ = expressions.NewUnaryOperation(opcode.Minus, $2.(expression.Expression))
}
| '+' PrimaryExpression %prec neg
{
$$ = expressions.NewUnaryOperation(opcode.Plus, $2.(expression.Expression))
}
Function:
PrimaryExpression FunctionCall
{
x := yylex.(*lexer)
f, ok := $1.(*expressions.Ident)
if !ok {
x.err("expected identifier or qualified identifier")
return 1
}
var err error
args := $2.([]interface{})
if $$, err = expressions.NewCall(f.O, args[1].([]expression.Expression), args[0].(bool)); err != nil {
x.err("%v", err)
return 1
}
}
| FunctionNameConflict FunctionCall
{
x := yylex.(*lexer)
var err error
args := $2.([]interface{})
$$, err = expressions.NewCall($1.(string), args[1].([]expression.Expression), false)
if err != nil {
x.err("%v", err)
return 1
}
}
| "CAST" '(' Expression "AS" CastType ')'
{
/* See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast */
$$ = &expressions.FunctionCast{
Expr: $3.(expression.Expression),
Tp: $5.(*types.FieldType),
}
}
| "CASE" ExpressionOpt WhenClauseList ElseOpt "END"
{
x := &expressions.FunctionCase{WhenClauses: $3.([]*expressions.WhenClause)}
if $2 != nil {
x.Value = $2.(expression.Expression)
}
if $4 != nil {
x.ElseClause = $4.(expression.Expression)
}
$$ = x
}
| "VALUES" '(' Identifier ')'
{
// TODO: support qualified identifier for column_name
$$ = &expressions.Values{model.NewCIStr($3.(string))}
}
| "CONVERT" '(' Expression "USING" CharsetName ')'
{
// See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
$$ = &expressions.FunctionConvert{
Expr: $3.(expression.Expression),
Charset: $5.(string),
}
}
| "SUBSTRING" '(' Expression ',' Expression ')'
{
$$ = &expressions.FunctionSubstring{
StrExpr: $3.(expression.Expression),
Pos: $5.(expression.Expression),
}
}
| "SUBSTRING" '(' Expression "FROM" Expression ')'
{
$$ = &expressions.FunctionSubstring{
StrExpr: $3.(expression.Expression),
Pos: $5.(expression.Expression),
}
}
| "SUBSTRING" '(' Expression ',' Expression ',' Expression ')'
{
$$ = &expressions.FunctionSubstring{
StrExpr: $3.(expression.Expression),
Pos: $5.(expression.Expression),
Len: $7.(expression.Expression),
}
}
| "SUBSTRING" '(' Expression "FROM" Expression "FOR" Expression ')'
{
$$ = &expressions.FunctionSubstring{
StrExpr: $3.(expression.Expression),
Pos: $5.(expression.Expression),
Len: $7.(expression.Expression),
}
}
ExpressionOpt:
{
$$ = nil
}
| Expression
{
$$ = $1
}
WhenClauseList:
WhenClause
{
$$ = []*expressions.WhenClause{$1.(*expressions.WhenClause)}
}
| WhenClauseList WhenClause
{
$$ = append($1.([]*expressions.WhenClause), $2.(*expressions.WhenClause))
}
WhenClause:
"WHEN" Expression "THEN" Expression
{
$$ = &expressions.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
{
x := types.NewFieldType(mysql.TypeString)
x.Flen = $2.(int)
$$ = 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
}
FunctionNameConflict:
"DATABASE"
{
$$ = expressions.BuiltinFuncDatabase
}
| "SCHEMA"
{
$$ = expressions.BuiltinFuncDatabase
}
| "IF"
{
$$ = expressions.BuiltinFuncIf
}
| "LEFT"
{
$$ = expressions.BuiltinFuncLeft
}
PrimaryFactor:
PrimaryFactor '|' PrimaryFactor %prec '|'
{
$$ = expressions.NewBinaryOperation(opcode.Or, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '&' PrimaryFactor %prec '&'
{
$$ = expressions.NewBinaryOperation(opcode.And, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor "<<" PrimaryFactor %prec lsh
{
$$ = expressions.NewBinaryOperation(opcode.LeftShift, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor ">>" PrimaryFactor %prec rsh
{
$$ = expressions.NewBinaryOperation(opcode.RightShift, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '+' PrimaryFactor %prec '+'
{
$$ = expressions.NewBinaryOperation(opcode.Plus, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '-' PrimaryFactor %prec '-'
{
$$ = expressions.NewBinaryOperation(opcode.Minus, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '*' PrimaryFactor %prec '*'
{
$$ = expressions.NewBinaryOperation(opcode.Mul, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '/' PrimaryFactor %prec '/'
{
$$ = expressions.NewBinaryOperation(opcode.Div, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '%' PrimaryFactor %prec '%'
{
$$ = expressions.NewBinaryOperation(opcode.Mod, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor "DIV" PrimaryFactor %prec div
{
$$ = expressions.NewBinaryOperation(opcode.IntDiv, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor "MOD" PrimaryFactor %prec mod
{
$$ = expressions.NewBinaryOperation(opcode.Mod, $1.(expression.Expression), $3.(expression.Expression))
}
| PrimaryFactor '^' PrimaryFactor
{
$$ = expressions.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))
}
TableIdent:
Identifier
{
$$ = table.Ident{Name:model.NewCIStr($1.(string))}
}
| Identifier '.' Identifier
{
$$ = table.Ident{Schema:model.NewCIStr($1.(string)), Name:model.NewCIStr($3.(string))}
}
TableIdentList:
{
$$ = []table.Ident{}
}
| TableIdent
{
tbl := []table.Ident{$1.(table.Ident)}
$$ = tbl
}
| TableIdentList ',' TableIdent
{
$$ = append($1.([]table.Ident), $3.(table.Ident))
}
QuickOptional:
{
$$ = false
}
| "QUICK"
{
$$ = true
}
semiOpt:
/* EMPTY */
| ';'
/***************************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 *expressions.Variable
switch $4.(type) {
case string:
sqlText = $4.(string)
case *expressions.Variable:
sqlVar = $4.(*expressions.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 SelectStmtLimit SelectLockOpt
{
$$ = &stmts.SelectStmt {
Distinct: $2.(bool),
Fields: $3.([]*field.Field),
From: nil,
Lock: $5.(coldef.LockType),
}
}
| "SELECT" SelectStmtOpts SelectStmtFieldList "FROM"
FromClause SelectStmtWhere 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 = $6.(*rsets.WhereRset)
}
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
}
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
{
$$ = $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 semiOpt ')' AsOpt
{
$$ = &rsets.TableSource{Source: $2, Name: $5.(string)}
}
| '(' TableRefs ')'
{
$$ = $2
}
TableIdentOpt:
{
$$ = ""
}
| AsOpt
{
$$ = $1
}
JoinTable:
/* Use %prec to evaluate production TableRef before cross join */
TableRef CrossOpt "JOIN" TableRef %prec tableRefPriority
{
$$ = &rsets.JoinRset{Left: $1, Right: $4, Type: rsets.CrossJoin}
}
| TableRef CrossOpt "JOIN" TableRef "ON" Expression
{
$$ = &rsets.JoinRset{Left: $1, Right: $4, Type: rsets.CrossJoin, On: $6.(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
}
| "FULL"
{
$$ = rsets.FullJoin
}
OuterOpt:
{
$$ = nil
}
| "OUTER"
CrossOpt:
{
}
| "CROSS"
| "INNER"
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:
{
$$ = false
}
| "SQL_CALC_FOUND_ROWS"
{
$$ = true
}
SelectStmtFieldList:
FieldList CommaOpt
{
$$ = $1
}
SelectStmtWhere:
/* EMPTY */
{
$$ = nil
}
| WhereClause
SelectStmtGroup:
/* EMPTY */
{
$$ = nil
}
| GroupByClause
SelectStmtOrder:
/* EMPTY */
{
$$ = nil
}
| OrderBy
// See: https://dev.mysql.com/doc/refman/5.7/en/subqueries.html
SubSelect:
'(' SelectStmt ')'
{
s := $2.(stmt.Statement)
s.SetText(yylex.(*lexer).src[yyS[yypt - 1].col-1:yyS[yypt].col-1])
$$ = &expressions.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" ForUserOpt eq PasswordOpt
{
$$ = &stmts.SetPwdStmt{User: $3.(string), Password: $5.(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, "@@")
}
$$ = &expressions.Variable{Name: v, IsGlobal: isGlobal, IsSystem: true}
}
UserVariable:
"USER_VAR"
{
v := $1.(string)
v = strings.TrimPrefix(v, "@")
$$ = &expressions.Variable{Name: v, IsGlobal: false, IsSystem: false}
}
ForUserOpt:
{
$$ = ""
}
| "FOR" Username
{
$$ = $2.(string)
}
Username:
Identifier
{
$$ = $1.(string)
}
PasswordOpt:
"PASSWORD" '(' AuthString ')'
{
$$ = $3.(string)
}
AuthString:
Identifier
{
$$ = $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" "TABLES" ShowDatabaseNameOpt
{
$$ = &stmts.ShowStmt{
Target: stmt.ShowTables,
DBName: $3.(string)}
}
| "SHOW" "TABLES" ShowDatabaseNameOpt
{
$$ = &stmts.ShowStmt{
Target: stmt.ShowTables,
DBName: $3.(string)}
}
| "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}
}
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
| DoStmt
| DropDatabaseStmt
| DropIndexStmt
| DropTableStmt
| InsertIntoStmt
| PreparedStmt
| RollbackStmt
| SelectStmt
| SetStmt
| ShowStmt
| TruncateTableStmt
| UnionStmt
| UpdateStmt
| UseStmt
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:
{
$$ = nil
}
| ColumnDef
{
$$ = $1.(*coldef.ColumnDef)
}
| TableConstraint
{
$$ = $1.(*coldef.TableConstraint)
}
TableElementList:
{
$$ = []interface{}{}
}
| TableElement
{
if $1 != nil {
$$ = []interface{}{$1.(interface{})}
} else {
$$ = []interface{}{}
}
}
| TableElementList ',' TableElement
{
if $3 != nil {
$$ = append($1.([]interface{}), $3)
} else {
$$ = $1
}
}
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)}
}
TableOpts:
{
$$ = []*coldef.TableOpt{}
}
| TableOpt
{
$$ = []*coldef.TableOpt{$1.(*coldef.TableOpt)}
}
| TableOpts TableOpt
{
$$ = append($1.([]*coldef.TableOpt), $2.(*coldef.TableOpt))
}
| TableOpts ',' 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
}
| "duration"
{
x := types.NewFieldType($1.(byte))
$$ = x
}
| "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
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)
$$ = 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:
"CHAR" FieldLen OptBinary
{
x := types.NewFieldType(mysql.TypeString)
x.Flen = $2.(int)
if $3.(bool) {
x.Flag |= mysql.BinaryFlag
}
$$ = x
}
| "CHAR" OptBinary
{
x := types.NewFieldType(mysql.TypeString)
if $2.(bool) {
x.Flag |= mysql.BinaryFlag
}
$$ = x
}
| "VARCHAR" FieldLen OptBinary OptCharset OptCollate
{
x := types.NewFieldType(mysql.TypeVarchar)
x.Flen = $2.(int)
if $3.(bool) {
x.Flag |= mysql.BinaryFlag
}
x.Charset = $4.(string)
x.Collate = $5.(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
}
BlobType:
"TINYBLOB"
{
x := types.NewFieldType(mysql.TypeTinyBlob)
x.Charset = charset.CharsetBin
x.Collate = charset.CharsetBin
$$ = x
}
| "BLOB"
{
x := types.NewFieldType(mysql.TypeBlob)
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"
{
x := types.NewFieldType(mysql.TypeBlob)
$$ = 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"
{
x := types.NewFieldType(mysql.TypeYear)
$$ = 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{}
}
| FieldOpt
{
$$ = []*field.Opt{$1.(*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)
}
/************************************************************************************
* Union statement
* See: https://dev.mysql.com/doc/refman/5.7/en/union.html
***********************************************************************************/
UnionStmt:
SelectStmt "UNION" UnionOpt SelectStmt
{
ds := []bool {$3.(bool)}
ss := []*stmts.SelectStmt{$1.(*stmts.SelectStmt), $4.(*stmts.SelectStmt)}
$$ = &stmts.UnionStmt{
Distincts: ds,
Selects: ss,
}
}
| UnionStmt "UNION" UnionOpt SelectStmt
{
s := $1.(*stmts.UnionStmt)
s.Distincts = append(s.Distincts, $3.(bool))
s.Selects = append(s.Selects, $4.(*stmts.SelectStmt))
$$ = s
}
UnionOpt:
{
$$ = true
}
| "ALL"
{
$$ = false
}
| "DISTINCT"
{
$$ = true
}
/************************************************************************************/
UpdateStmt:
"UPDATE" LowPriorityOptional IgnoreOptional TableIdent SetOpt AssignmentList WhereClauseOptional OrderByOptional LimitClause
{
var expr expression.Expression
if w := $7; w != nil {
expr = w.(*rsets.WhereRset).Expr
}
st := &stmts.UpdateStmt{
LowPriority: $2.(bool),
TableIdent: $4.(table.Ident),
List: $6.([]expressions.Assignment),
Where: expr}
if $8 != nil {
st.Order = $8.(*rsets.OrderByRset)
}
if $9 != nil {
st.Limit = $9.(*rsets.LimitRset)
}
$$ = st
if yylex.(*lexer).root {
break
}
}
UseStmt:
"USE" DBName
{
$$ = &stmts.UseStmt{DBName: $2.(string)}
if yylex.(*lexer).root {
break
}
}
WhereClause:
"WHERE" Expression
{
$$ = &rsets.WhereRset{Expr: expressions.Expr($2)}
}
WhereClauseOptional:
{
$$ = nil
}
| WhereClause
{
$$ = $1
}
SetOpt:
{
}
| "SET"
{
}
CommaOpt:
{
}
| ','
{
}
%%