Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions evaluator/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ var Funcs = map[string]Func{
"ifnull": {builtinIfNull, 2, 2},
"nullif": {builtinNullIf, 2, 2},

// miscellaneous functions
// get_lock() and release_lock() is parsed but do nothing.
// It is used for preventing error in Ruby's activerecord migrations.
"get_lock": {builtinLock, 2, 2},
"release_lock": {builtinLock, 1, 1},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define a 'builtinReleaseLock' is cleaner, even if it does nothing.


// only used by new plan
ast.AndAnd: {builtinAndAnd, 2, 2},
ast.OrOr: {builtinOrOr, 2, 2},
Expand Down
6 changes: 6 additions & 0 deletions evaluator/builtin_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,9 @@ func builtinGetVar(args []types.Datum, ctx context.Context) (types.Datum, error)
}
return types.Datum{}, nil
}

// The lock function will do nothing.
func builtinLock(args []types.Datum, _ context.Context) (d types.Datum, err error) {
d.SetInt64(1)
return d, nil
}
12 changes: 12 additions & 0 deletions evaluator/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,15 @@ func (s *testEvaluatorSuite) TestIsNullFunc(c *C) {
c.Assert(err, IsNil)
c.Assert(v.GetInt64(), Equals, int64(1))
}

func (s *testEvaluatorSuite) TestLock(c *C) {
defer testleak.AfterTest(c)()

v, err := builtinLock(types.MakeDatums(1), nil)
c.Assert(err, IsNil)
c.Assert(v.GetInt64(), Equals, int64(1))

v, err = builtinLock(types.MakeDatums(nil), nil)
c.Assert(err, IsNil)
c.Assert(v.GetInt64(), Equals, int64(1))
}
17 changes: 17 additions & 0 deletions infoschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
catalogVal = "def"
tableProfiling = "PROFILING"
tablePartitions = "PARTITIONS"
tableKeyColumm = "KEY_COLUMN_USAGE"
)

type columnInfo struct {
Expand Down Expand Up @@ -197,6 +198,21 @@ var collationsCols = []columnInfo{
{"SORTLEN", mysql.TypeLonglong, 3, 0, nil, nil},
}

var keyColumnUsageCols = []columnInfo{
{"CONSTRAINT_CATALOG", mysql.TypeVarchar, 512, mysql.NotNullFlag, nil, nil},
{"CONSTRAINT_SCHEMA", mysql.TypeVarchar, 64, mysql.NotNullFlag, nil, nil},
{"CONSTRAINT_NAME", mysql.TypeVarchar, 64, mysql.NotNullFlag, nil, nil},
{"TABLE_CATALOG", mysql.TypeVarchar, 512, mysql.NotNullFlag, nil, nil},
{"TABLE_SCHEMA", mysql.TypeVarchar, 64, mysql.NotNullFlag, nil, nil},
{"TABLE_NAME", mysql.TypeVarchar, 64, mysql.NotNullFlag, nil, nil},
{"COLUMN_NAME", mysql.TypeVarchar, 64, mysql.NotNullFlag, nil, nil},
{"ORDINAL_POSITION", mysql.TypeLonglong, 10, mysql.NotNullFlag, nil, nil},
{"POSITION_IN_UNIQUE_CONSTRAINT", mysql.TypeLonglong, 10, 0, nil, nil},
{"REFERENCED_TABLE_SCHEMA", mysql.TypeVarchar, 64, 0, nil, nil},
{"REFERENCED_TABLE_NAME", mysql.TypeVarchar, 64, 0, nil, nil},
{"REFERENCED_COLUMN_NAME", mysql.TypeVarchar, 64, 0, nil, nil},
}

// See https://dev.mysql.com/doc/refman/5.7/en/partitions-table.html
var partitionsCols = []columnInfo{
{"TABLE_CATALOG", mysql.TypeVarchar, 512, 0, nil, nil},
Expand Down Expand Up @@ -481,6 +497,7 @@ var tableNameToColumns = map[string]([]columnInfo){
tableFiles: filesCols,
tableProfiling: profilingCols,
tablePartitions: partitionsCols,
tableKeyColumm: keyColumnUsageCols,
}

func createMemoryTable(meta *model.TableInfo, alloc autoid.Allocator) (table.Table, error) {
Expand Down
12 changes: 11 additions & 1 deletion parser/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ import (
full "FULL"
fulltext "FULLTEXT"
ge ">="
getLock "GET_LOCK"
global "GLOBAL"
grant "GRANT"
grants "GRANTS"
Expand Down Expand Up @@ -247,6 +248,7 @@ import (
redundant "REDUNDANT"
references "REFERENCES"
regexpKwd "REGEXP"
releaseLock "RELEASE_LOCK"
repeat "REPEAT"
repeatable "REPEATABLE"
replace "REPLACE"
Expand Down Expand Up @@ -1966,7 +1968,7 @@ NotKeywordToken:
| "IFNULL" | "ISNULL" | "LAST_INSERT_ID" | "LCASE" | "LENGTH" | "LOCATE" | "LOWER" | "LTRIM" | "MAX" | "MICROSECOND" | "MIN"
| "MINUTE" | "NULLIF" | "MONTH" | "MONTHNAME" | "NOW" | "POW" | "POWER" | "RAND" | "SECOND" | "SQL_CALC_FOUND_ROWS" | "SUBDATE"
| "SUBSTRING" %prec lowerThanLeftParen | "SUBSTRING_INDEX" | "SUM" | "TRIM" | "RTRIM" | "UCASE" | "UPPER" | "VERSION"
| "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK" | "ROUND" | "STATS_PERSISTENT"
| "WEEKDAY" | "WEEKOFYEAR" | "YEARWEEK" | "ROUND" | "STATS_PERSISTENT" | "GET_LOCK" | "RELEASE_LOCK"

/************************************************************************************
*
Expand Down Expand Up @@ -2765,6 +2767,14 @@ FunctionCallNonKeyword:
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: $3.([]ast.ExprNode)}
}
| "GET_LOCK" '(' Expression ',' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode), $5.(ast.ExprNode)}}
}
| "RELEASE_LOCK" '(' Expression ')'
{
$$ = &ast.FuncCallExpr{FnName: model.NewCIStr($1.(string)), Args: []ast.ExprNode{$3.(ast.ExprNode)}}
}

DateArithOpt:
"DATE_ADD"
Expand Down
6 changes: 5 additions & 1 deletion parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (s *testParserSuite) TestSimple(c *C) {
"delay_key_write", "isolation", "repeatable", "committed", "uncommitted", "only", "serializable", "level",
"curtime", "variables", "dayname", "version", "btree", "hash", "row_format", "dynamic", "fixed", "compressed",
"compact", "redundant", "sql_no_cache sql_no_cache", "sql_cache sql_cache", "action", "round",
"enable", "disable", "reverse", "space", "privileges",
"enable", "disable", "reverse", "space", "privileges", "get_lock", "release_lock",
}
for _, kw := range unreservedKws {
src := fmt.Sprintf("SELECT %s FROM tbl;", kw)
Expand Down Expand Up @@ -618,6 +618,10 @@ func (s *testParserSuite) TestBuiltin(c *C) {
{`select adddate("2011-11-11 10:10:10.123456", 10)`, true},
{`select adddate("2011-11-11 10:10:10.123456", 0.10)`, true},
{`select adddate("2011-11-11 10:10:10.123456", "11,11")`, true},

// For misc functions
{`SELECT GET_LOCK('lock1',10);`, true},
{`SELECT RELEASE_LOCK('lock1');`, true},
}
s.RunTest(c, table)
}
Expand Down
6 changes: 6 additions & 0 deletions parser/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ 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}
get_lock {g}{e}{t}_{l}{o}{c}{k}
global {g}{l}{o}{b}{a}{l}
grant {g}{r}{a}{n}{t}
grants {g}{r}{a}{n}{t}{s}
Expand Down Expand Up @@ -447,6 +448,7 @@ quarter {q}{u}{a}{r}{t}{e}{r}
quick {q}{u}{i}{c}{k}
rand {r}{a}{n}{d}
read {r}{e}{a}{d}
release_lock {r}{e}{l}{e}{a}{s}{e}_{l}{o}{c}{k}
repeat {r}{e}{p}{e}{a}{t}
repeatable {r}{e}{p}{e}{a}{t}{a}{b}{l}{e}
references {r}{e}{f}{e}{r}{e}{n}{c}{e}{s}
Expand Down Expand Up @@ -985,11 +987,15 @@ redundant lval.item = string(l.val)
return statsPersistent
{status} lval.item = string(l.val)
return status
{get_lock} lval.item = string(l.val)
return getLock
{global} lval.item = string(l.val)
return global
{rand} lval.item = string(l.val)
return rand
{read} return read
{release_lock} lval.item = string(l.val)
return releaseLock
{repeat} lval.item = string(l.val)
return repeat
{repeatable} lval.item = string(l.val)
Expand Down
2 changes: 2 additions & 0 deletions plan/typeinferer.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) {
// expr2 or expr3 returns a floating-point value floating-point
// expr2 or expr3 returns an integer integer
tp = x.Args[1].GetType()
case "get_lock", "release_lock":
tp = types.NewFieldType(mysql.TypeLonglong)
default:
tp = types.NewFieldType(mysql.TypeUnspecified)
}
Expand Down