diff --git a/executor/set.go b/executor/set.go index ce9287a10d863..a3f37e6d5819e 100644 --- a/executor/set.go +++ b/executor/set.go @@ -115,7 +115,7 @@ func (e *SetExecutor) setSysVariable(name string, v *expression.VarAssignment) e sessionVars := e.ctx.GetSessionVars() sysVar := variable.GetSysVar(name) if sysVar == nil { - return variable.UnknownSystemVar.GenWithStackByArgs(name) + return variable.ErrUnknownSystemVar.GenWithStackByArgs(name) } if sysVar.Scope == variable.ScopeNone { return errors.Errorf("Variable '%s' is a read only variable", name) diff --git a/executor/set_test.go b/executor/set_test.go index a4b96c4f07800..343a7fa2b2875 100644 --- a/executor/set_test.go +++ b/executor/set_test.go @@ -153,12 +153,12 @@ func (s *testSuite5) TestSetVar(c *C) { tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("READ-COMMITTED")) // error _, err = tk.Exec("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@session.tx_isolation").Check(testkit.Rows("READ-COMMITTED")) tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("READ-COMMITTED")) // Fails _, err = tk.Exec("SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@global.tx_isolation").Check(testkit.Rows("REPEATABLE-READ")) tk.MustQuery("select @@global.transaction_isolation").Check(testkit.Rows("REPEATABLE-READ")) @@ -168,29 +168,29 @@ func (s *testSuite5) TestSetVar(c *C) { tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("READ-COMMITTED")) _, err = tk.Exec("SET SESSION tx_isolation = 'READ-UNCOMMITTED'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@session.tx_isolation").Check(testkit.Rows("READ-COMMITTED")) tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("READ-COMMITTED")) // fails _, err = tk.Exec("SET SESSION transaction_isolation = 'SERIALIZABLE'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@session.tx_isolation").Check(testkit.Rows("READ-COMMITTED")) tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("READ-COMMITTED")) // fails _, err = tk.Exec("SET GLOBAL transaction_isolation = 'SERIALIZABLE'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@global.tx_isolation").Check(testkit.Rows("REPEATABLE-READ")) tk.MustQuery("select @@global.transaction_isolation").Check(testkit.Rows("REPEATABLE-READ")) _, err = tk.Exec("SET GLOBAL transaction_isolation = 'READ-UNCOMMITTED'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@global.tx_isolation").Check(testkit.Rows("REPEATABLE-READ")) tk.MustQuery("select @@global.transaction_isolation").Check(testkit.Rows("REPEATABLE-READ")) _, err = tk.Exec("SET GLOBAL tx_isolation = 'SERIALIZABLE'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) tk.MustQuery("select @@global.tx_isolation").Check(testkit.Rows("REPEATABLE-READ")) tk.MustQuery("select @@global.transaction_isolation").Check(testkit.Rows("REPEATABLE-READ")) @@ -314,7 +314,7 @@ func (s *testSuite5) TestSetVar(c *C) { tk.MustExec("SET SESSION tidb_skip_isolation_level_check = 1") tk.MustExec("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE") tk.MustQuery("show warnings").Check(testkit.Rows( - "Warning 1105 The isolation level 'SERIALIZABLE' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error")) + "Warning 8048 The isolation level 'SERIALIZABLE' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error")) tk.MustQuery("select @@session.tx_isolation").Check(testkit.Rows("SERIALIZABLE")) tk.MustQuery("select @@session.transaction_isolation").Check(testkit.Rows("SERIALIZABLE")) @@ -323,7 +323,7 @@ func (s *testSuite5) TestSetVar(c *C) { tk.MustExec("SET SESSION tidb_skip_isolation_level_check = 1") tk.MustExec("SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED") tk.MustQuery("show warnings").Check(testkit.Rows( - "Warning 1105 The isolation level 'READ-UNCOMMITTED' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error")) + "Warning 8048 The isolation level 'READ-UNCOMMITTED' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error")) tk.MustQuery("select @@global.tx_isolation").Check(testkit.Rows("READ-UNCOMMITTED")) tk.MustQuery("select @@global.transaction_isolation").Check(testkit.Rows("READ-UNCOMMITTED")) @@ -765,7 +765,7 @@ func (s *testSuite5) TestValidateSetVar(c *C) { tk.MustExec("SET GLOBAL tidb_skip_isolation_level_check = 0") tk.MustExec("SET SESSION tidb_skip_isolation_level_check = 0") _, err = tk.Exec("set @@tx_isolation='SERIALIZABLE'") - c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedValueForVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnsupportedIsolationLevel), IsTrue, Commentf("err %v", err)) } func (s *testSuite5) TestSelectGlobalVar(c *C) { @@ -783,9 +783,9 @@ func (s *testSuite5) TestSelectGlobalVar(c *C) { // test for unknown variable. err := tk.ExecToErr("select @@invalid") - c.Assert(terror.ErrorEqual(err, variable.UnknownSystemVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnknownSystemVar), IsTrue, Commentf("err %v", err)) err = tk.ExecToErr("select @@global.invalid") - c.Assert(terror.ErrorEqual(err, variable.UnknownSystemVar), IsTrue, Commentf("err %v", err)) + c.Assert(terror.ErrorEqual(err, variable.ErrUnknownSystemVar), IsTrue, Commentf("err %v", err)) } func (s *testSuite5) TestEnableNoopFunctionsVar(c *C) { diff --git a/expression/integration_test.go b/expression/integration_test.go index 2750ec6822433..642dbc914e88d 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -4344,7 +4344,7 @@ func (s *testIntegrationSuite) TestForeignKeyVar(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("SET FOREIGN_KEY_CHECKS=1") - tk.MustQuery("SHOW WARNINGS").Check(testkit.Rows("Warning 1105 variable 'foreign_key_checks' does not yet support value: 1")) + tk.MustQuery("SHOW WARNINGS").Check(testkit.Rows("Warning 8047 variable 'foreign_key_checks' does not yet support value: 1")) } func (s *testIntegrationSuite) TestUserVarMockWindFunc(c *C) { diff --git a/go.mod b/go.mod index 6cfa8d89f33ef..99d942da1d054 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e github.com/pingcap/kvproto v0.0.0-20191104103048-40f562012fb1 github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 - github.com/pingcap/parser v0.0.0-20191107084102-68af6554dec7 + github.com/pingcap/parser v0.0.0-20191111144324-e3789d96ce4f github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 github.com/pingcap/tidb-tools v3.0.6-0.20191106033616-90632dda3863+incompatible github.com/pingcap/tipb v0.0.0-20191105120856-bd4b782c8393 diff --git a/go.sum b/go.sum index 1cd066437080a..50589dbc43b15 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,8 @@ github.com/pingcap/kvproto v0.0.0-20191104103048-40f562012fb1/go.mod h1:WWLmULLO github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/parser v0.0.0-20191107084102-68af6554dec7 h1:vjPDsANQmfb+RHVfQvqzb/xpzkQhFdICUEjtA8XvAYw= -github.com/pingcap/parser v0.0.0-20191107084102-68af6554dec7/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/parser v0.0.0-20191111144324-e3789d96ce4f h1:lcI2PXJM/qkF93w6+Sq1AhA5N9pNrAszTWxhGRAxtgM= +github.com/pingcap/parser v0.0.0-20191111144324-e3789d96ce4f/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0 h1:GIEq+wZfrl2bcJxpuSrEH4H7/nlf5YdmpS+dU9lNIt8= github.com/pingcap/pd v1.1.0-beta.0.20190923032047-5c648dc365e0/go.mod h1:G/6rJpnYwM0LKMec2rI82/5Kg6GaZMvlfB+e6/tvYmI= github.com/pingcap/tidb-tools v3.0.6-0.20191106033616-90632dda3863+incompatible h1:H1jg0aDWz2SLRh3hNBo2HFtnuHtudIUvBumU7syRkic= diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index d50afb958450b..ee14e317ae949 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -1045,7 +1045,7 @@ func (er *expressionRewriter) rewriteVariable(v *ast.VariableExpr) { } sysVar := variable.SysVars[name] if sysVar == nil { - er.err = variable.UnknownSystemVar.GenWithStackByArgs(name) + er.err = variable.ErrUnknownSystemVar.GenWithStackByArgs(name) return } // Variable is @@gobal.variable_name or variable is only global scope variable. diff --git a/session/session.go b/session/session.go index 3bb83e2ac2f10..70fec5373d495 100644 --- a/session/session.go +++ b/session/session.go @@ -935,7 +935,7 @@ func (s *session) GetGlobalSysVar(name string) (string, error) { if sv, ok := variable.SysVars[name]; ok { return sv.Value, nil } - return "", variable.UnknownSystemVar.GenWithStackByArgs(name) + return "", variable.ErrUnknownSystemVar.GenWithStackByArgs(name) } return "", err } diff --git a/sessionctx/variable/sysvar.go b/sessionctx/variable/sysvar.go index d253a9ba19834..3954d7f6027d1 100644 --- a/sessionctx/variable/sysvar.go +++ b/sessionctx/variable/sysvar.go @@ -60,32 +60,18 @@ func GetSysVar(name string) *SysVar { // PluginVarNames is global plugin var names set. var PluginVarNames []string -// Variable error codes. -const ( - CodeUnknownStatusVar terror.ErrCode = 1 - CodeUnknownSystemVar terror.ErrCode = mysql.ErrUnknownSystemVariable - CodeIncorrectScope terror.ErrCode = mysql.ErrIncorrectGlobalLocalVar - CodeUnknownTimeZone terror.ErrCode = mysql.ErrUnknownTimeZone - CodeReadOnly terror.ErrCode = mysql.ErrVariableIsReadonly - CodeWrongValueForVar terror.ErrCode = mysql.ErrWrongValueForVar - CodeWrongTypeForVar terror.ErrCode = mysql.ErrWrongTypeForVar - CodeTruncatedWrongValue terror.ErrCode = mysql.ErrTruncatedWrongValue - CodeMaxPreparedStmtCountReached terror.ErrCode = mysql.ErrMaxPreparedStmtCountReached -) - // Variable errors var ( - UnknownStatusVar = terror.ClassVariable.New(CodeUnknownStatusVar, "unknown status variable") - UnknownSystemVar = terror.ClassVariable.New(CodeUnknownSystemVar, mysql.MySQLErrName[mysql.ErrUnknownSystemVariable]) - ErrIncorrectScope = terror.ClassVariable.New(CodeIncorrectScope, mysql.MySQLErrName[mysql.ErrIncorrectGlobalLocalVar]) - ErrUnknownTimeZone = terror.ClassVariable.New(CodeUnknownTimeZone, mysql.MySQLErrName[mysql.ErrUnknownTimeZone]) - ErrReadOnly = terror.ClassVariable.New(CodeReadOnly, "variable is read only") - ErrWrongValueForVar = terror.ClassVariable.New(CodeWrongValueForVar, mysql.MySQLErrName[mysql.ErrWrongValueForVar]) - ErrWrongTypeForVar = terror.ClassVariable.New(CodeWrongTypeForVar, mysql.MySQLErrName[mysql.ErrWrongTypeForVar]) - ErrTruncatedWrongValue = terror.ClassVariable.New(CodeTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue]) - ErrMaxPreparedStmtCountReached = terror.ClassVariable.New(CodeMaxPreparedStmtCountReached, mysql.MySQLErrName[mysql.ErrMaxPreparedStmtCountReached]) - ErrUnsupportedValueForVar = terror.ClassVariable.New(CodeUnknownStatusVar, "variable '%s' does not yet support value: %s") - ErrUnsupportedIsolationLevel = terror.ClassVariable.New(CodeUnknownStatusVar, "The isolation level '%s' is not supported. Set tidb_skip_isolation_level_check=1 to skip this error") + ErrUnsupportedValueForVar = terror.ClassVariable.New(mysql.ErrUnsupportedValueForVar, mysql.MySQLErrName[mysql.ErrUnsupportedValueForVar]) + ErrUnknownSystemVar = terror.ClassVariable.New(mysql.ErrUnknownSystemVariable, mysql.MySQLErrName[mysql.ErrUnknownSystemVariable]) + ErrIncorrectScope = terror.ClassVariable.New(mysql.ErrIncorrectGlobalLocalVar, mysql.MySQLErrName[mysql.ErrIncorrectGlobalLocalVar]) + ErrUnknownTimeZone = terror.ClassVariable.New(mysql.ErrUnknownTimeZone, mysql.MySQLErrName[mysql.ErrUnknownTimeZone]) + ErrReadOnly = terror.ClassVariable.New(mysql.ErrVariableIsReadonly, mysql.MySQLErrName[mysql.ErrVariableIsReadonly]) + ErrWrongValueForVar = terror.ClassVariable.New(mysql.ErrWrongValueForVar, mysql.MySQLErrName[mysql.ErrWrongValueForVar]) + ErrWrongTypeForVar = terror.ClassVariable.New(mysql.ErrWrongTypeForVar, mysql.MySQLErrName[mysql.ErrWrongTypeForVar]) + ErrTruncatedWrongValue = terror.ClassVariable.New(mysql.ErrTruncatedWrongValue, mysql.MySQLErrName[mysql.ErrTruncatedWrongValue]) + ErrMaxPreparedStmtCountReached = terror.ClassVariable.New(mysql.ErrMaxPreparedStmtCountReached, mysql.MySQLErrName[mysql.ErrMaxPreparedStmtCountReached]) + ErrUnsupportedIsolationLevel = terror.ClassVariable.New(mysql.ErrUnsupportedIsolationLevel, mysql.MySQLErrName[mysql.ErrUnsupportedIsolationLevel]) ) func init() { @@ -97,14 +83,16 @@ func init() { // Register terror to mysql error map. mySQLErrCodes := map[terror.ErrCode]uint16{ - CodeUnknownSystemVar: mysql.ErrUnknownSystemVariable, - CodeIncorrectScope: mysql.ErrIncorrectGlobalLocalVar, - CodeUnknownTimeZone: mysql.ErrUnknownTimeZone, - CodeReadOnly: mysql.ErrVariableIsReadonly, - CodeWrongValueForVar: mysql.ErrWrongValueForVar, - CodeWrongTypeForVar: mysql.ErrWrongTypeForVar, - CodeTruncatedWrongValue: mysql.ErrTruncatedWrongValue, - CodeMaxPreparedStmtCountReached: mysql.ErrMaxPreparedStmtCountReached, + mysql.ErrUnsupportedValueForVar: mysql.ErrUnsupportedValueForVar, + mysql.ErrUnknownSystemVariable: mysql.ErrUnknownSystemVariable, + mysql.ErrIncorrectGlobalLocalVar: mysql.ErrIncorrectGlobalLocalVar, + mysql.ErrUnknownTimeZone: mysql.ErrUnknownTimeZone, + mysql.ErrVariableIsReadonly: mysql.ErrVariableIsReadonly, + mysql.ErrWrongValueForVar: mysql.ErrWrongValueForVar, + mysql.ErrWrongTypeForVar: mysql.ErrWrongTypeForVar, + mysql.ErrTruncatedWrongValue: mysql.ErrTruncatedWrongValue, + mysql.ErrMaxPreparedStmtCountReached: mysql.ErrMaxPreparedStmtCountReached, + mysql.ErrUnsupportedIsolationLevel: mysql.ErrUnsupportedIsolationLevel, } terror.ErrClassToMySQLCodes[terror.ClassVariable] = mySQLErrCodes } diff --git a/sessionctx/variable/sysvar_test.go b/sessionctx/variable/sysvar_test.go index 5a23978f98f56..7a7ed4ae5a3bd 100644 --- a/sessionctx/variable/sysvar_test.go +++ b/sessionctx/variable/sysvar_test.go @@ -17,6 +17,8 @@ import ( "testing" . "github.com/pingcap/check" + "github.com/pingcap/parser/mysql" + "github.com/pingcap/parser/terror" ) func TestT(t *testing.T) { @@ -69,3 +71,21 @@ func (*testSysVarSuite) TestBoolToInt32(c *C) { c.Assert(BoolToInt32(true), Equals, int32(1)) c.Assert(BoolToInt32(false), Equals, int32(0)) } + +func (*testSysVarSuite) TestError(c *C) { + kvErrs := []*terror.Error{ + ErrUnsupportedValueForVar, + ErrUnknownSystemVar, + ErrIncorrectScope, + ErrUnknownTimeZone, + ErrReadOnly, + ErrWrongValueForVar, + ErrWrongTypeForVar, + ErrTruncatedWrongValue, + ErrMaxPreparedStmtCountReached, + ErrUnsupportedIsolationLevel, + } + for _, err := range kvErrs { + c.Assert(err.ToSQLError().Code != mysql.ErrUnknown, IsTrue) + } +} diff --git a/sessionctx/variable/varsutil.go b/sessionctx/variable/varsutil.go index 6a783feb775a0..b6fd23d72eae4 100644 --- a/sessionctx/variable/varsutil.go +++ b/sessionctx/variable/varsutil.go @@ -108,7 +108,7 @@ func GetSessionSystemVar(s *SessionVars, key string) (string, error) { func GetSessionOnlySysVars(s *SessionVars, key string) (string, bool, error) { sysVar := SysVars[key] if sysVar == nil { - return "", false, UnknownSystemVar.GenWithStackByArgs(key) + return "", false, ErrUnknownSystemVar.GenWithStackByArgs(key) } // For virtual system variables: switch sysVar.Name { @@ -172,7 +172,7 @@ func GetGlobalSystemVar(s *SessionVars, key string) (string, error) { func GetScopeNoneSystemVar(key string) (string, bool, error) { sysVar := SysVars[key] if sysVar == nil { - return "", false, UnknownSystemVar.GenWithStackByArgs(key) + return "", false, ErrUnknownSystemVar.GenWithStackByArgs(key) } if sysVar.Scope == ScopeNone { return sysVar.Value, true, nil @@ -188,7 +188,7 @@ func SetSessionSystemVar(vars *SessionVars, name string, value types.Datum) erro name = strings.ToLower(name) sysVar := SysVars[name] if sysVar == nil { - return UnknownSystemVar + return ErrUnknownSystemVar } sVal := "" var err error @@ -209,7 +209,7 @@ func SetSessionSystemVar(vars *SessionVars, name string, value types.Datum) erro func ValidateGetSystemVar(name string, isGlobal bool) error { sysVar, exists := SysVars[name] if !exists { - return UnknownSystemVar.GenWithStackByArgs(name) + return ErrUnknownSystemVar.GenWithStackByArgs(name) } switch sysVar.Scope { case ScopeGlobal, ScopeNone: @@ -280,7 +280,7 @@ func ValidateSetSystemVar(vars *SessionVars, name string, value string) (string, if val := GetSysVar(name); val != nil { return val.Value, nil } - return value, UnknownSystemVar.GenWithStackByArgs(name) + return value, ErrUnknownSystemVar.GenWithStackByArgs(name) } switch name { case ConnectTimeout: diff --git a/util/mock/context.go b/util/mock/context.go index 139515dd59855..2b488a8679718 100644 --- a/util/mock/context.go +++ b/util/mock/context.go @@ -110,7 +110,7 @@ func (c *Context) GetClient() kv.Client { func (c *Context) GetGlobalSysVar(ctx sessionctx.Context, name string) (string, error) { v := variable.GetSysVar(name) if v == nil { - return "", variable.UnknownSystemVar.GenWithStackByArgs(name) + return "", variable.ErrUnknownSystemVar.GenWithStackByArgs(name) } return v.Value, nil } @@ -119,7 +119,7 @@ func (c *Context) GetGlobalSysVar(ctx sessionctx.Context, name string) (string, func (c *Context) SetGlobalSysVar(ctx sessionctx.Context, name string, value string) error { v := variable.GetSysVar(name) if v == nil { - return variable.UnknownSystemVar.GenWithStackByArgs(name) + return variable.ErrUnknownSystemVar.GenWithStackByArgs(name) } v.Value = value return nil