From b255e058e545179bc92cfabbef8ff30baa07f3ec Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 5 Mar 2020 20:01:28 +0800 Subject: [PATCH] [parser] *: set charset and collate for string literals correctly (#761) * done * address comment * fix * revert --- parser/ast/expressions.go | 2 +- parser/ast/expressions_test.go | 3 +- parser/ast/functions_test.go | 3 +- parser/ast/misc_test.go | 3 +- parser/parser.go | 96 ++++++++++++------------- parser/parser.y | 96 ++++++++++++------------- parser/test_driver/test_driver.go | 4 +- parser/test_driver/test_driver_datum.go | 4 +- 8 files changed, 107 insertions(+), 104 deletions(-) diff --git a/parser/ast/expressions.go b/parser/ast/expressions.go index c1e47aafc2..9d79bae087 100755 --- a/parser/ast/expressions.go +++ b/parser/ast/expressions.go @@ -65,7 +65,7 @@ type ValueExpr interface { } // NewValueExpr creates a ValueExpr with value, and sets default field type. -var NewValueExpr func(interface{}) ValueExpr +var NewValueExpr func(value interface{}, charset string, collate string) ValueExpr // NewParamMarkerExpr creates a ParamMarkerExpr. var NewParamMarkerExpr func(offset int) ParamMarkerExpr diff --git a/parser/ast/expressions_test.go b/parser/ast/expressions_test.go index e409e9b71f..ff655ba05a 100644 --- a/parser/ast/expressions_test.go +++ b/parser/ast/expressions_test.go @@ -17,6 +17,7 @@ import ( . "github.com/pingcap/check" . "github.com/pingcap/parser/ast" "github.com/pingcap/parser/format" + "github.com/pingcap/parser/mysql" ) var _ = Suite(&testExpressionsSuite{}) @@ -88,7 +89,7 @@ func (tc *testExpressionsSuite) TestExpresionsVisitorCover(c *C) { {&PositionExpr{}, 0, 0}, {&RowExpr{Values: []ExprNode{ce, ce}}, 2, 2}, {&UnaryOperationExpr{V: ce}, 1, 1}, - {NewValueExpr(0), 0, 0}, + {NewValueExpr(0, mysql.DefaultCharset, mysql.DefaultCollationName), 0, 0}, {&ValuesExpr{Column: &ColumnNameExpr{Name: &ColumnName{}}}, 0, 0}, {&VariableExpr{Value: ce}, 1, 1}, } diff --git a/parser/ast/functions_test.go b/parser/ast/functions_test.go index 1c996bd617..edcc184614 100644 --- a/parser/ast/functions_test.go +++ b/parser/ast/functions_test.go @@ -17,6 +17,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/parser" . "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/test_driver" ) @@ -26,7 +27,7 @@ type testFunctionsSuite struct { } func (ts *testFunctionsSuite) TestFunctionsVisitorCover(c *C) { - valueExpr := NewValueExpr(42) + valueExpr := NewValueExpr(42, mysql.DefaultCharset, mysql.DefaultCollationName) stmts := []Node{ &AggregateFuncExpr{Args: []ExprNode{valueExpr}}, &FuncCallExpr{Args: []ExprNode{valueExpr}}, diff --git a/parser/ast/misc_test.go b/parser/ast/misc_test.go index 346ab5f52c..744e66f38b 100644 --- a/parser/ast/misc_test.go +++ b/parser/ast/misc_test.go @@ -18,6 +18,7 @@ import ( "github.com/pingcap/parser" . "github.com/pingcap/parser/ast" "github.com/pingcap/parser/auth" + "github.com/pingcap/parser/mysql" ) var _ = Suite(&testMiscSuite{}) @@ -44,7 +45,7 @@ func (visitor1) Enter(in Node) (Node, bool) { } func (ts *testMiscSuite) TestMiscVisitorCover(c *C) { - valueExpr := NewValueExpr(42) + valueExpr := NewValueExpr(42, mysql.DefaultCharset, mysql.DefaultCollationName) stmts := []Node{ &AdminStmt{}, &AlterUserStmt{}, diff --git a/parser/parser.go b/parser/parser.go index c3a861e419..e9dffaec8f 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -10571,7 +10571,7 @@ yynewstate: } case 182: { - parser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr(yyS[yypt-0].ident)} + parser.yyVAL.item = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation)} } case 183: { @@ -10864,7 +10864,7 @@ yynewstate: } case 234: { - parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP"), Args: []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)}} + parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP"), Args: []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)}} } case 235: { @@ -10888,15 +10888,15 @@ yynewstate: } case 244: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].expr) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].expr, parser.charset, parser.collation) } case 245: { - parser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr(yyS[yypt-0].item)} + parser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation)} } case 246: { - parser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(yyS[yypt-0].item)} + parser.yyVAL.expr = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation)} } case 250: { @@ -11856,7 +11856,7 @@ yynewstate: } case 439: { - expr := ast.NewValueExpr(yyS[yypt-0].item) + expr := ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) parser.yyVAL.item = []ast.ExprNode{expr} } case 440: @@ -12369,27 +12369,27 @@ yynewstate: } case 907: { - parser.yyVAL.expr = ast.NewValueExpr(false) + parser.yyVAL.expr = ast.NewValueExpr(false, parser.charset, parser.collation) } case 908: { - parser.yyVAL.expr = ast.NewValueExpr(nil) + parser.yyVAL.expr = ast.NewValueExpr(nil, parser.charset, parser.collation) } case 909: { - parser.yyVAL.expr = ast.NewValueExpr(true) + parser.yyVAL.expr = ast.NewValueExpr(true, parser.charset, parser.collation) } case 910: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 911: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 912: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 913: { @@ -12403,7 +12403,7 @@ yynewstate: yylex.AppendError(yylex.Errorf("Get collation error for charset: %s", yyS[yypt-1].ident)) return 1 } - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) tp := expr.GetType() tp.Charset = yyS[yypt-1].ident tp.Collate = co @@ -12414,22 +12414,22 @@ yynewstate: } case 915: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 916: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 917: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) parser.yyVAL.expr = expr } case 918: { valExpr := yyS[yypt-1].expr.(ast.ValueExpr) strLit := valExpr.GetString() - expr := ast.NewValueExpr(strLit + yyS[yypt-0].ident) + expr := ast.NewValueExpr(strLit+yyS[yypt-0].ident, parser.charset, parser.collation) // Fix #4239, use first string literal as projection name. if valExpr.GetProjectionOffset() >= 0 { expr.SetProjectionOffset(valExpr.GetProjectionOffset()) @@ -12712,7 +12712,7 @@ yynewstate: case 975: { // See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert - charset1 := ast.NewValueExpr(yyS[yypt-1].item) + charset1 := ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(yyS[yypt-5].ident), Args: []ast.ExprNode{yyS[yypt-3].expr, charset1}, @@ -12728,12 +12728,12 @@ yynewstate: } case 978: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{yyS[yypt-2].expr, expr}} } case 979: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) extract := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{yyS[yypt-2].expr, expr}} parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONUnquote), Args: []ast.ExprNode{extract}} } @@ -12783,7 +12783,7 @@ yynewstate: } case 1036: { - nilVal := ast.NewValueExpr(nil) + nilVal := ast.NewValueExpr(nil, parser.charset, parser.collation) args := yyS[yypt-1].item.([]ast.ExprNode) parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.CharFunc), @@ -12792,7 +12792,7 @@ yynewstate: } case 1037: { - charset1 := ast.NewValueExpr(yyS[yypt-1].item) + charset1 := ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation) args := yyS[yypt-3].item.([]ast.ExprNode) parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.CharFunc), @@ -12801,17 +12801,17 @@ yynewstate: } case 1038: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.DateLiteral), Args: []ast.ExprNode{expr}} } case 1039: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimeLiteral), Args: []ast.ExprNode{expr}} } case 1040: { - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimestampLiteral), Args: []ast.ExprNode{expr}} } case 1041: @@ -12830,7 +12830,7 @@ yynewstate: { // This is ODBC syntax for date and time literals. // See: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html - expr := ast.NewValueExpr(yyS[yypt-1].ident) + expr := ast.NewValueExpr(yyS[yypt-1].ident, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{FnName: model.NewCIStr(yyS[yypt-2].ident), Args: []ast.ExprNode{expr}} } case 1045: @@ -12954,7 +12954,7 @@ yynewstate: } case 1061: { - nilVal := ast.NewValueExpr(nil) + nilVal := ast.NewValueExpr(nil, parser.charset, parser.collation) direction := &ast.TrimDirectionExpr{Direction: yyS[yypt-3].item.(ast.TrimDirectionType)} parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(yyS[yypt-5].ident), @@ -12980,14 +12980,14 @@ yynewstate: { parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(yyS[yypt-6].ident), - Args: []ast.ExprNode{yyS[yypt-4].expr, ast.NewValueExpr("CHAR"), ast.NewValueExpr(yyS[yypt-1].item)}, + Args: []ast.ExprNode{yyS[yypt-4].expr, ast.NewValueExpr("CHAR", parser.charset, parser.collation), ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)}, } } case 1065: { parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(yyS[yypt-6].ident), - Args: []ast.ExprNode{yyS[yypt-4].expr, ast.NewValueExpr("BINARY"), ast.NewValueExpr(yyS[yypt-1].item)}, + Args: []ast.ExprNode{yyS[yypt-4].expr, ast.NewValueExpr("BINARY", parser.charset, parser.collation), ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)}, } } case 1067: @@ -13033,7 +13033,7 @@ yynewstate: objNameExpr := &ast.TableNameExpr{ Name: yyS[yypt-3].item.(*ast.TableName), } - valueExpr := ast.NewValueExpr(yyS[yypt-1].item) + valueExpr := ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation) parser.yyVAL.expr = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.SetVal), Args: []ast.ExprNode{objNameExpr, valueExpr}, @@ -13117,7 +13117,7 @@ yynewstate: } case 1091: { - args := []ast.ExprNode{ast.NewValueExpr(1)} + args := []ast.ExprNode{ast.NewValueExpr(1, parser.charset, parser.collation)} if yyS[yypt-0].item != nil { parser.yyVAL.expr = &ast.WindowFuncExpr{F: yyS[yypt-4].ident, Args: args, Spec: *(yyS[yypt-0].item.(*ast.WindowSpec))} } else { @@ -13216,11 +13216,11 @@ yynewstate: } case 1104: { - parser.yyVAL.item = ast.NewValueExpr(",") + parser.yyVAL.item = ast.NewValueExpr(",", parser.charset, parser.collation) } case 1105: { - parser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].ident) + parser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) } case 1106: { @@ -13236,7 +13236,7 @@ yynewstate: } case 1109: { - expr := ast.NewValueExpr(yyS[yypt-1].item) + expr := ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation) parser.yyVAL.item = expr } case 1110: @@ -13884,7 +13884,7 @@ yynewstate: } case 1223: { - parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-1].item)} + parser.yyVAL.item = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)} } case 1224: { @@ -13912,7 +13912,7 @@ yynewstate: } case 1230: { - parser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-1].item)} + parser.yyVAL.item = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)} } case 1231: { @@ -14001,7 +14001,7 @@ yynewstate: } case 1250: { - args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)} + args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)} if yyS[yypt-0].item != nil { args = append(args, yyS[yypt-0].item.(ast.ExprNode)) } @@ -14009,7 +14009,7 @@ yynewstate: } case 1251: { - args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item)} + args := []ast.ExprNode{ast.NewValueExpr(yyS[yypt-1].item, parser.charset, parser.collation)} if yyS[yypt-0].item != nil { args = append(args, yyS[yypt-0].item.(ast.ExprNode)) } @@ -14262,7 +14262,7 @@ yynewstate: } case 1312: { - parser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].item) + parser.yyVAL.item = ast.NewValueExpr(yyS[yypt-0].item, parser.charset, parser.collation) } case 1313: { @@ -14661,21 +14661,21 @@ yynewstate: case 1372: { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr(yyS[yypt-0].ident) + expr := ast.NewValueExpr(yyS[yypt-0].ident, parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_isolation", Value: expr, IsSystem: true}) parser.yyVAL.item = varAssigns } case 1373: { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr("0") + expr := ast.NewValueExpr("0", parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_read_only", Value: expr, IsSystem: true}) parser.yyVAL.item = varAssigns } case 1374: { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr("1") + expr := ast.NewValueExpr("1", parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_read_only", Value: expr, IsSystem: true}) parser.yyVAL.item = varAssigns } @@ -14697,7 +14697,7 @@ yynewstate: } case 1379: { - parser.yyVAL.expr = ast.NewValueExpr("ON") + parser.yyVAL.expr = ast.NewValueExpr("ON", parser.charset, parser.collation) } case 1384: { @@ -14745,22 +14745,22 @@ yynewstate: { parser.yyVAL.item = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr(yyS[yypt-0].item.(string)), + Value: ast.NewValueExpr(yyS[yypt-0].item.(string), parser.charset, parser.collation), } } case 1392: { parser.yyVAL.item = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr(yyS[yypt-2].item.(string)), + Value: ast.NewValueExpr(yyS[yypt-2].item.(string), parser.charset, parser.collation), } } case 1393: { parser.yyVAL.item = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr(yyS[yypt-2].item.(string)), - ExtendValue: ast.NewValueExpr(yyS[yypt-0].item.(string)), + Value: ast.NewValueExpr(yyS[yypt-2].item.(string), parser.charset, parser.collation), + ExtendValue: ast.NewValueExpr(yyS[yypt-0].item.(string), parser.charset, parser.collation), } } case 1394: @@ -14774,7 +14774,7 @@ yynewstate: } case 1396: { - parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item.(string)) + parser.yyVAL.expr = ast.NewValueExpr(yyS[yypt-0].item.(string), parser.charset, parser.collation) } case 1397: { diff --git a/parser/parser.y b/parser/parser.y index a190360820..752f5914b6 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -2550,7 +2550,7 @@ ColumnOption: } | "COMMENT" stringLit { - $$ = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr($2)} + $$ = &ast.ColumnOption{Tp: ast.ColumnOptionComment, Expr: ast.NewValueExpr($2, parser.charset, parser.collation)} } | ConstraintKeywordOpt "CHECK" '(' Expression ')' EnforcedOrNotOrNotNullOpt { @@ -2891,7 +2891,7 @@ NowSymOptionFraction: } | NowSymFunc '(' NUM ')' { - $$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP"), Args: []ast.ExprNode{ast.NewValueExpr($3)}} + $$ = &ast.FuncCallExpr{FnName: model.NewCIStr("CURRENT_TIMESTAMP"), Args: []ast.ExprNode{ast.NewValueExpr($3, parser.charset, parser.collation)}} } NextValueForSequence: @@ -2934,15 +2934,15 @@ NowSym: SignedLiteral: Literal { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | '+' NumLiteral { - $$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr($2)} + $$ = &ast.UnaryOperationExpr{Op: opcode.Plus, V: ast.NewValueExpr($2, parser.charset, parser.collation)} } | '-' NumLiteral { - $$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr($2)} + $$ = &ast.UnaryOperationExpr{Op: opcode.Minus, V: ast.NewValueExpr($2, parser.charset, parser.collation)} } NumLiteral: @@ -4173,7 +4173,7 @@ FuncDatetimePrecListOpt: FuncDatetimePrecList: intLit { - expr := ast.NewValueExpr($1) + expr := ast.NewValueExpr($1, parser.charset, parser.collation) $$ = []ast.ExprNode{expr} } @@ -5171,27 +5171,27 @@ ODBCDateTimeType: Literal: "FALSE" { - $$ = ast.NewValueExpr(false) + $$ = ast.NewValueExpr(false, parser.charset, parser.collation) } | "NULL" { - $$ = ast.NewValueExpr(nil) + $$ = ast.NewValueExpr(nil, parser.charset, parser.collation) } | "TRUE" { - $$ = ast.NewValueExpr(true) + $$ = ast.NewValueExpr(true, parser.charset, parser.collation) } | floatLit { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | decLit { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | intLit { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | StringLiteral %prec lowerThanStringLitToken { @@ -5205,7 +5205,7 @@ Literal: yylex.AppendError(yylex.Errorf("Get collation error for charset: %s", $1)) return 1 } - expr := ast.NewValueExpr($2) + expr := ast.NewValueExpr($2, parser.charset, parser.collation) tp := expr.GetType() tp.Charset = $1 tp.Collate = co @@ -5216,24 +5216,24 @@ Literal: } | hexLit { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | bitLit { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } StringLiteral: stringLit { - expr := ast.NewValueExpr($1) + expr := ast.NewValueExpr($1, parser.charset, parser.collation) $$ = expr } | StringLiteral stringLit { valExpr := $1.(ast.ValueExpr) strLit := valExpr.GetString() - expr := ast.NewValueExpr(strLit + $2) + expr := ast.NewValueExpr(strLit+$2, parser.charset, parser.collation) // Fix #4239, use first string literal as projection name. if valExpr.GetProjectionOffset() >= 0 { expr.SetProjectionOffset(valExpr.GetProjectionOffset()) @@ -5544,7 +5544,7 @@ SimpleExpr: | "CONVERT" '(' Expression "USING" CharsetName ')' { // See https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert - charset1 := ast.NewValueExpr($5) + charset1 := ast.NewValueExpr($5, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr($1), Args: []ast.ExprNode{$3, charset1}, @@ -5560,12 +5560,12 @@ SimpleExpr: } | SimpleIdent jss stringLit { - expr := ast.NewValueExpr($3) + expr := ast.NewValueExpr($3, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{$1, expr}} } | SimpleIdent juss stringLit { - expr := ast.NewValueExpr($3) + expr := ast.NewValueExpr($3, parser.charset, parser.collation) extract := &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONExtract), Args: []ast.ExprNode{$1, expr}} $$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.JSONUnquote), Args: []ast.ExprNode{extract}} } @@ -5680,7 +5680,7 @@ FunctionCallKeyword: } | "CHAR" '(' ExpressionList ')' { - nilVal := ast.NewValueExpr(nil) + nilVal := ast.NewValueExpr(nil, parser.charset, parser.collation) args := $3.([]ast.ExprNode) $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.CharFunc), @@ -5689,7 +5689,7 @@ FunctionCallKeyword: } | "CHAR" '(' ExpressionList "USING" CharsetName ')' { - charset1 := ast.NewValueExpr($5) + charset1 := ast.NewValueExpr($5, parser.charset, parser.collation) args := $3.([]ast.ExprNode) $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.CharFunc), @@ -5698,17 +5698,17 @@ FunctionCallKeyword: } | "DATE" stringLit { - expr := ast.NewValueExpr($2) + expr := ast.NewValueExpr($2, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.DateLiteral), Args: []ast.ExprNode{expr}} } | "TIME" stringLit { - expr := ast.NewValueExpr($2) + expr := ast.NewValueExpr($2, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimeLiteral), Args: []ast.ExprNode{expr}} } | "TIMESTAMP" stringLit { - expr := ast.NewValueExpr($2) + expr := ast.NewValueExpr($2, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{FnName: model.NewCIStr(ast.TimestampLiteral), Args: []ast.ExprNode{expr}} } | "INSERT" '(' ExpressionListOpt ')' @@ -5727,7 +5727,7 @@ FunctionCallKeyword: { // This is ODBC syntax for date and time literals. // See: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html - expr := ast.NewValueExpr($3) + expr := ast.NewValueExpr($3, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{FnName: model.NewCIStr($2), Args: []ast.ExprNode{expr}} } @@ -5853,7 +5853,7 @@ FunctionCallNonKeyword: } | builtinTrim '(' TrimDirection "FROM" Expression ')' { - nilVal := ast.NewValueExpr(nil) + nilVal := ast.NewValueExpr(nil, parser.charset, parser.collation) direction := &ast.TrimDirectionExpr{Direction: $3.(ast.TrimDirectionType)} $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr($1), @@ -5879,14 +5879,14 @@ FunctionCallNonKeyword: { $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr($1), - Args: []ast.ExprNode{$3, ast.NewValueExpr("CHAR"), ast.NewValueExpr($6)}, + Args: []ast.ExprNode{$3, ast.NewValueExpr("CHAR", parser.charset, parser.collation), ast.NewValueExpr($6, parser.charset, parser.collation)}, } } | weightString '(' Expression "AS" "BINARY" FieldLen ')' { $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr($1), - Args: []ast.ExprNode{$3, ast.NewValueExpr("BINARY"), ast.NewValueExpr($6)}, + Args: []ast.ExprNode{$3, ast.NewValueExpr("BINARY", parser.charset, parser.collation), ast.NewValueExpr($6, parser.charset, parser.collation)}, } } | FunctionNameSequence @@ -5947,7 +5947,7 @@ FunctionNameSequence: objNameExpr := &ast.TableNameExpr{ Name: $3.(*ast.TableName), } - valueExpr := ast.NewValueExpr($5) + valueExpr := ast.NewValueExpr($5, parser.charset, parser.collation) $$ = &ast.FuncCallExpr{ FnName: model.NewCIStr(ast.SetVal), Args: []ast.ExprNode{objNameExpr, valueExpr}, @@ -6034,7 +6034,7 @@ SumExpr: } | builtinCount '(' '*' ')' OptWindowingClause { - args := []ast.ExprNode{ast.NewValueExpr(1)} + args := []ast.ExprNode{ast.NewValueExpr(1, parser.charset, parser.collation)} if $5 != nil { $$ = &ast.WindowFuncExpr{F: $1, Args: args, Spec: *($5.(*ast.WindowSpec))} } else { @@ -6134,11 +6134,11 @@ SumExpr: OptGConcatSeparator: { - $$ = ast.NewValueExpr(",") + $$ = ast.NewValueExpr(",", parser.charset, parser.collation) } | "SEPARATOR" stringLit { - $$ = ast.NewValueExpr($2) + $$ = ast.NewValueExpr($2, parser.charset, parser.collation) } FunctionCallGeneric: @@ -6157,7 +6157,7 @@ FuncDatetimePrec: } | '(' intLit ')' { - expr := ast.NewValueExpr($2) + expr := ast.NewValueExpr($2, parser.charset, parser.collation) $$ = expr } @@ -6902,7 +6902,7 @@ WindowFrameStart: } | NumLiteral "PRECEDING" { - $$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($1)} + $$ = ast.FrameBound{Type: ast.Preceding, Expr: ast.NewValueExpr($1, parser.charset, parser.collation)} } | paramMarker "PRECEDING" { @@ -6934,7 +6934,7 @@ WindowFrameBound: } | NumLiteral "FOLLOWING" { - $$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($1)} + $$ = ast.FrameBound{Type: ast.Following, Expr: ast.NewValueExpr($1, parser.charset, parser.collation)} } | paramMarker "FOLLOWING" { @@ -7031,7 +7031,7 @@ OptLeadLagInfo: } | ',' NumLiteral OptLLDefault { - args := []ast.ExprNode{ast.NewValueExpr($2)} + args := []ast.ExprNode{ast.NewValueExpr($2, parser.charset, parser.collation)} if $3 != nil { args = append(args, $3.(ast.ExprNode)) } @@ -7039,7 +7039,7 @@ OptLeadLagInfo: } | ',' paramMarker OptLLDefault { - args := []ast.ExprNode{ast.NewValueExpr($2)} + args := []ast.ExprNode{ast.NewValueExpr($2, parser.charset, parser.collation)} if $3 != nil { args = append(args, $3.(ast.ExprNode)) } @@ -7336,7 +7336,7 @@ LimitClause: LimitOption: LengthNum { - $$ = ast.NewValueExpr($1) + $$ = ast.NewValueExpr($1, parser.charset, parser.collation) } | paramMarker { @@ -7791,21 +7791,21 @@ TransactionChar: "ISOLATION" "LEVEL" IsolationLevel { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr($3) + expr := ast.NewValueExpr($3, parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_isolation", Value: expr, IsSystem: true}) $$ = varAssigns } | "READ" "WRITE" { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr("0") + expr := ast.NewValueExpr("0", parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_read_only", Value: expr, IsSystem: true}) $$ = varAssigns } | "READ" "ONLY" { varAssigns := []*ast.VariableAssignment{} - expr := ast.NewValueExpr("1") + expr := ast.NewValueExpr("1", parser.charset, parser.collation) varAssigns = append(varAssigns, &ast.VariableAssignment{Name: "tx_read_only", Value: expr, IsSystem: true}) $$ = varAssigns } @@ -7831,7 +7831,7 @@ IsolationLevel: SetExpr: "ON" { - $$ = ast.NewValueExpr("ON") + $$ = ast.NewValueExpr("ON", parser.charset, parser.collation) } | ExprOrDefault @@ -7889,22 +7889,22 @@ VariableAssignment: { $$ = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr($2.(string)), + Value: ast.NewValueExpr($2.(string), parser.charset, parser.collation), } } | "NAMES" CharsetName "COLLATE" "DEFAULT" { $$ = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr($2.(string)), + Value: ast.NewValueExpr($2.(string), parser.charset, parser.collation), } } | "NAMES" CharsetName "COLLATE" StringName { $$ = &ast.VariableAssignment{ Name: ast.SetNames, - Value: ast.NewValueExpr($2.(string)), - ExtendValue: ast.NewValueExpr($4.(string)), + Value: ast.NewValueExpr($2.(string), parser.charset, parser.collation), + ExtendValue: ast.NewValueExpr($4.(string), parser.charset, parser.collation), } } | "NAMES" "DEFAULT" @@ -7920,7 +7920,7 @@ VariableAssignment: CharsetNameOrDefault: CharsetName { - $$ = ast.NewValueExpr($1.(string)) + $$ = ast.NewValueExpr($1.(string), parser.charset, parser.collation) } | "DEFAULT" { diff --git a/parser/test_driver/test_driver.go b/parser/test_driver/test_driver.go index d101db35d0..8bd6ae80a7 100644 --- a/parser/test_driver/test_driver.go +++ b/parser/test_driver/test_driver.go @@ -148,13 +148,13 @@ func (n *ValueExpr) Format(w io.Writer) { } // newValueExpr creates a ValueExpr with value, and sets default field type. -func newValueExpr(value interface{}) ast.ValueExpr { +func newValueExpr(value interface{}, charset string, collate string) ast.ValueExpr { if ve, ok := value.(*ValueExpr); ok { return ve } ve := &ValueExpr{} ve.SetValue(value) - DefaultTypeForValue(value, &ve.Type) + DefaultTypeForValue(value, &ve.Type, charset, collate) ve.projectionOffset = -1 return ve } diff --git a/parser/test_driver/test_driver_datum.go b/parser/test_driver/test_driver_datum.go index da38f426d4..ea2a4ba066 100644 --- a/parser/test_driver/test_driver_datum.go +++ b/parser/test_driver/test_driver_datum.go @@ -431,7 +431,7 @@ func SetBinChsClnFlag(ft *types.FieldType) { const DefaultFsp = int8(0) // DefaultTypeForValue returns the default FieldType for the value. -func DefaultTypeForValue(value interface{}, tp *types.FieldType) { +func DefaultTypeForValue(value interface{}, tp *types.FieldType, charset string, collate string) { switch x := value.(type) { case nil: tp.Tp = mysql.TypeNull @@ -465,7 +465,7 @@ func DefaultTypeForValue(value interface{}, tp *types.FieldType) { // TODO: tp.Flen should be len(x) * 3 (max bytes length of CharsetUTF8) tp.Flen = len(x) tp.Decimal = types.UnspecifiedLength - tp.Charset, tp.Collate = charset.GetDefaultCharsetAndCollate() + tp.Charset, tp.Collate = charset, collate case float32: tp.Tp = mysql.TypeFloat s := strconv.FormatFloat(float64(x), 'f', -1, 32)