[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/dearcode/sqlparser/master/sql.y [Back]  [Original]

/*
Copyright 2017 Google 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,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

%{
package sqlparser

func setParseTree(yylex interface{}, stmt Statement) {
  yylex.(*Tokenizer).ParseTree = stmt
}

func setAllowComments(yylex interface{}, allow bool) {
  yylex.(*Tokenizer).AllowComments = allow
}

func setDDL(yylex interface{}, ddl *DDL) {
  yylex.(*Tokenizer).partialDDL = ddl
}

func incNesting(yylex interface{}) bool {
  yylex.(*Tokenizer).nesting++
  if yylex.(*Tokenizer).nesting == 200 {
    return true
  }
  return false
}

func decNesting(yylex interface{}) {
  yylex.(*Tokenizer).nesting--
}

// forceEOF forces the lexer to end prematurely. Not all SQL statements
// are supported by the Parser, thus calling forceEOF will make the lexer
// return EOF early.
func forceEOF(yylex interface{}) {
  yylex.(*Tokenizer).ForceEOF = true
}

%}

%union {
  empty         struct{}
  statement     Statement
  selStmt       SelectStatement
  ddl           *DDL
  ins           *Insert
  byt           byte
  bytes         []byte
  bytes2        [][]byte
  str           string
  strs          []string
  selectExprs   SelectExprs
  selectExpr    SelectExpr
  columns       Columns
  partitions    Partitions
  colName       *ColName
  tableExprs    TableExprs
  tableExpr     TableExpr
  joinCondition JoinCondition
  tableName     TableName
  tableNames    TableNames
  indexHints    *IndexHints
  expr          Expr
  exprs         Exprs
  boolVal       BoolVal
  colTuple      ColTuple
  values        Values
  valTuple      ValTuple
  subquery      *Subquery
  whens         []*When
  when          *When
  orderBy       OrderBy
  order         *Order
  limit         *Limit
  updateExprs   UpdateExprs
  setExprs      SetExprs
  updateExpr    *UpdateExpr
  setExpr       *SetExpr
  colIdent      ColIdent
  tableIdent    TableIdent
  convertType   *ConvertType
  aliasedTableName *AliasedTableExpr
  TableSpec     *TableSpec
  columnOption  columnOption
  columnOptions []columnOption
  TableOption   TableOption
  columnType    ColumnType
  colKeyOpt     ColumnKeyOption
  optVal        *SQLVal
  LengthScaleOption LengthScaleOption
  columnDefinition *ColumnDefinition
  indexDefinition *IndexDefinition
  indexInfo     *IndexInfo
  indexColumn   *IndexColumn
  indexColumns  []*IndexColumn
  partDefs      []*PartitionDefinition
  partDef       *PartitionDefinition
  partSpec      *PartitionSpec
  vindexParam   VindexParam
  vindexParams  []VindexParam
  ForeignOptionList []ForeignOption
  ForeignOption ForeignOption
}

%token LEX_ERROR
%left  UNION 
%token  SELECT INSERT UPDATE DELETE FROM WHERE GROUP HAVING ORDER BY LIMIT OFFSET FOR
%token  ALL DISTINCT AS EXISTS ASC DESC INTO DUPLICATE KEY DEFAULT SET LOCK KEYS
%token  VALUES LAST_INSERT_ID
%token  NEXT VALUE SHARE MODE
%token  SQL_NO_CACHE SQL_CACHE
%left  JOIN STRAIGHT_JOIN LEFT RIGHT INNER OUTER CROSS NATURAL USE FORCE
%left  ON USING
%token  '(' ',' ')'
%token  HEX STRING INTEGRAL FLOAT HEXNUM VALUE_ARG LIST_ARG COMMENT COMMENT_KEYWORD BIT_LITERAL
%token  NULL TRUE FALSE

// Precedence dictated by mysql. But the vitess grammar is simplified.
// Some of these operators don't conflict in our situation. Nevertheless,
// it's better to have these listed in the correct order. Also, we don't
// support all operators yet.
%left  OR
%left  AND
%right  NOT '!'
%left  BETWEEN CASE WHEN THEN ELSE END
%left  '=' '' LE GE NE NULL_SAFE_EQUAL IS LIKE REGEXP IN
%left  '|'
%left  '&'
%left  SHIFT_LEFT SHIFT_RIGHT
%left  '+' '-'
%left  '*' '/' DIV '%' MOD
%left  '^'
%right  '~' UNARY
%right  BINARY UNDERSCORE_BINARY
%left  COLLATE
%right  INTERVAL
%nonassoc  '.'

// There is no need to define precedence for the JSON
// operators because the syntax is restricted enough that
// they don't cause conflicts.
%token  JSON_EXTRACT_OP JSON_UNQUOTE_EXTRACT_OP

// DDL Tokens
%token  CREATE ALTER DROP RENAME ANALYZE ADD MODIFY CHANGE
%token  TABLE INDEX VIEW TO IGNORE IF UNIQUE PRIMARY COLUMN CONSTRAINT SPATIAL FULLTEXT FOREIGN REFERENCES CASCADE RESTRICT NO ACTION
%token  SHOW DESCRIBE EXPLAIN DATE ESCAPE REPAIR OPTIMIZE TRUNCATE
%token  MAXVALUE PARTITION REORGANIZE LESS THAN PROCEDURE TRIGGER
%token  VINDEX VINDEXES
%token  ENGINE STATUS VARIABLES

// Transaction Tokens
%token  BEGIN START TRANSACTION COMMIT ROLLBACK

// Type Tokens
%token  BIT TINYINT SMALLINT MEDIUMINT INT INTEGER BIGINT INTNUM
%token  REAL DOUBLE FLOAT_TYPE DECIMAL NUMERIC 
%token  TIME TIMESTAMP DATETIME YEAR
%token  CHAR VARCHAR BOOL CHARACTER VARBINARY NCHAR
%token  TEXT TINYTEXT MEDIUMTEXT LONGTEXT
%token  BLOB TINYBLOB MEDIUMBLOB LONGBLOB JSON ENUM

// Type Modifiers
%token  NULLX AUTO_INCREMENT APPROXNUM SIGNED UNSIGNED ZEROFILL

// Supported SHOW tokens
%token  DATABASES TABLES VITESS_KEYSPACES VITESS_SHARDS VITESS_TABLETS VSCHEMA_TABLES

// SET tokens
%token  NAMES CHARSET GLOBAL SESSION

// Functions
%token  CURRENT_TIMESTAMP DATABASE CURRENT_DATE NOW
%token  CURRENT_TIME LOCALTIME LOCALTIMESTAMP
%token  UTC_DATE UTC_TIME UTC_TIMESTAMP
%token  REPLACE
%token  CONVERT CAST
%token  GROUP_CONCAT SEPARATOR

// Match
%token  MATCH AGAINST BOOLEAN LANGUAGE WITH QUERY EXPANSION

// MySQL reserved words that are unused by this grammar will map to this token.
%token  UNUSED ID 

%type  command
%type  select_statement base_select union_lhs union_rhs
%type  insert_statement update_statement delete_statement set_statement
%type  create_statement alter_statement rename_statement drop_statement truncate_statement
%type  create_table_prefix
%type  analyze_statement show_statement use_statement other_statement
%type  begin_statement commit_statement rollback_statement
%type  comment_opt comment_list
%type  union_op insert_or_replace
%type  distinct_opt straight_join_opt cache_opt match_option separator_opt
%type  like_escape_opt
%type  select_expression_list select_expression_list_opt
%type  select_expression
%type  expression
%type  from_opt table_references
%type  table_reference table_factor join_table
%type  join_condition join_condition_opt on_expression_opt
%type  table_name_list
%type  inner_join outer_join straight_join natural_join
%type  table_name into_table_name
%type  aliased_table_name
%type  index_hint_list
%type  where_expression_opt
%type  condition
%type  boolean_value
%type  compare
%type  insert_data
%type  value value_expression num_val
%type  function_call_keyword function_call_nonkeyword function_call_generic function_call_conflict
%type  is_suffix
%type  col_tuple
%type  expression_list
%type  tuple_list
%type  row_tuple tuple_or_empty
%type  tuple_expression
%type  subquery
%type  column_name
%type  when_expression_list
%type  when_expression
%type  expression_opt else_expression_opt
%type  group_by_opt
%type  having_opt
%type  order_by_opt order_list
%type  order
%type  asc_desc_opt
%type  limit_opt
%type  lock_opt
%type  ins_column_list column_list
%type  opt_partition_clause partition_list
%type  on_dup_opt
%type  update_list
%type  set_list
%type  charset_or_character_set
%type  update_expression
%type  set_expression
%type  for_from
%type  ignore_opt default_opt
%type  exists_opt
%type  not_exists_opt non_add_drop_or_rename_operation to_opt index_opt constraint_opt
%type  reserved_keyword non_reserved_keyword
%type  sql_id reserved_sql_id col_alias as_ci_opt using_opt
%type  charset_value
%type  table_id reserved_table_id table_alias as_opt_id
%type  as_opt
%type  force_eof ddl_force_eof
%type  charset
%type  set_session_or_global show_session_or_global
%type  convert_type
%type  column_type
%type  int_type decimal_type numeric_type time_type char_type
%type  length_opt column_default_opt column_comment_opt on_update_opt current_timestamp_opt
%type  charset_opt collate_opt
%type  unsigned_opt zero_fill_opt
%type  float_length_opt decimal_length_opt
%type  null_opt auto_increment_opt
%type  column_key_opt
%type  enum_values
%type  column_definition
%type  index_definition
%type  index_or_key
%type  table_spec table_column_list 
%type  table_column_option
%type  table_column_opt_list
%type  table_opt_value 
%type  table_option table_option_list
%type  index_info constraint_index_info
%type  foreign_option_list foreign_option
%type  index_column
%type  index_column_list
%type  partition_definitions
%type  partition_definition
%type  partition_operation
%type  vindex_param
%type  vindex_param_list vindex_params_opt
%type  vindex_type vindex_type_opt
%type  alter_object_type
%type  any_string foreign_action

%start any_command

%%

any_command:
  command semicolon_opt
  {
    setParseTree(yylex, $1)
  }

semicolon_opt:
/*empty*/ {}
| ';' {}

command:
  select_statement
  {
    $$ = $1
  }
| insert_statement
| update_statement
| delete_statement
| set_statement
| create_statement
| alter_statement
| rename_statement
| drop_statement
| truncate_statement
| analyze_statement
| show_statement
| use_statement
| begin_statement
| commit_statement
| rollback_statement
| other_statement

select_statement:
  base_select order_by_opt limit_opt lock_opt
  {
    sel := $1.(*Select)
    sel.OrderBy = $2
    sel.Limit = $3
    sel.Lock = $4
    $$ = sel
  }
| union_lhs union_op union_rhs order_by_opt limit_opt lock_opt
  {
    $$ = &Union{Type: $2, Left: $1, Right: $3, OrderBy: $4, Limit: $5, Lock: $6}
  }
| SELECT comment_opt cache_opt NEXT num_val for_from table_name
  {
    $$ = &Select{Comments: Comments($2), Cache: $3, SelectExprs: SelectExprs{Nextval{Expr: $5}}, From: TableExprs{&AliasedTableExpr{Expr: $7}}}
  }


// base_select is an unparenthesized SELECT with no order by clause or beyond.
base_select:
  SELECT comment_opt cache_opt distinct_opt straight_join_opt select_expression_list from_opt where_expression_opt group_by_opt having_opt
  {
    $$ = &Select{Comments: Comments($2), Cache: $3, Distinct: $4, Hints: $5, SelectExprs: $6, From: $7, Where: NewWhere(WhereStr, $8), GroupBy: GroupBy($9), Having: NewWhere(HavingStr, $10)}
  }

union_lhs:
  select_statement
  {
    $$ = $1
  }
| openb select_statement closeb
  {
    $$ = &ParenSelect{Select: $2}
  }

union_rhs:
  base_select
  {
    $$ = $1
  }
| openb select_statement closeb
  {
    $$ = &ParenSelect{Select: $2}
  }


insert_statement:
  insert_or_replace comment_opt ignore_opt into_table_name opt_partition_clause insert_data on_dup_opt
  {
    // insert_data returns a *Insert pre-filled with Columns & Values
    ins := $6
    ins.Action = $1
    ins.Comments = $2
    ins.Ignore = $3
    ins.Table = $4
    ins.Partitions = $5
    ins.OnDup = OnDup($7)
    $$ = ins
  }
| insert_or_replace comment_opt ignore_opt into_table_name opt_partition_clause SET update_list on_dup_opt
  {
    cols := make(Columns, 0, len($7))
    vals := make(ValTuple, 0, len($8))
    for _, updateList := range $7 {
      cols = append(cols, updateList.Name.Name)
      vals = append(vals, updateList.Expr)
    }
    $$ = &Insert{Action: $1, Comments: Comments($2), Ignore: $3, Table: $4, Partitions: $5, Columns: cols, Rows: Values{vals}, OnDup: OnDup($8)}
  }

insert_or_replace:
  INSERT
  {
    $$ = InsertStr
  }
| REPLACE
  {
    $$ = ReplaceStr
  }

update_statement:
  UPDATE comment_opt table_references SET update_list where_expression_opt order_by_opt limit_opt
  {
    $$ = &Update{Comments: Comments($2), TableExprs: $3, Exprs: $5, Where: NewWhere(WhereStr, $6), OrderBy: $7, Limit: $8}
  }

delete_statement:
  DELETE comment_opt FROM table_name opt_partition_clause where_expression_opt order_by_opt limit_opt
  {
    $$ = &Delete{Comments: Comments($2), TableExprs:  TableExprs{&AliasedTableExpr{Expr:$4}}, Partitions: $5, Where: NewWhere(WhereStr, $6), OrderBy: $7, Limit: $8}
  }
| DELETE comment_opt table_name_list from_or_using table_references where_expression_opt
  {
    $$ = &Delete{Comments: Comments($2), Targets: $3, TableExprs: $5, Where: NewWhere(WhereStr, $6)}
  }

from_or_using:
  FROM {}
| USING {}

table_name_list:
  table_name
  {
    $$ = TableNames{$1}
  }
| table_name_list ',' table_name
  {
    $$ = append($$, $3)
  }

opt_partition_clause:
  {
    $$ = nil
  }
| PARTITION openb partition_list closeb
  {
  $$ = $3
  }

set_statement:
  SET comment_opt set_list
  {
    $$ = &Set{Comments: Comments($2), Exprs: $3}
   }
| SET comment_opt set_session_or_global set_list
  {
    $$ = &Set{Comments: Comments($2), Scope: $3, Exprs: $4}
   }

set_session_or_global:
  SESSION
  {
    $$ = SessionStr
  }
| GLOBAL
  {
    $$ = GlobalStr
  }

create_statement:
  create_table_prefix table_spec
  {
    $1.TableSpec = $2
    $$ = $1
  }
 | create_table_prefix '(' LIKE table_name ')'
  {
    $$ = $1
    $1.Table = $4
    $1.LikeTable = $4
  }
| CREATE DATABASE not_exists_opt ID table_option_list
  {
    $$ = &DDL{Action: CreateDatabaseStr, Table: TableName{Qualifier:TableIdent{string($4)}}, TableSpec:&TableSpec{Option:$5}}
  }
| CREATE constraint_opt INDEX ID using_opt ON table_name ddl_force_eof
  {
    // Change this to an alter statement
    $$ = &DDL{Action: AlterStr, Table: $7, NewName:$7}
  }
| CREATE VIEW table_name ddl_force_eof
  {
    $$ = &DDL{Action: CreateStr, NewName: $3.ToViewName()}
  }
| CREATE OR REPLACE VIEW table_name ddl_force_eof
  {
    $$ = &DDL{Action: CreateStr, NewName: $5.ToViewName()}
  }
| CREATE VINDEX sql_id vindex_type_opt vindex_params_opt
  {
    $$ = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{
        Name: $3,
        Type: $4,
        Params: $5,
    }}
  }

vindex_type_opt:
  {
    $$ = NewColIdent("")
  }
| USING vindex_type
  {
    $$ = $2
  }

vindex_type:
  ID
  {
    $$ = NewColIdent(string($1))
  }

vindex_params_opt:
  {
    var v []VindexParam
    $$ = v
  }
| WITH vindex_param_list
  {
    $$ = $2
  }

vindex_param_list:
  vindex_param
  {
    $$ = make([]VindexParam, 0, 4)
    $$ = append($$, $1)
  }
| vindex_param_list ',' vindex_param
  {
    $$ = append($$, $3)
  }

vindex_param:
  reserved_sql_id '=' table_opt_value
  {
    $$ = VindexParam{Key: $1, Val: $3}
  }

create_table_prefix:
  CREATE TABLE not_exists_opt table_name
  {
    $$ = &DDL{Action: CreateTableStr, NewName: $4}
    setDDL(yylex, $$)
  }
 | CREATE TABLE not_exists_opt table_name LIKE table_name
  {
    $$ = &DDL{Action: CreateTableStr, NewName: $4, Table: $6, LikeTable:$6}
    setDDL(yylex, $$)
  }

table_spec:
  '(' table_column_list ')' table_option_list
  {
    $$ = $2
    $$.Option = $4
  }

table_column_list:
  column_definition
  {
    $$ = &TableSpec{}
    $$.AddColumn($1)
  }
| table_column_list ',' column_definition
  {
    $$.AddColumn($3)
  }
| table_column_list ',' index_definition
  {
    $$.AddIndex($3)
  } 

column_definition:
  column_name column_type table_column_opt_list
  {

    $$ = &ColumnDefinition{Name: $1.Name, Type: $2, options:$3}
    $$.mergeOptions()
  }

table_column_opt_list:
{
    $$ = []columnOption{}
}
| table_column_opt_list table_column_option
{
    $$ = append($1, $2)
}

table_column_option:
 null_opt
{
    $$ = columnOption{key:"null_opt", value:$1}
}
| column_default_opt
{
    $$ = columnOption{key:"column_default_opt", value:$1}
}
| on_update_opt
{
    $$ = columnOption{key:"on_update_opt", value:$1}
}
| auto_increment_opt
{
    $$ = columnOption{key:"auto_increment_opt", value:$1}
}
| column_key_opt
{
    $$ = columnOption{key:"column_key_opt", value:$1}
}
| column_comment_opt
{
    $$ = columnOption{key:"column_comment_opt", value:$1}
}
|charset_opt
{
    $$ = columnOption{key:"charset_opt", value:$1}
}
|collate_opt
{
    $$ = columnOption{key:"collate_opt", value:$1}
}


column_type:
  numeric_type unsigned_opt zero_fill_opt
  {
    $$ = $1
    $$.Unsigned = $2
    $$.Zerofill = $3
  }
| char_type
| time_type

numeric_type:
  int_type length_opt
  {
    $$ = $1
    $$.Length = $2
  }
| decimal_type
  {
    $$ = $1
  }

int_type:
  BIT
  {
    $$ = ColumnType{Type: string($1)}
  }
| TINYINT
  {
    $$ = ColumnType{Type: string($1)}
  }
| SMALLINT
  {
    $$ = ColumnType{Type: string($1)}
  }
| MEDIUMINT
  {
    $$ = ColumnType{Type: string($1)}
  }
| INT
  {
    $$ = ColumnType{Type: string($1)}
  }
| INTEGER
  {
    $$ = ColumnType{Type: string($1)}
  }
| BIGINT
  {
    $$ = ColumnType{Type: string($1)}
  }
| BOOLEAN
  {
    $$ = ColumnType{Type: string($1)}
  }

decimal_type:
REAL float_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }
| DOUBLE UNUSED float_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $3.Length
    $$.Scale = $3.Scale
  }
| DOUBLE float_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }
| FLOAT_TYPE float_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }
| DECIMAL decimal_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }
| NUMERIC decimal_length_opt
  {
    $$ = ColumnType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }

time_type:
  DATE
  {
    $$ = ColumnType{Type: string($1)}
  }
| TIME length_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2}
  }
| TIMESTAMP length_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2}
  }
| DATETIME length_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2}
  }
| YEAR
  {
    $$ = ColumnType{Type: string($1)}
  }

char_type:
  CHAR length_opt charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2, Charset: $3, Collate: $4}
  }
| VARCHAR length_opt charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2, Charset: $3, Collate: $4}
  }
| BINARY length_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2}
  }
| VARBINARY length_opt
  {
    $$ = ColumnType{Type: string($1), Length: $2}
  }
| TEXT charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3}
  }
| TINYTEXT charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3}
  }
| MEDIUMTEXT charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3}
  }
| LONGTEXT charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), Charset: $2, Collate: $3}
  }
| BLOB
  {
    $$ = ColumnType{Type: string($1)}
  }
| TINYBLOB
  {
    $$ = ColumnType{Type: string($1)}
  }
| MEDIUMBLOB
  {
    $$ = ColumnType{Type: string($1)}
  }
| LONGBLOB
  {
    $$ = ColumnType{Type: string($1)}
  }
| JSON
  {
    $$ = ColumnType{Type: string($1)}
  }
| ENUM '(' enum_values ')' charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), EnumValues: $3, Charset: $5, Collate: $6}
  }
// need set_values / SetValues ?
| SET '(' enum_values ')' charset_opt collate_opt
  {
    $$ = ColumnType{Type: string($1), EnumValues: $3, Charset: $5, Collate: $6}
  }

enum_values:
  STRING
  {
    $$ = make([]string, 0, 4)
    $$ = append($$, "'" + string($1) + "'")
  }
| enum_values ',' STRING
  {
    $$ = append($1, "'" + string($3) + "'")
  }

length_opt:
  {
    $$ = nil
  }
| '(' INTEGRAL ')'
  {
    $$ = NewIntVal($2)
  }

float_length_opt:
  {
    $$ = LengthScaleOption{}
  }
| '(' INTEGRAL ',' INTEGRAL ')'
  {
    $$ = LengthScaleOption{
        Length: NewIntVal($2),
        Scale: NewIntVal($4),
    }
  }

decimal_length_opt:
  {
    $$ = LengthScaleOption{}
  }
| '(' INTEGRAL ')'
  {
    $$ = LengthScaleOption{
        Length: NewIntVal($2),
    }
  }
| '(' INTEGRAL ',' INTEGRAL ')'
  {
    $$ = LengthScaleOption{
        Length: NewIntVal($2),
        Scale: NewIntVal($4),
    }
  }

unsigned_opt:
  {
    $$ = BoolVal(false)
  }
| UNSIGNED
  {
    $$ = BoolVal(true)
  }

zero_fill_opt:
  {
    $$ = BoolVal(false)
  }
| ZEROFILL
  {
    $$ = BoolVal(true)
  }

// Null opt returns false to mean NULL (i.e. the default) and true for NOT NULL
null_opt:
 NULL
  {
    $$ = BoolVal(false)
  }
| NOT NULL
  {
    $$ = BoolVal(true)
  }

column_default_opt:
 DEFAULT STRING
  {
    $$ = NewStrVal($2)
  }
| DEFAULT INTEGRAL
  {
    $$ = NewIntVal($2)
  }
| DEFAULT FLOAT
  {
    $$ = NewFloatVal($2)
  }
| DEFAULT NULL
  {
    $$ = NewValArg($2)
  }
| DEFAULT current_timestamp_opt
  {
    $$ = $2
  }
| DEFAULT NOW 
  {
    $$ = NewValArg($2)
  }
| DEFAULT NOW '(' ')'
  {
    $$ = NewValArg($2)
  }
| DEFAULT BIT_LITERAL
  {
    $$ = NewBitVal($2)
  }

current_timestamp_opt:
CURRENT_TIMESTAMP
{
    $$ = NewValArg($1)
}
| CURRENT_TIMESTAMP '(' INTEGRAL ')'
{
    $$ = NewValArg($1)
}
| CURRENT_TIMESTAMP '(' ')'
{
    $$ = NewValArg($1)
}


on_update_opt:
ON UPDATE current_timestamp_opt
{
  $$ = $3
}

auto_increment_opt:
AUTO_INCREMENT
  {
    $$ = BoolVal(true)
  }

charset_opt:
CHARSET ID
  {
    $$ = string($2)
  }
| CHARSET '=' ID
  {
    $$ = string($3)
  }
| CHARSET STRING
  {
    $$ = string($2)
  }
| CHARSET '=' STRING
  {
    $$ = string($3)
  }
| CHARACTER SET ID
  {
    $$ = string($3)
  }
| CHARACTER SET '=' ID
  {
    $$ = string($4)
  }
| CHARACTER SET STRING
  {
    $$ = string($3)
  }
| CHARACTER SET '=' STRING
  {
    $$ = string($4)
  }
| CHARACTER SET BINARY
  {
    $$ = string($3)
  }

collate_opt:
COLLATE ID
  {
    $$ = string($2)
  }
| COLLATE '=' ID
  {
    $$ = string($3)
  }
| COLLATE STRING
  {
    $$ = string($2)
  }
| COLLATE BINARY
  {
    $$ = string($2)
  }

column_key_opt:
PRIMARY KEY
  {
    $$ = colKeyPrimary
  }
| KEY
  {
    $$ = colKey
  }
| UNIQUE KEY
  {
    $$ = colKeyUniqueKey
  }
| UNIQUE
  {
    $$ = colKeyUnique
  }

column_comment_opt:
COMMENT_KEYWORD STRING
  {
    $$ = NewStrVal($2)
  }

index_definition:
  index_info '(' index_column_list ')' column_comment_opt
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3}
  }
|  index_info '(' index_column_list ')' using_opt column_comment_opt
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3, Using: $5}
  }
|  index_info '(' index_column_list ')' using_opt
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3, Using: $5}
  }
|  index_info using_opt '(' index_column_list ')' 
  {
    $$ = &IndexDefinition{Info: $1, Columns: $4, Using: $2}
  }
|  index_info '(' index_column_list ')' 
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3}
  }
| constraint_index_info '(' index_column_list ')' 
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3}
  }
| constraint_index_info '(' index_column_list ')' REFERENCES table_name '(' index_column_list ')' foreign_option_list
  {
    $$ = &IndexDefinition{Info: $1, Columns: $3}
    $$.ReferencesTable = $6
    $$.ReferencesColumns = $8
    $$.ReferencesOption = $10

  }


constraint_index_info:
    CONSTRAINT ID PRIMARY KEY
    {
        $$ = &IndexInfo{Type: "PRIMARY", Name: NewColIdent(string($2)), Primary: true}
    }
    | CONSTRAINT ID UNIQUE 
    {
        $$ = &IndexInfo{Type:"UNIQUE", Name: NewColIdent(string($2)), Unique: true}
    }
    | CONSTRAINT ID UNIQUE index_or_key
    {
        $$ = &IndexInfo{Type: "UNIQUE", Name: NewColIdent(string($2)), Unique: true}
    }
    | CONSTRAINT ID FOREIGN KEY
    {
        $$ = &IndexInfo{Type: "FOREIGN", Name: NewColIdent(string($2)), Foreign: true}
    }


foreign_option_list:
    foreign_option
    {
        $$=$1
    }
    | foreign_option foreign_option
    {
        $$=$1.Merge($2)
    }


foreign_option:
    ON DELETE foreign_action
    {
        $$=ForeignOption{OnUpdate:$3}
    }
    | ON UPDATE foreign_action
    {
        $$=ForeignOption{OnDelete:$3}
    }


foreign_action:
    RESTRICT 
    {
        $$=$1
    }
    | CASCADE 
    {
        $$=$1
    }
    | SET NULL 
    {
        $$=append(append($1, ' '), $2...)
    }
    | NO ACTION 
    {
        $$=append(append($1, ' '), $2...)
    }
    | SET DEFAULT
    {
        $$=append(append($1, ' '), $2...)
    }


index_info:
  PRIMARY KEY
  {
    $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true}
  }
| PRIMARY KEY ID
  {
    $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true}
  }
| UNIQUE index_or_key ID
  {
    $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent(string($3)), Unique: true}
  }
| UNIQUE ID
  {
    $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: true}
  }
| index_or_key ID
  {
    $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: false}
  }
| FULLTEXT index_or_key ID
  {
    $$ = &IndexInfo{Type: string($2), Name: NewColIdent(string($3)), Unique: false}
  }
| SPATIAL index_or_key ID
  {
    $$ = &IndexInfo{Type: string($2), Name: NewColIdent(string($3)), Unique: false}
  }


index_or_key:
    INDEX
  {
    $$ = string($1)
  }
  | KEY
  {
    $$ = string($1)
  }

index_column_list:
  index_column
  {
    $$ = []*IndexColumn{$1}
  }
| index_column_list ',' index_column
  {
    $$ = append($$, $3)
  }

index_column:
  sql_id length_opt
  {
      $$ = &IndexColumn{Column: $1, Length: $2}
  }
  | sql_id ASC
  {
      $$ = &IndexColumn{Column: $1}
  }
  | sql_id DESC
  {
      $$ = &IndexColumn{Column: $1}
  }

table_option_list:
  {
    $$ = TableOption{}
  }
 | table_option
  {
    $$ = $1
  }
 | table_option_list table_option 
  {
    $$ = $1.Merge($2)
  }
 | table_option_list ',' table_option 
  {
    $$ = $1.Merge($3)
  }


table_option:
AUTO_INCREMENT INTEGRAL
{
    $$ = TableOption{AutoIncrement: IntegerPtr($2)}

}
|AUTO_INCREMENT '=' INTEGRAL
{
    $$ = TableOption{AutoIncrement: IntegerPtr($3)}
}
|ENGINE any_string
  {
    $$ = TableOption{Engine:$2}
  }
|DEFAULT charset_opt
  {
    $$ = TableOption{Charset:[]byte($2)}
  }
|charset_opt
  {
    $$ = TableOption{Charset:[]byte($1)}
  }
|collate_opt
  {
    $$ = TableOption{Collate:[]byte($1)}
  }
|DEFAULT collate_opt
  {
    $$ = TableOption{Collate:[]byte($2)}
  }
|COMMENT_KEYWORD any_string
  {
    $$ = TableOption{Comment:$2}
  }
| any_string
{
    $$ = TableOption{Common:$1}
}
| any_string any_string
{
    $$ = TableOption{Common:append(append($1, '='), $2...)}
}
  
any_string:
    '=' ID 
    {
        $$ = $2
    }
    | '=' STRING
    {
        $$ = $2 
    }
    | '=' INTEGRAL
    {
        $$ = $2 
    }
    | ID
    {
        $$ = $1
    }
    | STRING
    {
        $$ = $1
    }
    | INTEGRAL
    {
        $$ = $1
    }
    | table_opt_value
    {
        $$ = []byte($1)
    }


table_opt_value:
  reserved_sql_id
  {
    $$ = $1.String()
  }
| STRING
  {
    $$ = string($1) 
  }
| INTEGRAL
  {
    $$ = string($1) 
  }

alter_statement:
  ALTER ignore_opt TABLE table_name non_add_drop_or_rename_operation force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name ADD UNIQUE alter_object_type force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Unique: true, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name ADD alter_object_type force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name MODIFY alter_object_type force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name CHANGE alter_object_type force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name DROP alter_object_type force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER ignore_opt TABLE table_name ADD VINDEX sql_id '(' column_list ')' vindex_type_opt vindex_params_opt
  {
    $$ = &DDL{
        Action: AddColVindexStr,
        Table: $4,
        VindexSpec: &VindexSpec{
            Name: $7,
            Type: $11,
            Params: $12,
        },
        VindexCols: $9,
      }
  }
| ALTER ignore_opt TABLE table_name DROP VINDEX sql_id
  {
    $$ = &DDL{
        Action: DropColVindexStr,
        Table: $4,
        VindexSpec: &VindexSpec{
            Name: $7,
        },
      }
  }
| ALTER ignore_opt TABLE table_name RENAME to_opt table_name
  {
    // Change this to a rename statement
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $7}
  }
| ALTER ignore_opt TABLE table_name RENAME index_opt force_eof
  {
    // Rename an index can just be an alter
    $$ = &DDL{Action: AlterTableStr, Table: $4, NewName: $4}
  }
| ALTER VIEW table_name ddl_force_eof
  {
    $$ = &DDL{Action: AlterTableStr, Table: $3.ToViewName(), NewName: $3.ToViewName()}
  }
| ALTER ignore_opt TABLE table_name table_option_list
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, Option: $5}
  }
| ALTER ignore_opt TABLE table_name partition_operation
  {
    $$ = &DDL{Action: AlterTableStr, Table: $4, PartitionSpec: $5}
  }

alter_object_type:
  COLUMN
| CONSTRAINT
| FOREIGN
| FULLTEXT
| ID
| INDEX
| KEY
| PRIMARY
| SPATIAL
| PARTITION
| UNIQUE

partition_operation:
  REORGANIZE PARTITION sql_id INTO openb partition_definitions closeb
  {
    $$ = &PartitionSpec{Action: ReorganizeStr, Name: $3, Definitions: $6}
  }

partition_definitions:
  partition_definition
  {
    $$ = []*PartitionDefinition{$1}
  }
| partition_definitions ',' partition_definition
  {
    $$ = append($1, $3)
  }

partition_definition:
  PARTITION sql_id VALUES LESS THAN openb value_expression closeb
  {
    $$ = &PartitionDefinition{Name: $2, Limit: $7}
  }
| PARTITION sql_id VALUES LESS THAN openb MAXVALUE closeb
  {
    $$ = &PartitionDefinition{Name: $2, Maxvalue: true}
  }

rename_statement:
  RENAME TABLE table_name TO table_name
  {
    $$ = &DDL{Action: RenameStr, Table: $3, NewName: $5}
  }

drop_statement:
  DROP TABLE exists_opt table_name
  {
    var exists bool
    if $3 != 0 {
      exists = true
    }
    $$ = &DDL{Action: DropTableStr, Table: $4, IfExists: exists}
  }
| DROP DATABASE exists_opt ID ddl_force_eof
  {
    $$ = &DDL{Action: DropDatabaseStr, Table: TableName{Qualifier:TableIdent{string($4)}}}
  }
| DROP INDEX ID ON table_name ddl_force_eof
  {
    // Change this to an alter statement
    $$ = &DDL{Action: AlterTableStr, Table: $5, NewName: $5}
  }
| DROP VIEW exists_opt table_name ddl_force_eof
  {
    var exists bool
    if $3 != 0 {
      exists = true
    }
    $$ = &DDL{Action: DropViewStr, Table: $4.ToViewName(), IfExists: exists}
  }

truncate_statement:
  TRUNCATE TABLE table_name
  {
    $$ = &DDL{Action: TruncateStr, Table: $3}
  }
| TRUNCATE table_name
  {
    $$ = &DDL{Action: TruncateStr, Table: $2}
  }
analyze_statement:
  ANALYZE TABLE table_name
  {
    $$ = &DDL{Action: AlterStr, Table: $3, NewName: $3}
  }

show_statement:
  SHOW BINARY ID ddl_force_eof /* SHOW BINARY LOGS */
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CHARACTER SET ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CREATE DATABASE ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
/* Rule to handle SHOW CREATE EVENT, SHOW CREATE FUNCTION, etc. */
| SHOW CREATE ID ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CREATE PROCEDURE ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CREATE TABLE ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CREATE TRIGGER ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW CREATE VIEW ddl_force_eof
  {
    $$ = &Show{Type: string($2) + " " + string($3)}
  }
| SHOW DATABASES ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW INDEX ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW KEYS ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW PROCEDURE ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW show_session_or_global STATUS ddl_force_eof
  {
    $$ = &Show{Scope: $2, Type: string($3)}
  }
| SHOW TABLE ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW TABLES ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW show_session_or_global VARIABLES ddl_force_eof
  {
    $$ = &Show{Scope: $2, Type: string($3)}
  }
| SHOW VINDEXES
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW VINDEXES ON table_name
  {
    $$ = &Show{Type: string($2), OnTable: $4}
  }
| SHOW VITESS_KEYSPACES
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW VITESS_SHARDS
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW VITESS_TABLETS
  {
    $$ = &Show{Type: string($2)}
  }
| SHOW VSCHEMA_TABLES
  {
    $$ = &Show{Type: string($2)}
  }
/*
 * Catch-all for show statements without vitess keywords:
 *
 *  SHOW BINARY LOGS
 *  SHOW INVALID
 */
| SHOW ID ddl_force_eof
  {
    $$ = &Show{Type: string($2)}
  }

show_session_or_global:
  /* empty */
  {
    $$ = ""
  }
| SESSION
  {
    $$ = SessionStr
  }
| GLOBAL
  {
    $$ = GlobalStr
  }

use_statement:
  USE table_id
  {
    $$ = &Use{DBName: $2}
  }
| USE
  {
    $$ = &Use{DBName:TableIdent{v:""}}
  }

begin_statement:
  BEGIN
  {
    $$ = &Begin{}
  }
| START TRANSACTION
  {
    $$ = &Begin{}
  }

commit_statement:
  COMMIT
  {
    $$ = &Commit{}
  }

rollback_statement:
  ROLLBACK
  {
    $$ = &Rollback{}
  }

other_statement:
  DESC force_eof
  {
    $$ = &OtherRead{}
  }
| DESCRIBE force_eof
  {
    $$ = &OtherRead{}
  }
| EXPLAIN force_eof
  {
    $$ = &OtherRead{}
  }
| REPAIR force_eof
  {
    $$ = &OtherAdmin{}
  }
| OPTIMIZE force_eof
  {
    $$ = &OtherAdmin{}
  }

comment_opt:
  {
    setAllowComments(yylex, true)
  }
  comment_list
  {
    $$ = $2
    setAllowComments(yylex, false)
  }

comment_list:
  {
    $$ = nil
  }
| comment_list COMMENT
  {
    $$ = append($1, $2)
  }

union_op:
  UNION
  {
    $$ = UnionStr
  }
| UNION ALL
  {
    $$ = UnionAllStr
  }
| UNION DISTINCT
  {
    $$ = UnionDistinctStr
  }

cache_opt:
{
  $$ = ""
}
| SQL_NO_CACHE
{
  $$ = SQLNoCacheStr
}
| SQL_CACHE
{
  $$ = SQLCacheStr
}

distinct_opt:
  {
    $$ = ""
  }
| DISTINCT
  {
    $$ = DistinctStr
  }

straight_join_opt:
  {
    $$ = ""
  }
| STRAIGHT_JOIN
  {
    $$ = StraightJoinHint
  }

select_expression_list_opt:
  {
    $$ = nil
  }
| select_expression_list
  {
    $$ = $1
  }

select_expression_list:
  select_expression
  {
    $$ = SelectExprs{$1}
  }
| select_expression_list ',' select_expression
  {
    $$ = append($$, $3)
  }

select_expression:
  '*'
  {
    $$ = &StarExpr{}
  }
| expression as_ci_opt
  {
    $$ = &AliasedExpr{Expr: $1, As: $2}
  }
| table_id '.' '*'
  {
    $$ = &StarExpr{TableName: TableName{Name: $1}}
  }
| table_id '.' reserved_table_id '.' '*'
  {
    $$ = &StarExpr{TableName: TableName{Qualifier: $1, Name: $3}}
  }

as_ci_opt:
  {
    $$ = ColIdent{}
  }
| col_alias
  {
    $$ = $1
  }
| AS col_alias
  {
    $$ = $2
  }

col_alias:
  sql_id
| STRING
  {
    $$ = NewColIdent(string($1))
  }

from_opt:
  {
    $$ = TableExprs{&AliasedTableExpr{Expr:TableName{Name: NewTableIdent("dual")}}}
  }
| FROM table_references
  {
    $$ = $2
  }

table_references:
  table_reference
  {
    $$ = TableExprs{$1}
  }
| table_references ',' table_reference
  {
    $$ = append($$, $3)
  }

table_reference:
  table_factor
| join_table

table_factor:
  aliased_table_name
  {
    $$ = $1
  }
| subquery as_opt table_id
  {
    $$ = &AliasedTableExpr{Expr:$1, As: $3}
  }
| openb table_references closeb
  {
    $$ = &ParenTableExpr{Exprs: $2}
  }

aliased_table_name:
table_name as_opt_id index_hint_list
  {
    $$ = &AliasedTableExpr{Expr:$1, As: $2, Hints: $3}
  }
| table_name PARTITION openb partition_list closeb as_opt_id index_hint_list
  {
    $$ = &AliasedTableExpr{Expr:$1, Partitions: $4, As: $6, Hints: $7}
  }

column_list:
  sql_id
  {
    $$ = Columns{$1}
  }
| column_list ',' sql_id
  {
    $$ = append($$, $3)
  }

partition_list:
  sql_id
  {
    $$ = Partitions{$1}
  }
| partition_list ',' sql_id
  {
    $$ = append($$, $3)
  }

// There is a grammar conflict here:
// 1: INSERT INTO a SELECT * FROM b JOIN c ON b.i = c.i
// 2: INSERT INTO a SELECT * FROM b JOIN c ON DUPLICATE KEY UPDATE a.i = 1
// When yacc encounters the ON clause, it cannot determine which way to
// resolve. The %prec override below makes the parser choose the
// first construct, which automatically makes the second construct a
// syntax error. This is the same behavior as MySQL.
join_table:
  table_reference inner_join table_factor join_condition_opt
  {
    $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4}
  }
| table_reference straight_join table_factor on_expression_opt
  {
    $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4}
  }
| table_reference outer_join table_reference join_condition
  {
    $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3, Condition: $4}
  }
| table_reference natural_join table_factor
  {
    $$ = &JoinTableExpr{LeftExpr: $1, Join: $2, RightExpr: $3}
  }

join_condition:
  ON expression
  { $$ = JoinCondition{On: $2} }
| USING '(' column_list ')'
  { $$ = JoinCondition{Using: $3} }

join_condition_opt:
%prec JOIN
  { }
| join_condition
  { $$ = $1 }

on_expression_opt:
%prec JOIN
  { }
| ON expression
  { $$ = JoinCondition{On: $2} }

as_opt:
  { $$ = struct{}{} }
| AS
  { $$ = struct{}{} }

as_opt_id:
  {
    $$ = NewTableIdent("")
  }
| table_alias
  {
    $$ = $1
  }
| AS table_alias
  {
    $$ = $2
  }

table_alias:
  table_id
| STRING
  {
    $$ = NewTableIdent(string($1))
  }

inner_join:
  JOIN
  {
    $$ = JoinStr
  }
| INNER JOIN
  {
    $$ = JoinStr
  }
| CROSS JOIN
  {
    $$ = JoinStr
  }

straight_join:
  STRAIGHT_JOIN
  {
    $$ = StraightJoinStr
  }

outer_join:
  LEFT JOIN
  {
    $$ = LeftJoinStr
  }
| LEFT OUTER JOIN
  {
    $$ = LeftJoinStr
  }
| RIGHT JOIN
  {
    $$ = RightJoinStr
  }
| RIGHT OUTER JOIN
  {
    $$ = RightJoinStr
  }

natural_join:
 NATURAL JOIN
  {
    $$ = NaturalJoinStr
  }
| NATURAL outer_join
  {
    if $2 == LeftJoinStr {
      $$ = NaturalLeftJoinStr
    } else {
      $$ = NaturalRightJoinStr
    }
  }

into_table_name:
  INTO table_name
  {
    $$ = $2
  }
| table_name
  {
    $$ = $1
  }

table_name:
  table_id
  {
    $$ = TableName{Name: $1}
  }
| table_id '.' reserved_table_id
  {
    $$ = TableName{Qualifier: $1, Name: $3}
  }

index_hint_list:
  {
    $$ = nil
  }
| USE INDEX openb column_list closeb
  {
    $$ = &IndexHints{Type: UseStr, Indexes: $4}
  }
| IGNORE INDEX openb column_list closeb
  {
    $$ = &IndexHints{Type: IgnoreStr, Indexes: $4}
  }
| FORCE INDEX openb column_list closeb
  {
    $$ = &IndexHints{Type: ForceStr, Indexes: $4}
  }

where_expression_opt:
  {
    $$ = nil
  }
| WHERE expression
  {
    $$ = $2
  }

expression:
  condition
  {
    $$ = $1
  }
| expression AND expression
  {
    $$ = &AndExpr{Left: $1, Right: $3}
  }
| expression OR expression
  {
    $$ = &OrExpr{Left: $1, Right: $3}
  }
| NOT expression
  {
    $$ = &NotExpr{Expr: $2}
  }
| expression IS is_suffix
  {
    $$ = &IsExpr{Operator: $3, Expr: $1}
  }
| value_expression
  {
    $$ = $1
  }
| DEFAULT default_opt
  {
    $$ = &Default{ColName: $2}
  }

default_opt:
  /* empty */
  {
    $$ = ""
  }
| openb ID closeb
  {
    $$ = string($2)
  }

boolean_value:
  TRUE
  {
    $$ = BoolVal(true)
  }
| FALSE
  {
    $$ = BoolVal(false)
  }

condition:
  value_expression compare value_expression
  {
    $$ = &ComparisonExpr{Left: $1, Operator: $2, Right: $3}
  }
| value_expression IN col_tuple
  {
    $$ = &ComparisonExpr{Left: $1, Operator: InStr, Right: $3}
  }
| value_expression NOT IN col_tuple
  {
    $$ = &ComparisonExpr{Left: $1, Operator: NotInStr, Right: $4}
  }
| value_expression LIKE value_expression like_escape_opt
  {
    $$ = &ComparisonExpr{Left: $1, Operator: LikeStr, Right: $3, Escape: $4}
  }
| value_expression NOT LIKE value_expression like_escape_opt
  {
    $$ = &ComparisonExpr{Left: $1, Operator: NotLikeStr, Right: $4, Escape: $5}
  }
| value_expression REGEXP value_expression
  {
    $$ = &ComparisonExpr{Left: $1, Operator: RegexpStr, Right: $3}
  }
| value_expression NOT REGEXP value_expression
  {
    $$ = &ComparisonExpr{Left: $1, Operator: NotRegexpStr, Right: $4}
  }
| value_expression BETWEEN value_expression AND value_expression
  {
    $$ = &RangeCond{Left: $1, Operator: BetweenStr, From: $3, To: $5}
  }
| value_expression NOT BETWEEN value_expression AND value_expression
  {
    $$ = &RangeCond{Left: $1, Operator: NotBetweenStr, From: $4, To: $6}
  }
| EXISTS subquery
  {
    $$ = &ExistsExpr{Subquery: $2}
  }

is_suffix:
  NULL
  {
    $$ = IsNullStr
  }
| NOT NULL
  {
    $$ = IsNotNullStr
  }
| TRUE
  {
    $$ = IsTrueStr
  }
| NOT TRUE
  {
    $$ = IsNotTrueStr
  }
| FALSE
  {
    $$ = IsFalseStr
  }
| NOT FALSE
  {
    $$ = IsNotFalseStr
  }

compare:
  '='
  {
    $$ = EqualStr
  }
| ''
  {
    $$ = GreaterThanStr
  }
| LE
  {
    $$ = LessEqualStr
  }
| GE
  {
    $$ = GreaterEqualStr
  }
| NE
  {
    $$ = NotEqualStr
  }
| NULL_SAFE_EQUAL
  {
    $$ = NullSafeEqualStr
  }

like_escape_opt:
  {
    $$ = nil
  }
| ESCAPE value_expression
  {
    $$ = $2
  }

col_tuple:
  row_tuple
  {
    $$ = $1
  }
| subquery
  {
    $$ = $1
  }
| LIST_ARG
  {
    $$ = ListArg($1)
  }

subquery:
  openb select_statement closeb
  {
    $$ = &Subquery{$2}
  }

expression_list:
  expression
  {
    $$ = Exprs{$1}
  }
| expression_list ',' expression
  {
    $$ = append($1, $3)
  }

value_expression:
  value
  {
    $$ = $1
  }
| boolean_value
  {
    $$ = $1
  }
| column_name
  {
    $$ = $1
  }
| tuple_expression
  {
    $$ = $1
  }
| subquery
  {
    $$ = $1
  }
| value_expression '&' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: BitAndStr, Right: $3}
  }
| value_expression '|' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: BitOrStr, Right: $3}
  }
| value_expression '^' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: BitXorStr, Right: $3}
  }
| value_expression '+' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: PlusStr, Right: $3}
  }
| value_expression '-' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: MinusStr, Right: $3}
  }
| value_expression INTEGRAL
  {
    $$ = &BinaryExpr{Left: $1, Operator: MinusStr, Right: NewIntVal($2)}
  }
| value_expression '*' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: MultStr, Right: $3}
  }
| value_expression '/' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: DivStr, Right: $3}
  }
| value_expression DIV value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: IntDivStr, Right: $3}
  }
| value_expression '%' value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: ModStr, Right: $3}
  }
| value_expression MOD value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: ModStr, Right: $3}
  }
| value_expression SHIFT_LEFT value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: ShiftLeftStr, Right: $3}
  }
| value_expression SHIFT_RIGHT value_expression
  {
    $$ = &BinaryExpr{Left: $1, Operator: ShiftRightStr, Right: $3}
  }
| column_name JSON_EXTRACT_OP value
  {
    $$ = &BinaryExpr{Left: $1, Operator: JSONExtractOp, Right: $3}
  }
| column_name JSON_UNQUOTE_EXTRACT_OP value
  {
    $$ = &BinaryExpr{Left: $1, Operator: JSONUnquoteExtractOp, Right: $3}
  }
| value_expression COLLATE charset
  {
    $$ = &CollateExpr{Expr: $1, Charset: $3}
  }
| BINARY value_expression %prec UNARY
  {
    $$ = &UnaryExpr{Operator: BinaryStr, Expr: $2}
  }
| UNDERSCORE_BINARY value_expression %prec UNARY
  {
    $$ = &UnaryExpr{Operator: UBinaryStr, Expr: $2}
  }
| '+'  value_expression %prec UNARY
  {
    if num, ok := $2.(*SQLVal); ok && num.Type == IntVal {
      $$ = num
    } else {
      $$ = &UnaryExpr{Operator: UPlusStr, Expr: $2}
    }
  }
| '-'  value_expression %prec UNARY
  {
    if num, ok := $2.(*SQLVal); ok && num.Type == IntVal {
      // Handle double negative
      if num.Val[0] == '-' {
        num.Val = num.Val[1:]
        $$ = num
      } else {
        $$ = NewIntVal(append([]byte("-"), num.Val...))
      }
    } else {
      $$ = &UnaryExpr{Operator: UMinusStr, Expr: $2}
    }
  }
| '~'  value_expression
  {
    $$ = &UnaryExpr{Operator: TildaStr, Expr: $2}
  }
| '!' value_expression %prec UNARY
  {
    $$ = &UnaryExpr{Operator: BangStr, Expr: $2}
  }
| INTERVAL value_expression sql_id
  {
    // This rule prevents the usage of INTERVAL
    // as a function. If support is needed for that,
    // we'll need to revisit this. The solution
    // will be non-trivial because of grammar conflicts.
    $$ = &IntervalExpr{Expr: $2, Unit: $3.String()}
  }
| function_call_generic
| function_call_keyword
| function_call_nonkeyword
| function_call_conflict

/*
  Regular function calls without special token or syntax, guaranteed to not
  introduce side effects due to being a simple identifier
*/
function_call_generic:
  sql_id openb select_expression_list_opt closeb
  {
    $$ = &FuncExpr{Name: $1, Exprs: $3}
  }
| sql_id openb DISTINCT select_expression_list closeb
  {
    $$ = &FuncExpr{Name: $1, Distinct: true, Exprs: $4}
  }
| table_id '.' reserved_sql_id openb select_expression_list_opt closeb
  {
    $$ = &FuncExpr{Qualifier: $1, Name: $3, Exprs: $5}
  }

/*
  Function calls using reserved keywords, with dedicated grammar rules
  as a result
*/
function_call_keyword:
  LEFT openb select_expression_list closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("left"), Exprs: $3}
  }
| RIGHT openb select_expression_list closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("right"), Exprs: $3}
  }
| CONVERT openb expression ',' convert_type closeb
  {
    $$ = &ConvertExpr{Expr: $3, Type: $5}
  }
| CAST openb expression AS convert_type closeb
  {
    $$ = &ConvertExpr{Expr: $3, Type: $5}
  }
| CONVERT openb expression USING charset closeb
  {
    $$ = &ConvertUsingExpr{Expr: $3, Type: $5}
  }
| MATCH openb select_expression_list closeb AGAINST openb value_expression match_option closeb
  {
  $$ = &MatchExpr{Columns: $3, Expr: $7, Option: $8}
  }
| GROUP_CONCAT openb distinct_opt select_expression_list order_by_opt separator_opt closeb
  {
    $$ = &GroupConcatExpr{Distinct: $3, Exprs: $4, OrderBy: $5, Separator: $6}
  }
| CASE expression_opt when_expression_list else_expression_opt END
  {
    $$ = &CaseExpr{Expr: $2, Whens: $3, Else: $4}
  }
| VALUES openb sql_id closeb
  {
    $$ = &ValuesFuncExpr{Name: $3}
  }

/*
  Function calls using non reserved keywords but with special syntax forms.
  Dedicated grammar rules are needed because of the special syntax
*/
function_call_nonkeyword:
  CURRENT_TIMESTAMP func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("current_timestamp")}
  }
| UTC_TIMESTAMP func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("utc_timestamp")}
  }
| UTC_TIME func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("utc_time")}
  }
| UTC_DATE func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("utc_date")}
  }
  // now
| LOCALTIME func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("localtime")}
  }
| NOW func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("now")}
  }
  // now
| LOCALTIMESTAMP func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("localtimestamp")}
  }
  // curdate
| CURRENT_DATE func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("current_date")}
  }
  // curtime
| CURRENT_TIME func_datetime_precision_opt
  {
    $$ = &FuncExpr{Name:NewColIdent("current_time")}
  }

func_datetime_precision_opt:
  /* empty */
| openb closeb

/*
  Function calls using non reserved keywords with *normal* syntax forms. Because
  the names are non-reserved, they need a dedicated rule so as not to conflict
*/
function_call_conflict:
  IF openb select_expression_list closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("if"), Exprs: $3}
  }
| DATABASE openb select_expression_list_opt closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("database"), Exprs: $3}
  }
| MOD openb select_expression_list closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("mod"), Exprs: $3}
  }
| REPLACE openb select_expression_list closeb
  {
    $$ = &FuncExpr{Name: NewColIdent("replace"), Exprs: $3}
  }

match_option:
/*empty*/
  {
    $$ = ""
  }
| IN BOOLEAN MODE
  {
    $$ = BooleanModeStr
  }
| IN NATURAL LANGUAGE MODE
 {
    $$ = NaturalLanguageModeStr
 }
| IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
 {
    $$ = NaturalLanguageModeWithQueryExpansionStr
 }
| WITH QUERY EXPANSION
 {
    $$ = QueryExpansionStr
 }

charset:
  ID
{
    $$ = string($1)
}
| STRING
{
    $$ = string($1)
}

convert_type:
  BINARY length_opt
  {
    $$ = &ConvertType{Type: string($1), Length: $2}
  }
| CHAR length_opt charset_opt
  {
    $$ = &ConvertType{Type: string($1), Length: $2, Charset: $3, Operator: CharacterSetStr}
  }
| CHAR length_opt ID
  {
    $$ = &ConvertType{Type: string($1), Length: $2, Charset: string($3)}
  }
| DATE
  {
    $$ = &ConvertType{Type: string($1)}
  }
| DATETIME length_opt
  {
    $$ = &ConvertType{Type: string($1), Length: $2}
  }
| DECIMAL decimal_length_opt
  {
    $$ = &ConvertType{Type: string($1)}
    $$.Length = $2.Length
    $$.Scale = $2.Scale
  }
| JSON
  {
    $$ = &ConvertType{Type: string($1)}
  }
| NCHAR length_opt
  {
    $$ = &ConvertType{Type: string($1), Length: $2}
  }
| SIGNED
  {
    $$ = &ConvertType{Type: string($1)}
  }
| SIGNED INTEGER
  {
    $$ = &ConvertType{Type: string($1)}
  }
| TIME length_opt
  {
    $$ = &ConvertType{Type: string($1), Length: $2}
  }
| UNSIGNED
  {
    $$ = &ConvertType{Type: string($1)}
  }
| UNSIGNED INTEGER
  {
    $$ = &ConvertType{Type: string($1)}
  }

expression_opt:
  {
    $$ = nil
  }
| expression
  {
    $$ = $1
  }

separator_opt:
  {
    $$ = string("")
  }
| SEPARATOR STRING
  {
    $$ = " separator '"+string($2)+"'"
  }

when_expression_list:
  when_expression
  {
    $$ = []*When{$1}
  }
| when_expression_list when_expression
  {
    $$ = append($1, $2)
  }

when_expression:
  WHEN expression THEN expression
  {
    $$ = &When{Cond: $2, Val: $4}
  }

else_expression_opt:
  {
    $$ = nil
  }
| ELSE expression
  {
    $$ = $2
  }

column_name:
  sql_id
  {
    $$ = &ColName{Name: $1}
  }
| table_id '.' reserved_sql_id
  {
    $$ = &ColName{Qualifier: TableName{Name: $1}, Name: $3}
  }
| table_id '.' reserved_table_id '.' reserved_sql_id
  {
    $$ = &ColName{Qualifier: TableName{Qualifier: $1, Name: $3}, Name: $5}
  }

value:
  STRING
  {
    $$ = NewStrVal($1)
  }
| HEX
  {
    $$ = NewHexVal($1)
  }
| BIT_LITERAL
  {
    $$ = NewBitVal($1)
  }
| INTEGRAL
  {
    $$ = NewIntVal($1)
  }
| FLOAT
  {
    $$ = NewFloatVal($1)
  }
| HEXNUM
  {
    $$ = NewHexNum($1)
  }
| VALUE_ARG
  {
    $$ = NewValArg($1)
  }
| NULL
  {
    $$ = &NullVal{}
  }

num_val:
  sql_id
  {
    // TODO(sougou): Deprecate this construct.
    if $1.Lowered() != "value" {
      yylex.Error("expecting value after next")
      return 1
    }
    $$ = NewIntVal([]byte("1"))
  }
| INTEGRAL VALUES
  {
    $$ = NewIntVal($1)
  }
| VALUE_ARG VALUES
  {
    $$ = NewValArg($1)
  }

group_by_opt:
  {
    $$ = nil
  }
| GROUP BY expression_list
  {
    $$ = $3
  }

having_opt:
  {
    $$ = nil
  }
| HAVING expression
  {
    $$ = $2
  }

order_by_opt:
  {
    $$ = nil
  }
| ORDER BY order_list
  {
    $$ = $3
  }

order_list:
  order
  {
    $$ = OrderBy{$1}
  }
| order_list ',' order
  {
    $$ = append($1, $3)
  }

order:
  expression asc_desc_opt
  {
    $$ = &Order{Expr: $1, Direction: $2}
  }

asc_desc_opt:
  {
    $$ = AscScr
  }
| ASC
  {
    $$ = AscScr
  }
| DESC
  {
    $$ = DescScr
  }

limit_opt:
  {
    $$ = nil
  }
| LIMIT expression
  {
    $$ = &Limit{Rowcount: $2}
  }
| LIMIT expression ',' expression
  {
    $$ = &Limit{Offset: $2, Rowcount: $4}
  }
| LIMIT expression OFFSET expression
  {
    $$ = &Limit{Offset: $4, Rowcount: $2}
  }

lock_opt:
  {
    $$ = ""
  }
| FOR UPDATE
  {
    $$ = ForUpdateStr
  }
| LOCK IN SHARE MODE
  {
    $$ = ShareModeStr
  }

// insert_data expands all combinations into a single rule.
// This avoids a shift/reduce conflict while encountering the
// following two possible constructs:
// insert into t1(a, b) (select * from t2)
// insert into t1(select * from t2)
// Because the rules are together, the parser can keep shifting
// the tokens until it disambiguates a as sql_id and select as keyword.
insert_data:
  VALUES tuple_list
  {
    $$ = &Insert{Rows: $2}
  }
| select_statement
  {
    $$ = &Insert{Rows: $1}
  }
| openb select_statement closeb
  {
    // Drop the redundant parenthesis.
    $$ = &Insert{Rows: $2}
  }
| openb ins_column_list closeb VALUES tuple_list
  {
    $$ = &Insert{Columns: $2, Rows: $5}
  }
| openb ins_column_list closeb select_statement
  {
    $$ = &Insert{Columns: $2, Rows: $4}
  }
| openb ins_column_list closeb openb select_statement closeb
  {
    // Drop the redundant parenthesis.
    $$ = &Insert{Columns: $2, Rows: $5}
  }

ins_column_list:
  sql_id
  {
    $$ = Columns{$1}
  }
| sql_id '.' sql_id
  {
    $$ = Columns{$3}
  }
| ins_column_list ',' sql_id
  {
    $$ = append($$, $3)
  }
| ins_column_list ',' sql_id '.' sql_id
  {
    $$ = append($$, $5)
  }

on_dup_opt:
  {
    $$ = nil
  }
| ON DUPLICATE KEY UPDATE update_list
  {
    $$ = $5
  }

tuple_list:
  tuple_or_empty
  {
    $$ = Values{$1}
  }
| tuple_list ',' tuple_or_empty
  {
    $$ = append($1, $3)
  }

tuple_or_empty:
  row_tuple
  {
    $$ = $1
  }
| openb closeb
  {
    $$ = ValTuple{}
  }

row_tuple:
  openb expression_list closeb
  {
    $$ = ValTuple($2)
  }

tuple_expression:
  row_tuple
  {
    if len($1) == 1 {
      $$ = &ParenExpr{$1[0]}
    } else {
      $$ = $1
    }
  }

update_list:
  update_expression
  {
    $$ = UpdateExprs{$1}
  }
| update_list ',' update_expression
  {
    $$ = append($1, $3)
  }

update_expression:
  column_name '=' expression
  {
    $$ = &UpdateExpr{Name: $1, Expr: $3}
  }

set_list:
  set_expression
  {
    $$ = SetExprs{$1}
  }
| set_list ',' set_expression
  {
    $$ = append($1, $3)
  }

set_expression:
  reserved_sql_id '=' expression
  {
    $$ = &SetExpr{Name: $1, Expr: $3}
  }
| charset_or_character_set charset_value collate_opt
  {
    $$ = &SetExpr{Name: NewColIdent(string($1)), Expr: $2}
  }

charset_or_character_set:
  CHARSET
| CHARACTER SET
  {
    $$ = []byte("charset")
  }
| NAMES

charset_value:
  sql_id
  {
    $$ = NewStrVal([]byte($1.String()))
  }
| STRING
  {
    $$ = NewStrVal($1)
  }
| DEFAULT
  {
    $$ = &Default{}
  }

for_from:
  FOR
| FROM

exists_opt:
  { $$ = 0 }
| IF EXISTS
  { $$ = 1 }

not_exists_opt:
  { $$ = struct{}{} }
| IF NOT EXISTS
  { $$ = struct{}{} }

ignore_opt:
  { $$ = "" }
| IGNORE
  { $$ = IgnoreStr }

non_add_drop_or_rename_operation:
  ALTER
  { $$ = struct{}{} }
| AUTO_INCREMENT
  { $$ = struct{}{} }
| CHARACTER
  { $$ = struct{}{} }
| COMMENT_KEYWORD
  { $$ = struct{}{} }
| DEFAULT
  { $$ = struct{}{} }
| ORDER
  { $$ = struct{}{} }
| CONVERT
  { $$ = struct{}{} }
| PARTITION
  { $$ = struct{}{} }
| UNUSED
  { $$ = struct{}{} }
| COLLATE
  { $$ = struct{}{} }

to_opt:
  { $$ = struct{}{} }
| TO
  { $$ = struct{}{} }
| AS
  { $$ = struct{}{} }

index_opt:
  INDEX
  { $$ = struct{}{} }
| KEY
  { $$ = struct{}{} }

constraint_opt:
  { $$ = struct{}{} }
| UNIQUE
  { $$ = struct{}{} }
| sql_id
  { $$ = struct{}{} }

using_opt:
USING sql_id
  { $$ = $2 }

sql_id:
  ID
  {
    $$ = NewColIdent(string($1))
  }
| non_reserved_keyword
  {
    $$ = NewColIdent(string($1))
  }

reserved_sql_id:
  sql_id
| reserved_keyword
  {
    $$ = NewColIdent(string($1))
  }

table_id:
  ID
  {
    $$ = NewTableIdent(string($1))
  }
| non_reserved_keyword
  {
    $$ = NewTableIdent(string($1))
  }

reserved_table_id:
  table_id
  {
    $$ = $1
  }
| reserved_keyword
  {
    $$ = NewTableIdent(string($1))
  }

/*
  These are not all necessarily reserved in MySQL, but some are.

  These are more importantly reserved because they may conflict with our grammar.
  If you want to move one that is not reserved in MySQL (i.e. ESCAPE) to the
  non_reserved_keywords, you'll need to deal with any conflicts.

  Sorted alphabetically
*/
reserved_keyword:
  ADD
| AND
| AS
| ASC
| AUTO_INCREMENT
| BETWEEN
| BINARY
| BY
| CASE
| COLLATE
| CONVERT
| CREATE
| CROSS
| CURRENT_DATE
| CURRENT_TIME
| CURRENT_TIMESTAMP
| DATABASE
| DATABASES
| DEFAULT
| DELETE
| DESC
| DESCRIBE
| DISTINCT
| DIV
| DROP
| ELSE
| END
| ESCAPE
| EXISTS
| EXPLAIN
| FALSE
| FOR
| FORCE
| FROM
| GROUP
| HAVING
| IF
| IGNORE
| IN
| INDEX
| INNER
| INSERT
| INTERVAL
| INTO
| IS
| JOIN
| KEY
| LEFT
| LIKE
| LIMIT
| LOCALTIME
| LOCALTIMESTAMP
| LOCK
| MATCH
| MAXVALUE
| MOD
| NATURAL
| NEXT // next should be doable as non-reserved, but is not due to the special `select next num_val` query that vitess supports
| NOT
| NULL
| ON
| OR
| ORDER
| OUTER
| REGEXP
| RENAME
| REPLACE
| RIGHT
| SELECT
| SEPARATOR
| SET
| SHOW
| STRAIGHT_JOIN
| TABLE
| TABLES
| THEN
| TO
| TRUE
| UNION
| UNIQUE
| UPDATE
| USE
| USING
| UTC_DATE
| UTC_TIME
| UTC_TIMESTAMP
| VALUES
| WHEN
| WHERE

/*
  These are non-reserved Vitess, because they don't cause conflicts in the grammar.
  Some of them may be reserved in MySQL. The good news is we backtick quote them
  when we rewrite the query, so no issue should arise.

  Sorted alphabetically
*/
non_reserved_keyword:
  AGAINST
| BEGIN
| BIGINT
| BIT
| BLOB
| BOOL
| CHAR
| CHARACTER
| CHARSET
| COMMENT_KEYWORD
| COMMIT
| DATE
| DATETIME
| DECIMAL
| DOUBLE
| DUPLICATE
| ENUM
| EXPANSION
| FLOAT_TYPE
| FOREIGN
| FULLTEXT
| GLOBAL
| INT
| INTEGER
| JSON
| KEYS
| LANGUAGE
| LAST_INSERT_ID
| LESS
| LONGBLOB
| LONGTEXT
| MEDIUMBLOB
| MEDIUMINT
| MEDIUMTEXT
| MODE
| NAMES
| NCHAR
| NUMERIC
| OFFSET
| OPTIMIZE
| PARTITION
| PRIMARY
| PROCEDURE
| QUERY
| REAL
| REORGANIZE
| REPAIR
| ROLLBACK
| SESSION
| SHARE
| SIGNED
| SMALLINT
| SPATIAL
| START
| ENGINE
| STATUS
| ACTION
| TEXT
| THAN
| TIME
| TIMESTAMP
| TINYBLOB
| TINYINT
| TINYTEXT
| TRANSACTION
| TRIGGER
| TRUNCATE
| UNSIGNED
| UNUSED
| VARBINARY
| VARCHAR
| VARIABLES
| VIEW
| VINDEX
| VINDEXES
| VITESS_KEYSPACES
| VITESS_SHARDS
| VITESS_TABLETS
| VSCHEMA_TABLES
| WITH
| YEAR
| ZEROFILL

openb:
  '('
  {
    if incNesting(yylex) {
      yylex.Error("max nesting level reached")
      return 1
    }
  }

closeb:
  ')'
  {
    decNesting(yylex)
  }

force_eof:
{
  forceEOF(yylex)
}

ddl_force_eof:
  {
    forceEOF(yylex)
  }
| openb
  {
    forceEOF(yylex)
  }
| reserved_sql_id
  {
    forceEOF(yylex)
  }

Web Proxy Viewer  |  New URL  |  Original Page