Skip to content

Commit

Permalink
*: add parser and definition for all unsupported builtin funcs (part …
Browse files Browse the repository at this point in the history
…2) (pingcap#2655)
  • Loading branch information
XuHuaiyu authored Feb 17, 2017
1 parent 2b9c173 commit 7f8f16f
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 1 deletion.
5 changes: 5 additions & 0 deletions ast/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ const (
Lower = "lower"
Lpad = "lpad"
LTrim = "ltrim"
MakeSet = "make_set"
Mid = "mid"
Oct = "oct"
Ord = "ord"
Quote = "quote"
Repeat = "repeat"
Replace = "replace"
Reverse = "reverse"
Expand Down
5 changes: 5 additions & 0 deletions expression/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ var funcs = map[string]functionClass{
ast.Lower: &lowerFunctionClass{baseFunctionClass{ast.Lower, 1, 1}},
ast.Lpad: &lpadFunctionClass{baseFunctionClass{ast.Lpad, 3, 3}},
ast.LTrim: &lTrimFunctionClass{baseFunctionClass{ast.LTrim, 1, 1}},
ast.Mid: &substringFunctionClass{baseFunctionClass{ast.Mid, 3, 3}},
ast.MakeSet: &makeSetFunctionClass{baseFunctionClass{ast.MakeSet, 2, -1}},
ast.Oct: &octFunctionClass{baseFunctionClass{ast.Oct, 1, 1}},
ast.Ord: &ordFunctionClass{baseFunctionClass{ast.Ord, 1, 1}},
ast.Quote: &quoteFunctionClass{baseFunctionClass{ast.Quote, 1, 1}},
ast.Repeat: &repeatFunctionClass{baseFunctionClass{ast.Repeat, 2, 2}},
ast.Replace: &replaceFunctionClass{baseFunctionClass{ast.Replace, 3, 3}},
ast.Reverse: &reverseFunctionClass{baseFunctionClass{ast.Reverse, 1, 1}},
Expand Down
76 changes: 76 additions & 0 deletions expression/builtin_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ var (
_ functionClass = &charLengthFunctionClass{}
_ functionClass = &findInSetFunctionClass{}
_ functionClass = &fieldFunctionClass{}
_ functionClass = &makeSetFunctionClass{}
_ functionClass = &octFunctionClass{}
_ functionClass = &ordFunctionClass{}
_ functionClass = &quoteFunctionClass{}
_ functionClass = &binFunctionClass{}
_ functionClass = &eltFunctionClass{}
_ functionClass = &exportSetFunctionClass{}
Expand Down Expand Up @@ -102,6 +106,10 @@ var (
_ builtinFunc = &builtinCharSig{}
_ builtinFunc = &builtinCharLengthSig{}
_ builtinFunc = &builtinFindInSetSig{}
_ builtinFunc = &builtinMakeSetSig{}
_ builtinFunc = &builtinOctSig{}
_ builtinFunc = &builtinOrdSig{}
_ builtinFunc = &builtinQuoteSig{}
_ builtinFunc = &builtinBinSig{}
_ builtinFunc = &builtinEltSig{}
_ builtinFunc = &builtinExportSetSig{}
Expand Down Expand Up @@ -1373,6 +1381,74 @@ func argsToSpecifiedType(args []types.Datum, allString bool, allNumber bool, ctx
return
}

type makeSetFunctionClass struct {
baseFunctionClass
}

func (c *makeSetFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMakeSetSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}

type builtinMakeSetSig struct {
baseBuiltinFunc
}

// https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_make-set
func (b *builtinMakeSetSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("make_set")
}

type octFunctionClass struct {
baseFunctionClass
}

func (c *octFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinOctSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}

type builtinOctSig struct {
baseBuiltinFunc
}

// https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_oct
func (b *builtinOctSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("oct")
}

type ordFunctionClass struct {
baseFunctionClass
}

func (c *ordFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinOrdSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}

type builtinOrdSig struct {
baseBuiltinFunc
}

// https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_ord
func (b *builtinOrdSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("ord")
}

type quoteFunctionClass struct {
baseFunctionClass
}

func (c *quoteFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinQuoteSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}

type builtinQuoteSig struct {
baseBuiltinFunc
}

// https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_quote
func (b *builtinQuoteSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("quote")
}

type binFunctionClass struct {
baseFunctionClass
}
Expand Down
7 changes: 7 additions & 0 deletions parser/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,12 @@ var tokenMap = map[string]int{
"LOW_PRIORITY": lowPriority,
"LPAD": lpad,
"LTRIM": ltrim,
"MAKE_SET": makeSet,
"MAX": max,
"MAXVALUE": maxValue,
"MAX_ROWS": maxRows,
"MICROSECOND": microsecond,
"MID": mid,
"MIN": min,
"MINUTE": minute,
"MIN_ROWS": minRows,
Expand All @@ -338,14 +340,18 @@ var tokenMap = map[string]int{
"NO_WRITE_TO_BINLOG": noWriteToBinLog,
"NULL": null,
"NULLIF": nullIf,
"OCT": oct,
"OCTET_LENGTH": octetLength,
"OFFSET": offset,
"ON": on,
"ONLY": only,
"OPTION": option,
"OR": or,
"ORD": ord,
"ORDER": order,
"OUTER": outer,
"PASSWORD": password,
"POSITION": position,
"POW": pow,
"POWER": power,
"PREPARE": prepare,
Expand All @@ -355,6 +361,7 @@ var tokenMap = map[string]int{
"PROCESSLIST": processlist,
"QUARTER": quarter,
"QUICK": quick,
"QUOTE": quote,
"RANGE": rangeKwd,
"RAND": rand,
"READ": read,
Expand Down
43 changes: 42 additions & 1 deletion parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -144,27 +144,34 @@ import (
longblobType "LONGBLOB"
longtextType "LONGTEXT"
lowPriority "LOW_PRIORITY"
makeSet "MAKE_SET"
maxValue "MAXVALUE"
mediumblobType "MEDIUMBLOB"
mediumIntType "MEDIUMINT"
mediumtextType "MEDIUMTEXT"
mid "MID"
minuteMicrosecond "MINUTE_MICROSECOND"
minuteSecond "MINUTE_SECOND"
mod "MOD"
not "NOT"
noWriteToBinLog "NO_WRITE_TO_BINLOG"
null "NULL"
numericType "NUMERIC"
oct "OCT"
octetLength "OCTET_LENGTH"
on "ON"
option "OPTION"
or "OR"
ord "ORD"
order "ORDER"
outer "OUTER"
partition "PARTITION"
partitions "PARTITIONS"
position "POSITION"
precisionType "PRECISION"
primary "PRIMARY"
procedure "PROCEDURE"
quote "QUOTE"
rangeKwd "RANGE"
read "READ"
realType "REAL"
Expand Down Expand Up @@ -2180,7 +2187,7 @@ NotKeywordToken:
"ABS" | "ADDDATE" | "ADMIN" | "BIN"| "COALESCE" | "CONCAT" | "CONCAT_WS" | "CONNECTION_ID" | "CUR_TIME"| "COUNT" | "DAY"
| "DATEDIFF" | "DATE_ADD" | "DATE_FORMAT" | "DATE_SUB" | "DAYNAME" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "ELT" | "EXPORT_SET" | "FROM_DAYS" | "FROM_BASE64" | "FIND_IN_SET" | "FOUND_ROWS"
| "GROUP_CONCAT"| "GREATEST" | "LEAST" | "HOUR" | "HEX" | "UNHEX" | "IFNULL" | "INSTR" | "ISNULL" | "LAST_INSERT_ID" | "LCASE" | "LENGTH" | "LOAD_FILE" | "LOCATE" | "LOWER" | "LPAD" | "LTRIM"
| "MAX" | "MICROSECOND" | "MIN" | "MINUTE" | "NULLIF" | "MONTH" | "MONTHNAME" | "NOW" | "POW" | "POWER" | "RAND"
| "MAKE_SET" | "MAX" | "MICROSECOND" | "MIN" | "MINUTE" | "NULLIF" | "MID" | "MONTH" | "MONTHNAME" | "NOW" | "OCT" | "OCTET_LENGTH" | "ORD" | "POSITION" | "POW" | "POWER" | "QUOTE" | "RAND"
"SECOND" | "SIGN" | "SLEEP" | "SQRT" | "SQL_CALC_FOUND_ROWS" | "STR_TO_DATE" | "SUBDATE" | "SUBSTRING" %prec lowerThanLeftParen |
"SUBSTRING_INDEX" | "SUM" | "TRIM" | "RTRIM" | "UCASE" | "UPPER" | "VERSION" | "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK" | "ROUND"
| "STATS_PERSISTENT" | "GET_LOCK" | "RELEASE_LOCK" | "CEIL" | "CEILING" | "FLOOR" | "FROM_UNIXTIME" | "TIMEDIFF" | "LN" | "LOG" | "LOG2" | "LOG10" | "FIELD_KWD"
Expand Down Expand Up @@ -3008,6 +3015,17 @@ FunctionCallNonKeyword:
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}
| "MAKE_SET" '(' ExpressionList ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
}
| "MID" '(' Expression ',' Expression ',' Expression ')'
{
$$ = &ast.FuncCallExpr{
FnName: model.NewCIStr($1),
Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode), $7.(ast.ExprNode)},
}
}
| "MICROSECOND" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
Expand Down Expand Up @@ -3036,6 +3054,25 @@ FunctionCallNonKeyword:
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: $3.([]ast.ExprNode)}
}
| "OCT" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}
| "OCTET_LENGTH" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Length), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}
| "ORD" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}
/* TODO: This will cause reduce/reduce conflict on in.
| "POSITION" '(' Expression "IN" Expression ')'
{
args := []ast.ExprNode{$5.(ast.ExprNode), $3.(ast.ExprNode)}
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.Locate), Args: args}
}
*/
| "POW" '(' Expression ',' Expression ')'
{
args := []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}
Expand All @@ -3046,6 +3083,10 @@ FunctionCallNonKeyword:
args := []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: args}
}
| "QUOTE" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}
| "RAND" '(' ExpressionOpt ')'
{

Expand Down
8 changes: 8 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,14 @@ func (s *testParserSuite) TestBuiltin(c *C) {
{`SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');`, true},
{`SELECT FIND_IN_SET('foo', 'foo,bar')`, true},
{`SELECT FIND_IN_SET('foo')`, false},
{`SELECT MAKE_SET(1,'a'), MAKE_SET(1,'a','b','c')`, true},
{`SELECT MID('Sakila', -5, 3)`, true},
{`SELECT OCT(12)`, true},
{`SELECT OCTET_LENGTH('text')`, true},
{`SELECT ORD('2')`, true},
// parser of POSITION will cause conflict now.
//{`SELECT POSITION('foobarbar' IN 'bar')`, false},
{`SELECT QUOTE('Don\'t!')`, true},
{`SELECT BIN(12)`, true},
{`SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo')`, true},
{`SELECT EXPORT_SET(5,'Y','N'), EXPORT_SET(5,'Y','N',','), EXPORT_SET(5,'Y','N',',',4)`, true},
Expand Down

0 comments on commit 7f8f16f

Please sign in to comment.