github.com/matrixorigin/matrixone@v0.7.0/pkg/frontend/variables.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package frontend
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"math"
    21  	bits2 "math/bits"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/container/types"
    29  	"github.com/matrixorigin/matrixone/pkg/defines"
    30  )
    31  
    32  var (
    33  	errorConvertToBoolFailed   = moerr.NewInternalError(context.Background(), "convert to the system variable bool type failed")
    34  	errorConvertToIntFailed    = moerr.NewInternalError(context.Background(), "convert to the system variable int type failed")
    35  	errorConvertToUintFailed   = moerr.NewInternalError(context.Background(), "convert to the system variable uint type failed")
    36  	errorConvertToDoubleFailed = moerr.NewInternalError(context.Background(), "convert to the system variable double type failed")
    37  	errorConvertToEnumFailed   = moerr.NewInternalError(context.Background(), "convert to the system variable enum type failed")
    38  	errorConvertToSetFailed    = moerr.NewInternalError(context.Background(), "convert to the system variable set type failed")
    39  	errorConvertToStringFailed = moerr.NewInternalError(context.Background(), "convert to the system variable string type failed")
    40  	errorConvertToNullFailed   = moerr.NewInternalError(context.Background(), "convert to the system variable null type failed")
    41  )
    42  
    43  func errorSystemVariableDoesNotExist() string { return "the system variable does not exist" }
    44  func errorSystemVariableIsSession() string    { return "the system variable is session" }
    45  func errorSystemVariableSessionEmpty() string {
    46  	return "the value of the system variable with scope session is empty"
    47  }
    48  func errorSystemVariableIsGlobal() string   { return "the system variable is global" }
    49  func errorSystemVariableIsReadOnly() string { return "the system variable is read only" }
    50  
    51  type Scope int
    52  
    53  const (
    54  	ScopeGlobal       Scope = iota //it is only in global
    55  	ScopeSession                   //it is only in session
    56  	ScopeBoth                      //it is both in global and session
    57  	ScopePersist                   //it is global and persisted
    58  	ScopePersistOnly               //it is persisted without updating global and session values
    59  	ScopeResetPersist              //to remove a persisted variable
    60  )
    61  
    62  func (s Scope) String() string {
    63  	switch s {
    64  	case ScopeGlobal:
    65  		return "GLOBAL"
    66  	case ScopeSession:
    67  		return "SESSION"
    68  	case ScopeBoth:
    69  		return "GLOBAL, SESSION"
    70  	case ScopePersist:
    71  		return "GLOBAL, PERSIST"
    72  	case ScopePersistOnly:
    73  		return "PERSIST"
    74  	case ScopeResetPersist:
    75  		return "RESET PERSIST"
    76  	default:
    77  		return "UNKNOWN_SYSTEM_SCOPE"
    78  	}
    79  }
    80  
    81  type SystemVariableType interface {
    82  	fmt.Stringer
    83  
    84  	// Convert the value to another value of the type
    85  	Convert(value interface{}) (interface{}, error)
    86  
    87  	// Type gets the type in the computation engine
    88  	Type() types.T
    89  
    90  	// MysqlType gets the mysql type
    91  	MysqlType() defines.MysqlType
    92  
    93  	// Zero gets the zero value for the type
    94  	Zero() interface{}
    95  }
    96  
    97  var _ SystemVariableType = SystemVariableBoolType{}
    98  var _ SystemVariableType = SystemVariableIntType{}
    99  var _ SystemVariableType = SystemVariableUintType{}
   100  var _ SystemVariableType = SystemVariableDoubleType{}
   101  var _ SystemVariableType = SystemVariableEnumType{}
   102  var _ SystemVariableType = SystemVariableSetType{}
   103  var _ SystemVariableType = SystemVariableStringType{}
   104  var _ SystemVariableType = SystemVariableNullType{}
   105  
   106  type SystemVariableNullType struct {
   107  }
   108  
   109  func (svnt SystemVariableNullType) String() string {
   110  	return "NULL"
   111  }
   112  
   113  func (svnt SystemVariableNullType) Convert(value interface{}) (interface{}, error) {
   114  	if value != nil {
   115  		return nil, errorConvertToNullFailed
   116  	}
   117  	return nil, nil
   118  }
   119  
   120  func (svnt SystemVariableNullType) Type() types.T {
   121  	return types.T_any
   122  }
   123  
   124  func (svnt SystemVariableNullType) MysqlType() defines.MysqlType {
   125  	return defines.MYSQL_TYPE_NULL
   126  }
   127  
   128  func (svnt SystemVariableNullType) Zero() interface{} {
   129  	return nil
   130  }
   131  
   132  type SystemVariableBoolType struct {
   133  	name string
   134  }
   135  
   136  func InitSystemVariableBoolType(name string) SystemVariableBoolType {
   137  	return SystemVariableBoolType{
   138  		name: name,
   139  	}
   140  }
   141  
   142  func (svbt SystemVariableBoolType) String() string {
   143  	return "BOOL"
   144  }
   145  
   146  func (svbt SystemVariableBoolType) Convert(value interface{}) (interface{}, error) {
   147  	cv1 := func(x int8) (interface{}, error) {
   148  		if x == 0 || x == 1 {
   149  			return x, nil
   150  		}
   151  		return nil, errorConvertToBoolFailed
   152  	}
   153  	cv2 := func(x float64) (interface{}, error) {
   154  		xx := int64(x)
   155  		rxx := float64(xx)
   156  		if x == rxx {
   157  			return cv1(int8(xx))
   158  		}
   159  		return nil, errorConvertToBoolFailed
   160  	}
   161  	cv3 := func(x string) (interface{}, error) {
   162  		switch strings.ToLower(x) {
   163  		case "on", "true":
   164  			return int8(1), nil
   165  		case "off", "false":
   166  			return int8(0), nil
   167  		}
   168  		return nil, errorConvertToBoolFailed
   169  	}
   170  	switch v := value.(type) {
   171  	case int:
   172  		return cv1(int8(v))
   173  	case uint:
   174  		return cv1(int8(v))
   175  	case int8:
   176  		return cv1(v)
   177  	case int16:
   178  		return cv1(int8(v))
   179  	case uint16:
   180  		return cv1(int8(v))
   181  	case int32:
   182  		return cv1(int8(v))
   183  	case uint32:
   184  		return cv1(int8(v))
   185  	case int64:
   186  		return cv1(int8(v))
   187  	case uint64:
   188  		return cv1(int8(v))
   189  	case bool:
   190  		if v {
   191  			return int8(1), nil
   192  		} else {
   193  			return int8(0), nil
   194  		}
   195  	case float32:
   196  		return cv2(float64(v))
   197  	case float64:
   198  		return cv2(v)
   199  	case string:
   200  		return cv3(v)
   201  	}
   202  	return nil, errorConvertToBoolFailed
   203  }
   204  
   205  func (svbt SystemVariableBoolType) IsTrue(v interface{}) bool {
   206  	if vv, ok := v.(int8); ok {
   207  		return vv == int8(1)
   208  	} else if vv3, ok3 := v.(int64); ok3 {
   209  		return vv3 == int64(1)
   210  	} else if vv2, ok2 := v.(string); ok2 {
   211  		return strings.ToLower(vv2) == "on"
   212  	}
   213  	return false
   214  }
   215  
   216  func (svbt SystemVariableBoolType) Type() types.T {
   217  	return types.T_bool
   218  }
   219  
   220  func (svbt SystemVariableBoolType) MysqlType() defines.MysqlType {
   221  	return defines.MYSQL_TYPE_BOOL
   222  }
   223  
   224  func (svbt SystemVariableBoolType) Zero() interface{} {
   225  	return int8(0)
   226  }
   227  
   228  type SystemVariableIntType struct {
   229  	name    string
   230  	minimum int64
   231  	maximum int64
   232  	//-1 ?
   233  	maybeMinusOne bool
   234  }
   235  
   236  func InitSystemVariableIntType(name string, minimum, maximum int64, maybeMinusOne bool) SystemVariableIntType {
   237  	return SystemVariableIntType{
   238  		name:          name,
   239  		minimum:       minimum,
   240  		maximum:       maximum,
   241  		maybeMinusOne: maybeMinusOne,
   242  	}
   243  }
   244  
   245  func (svit SystemVariableIntType) String() string {
   246  	return "INT"
   247  }
   248  
   249  func (svit SystemVariableIntType) Convert(value interface{}) (interface{}, error) {
   250  	cv1 := func(x int64) (interface{}, error) {
   251  		if x >= svit.minimum && x <= svit.maximum {
   252  			return x, nil
   253  		} else if svit.maybeMinusOne && x == -1 {
   254  			return x, nil
   255  		}
   256  		return nil, errorConvertToIntFailed
   257  	}
   258  	cv2 := func(x float64) (interface{}, error) {
   259  		xx := int64(x)
   260  		rxx := float64(xx)
   261  		if x == rxx {
   262  			return cv1(xx)
   263  		}
   264  		return nil, errorConvertToIntFailed
   265  	}
   266  
   267  	switch v := value.(type) {
   268  	case int:
   269  		return cv1(int64(v))
   270  	case uint:
   271  		return cv1(int64(v))
   272  	case int8:
   273  		return cv1(int64(v))
   274  	case uint8:
   275  		return cv1(int64(v))
   276  	case int16:
   277  		return cv1(int64(v))
   278  	case uint16:
   279  		return cv1(int64(v))
   280  	case int32:
   281  		return cv1(int64(v))
   282  	case uint32:
   283  		return cv1(int64(v))
   284  	case int64:
   285  		return cv1(v)
   286  	case uint64:
   287  		return cv1(int64(v))
   288  	case float32:
   289  		return cv2(float64(v))
   290  	case float64:
   291  		return cv2(v)
   292  	}
   293  	return nil, errorConvertToIntFailed
   294  }
   295  
   296  func (svit SystemVariableIntType) Type() types.T {
   297  	return types.T_int64
   298  }
   299  
   300  func (svit SystemVariableIntType) MysqlType() defines.MysqlType {
   301  	return defines.MYSQL_TYPE_LONGLONG
   302  }
   303  
   304  func (svit SystemVariableIntType) Zero() interface{} {
   305  	return int64(0)
   306  }
   307  
   308  type SystemVariableUintType struct {
   309  	name    string
   310  	minimum uint64
   311  	maximum uint64
   312  }
   313  
   314  func InitSystemVariableUintType(name string, minimum, maximum uint64) SystemVariableUintType {
   315  	return SystemVariableUintType{
   316  		name:    name,
   317  		minimum: minimum,
   318  		maximum: maximum,
   319  	}
   320  }
   321  
   322  func (svut SystemVariableUintType) String() string {
   323  	return "UINT"
   324  }
   325  
   326  func (svut SystemVariableUintType) Convert(value interface{}) (interface{}, error) {
   327  	cv1 := func(x uint64) (interface{}, error) {
   328  		if x >= svut.minimum && x <= svut.maximum {
   329  			return x, nil
   330  		}
   331  		return nil, errorConvertToUintFailed
   332  	}
   333  	cv2 := func(x float64) (interface{}, error) {
   334  		xx := uint64(x)
   335  		rxx := float64(xx)
   336  		if x == rxx {
   337  			return cv1(xx)
   338  		}
   339  		return nil, errorConvertToUintFailed
   340  	}
   341  
   342  	switch v := value.(type) {
   343  	case int:
   344  		return cv1(uint64(v))
   345  	case uint:
   346  		return cv1(uint64(v))
   347  	case int8:
   348  		return cv1(uint64(v))
   349  	case uint8:
   350  		return cv1(uint64(v))
   351  	case int16:
   352  		return cv1(uint64(v))
   353  	case uint16:
   354  		return cv1(uint64(v))
   355  	case int32:
   356  		return cv1(uint64(v))
   357  	case uint32:
   358  		return cv1(uint64(v))
   359  	case int64:
   360  		return cv1(uint64(v))
   361  	case uint64:
   362  		return cv1(v)
   363  	case float32:
   364  		return cv2(float64(v))
   365  	case float64:
   366  		return cv2(v)
   367  	}
   368  	return nil, errorConvertToUintFailed
   369  }
   370  
   371  func (svut SystemVariableUintType) Type() types.T {
   372  	return types.T_uint64
   373  }
   374  
   375  func (svut SystemVariableUintType) MysqlType() defines.MysqlType {
   376  	return defines.MYSQL_TYPE_LONGLONG
   377  }
   378  
   379  func (svut SystemVariableUintType) Zero() interface{} {
   380  	return uint64(0)
   381  }
   382  
   383  type SystemVariableDoubleType struct {
   384  	// Unused
   385  	// name    string
   386  	minimum float64
   387  	maximum float64
   388  }
   389  
   390  func (svdt SystemVariableDoubleType) String() string {
   391  	return "DOUBLE"
   392  }
   393  
   394  func (svdt SystemVariableDoubleType) Convert(value interface{}) (interface{}, error) {
   395  	cv1 := func(x float64) (interface{}, error) {
   396  		if x >= svdt.minimum && x <= svdt.maximum {
   397  			return x, nil
   398  		}
   399  		return nil, errorConvertToUintFailed
   400  	}
   401  
   402  	switch v := value.(type) {
   403  	case int:
   404  		return cv1(float64(v))
   405  	case uint:
   406  		return cv1(float64(v))
   407  	case int8:
   408  		return cv1(float64(v))
   409  	case uint8:
   410  		return cv1(float64(v))
   411  	case int16:
   412  		return cv1(float64(v))
   413  	case uint16:
   414  		return cv1(float64(v))
   415  	case int32:
   416  		return cv1(float64(v))
   417  	case uint32:
   418  		return cv1(float64(v))
   419  	case int64:
   420  		return cv1(float64(v))
   421  	case uint64:
   422  		return cv1(float64(v))
   423  	case float32:
   424  		return cv1(float64(v))
   425  	case float64:
   426  		return cv1(v)
   427  	}
   428  	return nil, errorConvertToDoubleFailed
   429  }
   430  
   431  func (svdt SystemVariableDoubleType) Type() types.T {
   432  	return types.T_float64
   433  }
   434  
   435  func (svdt SystemVariableDoubleType) MysqlType() defines.MysqlType {
   436  	return defines.MYSQL_TYPE_DOUBLE
   437  }
   438  
   439  func (svdt SystemVariableDoubleType) Zero() interface{} {
   440  	return float64(0)
   441  }
   442  
   443  var (
   444  	// panic
   445  	errorEnumHasMoreThan65535Values = moerr.NewInternalError(context.Background(), "the enum has more than 65535 values")
   446  )
   447  
   448  type SystemVariableEnumType struct {
   449  	name string
   450  	//tag name -> id
   451  	tagName2Id map[string]int
   452  
   453  	// id -> tag name
   454  	id2TagName []string
   455  }
   456  
   457  func InitSystemSystemEnumType(name string, values ...string) SystemVariableEnumType {
   458  	if len(values) > 65535 {
   459  		panic(errorEnumHasMoreThan65535Values)
   460  	}
   461  	tagName2Id := make(map[string]int)
   462  	for i, value := range values {
   463  		tagName2Id[strings.ToLower(value)] = i
   464  	}
   465  	return SystemVariableEnumType{
   466  		name:       name,
   467  		tagName2Id: tagName2Id,
   468  		id2TagName: values,
   469  	}
   470  }
   471  
   472  func (svet SystemVariableEnumType) String() string {
   473  	return "ENUM"
   474  }
   475  
   476  func (svet SystemVariableEnumType) Convert(value interface{}) (interface{}, error) {
   477  	cv1 := func(x int) (interface{}, error) {
   478  		if x >= 0 && x <= len(svet.id2TagName) {
   479  			return svet.id2TagName[x], nil
   480  		}
   481  		return nil, errorConvertToEnumFailed
   482  	}
   483  	cv2 := func(x float64) (interface{}, error) {
   484  		xx := int(x)
   485  		rxx := float64(xx)
   486  		if x == rxx {
   487  			return cv1(xx)
   488  		}
   489  		return nil, errorConvertToUintFailed
   490  	}
   491  
   492  	switch v := value.(type) {
   493  	case int:
   494  		return cv1(v)
   495  	case uint:
   496  		return cv1(int(v))
   497  	case int8:
   498  		return cv1(int(v))
   499  	case uint8:
   500  		return cv1(int(v))
   501  	case int16:
   502  		return cv1(int(v))
   503  	case uint16:
   504  		return cv1(int(v))
   505  	case int32:
   506  		return cv1(int(v))
   507  	case uint32:
   508  		return cv1(int(v))
   509  	case int64:
   510  		return cv1(int(v))
   511  	case uint64:
   512  		return cv1(int(v))
   513  	case float32:
   514  		return cv2(float64(v))
   515  	case float64:
   516  		return cv2(v)
   517  	case string:
   518  		if id, ok := svet.tagName2Id[strings.ToLower(v)]; ok {
   519  			return svet.id2TagName[id], nil
   520  		}
   521  	}
   522  	return nil, errorConvertToEnumFailed
   523  }
   524  
   525  func (svet SystemVariableEnumType) Type() types.T {
   526  	return types.T_varchar
   527  }
   528  
   529  func (svet SystemVariableEnumType) MysqlType() defines.MysqlType {
   530  	return defines.MYSQL_TYPE_VARCHAR
   531  }
   532  
   533  func (svet SystemVariableEnumType) Zero() interface{} {
   534  	return ""
   535  }
   536  
   537  const (
   538  	//reference : https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html#data-types-storage-reqs-strings
   539  	MaxMemberCountOfSetType = 64
   540  )
   541  
   542  var (
   543  	// panic error
   544  	errorValuesOfSetIsEmpty       = moerr.NewInternalError(context.Background(), "the count of values for set is empty")
   545  	errorValuesOfSetGreaterThan64 = moerr.NewInternalError(context.Background(), "the count of value is greater than 64")
   546  	errorValueHasComma            = moerr.NewInternalError(context.Background(), "the value has the comma")
   547  	errorValueIsDuplicate         = moerr.NewInternalError(context.Background(), "the value is duplicate")
   548  	errorValuesAreNotEnough       = moerr.NewInternalError(context.Background(), "values are not enough") // convert
   549  	errorValueIsInvalid           = moerr.NewInternalError(context.Background(), "the value is invalid")  // convert
   550  )
   551  
   552  type SystemVariableSetType struct {
   553  	// name                string
   554  	normalized2original map[string]string
   555  	value2BitIndex      map[string]int
   556  	bitIndex2Value      map[int]string
   557  }
   558  
   559  func (svst SystemVariableSetType) String() string {
   560  	return fmt.Sprintf("SET('%v')",
   561  		strings.Join(svst.Values(), "','"))
   562  }
   563  
   564  func (svst SystemVariableSetType) Values() []string {
   565  	bitsCount := 64 - bits2.LeadingZeros64(svst.bitmap())
   566  	var res []string
   567  	for i := 0; i < bitsCount; i++ {
   568  		res = append(res, svst.bitIndex2Value[i])
   569  	}
   570  	return res
   571  }
   572  
   573  func (svst SystemVariableSetType) bitmap() uint64 {
   574  	cnt := uint64(len(svst.value2BitIndex))
   575  	if cnt == 64 {
   576  		return math.MaxUint64
   577  	}
   578  	return uint64(1<<cnt) - 1
   579  }
   580  
   581  func (svst SystemVariableSetType) bits2string(bits uint64) (string, error) {
   582  	bld := strings.Builder{}
   583  	bitCount := 64 - bits2.LeadingZeros64(bits)
   584  	if bitCount > len(svst.bitIndex2Value) {
   585  		return "", errorValuesAreNotEnough
   586  	}
   587  
   588  	for i := 0; i < bitCount; i++ {
   589  		mask := uint64(1 << uint64(i))
   590  		if mask&bits != 0 {
   591  			v, ok := svst.bitIndex2Value[i]
   592  			if !ok {
   593  				return "", errorValueIsInvalid
   594  			}
   595  			bld.WriteString(v)
   596  			if i != 0 {
   597  				bld.WriteByte(',')
   598  			}
   599  		}
   600  	}
   601  
   602  	bldString := bld.String()
   603  	return bldString[:len(bldString)-1], nil
   604  }
   605  
   606  func (svst SystemVariableSetType) string2bits(s string) (uint64, error) {
   607  	if len(s) == 0 {
   608  		return 0, nil
   609  	}
   610  	ss := strings.Split(s, ",")
   611  	bits := uint64(0)
   612  	for _, sss := range ss {
   613  		normalized := strings.ToLower(strings.TrimRight(sss, " "))
   614  		if origin, ok := svst.normalized2original[normalized]; ok {
   615  			bits |= 1 << svst.value2BitIndex[origin]
   616  		} else {
   617  			if x, err := strconv.ParseUint(sss, 10, 64); err == nil {
   618  				if x == 0 {
   619  					continue
   620  				}
   621  				bitsCount := bits2.TrailingZeros64(x)
   622  				xv := 1 << uint64(bitsCount)
   623  				if _, ok2 := svst.bitIndex2Value[xv]; ok2 {
   624  					bits |= uint64(xv)
   625  					continue
   626  				}
   627  			}
   628  			return 0, errorValueIsInvalid
   629  		}
   630  	}
   631  	return bits, nil
   632  }
   633  
   634  func (svst SystemVariableSetType) Convert(value interface{}) (interface{}, error) {
   635  	if value == nil {
   636  		return nil, nil
   637  	}
   638  	cv1 := func(x uint64) (interface{}, error) {
   639  		if x <= svst.bitmap() {
   640  			return svst.bits2string(x)
   641  		}
   642  		return nil, errorConvertToSetFailed
   643  	}
   644  	cv2 := func(x string) (interface{}, error) {
   645  		bits, err := svst.string2bits(x)
   646  		if err != nil {
   647  			return nil, err
   648  		}
   649  		return svst.bits2string(bits)
   650  	}
   651  
   652  	switch v := value.(type) {
   653  	case int:
   654  		return cv1(uint64(v))
   655  	case uint:
   656  		return cv1(uint64(v))
   657  	case int8:
   658  		return cv1(uint64(v))
   659  	case uint8:
   660  		return cv1(uint64(v))
   661  	case int16:
   662  		return cv1(uint64(v))
   663  	case uint16:
   664  		return cv1(uint64(v))
   665  	case int32:
   666  		return cv1(uint64(v))
   667  	case uint32:
   668  		return cv1(uint64(v))
   669  	case int64:
   670  		return cv1(uint64(v))
   671  	case uint64:
   672  		return cv1(v)
   673  	case float32:
   674  		return cv1(uint64(v))
   675  	case float64:
   676  		return cv1(uint64(v))
   677  	case string:
   678  		return cv2(v)
   679  	case []byte:
   680  		return cv2(string(v))
   681  	}
   682  	return nil, errorConvertToSetFailed
   683  }
   684  
   685  func (svst SystemVariableSetType) Type() types.T {
   686  	return types.T_any
   687  }
   688  
   689  func (svst SystemVariableSetType) MysqlType() defines.MysqlType {
   690  	return defines.MYSQL_TYPE_SET
   691  }
   692  
   693  func (svst SystemVariableSetType) Zero() interface{} {
   694  	return ""
   695  }
   696  
   697  func InitSystemVariableSetType(name string, values ...string) SystemVariableSetType {
   698  	if len(values) == 0 {
   699  		panic(errorValuesOfSetIsEmpty)
   700  	}
   701  	if len(values) > MaxMemberCountOfSetType {
   702  		panic(errorValuesOfSetGreaterThan64)
   703  	}
   704  
   705  	normalized2original := make(map[string]string)
   706  	value2BitIndex := make(map[string]int)
   707  	bitIndex2Value := make(map[int]string)
   708  	for i, value := range values {
   709  		if strings.Contains(value, ",") {
   710  			panic(errorValueHasComma)
   711  		}
   712  		v := strings.TrimRight(value, " ")
   713  		lv := strings.ToLower(v)
   714  		if _, ok := normalized2original[lv]; ok {
   715  			panic(errorValueIsDuplicate)
   716  		}
   717  		normalized2original[lv] = v
   718  		value2BitIndex[v] = i
   719  		bitIndex2Value[i] = v
   720  	}
   721  
   722  	return SystemVariableSetType{
   723  		normalized2original: normalized2original,
   724  		value2BitIndex:      value2BitIndex,
   725  		bitIndex2Value:      bitIndex2Value,
   726  	}
   727  }
   728  
   729  type SystemVariableStringType struct {
   730  	name string
   731  }
   732  
   733  func InitSystemVariableStringType(name string) SystemVariableStringType {
   734  	return SystemVariableStringType{
   735  		name: name,
   736  	}
   737  }
   738  
   739  func (svst SystemVariableStringType) String() string {
   740  	return "STRING"
   741  }
   742  
   743  func (svst SystemVariableStringType) Convert(value interface{}) (interface{}, error) {
   744  	if value == nil {
   745  		return "", nil
   746  	}
   747  	if v, ok := value.(string); ok {
   748  		return v, nil
   749  	}
   750  	return nil, errorConvertToStringFailed
   751  }
   752  
   753  func (svst SystemVariableStringType) Type() types.T {
   754  	return types.T_varchar
   755  }
   756  
   757  func (svst SystemVariableStringType) MysqlType() defines.MysqlType {
   758  	return defines.MYSQL_TYPE_VARCHAR
   759  }
   760  
   761  func (svst SystemVariableStringType) Zero() interface{} {
   762  	return ""
   763  }
   764  
   765  type SystemVariable struct {
   766  	Name string
   767  
   768  	// scope of the system variable includes Global,Session,Both
   769  	Scope Scope
   770  
   771  	// can be changed during runtime
   772  	Dynamic bool
   773  
   774  	//can be set for single query by SET_VAR()
   775  	SetVarHintApplies bool
   776  
   777  	Type SystemVariableType
   778  
   779  	Default interface{}
   780  
   781  	UpdateSessVar func(*Session, map[string]interface{}, string, interface{}) error
   782  }
   783  
   784  func (sv SystemVariable) GetName() string {
   785  	return sv.Name
   786  }
   787  
   788  func (sv SystemVariable) GetScope() Scope {
   789  	return sv.Scope
   790  }
   791  
   792  func (sv SystemVariable) GetDynamic() bool {
   793  	return sv.Dynamic
   794  }
   795  
   796  func (sv SystemVariable) GetSetVarHintApplies() bool {
   797  	return sv.SetVarHintApplies
   798  }
   799  
   800  func (sv SystemVariable) GetType() SystemVariableType {
   801  	return sv.Type
   802  }
   803  
   804  func (sv SystemVariable) GetDefault() interface{} {
   805  	return sv.Default
   806  }
   807  
   808  type GlobalSystemVariables struct {
   809  	mu sync.Mutex
   810  	// name -> value/default
   811  	sysVars map[string]interface{}
   812  }
   813  
   814  // the set of variables
   815  var GSysVariables = &GlobalSystemVariables{
   816  	sysVars: make(map[string]interface{}),
   817  }
   818  
   819  // initialize system variables from definition
   820  func InitGlobalSystemVariables(gsv *GlobalSystemVariables) {
   821  	if gsv.sysVars == nil {
   822  		gsv.sysVars = make(map[string]interface{})
   823  	}
   824  	for _, def := range gSysVarsDefs {
   825  		gsv.sysVars[def.GetName()] = def.GetDefault()
   826  	}
   827  }
   828  
   829  // add custom system variables
   830  func (gsv *GlobalSystemVariables) AddSysVariables(vars []SystemVariable) {
   831  	gsv.mu.Lock()
   832  	defer gsv.mu.Unlock()
   833  	for _, v := range vars {
   834  		vv := v
   835  		lname := strings.ToLower(vv.GetName())
   836  		vv.Name = lname
   837  		gSysVarsDefs[lname] = vv
   838  		gsv.sysVars[lname] = vv.GetDefault()
   839  	}
   840  }
   841  
   842  // set values to system variables
   843  func (gsv *GlobalSystemVariables) SetValues(ctx context.Context, values map[string]interface{}) error {
   844  	gsv.mu.Lock()
   845  	defer gsv.mu.Unlock()
   846  	for name, val := range values {
   847  		name = strings.ToLower(name)
   848  		if sv, ok := gSysVarsDefs[name]; ok {
   849  			cv, err := sv.GetType().Convert(val)
   850  			if err != nil {
   851  				return err
   852  			}
   853  			gsv.sysVars[name] = cv
   854  		} else {
   855  			return moerr.NewInternalError(ctx, errorSystemVariableDoesNotExist())
   856  		}
   857  	}
   858  	return nil
   859  }
   860  
   861  // copy global system variable to session
   862  func (gsv *GlobalSystemVariables) CopySysVarsToSession() map[string]interface{} {
   863  	gsv.mu.Lock()
   864  	defer gsv.mu.Unlock()
   865  	sesSysVars := make(map[string]interface{}, len(gsv.sysVars))
   866  	for name, value := range gsv.sysVars {
   867  		sesSysVars[name] = value
   868  	}
   869  	return sesSysVars
   870  }
   871  
   872  // get system variable definition ,value.
   873  // return false, if there is no such variable.
   874  func (gsv *GlobalSystemVariables) GetGlobalSysVar(name string) (SystemVariable, interface{}, bool) {
   875  	gsv.mu.Lock()
   876  	defer gsv.mu.Unlock()
   877  	name = strings.ToLower(name)
   878  	if v, ok := gSysVarsDefs[name]; ok {
   879  		return v, gsv.sysVars[name], true
   880  	}
   881  	return SystemVariable{}, nil, false
   882  }
   883  
   884  // get the definition of the system variable
   885  func (gsv *GlobalSystemVariables) GetDefinitionOfSysVar(name string) (SystemVariable, bool) {
   886  	gsv.mu.Lock()
   887  	defer gsv.mu.Unlock()
   888  	name = strings.ToLower(name)
   889  	if v, ok := gSysVarsDefs[name]; ok {
   890  		return v, ok
   891  	}
   892  	return SystemVariable{}, false
   893  }
   894  
   895  // set global dynamic variable by SET GLOBAL
   896  func (gsv *GlobalSystemVariables) SetGlobalSysVar(ctx context.Context, name string, value interface{}) error {
   897  	gsv.mu.Lock()
   898  	defer gsv.mu.Unlock()
   899  	name = strings.ToLower(name)
   900  	if sv, ok := gSysVarsDefs[name]; ok {
   901  		if sv.GetScope() == ScopeSession {
   902  			return moerr.NewInternalError(ctx, errorSystemVariableIsSession())
   903  		}
   904  		if !sv.GetDynamic() {
   905  			return moerr.NewInternalError(ctx, errorSystemVariableIsReadOnly())
   906  		}
   907  		val, err := sv.GetType().Convert(value)
   908  		if err != nil {
   909  			return err
   910  		}
   911  		gsv.sysVars[name] = val
   912  	} else {
   913  		return moerr.NewInternalError(ctx, errorSystemVariableDoesNotExist())
   914  	}
   915  	return nil
   916  }
   917  
   918  func init() {
   919  	InitGlobalSystemVariables(GSysVariables)
   920  }
   921  
   922  // definitions of system variables
   923  var gSysVarsDefs = map[string]SystemVariable{
   924  	"port": {
   925  		Name:              "port",
   926  		Scope:             ScopeGlobal,
   927  		Dynamic:           false,
   928  		SetVarHintApplies: false,
   929  		Type:              InitSystemVariableIntType("port", 0, 65535, false),
   930  		Default:           int64(6001),
   931  	},
   932  	"host": {
   933  		Name:              "host",
   934  		Scope:             ScopeGlobal,
   935  		Dynamic:           false,
   936  		SetVarHintApplies: false,
   937  		Type:              InitSystemVariableStringType("host"),
   938  		Default:           "0.0.0.0",
   939  	},
   940  	"max_allowed_packet": {
   941  		Name:              "max_allowed_packet",
   942  		Scope:             ScopeBoth,
   943  		Dynamic:           true,
   944  		SetVarHintApplies: false,
   945  		Type:              InitSystemVariableIntType("max_allowed_packet", 1024, 1073741824, false),
   946  		Default:           int64(16777216),
   947  	},
   948  	"version_comment": {
   949  		Name:              "version_comment",
   950  		Scope:             ScopeGlobal,
   951  		Dynamic:           false,
   952  		SetVarHintApplies: false,
   953  		Type:              InitSystemVariableStringType("version_comment"),
   954  		Default:           "MatrixOne",
   955  	},
   956  	"tx_isolation": {
   957  		Name:              "tx_isolation",
   958  		Scope:             ScopeBoth,
   959  		Dynamic:           true,
   960  		SetVarHintApplies: false,
   961  		Type:              InitSystemSystemEnumType("tx_isolation", "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE"),
   962  		Default:           "REPEATABLE-READ",
   963  	},
   964  	"testglobalvar_dyn": {
   965  		Name:              "testglobalvar_dyn",
   966  		Scope:             ScopeGlobal,
   967  		Dynamic:           true,
   968  		SetVarHintApplies: false,
   969  		Type:              InitSystemVariableIntType("testglobalvar_dyn", 0, 100, false),
   970  		Default:           int64(0),
   971  	},
   972  	"testglobalvar_nodyn": {
   973  		Name:              "testglobalvar_nodyn",
   974  		Scope:             ScopeGlobal,
   975  		Dynamic:           false,
   976  		SetVarHintApplies: false,
   977  		Type:              InitSystemVariableIntType("testglobalvar_nodyn", 0, 100, false),
   978  		Default:           int64(0),
   979  	},
   980  	"testsessionvar_dyn": {
   981  		Name:              "testsessionvar_dyn",
   982  		Scope:             ScopeSession,
   983  		Dynamic:           true,
   984  		SetVarHintApplies: false,
   985  		Type:              InitSystemVariableIntType("testsessionvar_dyn", 0, 100, false),
   986  		Default:           int64(0),
   987  	},
   988  	"testsessionvar_nodyn": {
   989  		Name:              "testsessionvar_nodyn",
   990  		Scope:             ScopeSession,
   991  		Dynamic:           false,
   992  		SetVarHintApplies: false,
   993  		Type:              InitSystemVariableIntType("testsessionvar_nodyn", 0, 100, false),
   994  		Default:           int64(0),
   995  	},
   996  	"testbothvar_dyn": {
   997  		Name:              "testbothvar_dyn",
   998  		Scope:             ScopeBoth,
   999  		Dynamic:           true,
  1000  		SetVarHintApplies: false,
  1001  		Type:              InitSystemVariableIntType("testbothvar_dyn", 0, 100, false),
  1002  		Default:           int64(0),
  1003  	},
  1004  	"testbotchvar_nodyn": {
  1005  		Name:              "testbotchvar_nodyn",
  1006  		Scope:             ScopeBoth,
  1007  		Dynamic:           false,
  1008  		SetVarHintApplies: false,
  1009  		Type:              InitSystemVariableIntType("testbotchvar_nodyn", 0, 100, false),
  1010  		Default:           int64(0),
  1011  	},
  1012  	"character_set_client": {
  1013  		Name:              "character_set_client",
  1014  		Scope:             ScopeBoth,
  1015  		Dynamic:           true,
  1016  		SetVarHintApplies: false,
  1017  		Type:              InitSystemVariableStringType("character_set_client"),
  1018  		Default:           "utf8mb4",
  1019  	},
  1020  	"character_set_server": {
  1021  		Name:              "character_set_server",
  1022  		Scope:             ScopeBoth,
  1023  		Dynamic:           true,
  1024  		SetVarHintApplies: false,
  1025  		Type:              InitSystemVariableStringType("character_set_server"),
  1026  		Default:           "utf8mb4",
  1027  	},
  1028  	"character_set_database": {
  1029  		Name:              "character_set_database",
  1030  		Scope:             ScopeBoth,
  1031  		Dynamic:           true,
  1032  		SetVarHintApplies: false,
  1033  		Type:              InitSystemVariableStringType("character_set_database"),
  1034  		Default:           "utf8mb4",
  1035  	},
  1036  	"character_set_connection": {
  1037  		Name:              "character_set_connection",
  1038  		Scope:             ScopeBoth,
  1039  		Dynamic:           true,
  1040  		SetVarHintApplies: false,
  1041  		Type:              InitSystemVariableStringType("character_set_connection"),
  1042  		Default:           "utf8mb4",
  1043  	},
  1044  	"character_set_results": {
  1045  		Name:              "character_set_results",
  1046  		Scope:             ScopeBoth,
  1047  		Dynamic:           true,
  1048  		SetVarHintApplies: false,
  1049  		Type:              InitSystemVariableStringType("character_set_results"),
  1050  		Default:           "utf8mb4",
  1051  	},
  1052  	"collation_connection": {
  1053  		Name:              "collation_connection",
  1054  		Scope:             ScopeGlobal,
  1055  		Dynamic:           true,
  1056  		SetVarHintApplies: false,
  1057  		Type:              InitSystemVariableStringType("collation_connection"),
  1058  		Default:           "default",
  1059  	},
  1060  	"collation_server": {
  1061  		Name:              "collation_server",
  1062  		Scope:             ScopeGlobal,
  1063  		Dynamic:           true,
  1064  		SetVarHintApplies: false,
  1065  		Type:              InitSystemVariableStringType("collation_server"),
  1066  		Default:           "utf8mb4_bin",
  1067  	},
  1068  	"license": {
  1069  		Name:              "license",
  1070  		Scope:             ScopeGlobal,
  1071  		Dynamic:           true,
  1072  		SetVarHintApplies: false,
  1073  		Type:              InitSystemVariableStringType("license"),
  1074  		Default:           "APACHE",
  1075  	},
  1076  	"autocommit": {
  1077  		Name:              "autocommit",
  1078  		Scope:             ScopeBoth,
  1079  		Dynamic:           true,
  1080  		SetVarHintApplies: false,
  1081  		Type:              InitSystemVariableBoolType("autocommit"),
  1082  		Default:           int64(1),
  1083  	},
  1084  	"sql_mode": {
  1085  		Name:              "sql_mode",
  1086  		Scope:             ScopeBoth,
  1087  		Dynamic:           true,
  1088  		SetVarHintApplies: true,
  1089  		Type:              InitSystemVariableSetType("sql_mode", "ANSI", "TRADITIONAL", "ALLOW_INVALID_DATES", "ANSI_QUOTES", "ERROR_FOR_DIVISION_BY_ZERO", "HIGH_NOT_PRECEDENCE", "IGNORE_SPACE", "NO_AUTO_VALUE_ON_ZERO", "NO_BACKSLASH_ESCAPES", "NO_DIR_IN_CREATE", "NO_ENGINE_SUBSTITUTION", "NO_UNSIGNED_SUBTRACTION", "NO_ZERO_DATE", "NO_ZERO_IN_DATE", "ONLY_FULL_GROUP_BY", "PAD_CHAR_TO_FULL_LENGTH", "PIPES_AS_CONCAT", "REAL_AS_FLOAT", "STRICT_ALL_TABLES", "STRICT_TRANS_TABLES", "TIME_TRUNCATE_FRACTIONAL"),
  1090  		Default:           "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION",
  1091  	},
  1092  	"completion_type": {
  1093  		Name:              "completion_type",
  1094  		Scope:             ScopeBoth,
  1095  		Dynamic:           true,
  1096  		SetVarHintApplies: false,
  1097  		Type:              InitSystemSystemEnumType("completion_type", "NO_CHAIN", "CHAIN", "RELEASE"),
  1098  		Default:           "NO_CHAIN",
  1099  	},
  1100  	"time_zone": {
  1101  		Name:              "time_zone",
  1102  		Scope:             ScopeBoth,
  1103  		Dynamic:           true,
  1104  		SetVarHintApplies: true,
  1105  		Type:              InitSystemVariableStringType("time_zone"),
  1106  		Default:           "SYSTEM",
  1107  		UpdateSessVar:     updateTimeZone,
  1108  	},
  1109  	"auto_increment_increment": {
  1110  		Name:              "auto_increment_increment",
  1111  		Scope:             ScopeBoth,
  1112  		Dynamic:           true,
  1113  		SetVarHintApplies: true,
  1114  		Type:              InitSystemVariableIntType("auto_increment_increment", 1, 65535, false),
  1115  		Default:           int64(1),
  1116  	},
  1117  	"auto_increment_offset": {
  1118  		Name:              "auto_increment_offset",
  1119  		Scope:             ScopeBoth,
  1120  		Dynamic:           true,
  1121  		SetVarHintApplies: true,
  1122  		Type:              InitSystemVariableIntType("auto_increment_offset", 1, 65535, false),
  1123  		Default:           int64(1),
  1124  	},
  1125  	"init_connect": {
  1126  		Name:              "init_connect",
  1127  		Scope:             ScopeGlobal,
  1128  		Dynamic:           true,
  1129  		SetVarHintApplies: false,
  1130  		Type:              InitSystemVariableStringType("init_connect"),
  1131  		Default:           "",
  1132  	},
  1133  	"interactive_timeout": {
  1134  		Name:              "interactive_timeout",
  1135  		Scope:             ScopeBoth,
  1136  		Dynamic:           true,
  1137  		SetVarHintApplies: true,
  1138  		Type:              InitSystemVariableIntType("interactive_timeout", 1, 31536000, false),
  1139  		Default:           int64(28800),
  1140  	},
  1141  	"lower_case_table_names": {
  1142  		Name:              "lower_case_table_names",
  1143  		Scope:             ScopeGlobal,
  1144  		Dynamic:           false,
  1145  		SetVarHintApplies: false,
  1146  		Type:              InitSystemVariableIntType("lower_case_table_names", 0, 2, false),
  1147  		Default:           int64(0),
  1148  	},
  1149  	"net_write_timeout": {
  1150  		Name:              "net_write_timeout",
  1151  		Scope:             ScopeBoth,
  1152  		Dynamic:           true,
  1153  		SetVarHintApplies: false,
  1154  		Type:              InitSystemVariableIntType("net_write_timeout", 1, 31536000, false),
  1155  		Default:           int64(60),
  1156  	},
  1157  	"system_time_zone": {
  1158  		Name:              "system_time_zone",
  1159  		Scope:             ScopeGlobal,
  1160  		Dynamic:           false,
  1161  		SetVarHintApplies: false,
  1162  		Type:              InitSystemVariableStringType("system_time_zone"),
  1163  		Default:           "",
  1164  	},
  1165  	"transaction_isolation": {
  1166  		Name:              "transaction_isolation",
  1167  		Scope:             ScopeBoth,
  1168  		Dynamic:           true,
  1169  		SetVarHintApplies: false,
  1170  		Type:              InitSystemSystemEnumType("transaction_isolation", "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ", "SERIALIZABLE"),
  1171  		Default:           "REPEATABLE-READ",
  1172  	},
  1173  	"wait_timeout": {
  1174  		Name:              "wait_timeout",
  1175  		Scope:             ScopeBoth,
  1176  		Dynamic:           true,
  1177  		SetVarHintApplies: false,
  1178  		Type:              InitSystemVariableIntType("wait_timeout", 1, 2147483, false),
  1179  		Default:           int64(28800),
  1180  	},
  1181  	"sql_safe_updates": {
  1182  		Name:              "sql_safe_updates",
  1183  		Scope:             ScopeBoth,
  1184  		Dynamic:           true,
  1185  		SetVarHintApplies: false,
  1186  		Type:              InitSystemVariableIntType("sql_safe_updates", 0, 1, false),
  1187  		Default:           int64(0),
  1188  	},
  1189  	"profiling": {
  1190  		Name:              "profiling",
  1191  		Scope:             ScopeBoth,
  1192  		Dynamic:           true,
  1193  		SetVarHintApplies: false,
  1194  		Type:              InitSystemVariableIntType("profiling", 0, 1, false),
  1195  		Default:           int64(0),
  1196  	},
  1197  	"performance_schema": {
  1198  		Name:              "performance_schema",
  1199  		Scope:             ScopeBoth,
  1200  		Dynamic:           true,
  1201  		SetVarHintApplies: false,
  1202  		Type:              InitSystemVariableIntType("performance_schema", 0, 1, false),
  1203  		Default:           int64(0),
  1204  	},
  1205  	"transaction_read_only": {
  1206  		Name:              "transaction_read_only",
  1207  		Scope:             ScopeBoth,
  1208  		Dynamic:           true,
  1209  		SetVarHintApplies: false,
  1210  		Type:              InitSystemVariableIntType("transaction_read_only", 0, 1, false),
  1211  		Default:           int64(0),
  1212  	},
  1213  	"tx_read_only": {
  1214  		Name:              "tx_read_only",
  1215  		Scope:             ScopeBoth,
  1216  		Dynamic:           true,
  1217  		SetVarHintApplies: false,
  1218  		Type:              InitSystemVariableIntType("tx_read_only", 0, 1, false),
  1219  		Default:           int64(0),
  1220  	},
  1221  	"sql_select_limit": {
  1222  		Name:              "sql_select_limit",
  1223  		Scope:             ScopeBoth,
  1224  		Dynamic:           true,
  1225  		SetVarHintApplies: false,
  1226  		Type:              InitSystemVariableUintType("sql_select_limit", 0, 18446744073709551615),
  1227  		Default:           uint64(18446744073709551615),
  1228  	},
  1229  	"save_query_result": {
  1230  		Name:              "save_query_result",
  1231  		Scope:             ScopeBoth,
  1232  		Dynamic:           true,
  1233  		SetVarHintApplies: false,
  1234  		Type:              InitSystemVariableBoolType("save_query_result"),
  1235  		Default:           int64(0),
  1236  	},
  1237  	"query_result_timeout": {
  1238  		Name:              "query_result_timeout",
  1239  		Scope:             ScopeBoth,
  1240  		Dynamic:           true,
  1241  		SetVarHintApplies: false,
  1242  		Type:              InitSystemVariableUintType("query_result_timeout", 0, 18446744073709551615),
  1243  		Default:           uint64(24),
  1244  	},
  1245  	"query_result_maxsize": {
  1246  		Name:              "query_result_maxsize",
  1247  		Scope:             ScopeBoth,
  1248  		Dynamic:           true,
  1249  		SetVarHintApplies: false,
  1250  		Type:              InitSystemVariableUintType("query_result_maxsize", 0, 18446744073709551615),
  1251  		Default:           uint64(100),
  1252  	},
  1253  }
  1254  
  1255  func updateTimeZone(sess *Session, vars map[string]interface{}, name string, val interface{}) error {
  1256  	oldVal := vars[name]
  1257  	if oldVal == val {
  1258  		return nil
  1259  	}
  1260  
  1261  	tzStr := val.(string)
  1262  	if tzStr == "SYSTEM" {
  1263  		vars[name] = "SYSTEM"
  1264  		sess.SetTimeZone(time.Local)
  1265  	} else if tzStr[0] == '-' {
  1266  		if len(tzStr) != 6 {
  1267  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1268  		}
  1269  
  1270  		if tzStr[1] < '0' || tzStr[1] > '9' {
  1271  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1272  		}
  1273  		hour := int(tzStr[1]-'0') * 10
  1274  		if tzStr[2] < '0' || tzStr[2] > '9' {
  1275  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1276  		}
  1277  		hour += int(tzStr[2] - '0')
  1278  
  1279  		if tzStr[3] != ':' {
  1280  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1281  		}
  1282  
  1283  		if tzStr[4] < '0' || tzStr[4] > '9' {
  1284  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1285  		}
  1286  		minute := int(tzStr[4]-'0') * 10
  1287  		if tzStr[5] < '0' || tzStr[5] > '9' {
  1288  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1289  		}
  1290  		minute += int(tzStr[5] - '0')
  1291  
  1292  		minute += hour * 60
  1293  		if minute >= 14*60 {
  1294  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1295  		}
  1296  
  1297  		vars[name] = tzStr
  1298  		sess.SetTimeZone(time.FixedZone("FixedZone", -minute*60))
  1299  	} else if tzStr[0] == '+' {
  1300  		if len(tzStr) != 6 {
  1301  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1302  		}
  1303  
  1304  		if tzStr[1] < '0' || tzStr[1] > '9' {
  1305  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1306  		}
  1307  		hour := int(tzStr[1]-'0') * 10
  1308  		if tzStr[2] < '0' || tzStr[2] > '9' {
  1309  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1310  		}
  1311  		hour += int(tzStr[2] - '0')
  1312  
  1313  		if tzStr[3] != ':' {
  1314  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1315  		}
  1316  
  1317  		if tzStr[4] < '0' || tzStr[4] > '9' {
  1318  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1319  		}
  1320  		minute := int(tzStr[4]-'0') * 10
  1321  		if tzStr[5] < '0' || tzStr[5] > '9' {
  1322  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1323  		}
  1324  		minute += int(tzStr[5] - '0')
  1325  
  1326  		minute += hour * 60
  1327  		if minute > 14*60 {
  1328  			return moerr.NewInternalError(sess.requestCtx, "incorrect timezone "+tzStr)
  1329  		}
  1330  
  1331  		vars[name] = tzStr
  1332  		sess.SetTimeZone(time.FixedZone("FixedZone", minute*60))
  1333  	} else {
  1334  		loc, err := time.LoadLocation(tzStr)
  1335  		if err != nil {
  1336  			return err
  1337  		}
  1338  
  1339  		vars[name] = tzStr
  1340  		sess.SetTimeZone(loc)
  1341  	}
  1342  
  1343  	return nil
  1344  }