Merge branch 'master' into qiuyesuifeng/exists-subquery
This commit is contained in:
4
Makefile
4
Makefile
@ -36,8 +36,8 @@ parser:
|
||||
sed -i -e 's|//line.*||' -e 's/yyEofCode/yyEOFCode/' parser/parser.go; \
|
||||
elif [ $(ARCH) = $(MAC) ]; \
|
||||
then \
|
||||
sed -i "" 's|//line.*||' parser/parser.go; \
|
||||
sed -i "" 's/yyEofCode/yyEOFCode/' parser/parser.go; \
|
||||
/usr/bin/sed -i "" 's|//line.*||' parser/parser.go; \
|
||||
/usr/bin/sed -i "" 's/yyEofCode/yyEOFCode/' parser/parser.go; \
|
||||
fi
|
||||
|
||||
golex -o parser/scanner.go parser/scanner.l
|
||||
|
||||
@ -21,7 +21,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/juju/errors"
|
||||
"github.com/ngaut/log"
|
||||
@ -63,7 +62,6 @@ type DDL interface {
|
||||
|
||||
type ddl struct {
|
||||
store kv.Storage
|
||||
mu sync.Mutex
|
||||
infoHandle *infoschema.Handle
|
||||
}
|
||||
|
||||
|
||||
@ -416,20 +416,16 @@ func (o *BinaryOperation) evalPlus(a interface{}, b interface{}) (interface{}, e
|
||||
case int64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
return x + y, nil
|
||||
return types.AddInt64(x, y)
|
||||
case uint64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow
|
||||
return uint64(x) + y, nil
|
||||
return types.AddInteger(y, x)
|
||||
}
|
||||
case uint64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow
|
||||
return x + uint64(y), nil
|
||||
return types.AddInteger(x, y)
|
||||
case uint64:
|
||||
return x + y, nil
|
||||
return types.AddUint64(x, y)
|
||||
}
|
||||
case float64:
|
||||
switch y := b.(type) {
|
||||
@ -452,21 +448,16 @@ func (o *BinaryOperation) evalMinus(a interface{}, b interface{}) (interface{},
|
||||
case int64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
return x - y, nil
|
||||
return types.SubInt64(x, y)
|
||||
case uint64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow
|
||||
return uint64(x) - y, nil
|
||||
return types.SubIntWithUint(x, y)
|
||||
}
|
||||
case uint64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
// TODO: check overflow
|
||||
return x - uint64(y), nil
|
||||
return types.SubUintWithInt(x, y)
|
||||
case uint64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow
|
||||
return x - y, nil
|
||||
return types.SubUint64(x, y)
|
||||
}
|
||||
case float64:
|
||||
switch y := b.(type) {
|
||||
@ -489,22 +480,16 @@ func (o *BinaryOperation) evalMul(a interface{}, b interface{}) (interface{}, er
|
||||
case int64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
return x * y, nil
|
||||
return types.MulInt64(x, y)
|
||||
case uint64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow and negative number
|
||||
// if a negative int64 * uint64, MySQL may throw "BIGINT UNSIGNED value is out of range" error
|
||||
// we skip it now and handle it later.
|
||||
return uint64(x) * y, nil
|
||||
return types.MulInteger(y, x)
|
||||
}
|
||||
case uint64:
|
||||
switch y := b.(type) {
|
||||
case int64:
|
||||
// For MySQL, if any is unsigned, return unsigned
|
||||
// TODO: check overflow
|
||||
return x * uint64(y), nil
|
||||
return types.MulInteger(x, y)
|
||||
case uint64:
|
||||
return x * y, nil
|
||||
return types.MulUint64(x, y)
|
||||
}
|
||||
case float64:
|
||||
switch y := b.(type) {
|
||||
|
||||
@ -27,15 +27,6 @@ import (
|
||||
"github.com/pingcap/tidb/sessionctx/variable"
|
||||
)
|
||||
|
||||
// Builin functions entry key with name conflict with keywords.
|
||||
const (
|
||||
// BuiltinFuncDatabase is the keyword for Database function.
|
||||
BuiltinFuncDatabase = "database"
|
||||
// BuiltinFuncIf is the keyword for If function.
|
||||
BuiltinFuncIf = "if"
|
||||
BuiltinFuncLeft = "left"
|
||||
)
|
||||
|
||||
var builtin = map[string]struct {
|
||||
f func([]interface{}, map[interface{}]interface{}) (interface{}, error)
|
||||
minArgs int
|
||||
@ -44,8 +35,8 @@ var builtin = map[string]struct {
|
||||
isAggregate bool
|
||||
}{
|
||||
// common functions
|
||||
BuiltinFuncDatabase: {builtinDatabase, 0, 0, false, false},
|
||||
"coalesce": {builtinCoalesce, 1, -1, true, false},
|
||||
"database": {builtinDatabase, 0, 0, false, false},
|
||||
"coalesce": {builtinCoalesce, 1, -1, true, false},
|
||||
|
||||
// math functions
|
||||
"abs": {builtinAbs, 1, 1, true, false},
|
||||
@ -77,16 +68,16 @@ var builtin = map[string]struct {
|
||||
"yearweek": {builtinYearWeek, 1, 2, true, false},
|
||||
|
||||
// control functions
|
||||
BuiltinFuncIf: {builtinIf, 3, 3, true, false},
|
||||
"ifnull": {builtinIfNull, 2, 2, true, false},
|
||||
"nullif": {builtinNullIf, 2, 2, true, false},
|
||||
"if": {builtinIf, 3, 3, true, false},
|
||||
"ifnull": {builtinIfNull, 2, 2, true, false},
|
||||
"nullif": {builtinNullIf, 2, 2, true, false},
|
||||
|
||||
// string functions
|
||||
"concat": {builtinConcat, 1, -1, true, false},
|
||||
"concat_ws": {builtinConcatWS, 2, -1, true, false},
|
||||
BuiltinFuncLeft: {builtinLeft, 2, 2, true, false},
|
||||
"length": {builtinLength, 1, 1, true, false},
|
||||
"repeat": {builtinRepeat, 2, 2, true, false},
|
||||
"concat": {builtinConcat, 1, -1, true, false},
|
||||
"concat_ws": {builtinConcatWS, 2, -1, true, false},
|
||||
"left": {builtinLeft, 2, 2, true, false},
|
||||
"length": {builtinLength, 1, 1, true, false},
|
||||
"repeat": {builtinRepeat, 2, 2, true, false},
|
||||
|
||||
// information functions
|
||||
"found_rows": {builtinFoundRows, 0, 0, false, false},
|
||||
|
||||
@ -347,11 +347,6 @@ func staticExpr(e expression.Expression) (expression.Expression, error) {
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type exprTab struct {
|
||||
expr expression.Expression
|
||||
table string
|
||||
}
|
||||
|
||||
// IsCurrentTimeExpr returns whether e is CurrentTimeExpr.
|
||||
func IsCurrentTimeExpr(e expression.Expression) bool {
|
||||
x, ok := e.(*Ident)
|
||||
|
||||
487
parser/parser.y
487
parser/parser.y
@ -58,11 +58,11 @@ import (
|
||||
|
||||
/*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"
|
||||
|
||||
|
||||
abs "ABS"
|
||||
add "ADD"
|
||||
after "AFTER"
|
||||
all "ALL"
|
||||
@ -74,6 +74,7 @@ import (
|
||||
as "AS"
|
||||
asc "ASC"
|
||||
autoIncrement "AUTO_INCREMENT"
|
||||
avg "AVG"
|
||||
begin "BEGIN"
|
||||
between "BETWEEN"
|
||||
by "BY"
|
||||
@ -82,16 +83,24 @@ import (
|
||||
cast "CAST"
|
||||
character "CHARACTER"
|
||||
charsetKwd "CHARSET"
|
||||
coalesce "COALESCE"
|
||||
collation "COLLATE"
|
||||
column "COLUMN"
|
||||
columns "COLUMNS"
|
||||
commit "COMMIT"
|
||||
concat "CONCAT"
|
||||
concatWs "CONCAT_WS"
|
||||
constraint "CONSTRAINT"
|
||||
convert "CONVERT"
|
||||
count "COUNT"
|
||||
create "CREATE"
|
||||
cross "CROSS"
|
||||
database "DATABASE"
|
||||
databases "DATABASES"
|
||||
day "DAY"
|
||||
dayofmonth "DAYOFMONTH"
|
||||
dayofweek "DAYOFWEEK"
|
||||
dayofyear "DAYOFYEAR"
|
||||
deallocate "DEALLOCATE"
|
||||
defaultKwd "DEFAULT"
|
||||
delayed "DELAYED"
|
||||
@ -115,16 +124,20 @@ import (
|
||||
first "FIRST"
|
||||
foreign "FOREIGN"
|
||||
forKwd "FOR"
|
||||
foundRows "FOUND_ROWS"
|
||||
from "FROM"
|
||||
full "FULL"
|
||||
fulltext "FULLTEXT"
|
||||
ge ">="
|
||||
global "GLOBAL"
|
||||
group "GROUP"
|
||||
groupConcat "GROUP_CONCAT"
|
||||
having "HAVING"
|
||||
highPriority "HIGH_PRIORITY"
|
||||
hour "HOUR"
|
||||
ignore "IGNORE"
|
||||
ifKwd "IF"
|
||||
ifNull "IFNULL"
|
||||
in "IN"
|
||||
index "INDEX"
|
||||
inner "INNER"
|
||||
@ -135,19 +148,26 @@ import (
|
||||
key "KEY"
|
||||
le "<="
|
||||
left "LEFT"
|
||||
length "LENGTH"
|
||||
like "LIKE"
|
||||
limit "LIMIT"
|
||||
local "LOCAL"
|
||||
lock "LOCK"
|
||||
lowPriority "LOW_PRIORITY"
|
||||
lsh "<<"
|
||||
max "MAX"
|
||||
microsecond "MICROSECOND"
|
||||
min "MIN"
|
||||
minute "MINUTE"
|
||||
mod "MOD"
|
||||
mode "MODE"
|
||||
month "MONTH"
|
||||
names "NAMES"
|
||||
neq "!="
|
||||
neqSynonym "<>"
|
||||
not "NOT"
|
||||
null "NULL"
|
||||
nullIf "NULLIF"
|
||||
offset "OFFSET"
|
||||
on "ON"
|
||||
or "OR"
|
||||
@ -161,14 +181,15 @@ import (
|
||||
quick "QUICK"
|
||||
references "REFERENCES"
|
||||
regexp "REGEXP"
|
||||
repeat "REPEAT"
|
||||
right "RIGHT"
|
||||
rlike "RLIKE"
|
||||
rollback "ROLLBACK"
|
||||
row "ROW"
|
||||
rsh ">>"
|
||||
runeType "rune"
|
||||
schema "SCHEMA"
|
||||
schemas "SCHEMAS"
|
||||
second "SECOND"
|
||||
selectKwd "SELECT"
|
||||
session "SESSION"
|
||||
set "SET"
|
||||
@ -179,6 +200,7 @@ import (
|
||||
start "START"
|
||||
stringType "string"
|
||||
substring "SUBSTRING"
|
||||
sum "SUM"
|
||||
sysVar "SYS_VAR"
|
||||
tableKwd "TABLE"
|
||||
tables "TABLES"
|
||||
@ -198,9 +220,13 @@ import (
|
||||
values "VALUES"
|
||||
variables "VARIABLES"
|
||||
warnings "WARNINGS"
|
||||
week "WEEK"
|
||||
weekday "WEEKDAY"
|
||||
weekofyear "WEEKOFYEAR"
|
||||
when "WHEN"
|
||||
where "WHERE"
|
||||
xor "XOR"
|
||||
yearweek "YEARWEEK"
|
||||
zerofill "ZEROFILL"
|
||||
|
||||
calcFoundRows "SQL_CALC_FOUND_ROWS"
|
||||
@ -262,7 +288,6 @@ import (
|
||||
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"
|
||||
@ -307,6 +332,7 @@ import (
|
||||
DefaultKwdOpt "optional DEFAULT keyword"
|
||||
DefaultValueExpr "DefaultValueExpr(Now or Signed Literal)"
|
||||
DeleteFromStmt "DELETE FROM statement"
|
||||
DistinctOpt "Distinct option"
|
||||
DoStmt "Do statement"
|
||||
DropDatabaseStmt "DROP DATABASE statement"
|
||||
DropIndexStmt "DROP INDEX statement"
|
||||
@ -328,8 +354,11 @@ import (
|
||||
FieldList "field expression list"
|
||||
FromClause "From clause"
|
||||
Function "function expr"
|
||||
FunctionCall "function call post part"
|
||||
FunctionCallArgList "function call optional argument list"
|
||||
FunctionCallAgg "Function call on aggregate data"
|
||||
FunctionCallConflict "Function call with reserved keyword as function name"
|
||||
FunctionCallKeyword "Function call with keyword as function name"
|
||||
FunctionCallNonKeyword "Function call with nonkeyword as function name"
|
||||
FunctionNameConflict "Built-in function call names which are conflict with keywords"
|
||||
GlobalScope "The scope of variable"
|
||||
GroupByClause "GROUP BY clause"
|
||||
GroupByList "GROUP BY list"
|
||||
@ -463,7 +492,6 @@ import (
|
||||
NUM "numbers"
|
||||
LengthNum "Field length num(uint64)"
|
||||
|
||||
FunctionNameConflict "Built-in function call names which are conflict with keywords"
|
||||
|
||||
|
||||
%token tableRefPriority
|
||||
@ -471,6 +499,9 @@ import (
|
||||
%precedence lowerThanCalcFoundRows
|
||||
%precedence calcFoundRows
|
||||
|
||||
%precedence lowerThanInsertValues
|
||||
%precedence insertValues
|
||||
|
||||
%left join inner cross left right full
|
||||
/* A dummy token to force the priority of TableRef production in a join. */
|
||||
%left tableRefPriority
|
||||
@ -657,39 +688,6 @@ BeginTransactionStmt:
|
||||
$$ = &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{Val: expressions.TypeStar("*")} }
|
||||
}
|
||||
| ExpressionList
|
||||
|
||||
ColumnDef:
|
||||
ColumnName Type ConstraintOpts
|
||||
{
|
||||
@ -1593,14 +1591,16 @@ Identifier:
|
||||
identifier | UnReservedKeyword | NotKeywordToken
|
||||
|
||||
UnReservedKeyword:
|
||||
"AUTO_INCREMENT" | "AFTER" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "CHARSET" | "COLUMNS" | "COMMIT"
|
||||
"AUTO_INCREMENT" | "AFTER" | "AVG" | "BEGIN" | "BIT" | "BOOL" | "BOOLEAN" | "CHARSET" | "COLUMNS" | "COMMIT"
|
||||
| "DATE" | "DATETIME" | "DEALLOCATE" | "DO" | "END" | "ENGINE" | "ENGINES" | "EXECUTE" | "FIRST" | "FULL"
|
||||
| "LOCAL" | "NAMES" | "OFFSET" | "PASSWORD" %prec lowerThanEq | "PREPARE" | "QUICK" | "ROLLBACK" | "SESSION" | "SIGNED"
|
||||
| "START" | "GLOBAL" | "TABLES"| "TEXT" | "TIME" | "TIMESTAMP" | "TRANSACTION" | "TRUNCATE" | "UNKNOWN"
|
||||
| "VALUE" | "WARNINGS" | "YEAR" | "NOW" | "MODE"
|
||||
| "VALUE" | "WARNINGS" | "YEAR" | "MODE" | "WEEK" | "ANY" | "SOME"
|
||||
|
||||
NotKeywordToken:
|
||||
"SQL_CALC_FOUND_ROWS" | "SUBSTRING" %prec lowerThanLeftParen
|
||||
"ABS" | "COALESCE" | "CONCAT" | "CONCAT_WS" | "COUNT" | "DAY" | "DAYOFMONTH" | "DAYOFWEEK" | "DAYOFYEAR" | "FOUND_ROWS" | "GROUP_CONCAT"
|
||||
| "HOUR" | "IFNULL" | "LENGTH" | "MAX" | "MICROSECOND" | "MIN" | "MINUTE" | "NULLIF" | "MONTH" | "NOW" | "SECOND" | "SQL_CALC_FOUND_ROWS"
|
||||
| "SUBSTRING" %prec lowerThanLeftParen | "SUM" | "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK"
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
@ -1641,7 +1641,7 @@ InsertRest:
|
||||
{
|
||||
$$ = &stmts.InsertIntoStmt{ColNames: $2.([]string), Sel: $4.(*stmts.SelectStmt)}
|
||||
}
|
||||
| ValueSym ExpressionListList
|
||||
| ValueSym ExpressionListList %prec insertValues
|
||||
{
|
||||
$$ = &stmts.InsertIntoStmt{Lists: $2.([][]expression.Expression)}
|
||||
}
|
||||
@ -1723,7 +1723,6 @@ Literal:
|
||||
$$ = int64(1)
|
||||
}
|
||||
| floatLit
|
||||
| imaginaryLit
|
||||
| intLit
|
||||
| stringLit
|
||||
|
||||
@ -1844,30 +1843,51 @@ PrimaryExpression:
|
||||
}
|
||||
|
||||
Function:
|
||||
PrimaryExpression FunctionCall
|
||||
FunctionCallKeyword
|
||||
| FunctionCallNonKeyword
|
||||
| FunctionCallConflict
|
||||
| FunctionCallAgg
|
||||
|
||||
FunctionNameConflict:
|
||||
"DATABASE" | "SCHEMA" | "IF" | "LEFT" | "REPEAT"
|
||||
|
||||
FunctionCallConflict:
|
||||
FunctionNameConflict '(' ExpressionList ')'
|
||||
{
|
||||
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 {
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
x.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| FunctionNameConflict FunctionCall
|
||||
|
||||
DistinctOpt:
|
||||
{
|
||||
$$ = false
|
||||
}
|
||||
| "ALL"
|
||||
{
|
||||
$$ = false
|
||||
}
|
||||
| "DISTINCT"
|
||||
{
|
||||
$$ = true
|
||||
}
|
||||
| "DISTINCT" "ALL"
|
||||
{
|
||||
$$ = true
|
||||
}
|
||||
|
||||
FunctionCallKeyword:
|
||||
"AVG" '(' DistinctOpt ExpressionList ')'
|
||||
{
|
||||
x := yylex.(*lexer)
|
||||
var err error
|
||||
args := $2.([]interface{})
|
||||
$$, err = expressions.NewCall($1.(string), args[1].([]expression.Expression), false)
|
||||
$$, err = expressions.NewCall($1.(string), $4.([]expression.Expression), $3.(bool))
|
||||
if err != nil {
|
||||
x.err("", "%v", err)
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
@ -1890,11 +1910,6 @@ Function:
|
||||
}
|
||||
$$ = x
|
||||
}
|
||||
| "VALUES" '(' Identifier ')'
|
||||
{
|
||||
// TODO: support qualified identifier for column_name
|
||||
$$ = &expressions.Values{CIStr: model.NewCIStr($3.(string))}
|
||||
}
|
||||
| "CONVERT" '(' Expression "USING" CharsetName ')'
|
||||
{
|
||||
// See: https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
|
||||
@ -1912,6 +1927,237 @@ Function:
|
||||
IsConvert: true,
|
||||
}
|
||||
}
|
||||
| "DATE" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "VALUES" '(' Identifier ')' %prec lowerThanInsertValues
|
||||
{
|
||||
// TODO: support qualified identifier for column_name
|
||||
$$ = &expressions.Values{CIStr: model.NewCIStr($3.(string))}
|
||||
}
|
||||
| "WEEK" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "YEAR" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
FunctionCallNonKeyword:
|
||||
"COALESCE" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "ABS" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "CONCAT" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "CONCAT_WS" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "DAY" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "DAYOFWEEK" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "DAYOFMONTH" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "DAYOFYEAR" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "FOUND_ROWS" '(' ')'
|
||||
{
|
||||
args := []expression.Expression{}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "HOUR" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "IFNULL" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "LENGTH" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "MICROSECOND" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "MINUTE" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "MONTH" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "NOW" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression),false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "NULLIF" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression), false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "SECOND" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "SUBSTRING" '(' Expression ',' Expression ')'
|
||||
{
|
||||
$$ = &expressions.FunctionSubstring{
|
||||
@ -1942,7 +2188,104 @@ Function:
|
||||
Len: $7.(expression.Expression),
|
||||
}
|
||||
}
|
||||
| "WEEKDAY" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "WEEKOFYEAR" '(' Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$3.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "YEARWEEK" '(' ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $3.([]expression.Expression),false)
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
FunctionCallAgg:
|
||||
"COUNT" '(' DistinctOpt ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $4.([]expression.Expression), $3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "COUNT" '(' DistinctOpt '*' ')'
|
||||
{
|
||||
var err error
|
||||
args := []expression.Expression{ expressions.Value{Val: expressions.TypeStar("*")} }
|
||||
$$, err = expressions.NewCall($1.(string), args, $3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "GROUP_CONCAT" '(' DistinctOpt ExpressionList ')'
|
||||
{
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), $4.([]expression.Expression),$3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "MAX" '(' DistinctOpt Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$4.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, $3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "MIN" '(' DistinctOpt Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$4.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, $3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
| "SUM" '(' DistinctOpt Expression ')'
|
||||
{
|
||||
args := []expression.Expression{$4.(expression.Expression)}
|
||||
var err error
|
||||
$$, err = expressions.NewCall($1.(string), args, $3.(bool))
|
||||
if err != nil {
|
||||
l := yylex.(*lexer)
|
||||
l.err("", "%v", err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionOpt:
|
||||
{
|
||||
@ -2035,24 +2378,6 @@ CastType:
|
||||
}
|
||||
|
||||
|
||||
FunctionNameConflict:
|
||||
"DATABASE"
|
||||
{
|
||||
$$ = expressions.BuiltinFuncDatabase
|
||||
}
|
||||
| "SCHEMA"
|
||||
{
|
||||
$$ = expressions.BuiltinFuncDatabase
|
||||
}
|
||||
| "IF"
|
||||
{
|
||||
$$ = expressions.BuiltinFuncIf
|
||||
}
|
||||
| "LEFT"
|
||||
{
|
||||
$$ = expressions.BuiltinFuncLeft
|
||||
}
|
||||
|
||||
PrimaryFactor:
|
||||
PrimaryFactor '|' PrimaryFactor %prec '|'
|
||||
{
|
||||
|
||||
@ -317,7 +317,7 @@ func (s *testParserSuite) TestParser0(c *C) {
|
||||
"date", "datetime", "deallocate", "do", "end", "engine", "engines", "execute", "first", "full",
|
||||
"local", "names", "offset", "password", "prepare", "quick", "rollback", "session", "signed",
|
||||
"start", "global", "tables", "text", "time", "timestamp", "transaction", "truncate", "unknown",
|
||||
"value", "warnings", "year", "now", "substring", "mode",
|
||||
"value", "warnings", "year", "now", "substring", "mode", "any", "some",
|
||||
}
|
||||
for _, kw := range unreservedKws {
|
||||
src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
|
||||
|
||||
101
parser/scanner.l
101
parser/scanner.l
@ -224,6 +224,7 @@ x [xX]
|
||||
y [yY]
|
||||
z [zZ]
|
||||
|
||||
abs {a}{b}{s}
|
||||
add {a}{d}{d}
|
||||
after {a}{f}{t}{e}{r}
|
||||
all {a}{l}{l}
|
||||
@ -233,6 +234,7 @@ any {a}{n}{y}
|
||||
as {a}{s}
|
||||
asc {a}{s}{c}
|
||||
auto_increment {a}{u}{t}{o}_{i}{n}{c}{r}{e}{m}{e}{n}{t}
|
||||
avg {a}{v}{g}
|
||||
begin {b}{e}{g}{i}{n}
|
||||
between {b}{e}{t}{w}{e}{e}{n}
|
||||
by {b}{y}
|
||||
@ -240,16 +242,24 @@ case {c}{a}{s}{e}
|
||||
cast {c}{a}{s}{t}
|
||||
character {c}{h}{a}{r}{a}{c}{t}{e}{r}
|
||||
charset {c}{h}{a}{r}{s}{e}{t}
|
||||
coalesce {c}{o}{a}{l}{e}{s}{c}{e}
|
||||
collate {c}{o}{l}{l}{a}{t}{e}
|
||||
column {c}{o}{l}{u}{m}{n}
|
||||
columns {c}{o}{l}{u}{m}{n}{s}
|
||||
commit {c}{o}{m}{m}{i}{t}
|
||||
concat {c}{o}{n}{c}{a}{t}
|
||||
concat_ws {c}{o}{n}{c}{a}{t}_{w}{s}
|
||||
constraint {c}{o}{n}{s}{t}{r}{a}{i}{n}{t}
|
||||
convert {c}{o}{n}{v}{e}{r}{t}
|
||||
count {c}{o}{u}{n}{t}
|
||||
create {c}{r}{e}{a}{t}{e}
|
||||
cross {c}{r}{o}{s}{s}
|
||||
database {d}{a}{t}{a}{b}{a}{s}{e}
|
||||
databases {d}{a}{t}{a}{b}{a}{s}{e}{s}
|
||||
day {d}{a}{y}
|
||||
dayofweek {d}{a}{y}{o}{f}{w}{e}{e}{k}
|
||||
dayofmonth {d}{a}{y}{o}{f}{m}{o}{n}{t}{h}
|
||||
dayofyear {d}{a}{y}{o}{f}{y}{e}{a}{r}
|
||||
deallocate {d}{e}{a}{l}{l}{o}{c}{a}{t}{e}
|
||||
default {d}{e}{f}{a}{u}{l}{t}
|
||||
delayed {d}{e}{l}{a}{y}{e}{d}
|
||||
@ -271,14 +281,18 @@ explain {e}{x}{p}{l}{a}{i}{n}
|
||||
first {f}{i}{r}{s}{t}
|
||||
for {f}{o}{r}
|
||||
foreign {f}{o}{r}{e}{i}{g}{n}
|
||||
found_rows {f}{o}{u}{n}{d}_{r}{o}{w}{s}
|
||||
from {f}{r}{o}{m}
|
||||
full {f}{u}{l}{l}
|
||||
fulltext {f}{u}{l}{l}{t}{e}{x}{t}
|
||||
global {g}{l}{o}{b}{a}{l}
|
||||
group {g}{r}{o}{u}{p}
|
||||
group_concat {g}{r}{o}{u}{p}_{c}{o}{n}{c}{a}{t}
|
||||
having {h}{a}{v}{i}{n}{g}
|
||||
high_priority {h}{i}{g}{h}_{p}{r}{i}{o}{r}{i}{t}{y}
|
||||
hour {h}{o}{u}{r}
|
||||
if {i}{f}
|
||||
ifnull {i}{f}{n}{u}{l}{l}
|
||||
ignore {i}{g}{n}{o}{r}{e}
|
||||
in {i}{n}
|
||||
index {i}{n}{d}{e}{x}
|
||||
@ -289,13 +303,17 @@ is {i}{s}
|
||||
join {j}{o}{i}{n}
|
||||
key {k}{e}{y}
|
||||
left {l}{e}{f}{t}
|
||||
length {l}{e}{n}{g}{t}{h}
|
||||
like {l}{i}{k}{e}
|
||||
limit {l}{i}{m}{i}{t}
|
||||
local {l}{o}{c}{a}{l}
|
||||
lock {l}{o}{c}{k}
|
||||
low_priority {l}{o}{w}_{p}{r}{i}{o}{r}{i}{t}{y}
|
||||
microsecond {m}{i}{c}{r}{o}{s}{e}{c}{o}{n}{d}
|
||||
minute {m}{i}{n}{u}{t}{e}
|
||||
mod {m}{o}{d}
|
||||
mode {m}{o}{d}{e}
|
||||
month {m}{o}{n}{t}{h}
|
||||
names {n}{a}{m}{e}{s}
|
||||
not {n}{o}{t}
|
||||
offset {o}{f}{f}{s}{e}{t}
|
||||
@ -307,6 +325,7 @@ password {p}{a}{s}{s}{w}{o}{r}{d}
|
||||
prepare {p}{r}{e}{p}{a}{r}{e}
|
||||
primary {p}{r}{i}{m}{a}{r}{y}
|
||||
quick {q}{u}{i}{c}{k}
|
||||
repeat {r}{e}{p}{e}{a}{t}
|
||||
references {r}{e}{f}{e}{r}{e}{n}{c}{e}{s}
|
||||
regexp {r}{e}{g}{e}{x}{p}
|
||||
right {r}{i}{g}{h}{t}
|
||||
@ -315,6 +334,7 @@ rollback {r}{o}{l}{l}{b}{a}{c}{k}
|
||||
row {r}{o}{w}
|
||||
schema {s}{c}{h}{e}{m}{a}
|
||||
schemas {s}{c}{h}{e}{m}{a}{s}
|
||||
second {s}{e}{c}{o}{n}{d}
|
||||
select {s}{e}{l}{e}{c}{t}
|
||||
session {s}{e}{s}{s}{i}{o}{n}
|
||||
set {s}{e}{t}
|
||||
@ -323,22 +343,30 @@ show {s}{h}{o}{w}
|
||||
some {s}{o}{m}{e}
|
||||
start {s}{t}{a}{r}{t}
|
||||
substring {s}{u}{b}{s}{t}{r}{i}{n}{g}
|
||||
sum {s}{u}{m}
|
||||
table {t}{a}{b}{l}{e}
|
||||
tables {t}{a}{b}{l}{e}{s}
|
||||
then {t}{h}{e}{n}
|
||||
transaction {t}{r}{a}{n}{s}{a}{c}{t}{i}{o}{n}
|
||||
truncate {t}{r}{u}{n}{c}{a}{t}{e}
|
||||
max {m}{a}{x}
|
||||
min {m}{i}{n}
|
||||
unknown {u}{n}{k}{n}{o}{w}{n}
|
||||
union {u}{n}{i}{o}{n}
|
||||
unique {u}{n}{i}{q}{u}{e}
|
||||
nullif {n}{u}{l}{l}{i}{f}
|
||||
update {u}{p}{d}{a}{t}{e}
|
||||
value {v}{a}{l}{u}{e}
|
||||
values {v}{a}{l}{u}{e}{s}
|
||||
variables {v}{a}{r}{i}{a}{b}{l}{e}{s}
|
||||
warnings {w}{a}{r}{n}{i}{n}{g}{s}
|
||||
week {w}{e}{e}{k}
|
||||
weekday {w}{e}{e}{k}{d}{a}{y}
|
||||
weekofyear {w}{e}{e}{k}{o}{f}{y}{e}{a}{r}
|
||||
where {w}{h}{e}{r}{e}
|
||||
when {w}{h}{e}{n}
|
||||
xor {x}{o}{r}
|
||||
yearweek {y}{e}{a}{r}{w}{e}{e}{k}
|
||||
|
||||
null {n}{u}{l}{l}
|
||||
false {f}{a}{l}{s}{e}
|
||||
@ -455,6 +483,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
|
||||
"?" return placeholder
|
||||
|
||||
{abs} lval.item = string(l.val)
|
||||
return abs
|
||||
{add} return add
|
||||
{after} lval.item = string(l.val)
|
||||
return after
|
||||
@ -467,6 +497,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
{as} return as
|
||||
{auto_increment} lval.item = string(l.val)
|
||||
return autoIncrement
|
||||
{avg} lval.item = string(l.val)
|
||||
return avg
|
||||
{begin} lval.item = string(l.val)
|
||||
return begin
|
||||
{between} return between
|
||||
@ -476,18 +508,35 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
{character} return character
|
||||
{charset} lval.item = string(l.val)
|
||||
return charsetKwd
|
||||
{coalesce} lval.item = string(l.val)
|
||||
return coalesce
|
||||
{collate} return collation
|
||||
{column} return column
|
||||
{columns} lval.item = string(l.val)
|
||||
return columns
|
||||
{commit} lval.item = string(l.val)
|
||||
return commit
|
||||
{concat} lval.item = string(l.val)
|
||||
return concat
|
||||
{concat_ws} lval.item = string(l.val)
|
||||
return concatWs
|
||||
{constraint} return constraint
|
||||
{convert} return convert
|
||||
{count} lval.item = string(l.val)
|
||||
return count
|
||||
{create} return create
|
||||
{cross} return cross
|
||||
{database} return database
|
||||
{database} lval.item = string(l.val)
|
||||
return database
|
||||
{databases} return databases
|
||||
{day} lval.item = string(l.val)
|
||||
return day
|
||||
{dayofweek} lval.item = string(l.val)
|
||||
return dayofweek
|
||||
{dayofmonth} lval.item = string(l.val)
|
||||
return dayofmonth
|
||||
{dayofyear} lval.item = string(l.val)
|
||||
return dayofyear
|
||||
{deallocate} lval.item = string(l.val)
|
||||
return deallocate
|
||||
{default} return defaultKwd
|
||||
@ -517,14 +566,23 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
return first
|
||||
{for} return forKwd
|
||||
{foreign} return foreign
|
||||
{found_rows} lval.item = string(l.val)
|
||||
return foundRows
|
||||
{from} return from
|
||||
{full} lval.item = string(l.val)
|
||||
return full
|
||||
{fulltext} return fulltext
|
||||
{group} return group
|
||||
{group_concat} lval.item = string(l.val)
|
||||
return groupConcat
|
||||
{having} return having
|
||||
{high_priority} return highPriority
|
||||
{if} return ifKwd
|
||||
{hour} lval.item = string(l.val)
|
||||
return hour
|
||||
{if} lval.item = string(l.val)
|
||||
return ifKwd
|
||||
{ifnull} lval.item = string(l.val)
|
||||
return ifNull
|
||||
{ignore} return ignore
|
||||
{index} return index
|
||||
{inner} return inner
|
||||
@ -534,16 +592,29 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
{is} return is
|
||||
{join} return join
|
||||
{key} return key
|
||||
{left} return left
|
||||
{left} lval.item = string(l.val)
|
||||
return left
|
||||
{length} lval.item = string(l.val)
|
||||
return length
|
||||
{like} return like
|
||||
{limit} return limit
|
||||
{local} lval.item = string(l.val)
|
||||
return local
|
||||
{lock} return lock
|
||||
{low_priority} return lowPriority
|
||||
{max} lval.item = string(l.val)
|
||||
return max
|
||||
{microsecond} lval.item = string(l.val)
|
||||
return microsecond
|
||||
{min} lval.item = string(l.val)
|
||||
return min
|
||||
{minute} lval.item = string(l.val)
|
||||
return minute
|
||||
{mod} return mod
|
||||
{mode} lval.item = string(l.val)
|
||||
return mode
|
||||
{month} lval.item = string(l.val)
|
||||
return month
|
||||
{names} lval.item = string(l.val)
|
||||
return names
|
||||
{not} return not
|
||||
@ -565,7 +636,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
return rollback
|
||||
{row} lval.item = string(l.val)
|
||||
return row
|
||||
{schema} return schema
|
||||
{schema} lval.item = string(l.val)
|
||||
return schema
|
||||
{schemas} return schemas
|
||||
{session} lval.item = string(l.val)
|
||||
return session
|
||||
@ -575,6 +647,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
return start
|
||||
{global} lval.item = string(l.val)
|
||||
return global
|
||||
{repeat} lval.item = string(l.val)
|
||||
return repeat
|
||||
{regexp} return regexp
|
||||
{references} return references
|
||||
{rlike} return rlike
|
||||
@ -584,7 +658,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
|
||||
{user_var} lval.item = string(l.val)
|
||||
return userVar
|
||||
|
||||
{second} lval.item = string(l.val)
|
||||
return second
|
||||
{select} return selectKwd
|
||||
|
||||
{set} return set
|
||||
@ -592,6 +667,8 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
{show} return show
|
||||
{substring} lval.item = string(l.val)
|
||||
return substring
|
||||
{sum} lval.item = string(l.val)
|
||||
return sum
|
||||
{table} return tableKwd
|
||||
{tables} lval.item = string(l.val)
|
||||
return tables
|
||||
@ -600,11 +677,13 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
return transaction
|
||||
{truncate} lval.item = string(l.val)
|
||||
return truncate
|
||||
{update} return update
|
||||
{union} return union
|
||||
{unique} return unique
|
||||
{unknown} lval.item = string(l.val)
|
||||
return unknown
|
||||
{nullif} lval.item = string(l.val)
|
||||
return nullIf
|
||||
{update} return update
|
||||
{use} return use
|
||||
{using} return using
|
||||
{value} lval.item = string(l.val)
|
||||
@ -614,10 +693,18 @@ sys_var "@@"(({global}".")|({session}".")|{local}".")?{ident}
|
||||
return variables
|
||||
{warnings} lval.item = string(l.val)
|
||||
return warnings
|
||||
{week} lval.item = string(l.val)
|
||||
return week
|
||||
{weekday} lval.item = string(l.val)
|
||||
return weekday
|
||||
{weekofyear} lval.item = string(l.val)
|
||||
return weekofyear
|
||||
{when} return when
|
||||
{where} return where
|
||||
{xor} return xor
|
||||
|
||||
{yearweek} lval.item = string(l.val)
|
||||
return yearweek
|
||||
|
||||
{signed} lval.item = string(l.val)
|
||||
return signed
|
||||
{unsigned} return unsigned
|
||||
|
||||
@ -40,7 +40,6 @@ type dbTxn struct {
|
||||
store *dbStore // for commit
|
||||
startTs time.Time
|
||||
tID int64
|
||||
opCnt int64
|
||||
valid bool
|
||||
snapshotVals map[string][]byte // origin version in snapshot
|
||||
}
|
||||
|
||||
@ -32,7 +32,6 @@ import (
|
||||
"github.com/pingcap/tidb/meta/autoid"
|
||||
"github.com/pingcap/tidb/model"
|
||||
mysql "github.com/pingcap/tidb/mysqldef"
|
||||
"github.com/pingcap/tidb/parser/coldef"
|
||||
"github.com/pingcap/tidb/sessionctx/variable"
|
||||
"github.com/pingcap/tidb/table"
|
||||
"github.com/pingcap/tidb/util"
|
||||
@ -45,7 +44,6 @@ type Table struct {
|
||||
Name model.CIStr
|
||||
Columns []*column.Col
|
||||
|
||||
opt *coldef.TableOption
|
||||
indices []*column.IndexedCol
|
||||
recordPrefix string
|
||||
indexPrefix string
|
||||
|
||||
153
util/types/overflow.go
Normal file
153
util/types/overflow.go
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright 2015 PingCAP, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// ErrArithOverflow is the error for arthimetic operation overflow.
|
||||
var ErrArithOverflow = errors.New("operation overflow")
|
||||
|
||||
// AddUint64 adds uint64 a and b if no overflow, else, returns error.
|
||||
func AddUint64(a uint64, b uint64) (uint64, error) {
|
||||
if math.MaxUint64-a < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a + b, nil
|
||||
}
|
||||
|
||||
// AddInt64 adds int64 a and b if no overflow, otherwise, returns error.
|
||||
func AddInt64(a int64, b int64) (int64, error) {
|
||||
if (a > 0 && b > 0 && math.MaxInt64-a < b) ||
|
||||
(a < 0 && b < 0 && math.MinInt64-a > b) {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return a + b, nil
|
||||
}
|
||||
|
||||
// AddInteger adds uint64 a and int64 b and returns uint64 if no overflow error.
|
||||
func AddInteger(a uint64, b int64) (uint64, error) {
|
||||
if b >= 0 {
|
||||
return AddUint64(a, uint64(b))
|
||||
}
|
||||
|
||||
if uint64(-b) > a {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - uint64(-b), nil
|
||||
}
|
||||
|
||||
// SubUint64 substracts uint64 a with b and returns uint64 if no overflow error.
|
||||
func SubUint64(a uint64, b uint64) (uint64, error) {
|
||||
if a < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - b, nil
|
||||
}
|
||||
|
||||
// SubInt64 substracts int64 a with b and returns int64 if no overflow error.
|
||||
func SubInt64(a int64, b int64) (int64, error) {
|
||||
if (a > 0 && b < 0 && math.MaxInt64-a < -b) ||
|
||||
(a < 0 && b > 0 && math.MinInt64-a > -b) ||
|
||||
(a == 0 && b == math.MinInt64) {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a - b, nil
|
||||
}
|
||||
|
||||
// SubUintWithInt substracts uint64 a with int64 b and returns uint64 if no overflow error.
|
||||
func SubUintWithInt(a uint64, b int64) (uint64, error) {
|
||||
if b < 0 {
|
||||
return AddUint64(a, uint64(-b))
|
||||
}
|
||||
return SubUint64(a, uint64(b))
|
||||
}
|
||||
|
||||
// SubIntWithUint substracts int64 a with uint64 b and returns uint64 if no overflow error.
|
||||
func SubIntWithUint(a int64, b uint64) (uint64, error) {
|
||||
if a < 0 || uint64(a) < b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return uint64(a) - b, nil
|
||||
}
|
||||
|
||||
// MulUint64 multiplies uint64 a and b and returns uint64 if no overflow error.
|
||||
func MulUint64(a uint64, b uint64) (uint64, error) {
|
||||
if b > 0 && a > math.MaxUint64/b {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
return a * b, nil
|
||||
}
|
||||
|
||||
// MulInt64 multiplies int64 a and b and returns int64 if no overflow error.
|
||||
func MulInt64(a int64, b int64) (int64, error) {
|
||||
if a == 0 || b == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var (
|
||||
res uint64
|
||||
err error
|
||||
negative = false
|
||||
)
|
||||
|
||||
if a > 0 && b > 0 {
|
||||
res, err = MulUint64(uint64(a), uint64(b))
|
||||
} else if a < 0 && b < 0 {
|
||||
res, err = MulUint64(uint64(-a), uint64(-b))
|
||||
} else if a < 0 && b > 0 {
|
||||
negative = true
|
||||
res, err = MulUint64(uint64(-a), uint64(b))
|
||||
} else {
|
||||
negative = true
|
||||
res, err = MulUint64(uint64(a), uint64(-b))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, errors.Trace(err)
|
||||
}
|
||||
|
||||
if negative {
|
||||
// negative result
|
||||
if res > math.MaxInt64+1 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return -int64(res), nil
|
||||
}
|
||||
|
||||
// positive result
|
||||
if res > math.MaxInt64 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return int64(res), nil
|
||||
}
|
||||
|
||||
// MulInteger multiplies uint64 a and int64 b, and returns uint64 if no overflow error.
|
||||
func MulInteger(a uint64, b int64) (uint64, error) {
|
||||
if a == 0 || b == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if b < 0 {
|
||||
return 0, errors.Trace(ErrArithOverflow)
|
||||
}
|
||||
|
||||
return MulUint64(a, uint64(b))
|
||||
}
|
||||
265
util/types/overflow_test.go
Normal file
265
util/types/overflow_test.go
Normal file
@ -0,0 +1,265 @@
|
||||
// Copyright 2015 PingCAP, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
. "github.com/pingcap/check"
|
||||
)
|
||||
|
||||
var _ = Suite(&testOverflowSuite{})
|
||||
|
||||
type testOverflowSuite struct {
|
||||
}
|
||||
|
||||
func (s *testOverflowSuite) TestAdd(c *C) {
|
||||
tblUint64 := []struct {
|
||||
lsh uint64
|
||||
rsh uint64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxUint64, 1, 0, true},
|
||||
{math.MaxUint64, 0, math.MaxUint64, false},
|
||||
{1, 1, 2, false},
|
||||
}
|
||||
|
||||
for _, t := range tblUint64 {
|
||||
ret, err := AddUint64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt64 := []struct {
|
||||
lsh int64
|
||||
rsh int64
|
||||
ret int64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxInt64, 1, 0, true},
|
||||
{math.MaxInt64, 0, math.MaxInt64, false},
|
||||
{0, math.MinInt64, math.MinInt64, false},
|
||||
{-1, math.MinInt64, 0, true},
|
||||
{math.MaxInt64, math.MinInt64, -1, false},
|
||||
{1, 1, 2, false},
|
||||
{1, -1, 0, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt64 {
|
||||
ret, err := AddInt64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt := []struct {
|
||||
lsh uint64
|
||||
rsh int64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxUint64, math.MinInt64, math.MaxUint64 + math.MinInt64, false},
|
||||
{math.MaxInt64, math.MinInt64, 0, true},
|
||||
{0, -1, 0, true},
|
||||
{1, -1, 0, false},
|
||||
{0, 1, 1, false},
|
||||
{1, 1, 2, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt {
|
||||
ret, err := AddInteger(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testOverflowSuite) TestSub(c *C) {
|
||||
tblUint64 := []struct {
|
||||
lsh uint64
|
||||
rsh uint64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxUint64, 1, math.MaxUint64 - 1, false},
|
||||
{math.MaxUint64, 0, math.MaxUint64, false},
|
||||
{0, math.MaxUint64, 0, true},
|
||||
{0, 1, 0, true},
|
||||
{1, math.MaxUint64, 0, true},
|
||||
{1, 1, 0, false},
|
||||
}
|
||||
|
||||
for _, t := range tblUint64 {
|
||||
ret, err := SubUint64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt64 := []struct {
|
||||
lsh int64
|
||||
rsh int64
|
||||
ret int64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MinInt64, 0, math.MinInt64, false},
|
||||
{math.MinInt64, 1, 0, true},
|
||||
{math.MaxInt64, -1, 0, true},
|
||||
{0, math.MinInt64, 0, true},
|
||||
{-1, math.MinInt64, math.MaxInt64, false},
|
||||
{math.MinInt64, math.MaxInt64, 0, true},
|
||||
{math.MinInt64, math.MinInt64, 0, false},
|
||||
{math.MinInt64, -math.MaxInt64, -1, false},
|
||||
{1, 1, 0, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt64 {
|
||||
ret, err := SubInt64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt := []struct {
|
||||
lsh uint64
|
||||
rsh int64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{0, math.MinInt64, -math.MinInt64, false},
|
||||
{0, 1, 0, true},
|
||||
{math.MaxUint64, math.MinInt64, 0, true},
|
||||
{math.MaxInt64, math.MinInt64, 2*math.MaxInt64 + 1, false},
|
||||
{math.MaxUint64, -1, 0, true},
|
||||
{0, -1, 1, false},
|
||||
{1, 1, 0, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt {
|
||||
ret, err := SubUintWithInt(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt2 := []struct {
|
||||
lsh int64
|
||||
rsh uint64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MinInt64, 0, 0, true},
|
||||
{math.MaxInt64, 0, math.MaxInt64, false},
|
||||
{math.MaxInt64, math.MaxUint64, 0, true},
|
||||
{math.MaxInt64, -math.MinInt64, 0, true},
|
||||
{-1, 0, 0, true},
|
||||
{1, 1, 0, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt2 {
|
||||
ret, err := SubIntWithUint(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *testOverflowSuite) TestMul(c *C) {
|
||||
tblUint64 := []struct {
|
||||
lsh uint64
|
||||
rsh uint64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxUint64, 1, math.MaxUint64, false},
|
||||
{math.MaxUint64, 0, 0, false},
|
||||
{math.MaxUint64, 2, 0, true},
|
||||
{1, 1, 1, false},
|
||||
}
|
||||
|
||||
for _, t := range tblUint64 {
|
||||
ret, err := MulUint64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt64 := []struct {
|
||||
lsh int64
|
||||
rsh int64
|
||||
ret int64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxInt64, 1, math.MaxInt64, false},
|
||||
{math.MinInt64, 1, math.MinInt64, false},
|
||||
{math.MaxInt64, -1, -math.MaxInt64, false},
|
||||
{math.MinInt64, -1, 0, true},
|
||||
{math.MinInt64, 0, 0, false},
|
||||
{math.MaxInt64, 0, 0, false},
|
||||
{math.MaxInt64, math.MaxInt64, 0, true},
|
||||
{math.MaxInt64, math.MinInt64, 0, true},
|
||||
{math.MinInt64 / 10, 11, 0, true},
|
||||
{1, 1, 1, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt64 {
|
||||
ret, err := MulInt64(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
|
||||
tblInt := []struct {
|
||||
lsh uint64
|
||||
rsh int64
|
||||
ret uint64
|
||||
overflow bool
|
||||
}{
|
||||
{math.MaxUint64, 0, 0, false},
|
||||
{0, -1, 0, false},
|
||||
{1, -1, 0, true},
|
||||
{math.MaxUint64, -1, 0, true},
|
||||
{math.MaxUint64, 10, 0, true},
|
||||
{1, 1, 1, false},
|
||||
}
|
||||
|
||||
for _, t := range tblInt {
|
||||
ret, err := MulInteger(t.lsh, t.rsh)
|
||||
if t.overflow {
|
||||
c.Assert(err, NotNil)
|
||||
} else {
|
||||
c.Assert(ret, Equals, t.ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user