Skip to content

Commit

Permalink
parser: add generated column grammar. (pingcap#3428)
Browse files Browse the repository at this point in the history
  • Loading branch information
hicqu authored and tiancaiamao committed Jun 9, 2017
1 parent a7d33e5 commit ddc2ffc
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 6 deletions.
9 changes: 7 additions & 2 deletions ast/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,19 @@ const (
ColumnOptionOnUpdate // For Timestamp and Datetime only.
ColumnOptionFulltext
ColumnOptionComment
ColumnOptionGenerated
)

// ColumnOption is used for parsing column constraint info from SQL.
type ColumnOption struct {
node

Tp ColumnOptionType
Expr ExprNode // The value For Default or On Update.
Tp ColumnOptionType
// For ColumnOptionDefaultValue or ColumnOptionOnUpdate, it's the target value.
// For ColumnOptionGenerated, it's the target expression.
Expr ExprNode
// Stored is only for ColumnOptionGenerated, default is false.
Stored bool
}

// Accept implements Node Accept interface.
Expand Down
4 changes: 4 additions & 0 deletions parser/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ var tokenMap = map[string]int{
"AFTER": after,
"ALL": all,
"ALTER": alter,
"ALWAYS": always,
"ANALYZE": analyze,
"AND": and,
"ANY": any,
Expand Down Expand Up @@ -275,6 +276,7 @@ var tokenMap = map[string]int{
"FUNCTION": function,
"FLOOR": floor,
"FLUSH": flush,
"GENERATED": generated,
"GET_FORMAT": getFormat,
"GET_LOCK": getLock,
"GLOBAL": global,
Expand Down Expand Up @@ -428,6 +430,7 @@ var tokenMap = map[string]int{
"STARTING": starting,
"STATS_PERSISTENT": statsPersistent,
"STATUS": status,
"STORED": stored,
"SUBDATE": subDate,
"SUBTIME": subTime,
"STRCMP": strcmp,
Expand Down Expand Up @@ -480,6 +483,7 @@ var tokenMap = map[string]int{
"VARIABLES": variables,
"VERSION": version,
"VIEW": view,
"VIRTUAL": virtual,
"WARNINGS": warnings,
"WEEK": week,
"WEEKDAY": weekday,
Expand Down
41 changes: 37 additions & 4 deletions parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ import (
foreign "FOREIGN"
from "FROM"
fulltext "FULLTEXT"
generated "GENERATED"
grants "GRANTS"
group "GROUP"
having "HAVING"
Expand Down Expand Up @@ -197,6 +198,7 @@ import (
smallIntType "SMALLINT"
starting "STARTING"
tableKwd "TABLE"
stored "STORED"
terminated "TERMINATED"
then "THEN"
tinyblobType "TINYBLOB"
Expand All @@ -217,6 +219,7 @@ import (
values "VALUES"
varcharType "VARCHAR"
varbinaryType "VARBINARY"
virtual "VIRTUAL"
when "WHEN"
where "WHERE"
write "WRITE"
Expand Down Expand Up @@ -408,6 +411,7 @@ import (
/* the following tokens belong to UnReservedKeyword*/
action "ACTION"
after "AFTER"
always "ALWAYS"
any "ANY"
ascii "ASCII"
at "AT"
Expand Down Expand Up @@ -577,6 +581,7 @@ import (
CompareOp "Compare opcode"
ColumnOption "column definition option"
ColumnOptionList "column definition option list"
VirtualOrStored "indicate generated column is stored or not"
ColumnOptionListOpt "optional column definition option list"
Constraint "table constraint"
ConstraintElem "table constraint element"
Expand Down Expand Up @@ -1297,6 +1302,34 @@ ColumnOption:
// The CHECK clause is parsed but ignored by all storage engines.
$$ = &ast.ColumnOption{}
}
| GeneratedAlways "AS" '(' Expression ')' VirtualOrStored
{
startOffset := parser.startOffset(&yyS[yypt-2])
endOffset := parser.endOffset(&yyS[yypt-1])
expr := $4.(ast.ExprNode)
expr.SetText(parser.src[startOffset:endOffset])

$$ = &ast.ColumnOption{
Tp: ast.ColumnOptionGenerated,
Expr: expr,
Stored: $6.(bool),
}
}

GeneratedAlways: | "GENERATED" "ALWAYS"

VirtualOrStored:
{
$$ = false
}
| "VIRTUAL"
{
$$ = false
}
| "STORED"
{
$$ = true
}

ColumnOptionList:
ColumnOption
Expand Down Expand Up @@ -2305,7 +2338,7 @@ IdentifierOrReservedKeyword:
Identifier | ReservedKeyword

UnReservedKeyword:
"ACTION" | "ASCII" | "AUTO_INCREMENT" | "AFTER" | "AT" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "CHARSET"
"ACTION" | "ASCII" | "AUTO_INCREMENT" | "AFTER" | "ALWAYS" | "AT" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "BTREE" | "CHARSET"
| "COLUMNS" | "COMMIT" | "COMPACT" | "COMPRESSED" | "CONSISTENT" | "DATA" | "DATE" | "DATETIME" | "DEALLOCATE" | "DO"
| "DYNAMIC"| "END" | "ENGINE" | "ENGINES" | "ESCAPE" | "EXECUTE" | "FIELDS" | "FIRST" | "FIXED" | "FORMAT" | "FULL" |"GLOBAL"
| "HASH" | "LESS" | "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "REDUNDANT"
Expand All @@ -2325,17 +2358,17 @@ ReservedKeyword:
| "DAY_MINUTE" | "DAY_SECOND" | "DECIMAL" | "DEFAULT" | "DELETE" | "DESC" | "DESCRIBE"
| "DISTINCT" | "DIV" | "DOUBLE" | "DROP" | "DUAL" | "ELSE" | "ENCLOSED" | "ESCAPED"
| "EXISTS" | "EXPLAIN" | "FALSE" | "FLOAT" | "FOR" | "FORCE" | "FOREIGN" | "FROM"
| "FULLTEXT" | "GRANT" | "GROUP" | "HAVING" | "HOUR_MICROSECOND" | "HOUR_MINUTE"
| "FULLTEXT" | "GENERATED" | "GRANT" | "GROUP" | "HAVING" | "HOUR_MICROSECOND" | "HOUR_MINUTE"
| "HOUR_SECOND" | "IF" | "IGNORE" | "IN" | "INDEX" | "INFILE" | "INNER" | "INSERT" | "INT" | "INTO" | "INTEGER"
| "INTERVAL" | "IS" | "JOIN" | "KEY" | "KEYS" | "KILL" | "LEADING" | "LEFT" | "LIKE" | "LIMIT" | "LINES" | "LOAD"
| "LOCALTIME" | "LOCALTIMESTAMP" | "LOCK" | "LONGBLOB" | "LONGTEXT" | "MAXVALUE" | "MEDIUMBLOB" | "MEDIUMINT" | "MEDIUMTEXT"
| "MINUTE_MICROSECOND" | "MINUTE_SECOND" | "MOD" | "NOT" | "NO_WRITE_TO_BINLOG" | "NULL" | "NUMERIC"
| "ON" | "OPTION" | "OR" | "ORDER" | "OUTER" | "PARTITION" | "PRECISION" | "PRIMARY" | "PROCEDURE" | "RANGE" | "READ"
| "REAL" | "REFERENCES" | "REGEXP" | "RENAME" | "REPEAT" | "REPLACE" | "RESTRICT" | "REVOKE" | "RIGHT" | "RLIKE"
| "SCHEMA" | "SCHEMAS" | "SECOND_MICROSECOND" | "SELECT" | "SET" | "SHOW" | "SMALLINT"
| "STARTING" | "TABLE" | "TERMINATED" | "THEN" | "TINYBLOB" | "TINYINT" | "TINYTEXT" | "TO"
| "STARTING" | "TABLE" | "STORED" | "TERMINATED" | "THEN" | "TINYBLOB" | "TINYINT" | "TINYTEXT" | "TO"
| "TRAILING" | "TRIGGER" | "TRUE" | "UNION" | "UNIQUE" | "UNLOCK" | "UNSIGNED"
| "UPDATE" | "USE" | "USING" | "UTC_DATE" | "UTC_TIMESTAMP" | "VALUES" | "VARBINARY" | "VARCHAR"
| "UPDATE" | "USE" | "USING" | "UTC_DATE" | "UTC_TIMESTAMP" | "VALUES" | "VARBINARY" | "VARCHAR" | "VIRTUAL"
| "WHEN" | "WHERE" | "WRITE" | "XOR" | "YEAR_MONTH" | "ZEROFILL"
/*
| "DELAYED" | "HIGH_PRIORITY" | "LOW_PRIORITY"| "WITH"
Expand Down
33 changes: 33 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (s *testParserSuite) TestSimple(c *C) {
"trailing", "true", "union", "unique", "unlock", "unsigned",
"update", "use", "using", "utc_date", "values", "varbinary", "varchar",
"when", "where", "write", "xor", "year_month", "zerofill",
"generated", "virtual", "stored",
// TODO: support the following keywords
// "delayed" , "high_priority" , "low_priority", "with",
}
Expand Down Expand Up @@ -92,6 +93,7 @@ func (s *testParserSuite) TestSimple(c *C) {
"enable", "disable", "reverse", "space", "privileges", "get_lock", "release_lock", "sleep", "no", "greatest", "least",
"binlog", "hex", "unhex", "function", "indexes", "from_unixtime", "processlist", "events", "less", "than", "timediff",
"ln", "log", "log2", "log10", "timestampdiff", "pi", "quote", "none", "super", "default", "shared", "exclusive",
"always",
}
for _, kw := range unreservedKws {
src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
Expand Down Expand Up @@ -1693,3 +1695,34 @@ func (s *testParserSuite) TestAnalyze(c *C) {
}
s.RunTest(c, table)
}

func (s *testParserSuite) TestGeneratedColumn(c *C) {
defer testleak.AfterTest(c)()
tests := []struct {
input string
ok bool
expr string
}{
{"create table t (c int, d int generated always as (c + 1) virtual)", true, "c + 1"},
{"create table t (c int, d int as ( c + 1 ) virtual)", true, "c + 1"},
{"create table t (c int, d int as (1 + 1) stored)", true, "1 + 1"},
}
parser := New()
for _, tt := range tests {
stmtNodes, err := parser.Parse(tt.input, "", "")
if tt.ok {
c.Assert(err, IsNil)
stmtNode := stmtNodes[0]
for _, col := range stmtNode.(*ast.CreateTableStmt).Cols {
for _, opt := range col.Options {
if opt.Tp == ast.ColumnOptionGenerated {
c.Assert(opt.Expr.Text(), Equals, tt.expr)
}
}
}
} else {
c.Assert(err, NotNil)
}
}

}

0 comments on commit ddc2ffc

Please sign in to comment.