diff --git a/executor/ddl_test.go b/executor/ddl_test.go index b25211a8baa1e..f91bcf6d3be8e 100644 --- a/executor/ddl_test.go +++ b/executor/ddl_test.go @@ -26,6 +26,7 @@ import ( "github.com/pingcap/tidb/plan" "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/table" + "github.com/pingcap/tidb/terror" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/chunk" "github.com/pingcap/tidb/util/testkit" @@ -409,17 +410,15 @@ func (s *testSuite) TestSetDDLReorgWorkerCnt(c *C) { c.Assert(variable.GetDDLReorgWorkerCounter(), Equals, int32(1)) tk.MustExec("set tidb_ddl_reorg_worker_cnt = 100") c.Assert(variable.GetDDLReorgWorkerCounter(), Equals, int32(100)) - tk.MustExec("set tidb_ddl_reorg_worker_cnt = invalid_val") - c.Assert(variable.GetDDLReorgWorkerCounter(), Equals, int32(variable.DefTiDBDDLReorgWorkerCount)) + _, err := tk.Exec("set tidb_ddl_reorg_worker_cnt = invalid_val") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongTypeForVar), IsTrue) tk.MustExec("set tidb_ddl_reorg_worker_cnt = 100") c.Assert(variable.GetDDLReorgWorkerCounter(), Equals, int32(100)) - tk.MustExec("set tidb_ddl_reorg_worker_cnt = -1") - c.Assert(variable.GetDDLReorgWorkerCounter(), Equals, int32(variable.DefTiDBDDLReorgWorkerCount)) + _, err = tk.Exec("set tidb_ddl_reorg_worker_cnt = -1") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) - res := tk.MustQuery("select @@tidb_ddl_reorg_worker_cnt") - res.Check(testkit.Rows("-1")) tk.MustExec("set tidb_ddl_reorg_worker_cnt = 100") - res = tk.MustQuery("select @@tidb_ddl_reorg_worker_cnt") + res := tk.MustQuery("select @@tidb_ddl_reorg_worker_cnt") res.Check(testkit.Rows("100")) res = tk.MustQuery("select @@global.tidb_ddl_reorg_worker_cnt") diff --git a/executor/set_test.go b/executor/set_test.go index 064057f22acbf..bce2129bc7f6b 100644 --- a/executor/set_test.go +++ b/executor/set_test.go @@ -17,7 +17,9 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/terror" "github.com/pingcap/tidb/util/testkit" + "github.com/pingcap/tidb/util/testutil" "golang.org/x/net/context" ) @@ -88,16 +90,16 @@ func (s *testSuite) TestSetVar(c *C) { // Set default // {ScopeGlobal | ScopeSession, "low_priority_updates", "OFF"}, // For global var - tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("OFF")) + tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("0")) tk.MustExec(`set @@global.low_priority_updates="ON";`) - tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("ON")) + tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("1")) tk.MustExec(`set @@global.low_priority_updates=DEFAULT;`) // It will be set to compiled-in default value. - tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("OFF")) + tk.MustQuery(`select @@global.low_priority_updates;`).Check(testkit.Rows("0")) // For session - tk.MustQuery(`select @@session.low_priority_updates;`).Check(testkit.Rows("OFF")) + tk.MustQuery(`select @@session.low_priority_updates;`).Check(testkit.Rows("0")) tk.MustExec(`set @@global.low_priority_updates="ON";`) tk.MustExec(`set @@session.low_priority_updates=DEFAULT;`) // It will be set to global var value. - tk.MustQuery(`select @@session.low_priority_updates;`).Check(testkit.Rows("ON")) + tk.MustQuery(`select @@session.low_priority_updates;`).Check(testkit.Rows("1")) // For mysql jdbc driver issue. tk.MustQuery(`select @@session.tx_read_only;`).Check(testkit.Rows("0")) @@ -212,15 +214,15 @@ func (s *testSuite) TestSetVar(c *C) { tk.MustQuery("select @@session.tx_isolation").Check(testkit.Rows("READ-COMMITTED")) tk.MustExec("set global avoid_temporal_upgrade = on") - tk.MustQuery(`select @@global.avoid_temporal_upgrade;`).Check(testkit.Rows("ON")) + tk.MustQuery(`select @@global.avoid_temporal_upgrade;`).Check(testkit.Rows("1")) tk.MustExec("set @@global.avoid_temporal_upgrade = off") - tk.MustQuery(`select @@global.avoid_temporal_upgrade;`).Check(testkit.Rows("off")) + tk.MustQuery(`select @@global.avoid_temporal_upgrade;`).Check(testkit.Rows("0")) tk.MustExec("set session sql_log_bin = on") - tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("ON")) + tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("1")) tk.MustExec("set sql_log_bin = off") - tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("off")) + tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("0")) tk.MustExec("set @@sql_log_bin = on") - tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("ON")) + tk.MustQuery(`select @@session.sql_log_bin;`).Check(testkit.Rows("1")) } func (s *testSuite) TestSetCharset(c *C) { @@ -247,3 +249,66 @@ func (s *testSuite) TestSetCharset(c *C) { // Issue 1523 tk.MustExec(`SET NAMES binary`) } + +func (s *testSuite) TestValidateSetVar(c *C) { + tk := testkit.NewTestKit(c, s.store) + + _, err := tk.Exec("set global tidb_distsql_scan_concurrency='fff';") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongTypeForVar), IsTrue) + + _, err = tk.Exec("set global tidb_distsql_scan_concurrency=-1;") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) + + _, err = tk.Exec("set @@tidb_distsql_scan_concurrency='fff';") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongTypeForVar), IsTrue) + + _, err = tk.Exec("set @@tidb_distsql_scan_concurrency=-1;") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) + + _, err = tk.Exec("set @@tidb_batch_delete='ok';") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) + + tk.MustExec("set @@tidb_batch_delete='On';") + tk.MustExec("set @@tidb_batch_delete='oFf';") + tk.MustExec("set @@tidb_batch_delete=1;") + tk.MustExec("set @@tidb_batch_delete=0;") + + _, err = tk.Exec("set @@tidb_batch_delete=3;") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) + + _, err = tk.Exec("set @@tidb_mem_quota_mergejoin='tidb';") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongValueForVar), IsTrue) + + tk.MustExec("set @@group_concat_max_len=1") + tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Truncated incorrect group_concat_max_len value: '1'")) + result := tk.MustQuery("select @@group_concat_max_len;") + result.Check(testkit.Rows("4")) + + _, err = tk.Exec("set @@group_concat_max_len = 18446744073709551616") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongTypeForVar), IsTrue) + + // Test illegal type + _, err = tk.Exec("set @@group_concat_max_len='hello'") + c.Assert(terror.ErrorEqual(err, variable.ErrWrongTypeForVar), IsTrue) + + tk.MustExec("set @@default_week_format=-1") + tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Truncated incorrect default_week_format value: '-1'")) + result = tk.MustQuery("select @@default_week_format;") + result.Check(testkit.Rows("0")) + + tk.MustExec("set @@default_week_format=9") + tk.MustQuery("show warnings").Check(testutil.RowsWithSep("|", "Warning|1292|Truncated incorrect default_week_format value: '9'")) + result = tk.MustQuery("select @@default_week_format;") + result.Check(testkit.Rows("7")) + + _, err = tk.Exec("set @@error_count = 0") + c.Assert(terror.ErrorEqual(err, variable.ErrReadOnly), IsTrue) + + _, err = tk.Exec("set @@warning_count = 0") + c.Assert(terror.ErrorEqual(err, variable.ErrReadOnly), IsTrue) + + tk.MustExec("set time_zone='SySTeM'") + result = tk.MustQuery("select @@time_zone;") + result.Check(testkit.Rows("SYSTEM")) + +} diff --git a/session/session.go b/session/session.go index 066b9427004d5..311953b787f87 100644 --- a/session/session.go +++ b/session/session.go @@ -689,16 +689,22 @@ func (s *session) GetGlobalSysVar(name string) (string, error) { } // SetGlobalSysVar implements GlobalVarAccessor.SetGlobalSysVar interface. -func (s *session) SetGlobalSysVar(name string, value string) error { +func (s *session) SetGlobalSysVar(name, value string) error { if name == variable.SQLModeVar { value = mysql.FormatSQLModeStr(value) if _, err := mysql.GetSQLMode(value); err != nil { return errors.Trace(err) } } + var sVal string + var err error + sVal, err = variable.ValidateSetSystemVar(s.sessionVars, name, value) + if err != nil { + return errors.Trace(err) + } sql := fmt.Sprintf(`REPLACE %s.%s VALUES ('%s', '%s');`, - mysql.SystemDB, mysql.GlobalVariablesTable, strings.ToLower(name), value) - _, _, err := s.ExecRestrictedSQL(s, sql) + mysql.SystemDB, mysql.GlobalVariablesTable, strings.ToLower(name), sVal) + _, _, err = s.ExecRestrictedSQL(s, sql) return errors.Trace(err) } diff --git a/sessionctx/variable/session.go b/sessionctx/variable/session.go index 05bbd02b538bf..c792411e42b3e 100644 --- a/sessionctx/variable/session.go +++ b/sessionctx/variable/session.go @@ -545,8 +545,7 @@ func (s *SessionVars) SetSystemVar(name string, val string) error { case TiDBEnableTablePartition: s.EnableTablePartition = TiDBOptOn(val) case TiDBDDLReorgWorkerCount: - workerCnt := tidbOptPositiveInt32(val, DefTiDBDDLReorgWorkerCount) - SetDDLReorgWorkerCounter(int32(workerCnt)) + SetDDLReorgWorkerCounter(int32(tidbOptPositiveInt32(val, DefTiDBDDLReorgWorkerCount))) } s.systems[name] = val return nil diff --git a/sessionctx/variable/sysvar.go b/sessionctx/variable/sysvar.go index c2112ccf811c3..54bc6c7d83fb6 100644 --- a/sessionctx/variable/sysvar.go +++ b/sessionctx/variable/sysvar.go @@ -58,20 +58,26 @@ func GetSysVar(name string) *SysVar { // 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 + 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 ) // 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") + 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]) ) func init() { @@ -83,10 +89,13 @@ 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, + CodeUnknownSystemVar: mysql.ErrUnknownSystemVariable, + CodeIncorrectScope: mysql.ErrIncorrectGlobalLocalVar, + CodeUnknownTimeZone: mysql.ErrUnknownTimeZone, + CodeReadOnly: mysql.ErrVariableIsReadonly, + CodeWrongValueForVar: mysql.ErrWrongValueForVar, + CodeWrongTypeForVar: mysql.ErrWrongTypeForVar, + CodeTruncatedWrongValue: mysql.ErrTruncatedWrongValue, } terror.ErrClassToMySQLCodes[terror.ClassVariable] = mySQLErrCodes } @@ -101,17 +110,17 @@ func boolToIntStr(b bool) string { // we only support MySQL now var defaultSysVars = []*SysVar{ {ScopeGlobal, "gtid_mode", "OFF"}, - {ScopeGlobal, "flush_time", "0"}, - {ScopeSession, "pseudo_slave_mode", ""}, + {ScopeGlobal, FlushTime, "0"}, + {ScopeSession, PseudoSlaveMode, ""}, {ScopeNone, "performance_schema_max_mutex_classes", "200"}, - {ScopeGlobal | ScopeSession, "low_priority_updates", "OFF"}, - {ScopeGlobal | ScopeSession, "session_track_gtids", ""}, + {ScopeGlobal | ScopeSession, LowPriorityUpdates, "0"}, + {ScopeGlobal | ScopeSession, SessionTrackGtids, "OFF"}, {ScopeGlobal | ScopeSession, "ndbinfo_max_rows", ""}, {ScopeGlobal | ScopeSession, "ndb_index_stat_option", ""}, - {ScopeGlobal | ScopeSession, "old_passwords", "0"}, + {ScopeGlobal | ScopeSession, OldPasswords, "0"}, {ScopeNone, "innodb_version", "5.6.25"}, - {ScopeGlobal, "max_connections", "151"}, - {ScopeGlobal | ScopeSession, "big_tables", "OFF"}, + {ScopeGlobal, MaxConnections, "151"}, + {ScopeGlobal | ScopeSession, BigTables, "0"}, {ScopeNone, "skip_external_locking", "ON"}, {ScopeGlobal, "slave_pending_jobs_size_max", "16777216"}, {ScopeNone, "innodb_sync_array_size", "1"}, @@ -121,7 +130,7 @@ var defaultSysVars = []*SysVar{ {ScopeGlobal | ScopeSession, "sql_select_limit", "18446744073709551615"}, {ScopeGlobal, "ndb_show_foreign_key_mock_tables", ""}, {ScopeNone, "multi_range_count", "256"}, - {ScopeGlobal | ScopeSession, "default_week_format", "0"}, + {ScopeGlobal | ScopeSession, DefaultWeekFormat, "0"}, {ScopeGlobal | ScopeSession, "binlog_error_action", "IGNORE_ERROR"}, {ScopeGlobal, "slave_transaction_retries", "10"}, {ScopeGlobal | ScopeSession, "default_storage_engine", "InnoDB"}, @@ -137,7 +146,7 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "lc_messages_dir", "/usr/local/mysql-5.6.25-osx10.8-x86_64/share/"}, {ScopeGlobal, "ft_boolean_syntax", "+ -><()~*:\"\"&|"}, {ScopeGlobal, "table_definition_cache", "1400"}, - {ScopeNone, "skip_name_resolve", "OFF"}, + {ScopeNone, SkipNameResolve, "0"}, {ScopeNone, "performance_schema_max_file_handles", "32768"}, {ScopeSession, "transaction_allow_batching", ""}, {ScopeGlobal | ScopeSession, SQLModeVar, mysql.DefaultSQLMode}, @@ -148,7 +157,7 @@ var defaultSysVars = []*SysVar{ {ScopeGlobal, "innodb_max_purge_lag", "0"}, {ScopeGlobal | ScopeSession, "preload_buffer_size", "32768"}, {ScopeGlobal, "slave_checkpoint_period", "300"}, - {ScopeGlobal, "check_proxy_users", ""}, + {ScopeGlobal, CheckProxyUsers, "0"}, {ScopeNone, "have_query_cache", "YES"}, {ScopeGlobal, "innodb_flush_log_at_timeout", "1"}, {ScopeGlobal, "innodb_max_undo_log_size", ""}, @@ -164,7 +173,7 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "innodb_ft_sort_pll_degree", "2"}, {ScopeNone, "thread_stack", "262144"}, {ScopeGlobal, "relay_log_info_repository", "FILE"}, - {ScopeGlobal | ScopeSession, "sql_log_bin", "ON"}, + {ScopeGlobal | ScopeSession, SQLLogBin, "1"}, {ScopeGlobal, "super_read_only", "OFF"}, {ScopeGlobal | ScopeSession, "max_delayed_threads", "20"}, {ScopeNone, "protocol_version", "10"}, @@ -183,7 +192,7 @@ var defaultSysVars = []*SysVar{ {ScopeGlobal, "innodb_log_write_ahead_size", ""}, {ScopeNone, "innodb_log_group_home_dir", "./"}, {ScopeNone, "performance_schema_events_statements_history_size", "10"}, - {ScopeGlobal, "general_log", "OFF"}, + {ScopeGlobal, GeneralLog, "0"}, {ScopeGlobal, "validate_password_dictionary_file", ""}, {ScopeGlobal, "binlog_order_commits", "ON"}, {ScopeGlobal, "master_verify_checksum", "OFF"}, @@ -211,15 +220,15 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "innodb_autoinc_lock_mode", "1"}, {ScopeGlobal, "slave_net_timeout", "3600"}, {ScopeGlobal, "key_buffer_size", "8388608"}, - {ScopeGlobal | ScopeSession, "foreign_key_checks", "ON"}, + {ScopeGlobal | ScopeSession, ForeignKeyChecks, "1"}, {ScopeGlobal, "host_cache_size", "279"}, - {ScopeGlobal, "delay_key_write", "ON"}, + {ScopeGlobal, DelayKeyWrite, "ON"}, {ScopeNone, "metadata_locks_cache_size", "1024"}, {ScopeNone, "innodb_force_recovery", "0"}, {ScopeGlobal, "innodb_file_format_max", "Antelope"}, {ScopeGlobal | ScopeSession, "debug", ""}, {ScopeGlobal, "log_warnings", "1"}, - {ScopeGlobal, "offline_mode", ""}, + {ScopeGlobal, OfflineMode, "0"}, {ScopeGlobal | ScopeSession, "innodb_strict_mode", "OFF"}, {ScopeGlobal, "innodb_rollback_segments", "128"}, {ScopeGlobal | ScopeSession, "join_buffer_size", "262144"}, @@ -252,7 +261,7 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "thread_concurrency", "10"}, {ScopeGlobal | ScopeSession, "query_prealloc_size", "8192"}, {ScopeNone, "relay_log_space_limit", "0"}, - {ScopeGlobal | ScopeSession, "max_user_connections", "0"}, + {ScopeGlobal | ScopeSession, MaxUserConnections, "0"}, {ScopeNone, "performance_schema_max_thread_classes", "50"}, {ScopeGlobal, "innodb_api_trx_level", "0"}, {ScopeNone, "disconnect_on_expired_password", "ON"}, @@ -316,12 +325,12 @@ var defaultSysVars = []*SysVar{ {ScopeGlobal, "ndb_optimization_delay", ""}, {ScopeGlobal, "innodb_ft_num_word_optimize", "2000"}, {ScopeGlobal | ScopeSession, "max_join_size", "18446744073709551615"}, - {ScopeNone, "core_file", "OFF"}, + {ScopeNone, CoreFile, "0"}, {ScopeGlobal | ScopeSession, "max_seeks_for_key", "18446744073709551615"}, {ScopeNone, "innodb_log_buffer_size", "8388608"}, {ScopeGlobal, "delayed_insert_timeout", "300"}, {ScopeGlobal, "max_relay_log_size", "0"}, - {ScopeGlobal | ScopeSession, "max_sort_length", "1024"}, + {ScopeGlobal | ScopeSession, MaxSortLength, "1024"}, {ScopeNone, "metadata_locks_hash_instances", "8"}, {ScopeGlobal, "ndb_eventbuffer_free_percent", ""}, {ScopeNone, "large_files_support", "ON"}, @@ -461,7 +470,7 @@ var defaultSysVars = []*SysVar{ {ScopeGlobal | ScopeSession, "lock_wait_timeout", "31536000"}, {ScopeGlobal | ScopeSession, "read_buffer_size", "131072"}, {ScopeNone, "innodb_read_io_threads", "4"}, - {ScopeGlobal | ScopeSession, "max_sp_recursion_depth", "0"}, + {ScopeGlobal | ScopeSession, MaxSpRecursionDepth, "0"}, {ScopeNone, "ignore_builtin_innodb", "OFF"}, {ScopeGlobal, "rpl_semi_sync_master_enabled", ""}, {ScopeGlobal, "slow_query_log_file", "/usr/local/mysql/data/localhost-slow.log"}, @@ -558,7 +567,7 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "back_log", "80"}, {ScopeNone, "lower_case_file_system", "ON"}, {ScopeGlobal, "rpl_semi_sync_master_wait_no_slave", ""}, - {ScopeGlobal | ScopeSession, "group_concat_max_len", "1024"}, + {ScopeGlobal | ScopeSession, GroupConcatMaxLen, "1024"}, {ScopeSession, "pseudo_thread_id", ""}, {ScopeNone, "socket", "/tmp/myssock"}, {ScopeNone, "have_dynamic_loading", "YES"}, @@ -591,23 +600,23 @@ var defaultSysVars = []*SysVar{ {ScopeNone, "innodb_undo_directory", "."}, {ScopeNone, "bind_address", "*"}, {ScopeGlobal, "innodb_sync_spin_loops", "30"}, - {ScopeGlobal | ScopeSession, "sql_safe_updates", "OFF"}, + {ScopeGlobal | ScopeSession, SQLSafeUpdates, "0"}, {ScopeNone, "tmpdir", "/var/tmp/"}, {ScopeGlobal, "innodb_thread_concurrency", "0"}, {ScopeGlobal, "slave_allow_batching", "OFF"}, {ScopeGlobal, "innodb_buffer_pool_dump_pct", ""}, {ScopeGlobal | ScopeSession, "lc_time_names", "en_US"}, {ScopeGlobal | ScopeSession, "max_statement_time", ""}, - {ScopeGlobal | ScopeSession, "end_markers_in_json", "OFF"}, - {ScopeGlobal, "avoid_temporal_upgrade", "OFF"}, + {ScopeGlobal | ScopeSession, EndMakersInJSON, "0"}, + {ScopeGlobal, AvoidTemporalUpgrade, "0"}, {ScopeGlobal, "key_cache_age_threshold", "300"}, {ScopeGlobal, "innodb_status_output", "OFF"}, {ScopeSession, "identity", ""}, {ScopeGlobal | ScopeSession, "min_examined_row_limit", "0"}, {ScopeGlobal, "sync_frm", "ON"}, {ScopeGlobal, "innodb_online_alter_log_max_size", "134217728"}, - {ScopeSession, "warning_count", "0"}, - {ScopeSession, "error_count", "0"}, + {ScopeSession, WarningCount, "0"}, + {ScopeSession, ErrorCount, "0"}, /* TiDB specific variables */ {ScopeSession, TiDBSnapshot, ""}, {ScopeSession, TiDBImportingData, "0"}, @@ -683,6 +692,58 @@ const ( CharsetDatabase = "character_set_database" // CollationDatabase is the name for collation_database system variable. CollationDatabase = "collation_database" + // GeneralLog is the name for 'general_log' system variable. + GeneralLog = "general_log" + // AvoidTemporalUpgrade is the name for 'avoid_temporal_upgrade' system variable. + AvoidTemporalUpgrade = "avoid_temporal_upgrade" + // BigTables is the name for 'big_tables' system variable. + BigTables = "big_tables" + // CheckProxyUsers is the name for 'check_proxy_users' system variable. + CheckProxyUsers = "check_proxy_users" + // CoreFile is the name for 'core_file' system variable. + CoreFile = "core_file" + // DefaultWeekFormat is the name for 'default_week_format' system variable. + DefaultWeekFormat = "default_week_format" + // GroupConcatMaxLen is the name for 'group_concat_max_len' system variable. + GroupConcatMaxLen = "group_concat_max_len" + // DelayKeyWrite is the name for 'delay_key_write' system variable. + DelayKeyWrite = "delay_key_write" + // EndMakersInJSON is the name for 'end_markers_in_json' system variable. + EndMakersInJSON = "end_markers_in_json" + // SQLLogBin is the name for 'sql_log_bin' system variable. + SQLLogBin = "sql_log_bin" + // MaxSortLength is the name for 'max_sort_length' system variable. + MaxSortLength = "max_sort_length" + // MaxSpRecursionDepth is the name for 'max_sp_recursion_depth' system variable. + MaxSpRecursionDepth = "max_sp_recursion_depth" + // MaxUserConnections is the name for 'max_user_connections' system variable. + MaxUserConnections = "max_user_connections" + // OfflineMode is the name for 'offline_mode' system variable. + OfflineMode = "offline_mode" + // InteractiveTimeout is the name for 'interactive_timeout' system variable. + InteractiveTimeout = "interactive_timeout" + // FlushTime is the name for 'flush_time' system variable. + FlushTime = "flush_time" + // PseudoSlaveMode is the name for 'pseudo_slave_mode' system variable. + PseudoSlaveMode = "pseudo_slave_mode" + // LowPriorityUpdates is the name for 'low_priority_updates' system variable. + LowPriorityUpdates = "low_priority_updates" + // SessionTrackGtids is the name for 'session_track_gtids' system variable. + SessionTrackGtids = "session_track_gtids" + // OldPasswords is the name for 'old_passwords' system variable. + OldPasswords = "old_passwords" + // MaxConnections is the name for 'max_connections' system variable. + MaxConnections = "max_connections" + // SkipNameResolve is the name for 'skip_name_resolve' system variable. + SkipNameResolve = "skip_name_resolve" + // ForeignKeyChecks is the name for 'foreign_key_checks' system variable. + ForeignKeyChecks = "foreign_key_checks" + // SQLSafeUpdates is the name for 'sql_safe_updates' system variable. + SQLSafeUpdates = "sql_safe_updates" + // WarningCount is the name for 'warning_count' system variable. + WarningCount = "warning_count" + // ErrorCount is the name for 'error_count' system variable. + ErrorCount = "error_count" ) // GlobalVarAccessor is the interface for accessing global scope system and status variables. diff --git a/sessionctx/variable/varsutil.go b/sessionctx/variable/varsutil.go index 8e93112bdac50..3ad457c76838a 100644 --- a/sessionctx/variable/varsutil.go +++ b/sessionctx/variable/varsutil.go @@ -130,7 +130,13 @@ func SetSessionSystemVar(vars *SessionVars, name string, value types.Datum) erro if value.IsNull() { return vars.deleteSystemVar(name) } - sVal, err := value.ToString() + var sVal string + var err error + sVal, err = value.ToString() + if err != nil { + return errors.Trace(err) + } + sVal, err = ValidateSetSystemVar(vars, name, sVal) if err != nil { return errors.Trace(err) } @@ -156,6 +162,202 @@ func ValidateGetSystemVar(name string, isGlobal bool) error { return nil } +// ValidateSetSystemVar checks if system variable satisfies specific restriction. +func ValidateSetSystemVar(vars *SessionVars, name string, value string) (string, error) { + if strings.EqualFold(value, "DEFAULT") { + if val := GetSysVar(name); val != nil { + return val.Value, nil + } + return value, UnknownSystemVar.GenByArgs(name) + } + switch name { + case DefaultWeekFormat: + val, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 0 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "0", nil + } + if val > 7 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "7", nil + } + case DelayKeyWrite: + if strings.EqualFold(value, "ON") || value == "1" { + return "ON", nil + } else if strings.EqualFold(value, "OFF") || value == "0" { + return "OFF", nil + } else if strings.EqualFold(value, "ALL") || value == "2" { + return "ALL", nil + } + return value, ErrWrongValueForVar.GenByArgs(name, value) + case FlushTime: + val, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 0 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "0", nil + } + case GroupConcatMaxLen: + val, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 4 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "4", nil + } + if val > 18446744073709551615 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "18446744073709551615", nil + } + case InteractiveTimeout: + val, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 1 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "1", nil + } + case MaxConnections: + val, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 1 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "1", nil + } + if val > 100000 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "100000", nil + } + case MaxSortLength: + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 4 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "4", nil + } + if val > 8388608 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "8388608", nil + } + case MaxSpRecursionDepth: + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 0 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "0", nil + } + if val > 255 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "255", nil + } + case OldPasswords: + val, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 0 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "0", nil + } + if val > 2 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "2", nil + } + case MaxUserConnections: + val, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if val < 0 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "0", nil + } + if val > 4294967295 { + vars.StmtCtx.AppendWarning(ErrTruncatedWrongValue.GenByArgs(name, value)) + return "4294967295", nil + } + case SessionTrackGtids: + if strings.EqualFold(value, "OFF") || value == "0" { + return "OFF", nil + } else if strings.EqualFold(value, "OWN_GTID") || value == "1" { + return "OWN_GTID", nil + } else if strings.EqualFold(value, "ALL_GTIDS") || value == "2" { + return "ALL_GTIDS", nil + } + return value, ErrWrongValueForVar.GenByArgs(name, value) + case TimeZone: + if strings.EqualFold(value, "SYSTEM") { + return "SYSTEM", nil + } + return value, nil + case WarningCount, ErrorCount: + return value, ErrReadOnly.GenByArgs(name) + case GeneralLog, AvoidTemporalUpgrade, BigTables, CheckProxyUsers, CoreFile, EndMakersInJSON, SQLLogBin, OfflineMode, + PseudoSlaveMode, LowPriorityUpdates, SkipNameResolve, ForeignKeyChecks, SQLSafeUpdates: + if strings.EqualFold(value, "ON") || value == "1" { + return "1", nil + } else if strings.EqualFold(value, "OFF") || value == "0" { + return "0", nil + } + return value, ErrWrongValueForVar.GenByArgs(name, value) + case AutocommitVar, TiDBImportingData, TiDBSkipUTF8Check, TiDBOptAggPushDown, + TiDBOptInSubqUnFolding, TiDBEnableTablePartition, + TiDBBatchInsert, TiDBDisableTxnAutoRetry, TiDBEnableStreaming, + TiDBBatchDelete: + if strings.EqualFold(value, "ON") || value == "1" || strings.EqualFold(value, "OFF") || value == "0" { + return value, nil + } + return value, ErrWrongValueForVar.GenByArgs(name, value) + case TiDBIndexLookupConcurrency, TiDBIndexLookupJoinConcurrency, TiDBIndexJoinBatchSize, + TiDBIndexLookupSize, + TiDBHashJoinConcurrency, + TiDBHashAggPartialConcurrency, + TiDBHashAggFinalConcurrency, + TiDBDistSQLScanConcurrency, + TiDBIndexSerialScanConcurrency, TiDBDDLReorgWorkerCount, + TiDBBackoffLockFast, TiDBMaxChunkSize, + TiDBDMLBatchSize, TiDBOptimizerSelectivityLevel, + TiDBGeneralLog: + v, err := strconv.Atoi(value) + if err != nil { + return value, ErrWrongTypeForVar.GenByArgs(name) + } + if v <= 0 { + return value, ErrWrongValueForVar.GenByArgs(name, value) + } + return value, nil + case TiDBProjectionConcurrency, + TIDBMemQuotaQuery, + TIDBMemQuotaHashJoin, + TIDBMemQuotaMergeJoin, + TIDBMemQuotaSort, + TIDBMemQuotaTopn, + TIDBMemQuotaIndexLookupReader, + TIDBMemQuotaIndexLookupJoin, + TIDBMemQuotaNestedLoopApply, + TiDBRetryLimit: + _, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return value, ErrWrongValueForVar.GenByArgs(name) + } + return value, nil + } + return value, nil +} + // TiDBOptOn could be used for all tidb session variable options, we use "ON"/1 to turn on those options. func TiDBOptOn(opt string) bool { return strings.EqualFold(opt, "ON") || opt == "1" @@ -178,7 +380,7 @@ func tidbOptInt64(opt string, defaultVal int64) int64 { } func parseTimeZone(s string) (*time.Location, error) { - if s == "SYSTEM" { + if strings.EqualFold(s, "SYSTEM") { // TODO: Support global time_zone variable, it should be set to global time_zone value. return time.Local, nil } diff --git a/sessionctx/variable/varsutil_test.go b/sessionctx/variable/varsutil_test.go index 4ec98a2f26bb8..dce99c095bd6c 100644 --- a/sessionctx/variable/varsutil_test.go +++ b/sessionctx/variable/varsutil_test.go @@ -223,11 +223,11 @@ func (s *testVarsutilSuite) TestVarsutil(c *C) { SetSessionSystemVar(v, TiDBDDLReorgWorkerCount, types.NewIntDatum(1)) c.Assert(GetDDLReorgWorkerCounter(), Equals, int32(1)) - SetSessionSystemVar(v, TiDBDDLReorgWorkerCount, types.NewIntDatum(-1)) - c.Assert(GetDDLReorgWorkerCounter(), Equals, int32(DefTiDBDDLReorgWorkerCount)) + err = SetSessionSystemVar(v, TiDBDDLReorgWorkerCount, types.NewIntDatum(-1)) + c.Assert(terror.ErrorEqual(err, ErrWrongValueForVar), IsTrue) SetSessionSystemVar(v, TiDBDDLReorgWorkerCount, types.NewIntDatum(int64(maxDDLReorgWorkerCount)+1)) - c.Assert(GetDDLReorgWorkerCounter(), Equals, int32(maxDDLReorgWorkerCount)) + c.Assert(terror.ErrorEqual(err, ErrWrongValueForVar), IsTrue) err = SetSessionSystemVar(v, TiDBRetryLimit, types.NewStringDatum("3")) c.Assert(err, IsNil)