vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/set.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package engine
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"strings"
    25  
    26  	"vitess.io/vitess/go/vt/sysvars"
    27  
    28  	vtgatepb "vitess.io/vitess/go/vt/proto/vtgate"
    29  
    30  	"vitess.io/vitess/go/vt/log"
    31  
    32  	"vitess.io/vitess/go/vt/srvtopo"
    33  
    34  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    35  
    36  	"vitess.io/vitess/go/sqltypes"
    37  	"vitess.io/vitess/go/vt/key"
    38  	querypb "vitess.io/vitess/go/vt/proto/query"
    39  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    40  	"vitess.io/vitess/go/vt/schema"
    41  	"vitess.io/vitess/go/vt/vterrors"
    42  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    43  )
    44  
    45  type (
    46  	// Set contains the instructions to perform set.
    47  	Set struct {
    48  		Ops   []SetOp
    49  		Input Primitive
    50  
    51  		noTxNeeded
    52  	}
    53  
    54  	// SetOp is an interface that different type of set operations implements.
    55  	SetOp interface {
    56  		Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error
    57  		VariableName() string
    58  	}
    59  
    60  	// UserDefinedVariable implements the SetOp interface to execute user defined variables.
    61  	UserDefinedVariable struct {
    62  		Name string
    63  		Expr evalengine.Expr
    64  	}
    65  
    66  	// SysVarIgnore implements the SetOp interface to ignore the settings.
    67  	SysVarIgnore struct {
    68  		Name string
    69  		Expr string
    70  	}
    71  
    72  	// SysVarCheckAndIgnore implements the SetOp interface to check underlying setting and ignore if same.
    73  	SysVarCheckAndIgnore struct {
    74  		Name              string
    75  		Keyspace          *vindexes.Keyspace
    76  		TargetDestination key.Destination `json:",omitempty"`
    77  		Expr              string
    78  	}
    79  
    80  	// SysVarReservedConn implements the SetOp interface and will write the changes variable into the session
    81  	SysVarReservedConn struct {
    82  		Name              string
    83  		Keyspace          *vindexes.Keyspace
    84  		TargetDestination key.Destination `json:",omitempty"`
    85  		Expr              string
    86  		SupportSetVar     bool
    87  	}
    88  
    89  	// SysVarSetAware implements the SetOp interface and will write the changes variable into the session
    90  	// The special part is that these settings change the sessions behaviour in different ways
    91  	SysVarSetAware struct {
    92  		Name string
    93  		Expr evalengine.Expr
    94  	}
    95  
    96  	// VitessMetadata implements the SetOp interface and will write the changes variable into the topo server
    97  	VitessMetadata struct {
    98  		Name, Value string
    99  	}
   100  )
   101  
   102  var unsupportedSQLModes = []string{"ANSI_QUOTES", "NO_BACKSLASH_ESCAPES", "PIPES_AS_CONCAT", "REAL_AS_FLOAT"}
   103  
   104  var _ Primitive = (*Set)(nil)
   105  
   106  // RouteType implements the Primitive interface method.
   107  func (s *Set) RouteType() string {
   108  	return "Set"
   109  }
   110  
   111  // GetKeyspaceName implements the Primitive interface method.
   112  func (s *Set) GetKeyspaceName() string {
   113  	return ""
   114  }
   115  
   116  // GetTableName implements the Primitive interface method.
   117  func (s *Set) GetTableName() string {
   118  	return ""
   119  }
   120  
   121  // TryExecute implements the Primitive interface method.
   122  func (s *Set) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) {
   123  	input, err := vcursor.ExecutePrimitive(ctx, s.Input, bindVars, false)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	if len(input.Rows) != 1 {
   128  		return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "should get a single row")
   129  	}
   130  	env := evalengine.EnvWithBindVars(bindVars, vcursor.ConnCollation())
   131  	env.Row = input.Rows[0]
   132  	env.Fields = input.Fields
   133  	for _, setOp := range s.Ops {
   134  		err := setOp.Execute(ctx, vcursor, env)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  	}
   139  	return &sqltypes.Result{}, nil
   140  }
   141  
   142  // TryStreamExecute implements the Primitive interface method.
   143  func (s *Set) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error {
   144  	result, err := s.TryExecute(ctx, vcursor, bindVars, wantfields)
   145  	if err != nil {
   146  		return err
   147  	}
   148  	return callback(result)
   149  }
   150  
   151  // GetFields implements the Primitive interface method.
   152  func (s *Set) GetFields(context.Context, VCursor, map[string]*querypb.BindVariable) (*sqltypes.Result, error) {
   153  	return &sqltypes.Result{}, nil
   154  }
   155  
   156  // Inputs implements the Primitive interface
   157  func (s *Set) Inputs() []Primitive {
   158  	return []Primitive{s.Input}
   159  }
   160  
   161  func (s *Set) description() PrimitiveDescription {
   162  	other := map[string]any{
   163  		"Ops": s.Ops,
   164  	}
   165  	return PrimitiveDescription{
   166  		OperatorType: "Set",
   167  		Other:        other,
   168  	}
   169  }
   170  
   171  var _ SetOp = (*UserDefinedVariable)(nil)
   172  
   173  // MarshalJSON provides the type to SetOp for plan json
   174  func (u *UserDefinedVariable) MarshalJSON() ([]byte, error) {
   175  	return json.Marshal(struct {
   176  		Type string
   177  		Name string
   178  		Expr string
   179  	}{
   180  		Type: "UserDefinedVariable",
   181  		Name: u.Name,
   182  		Expr: evalengine.FormatExpr(u.Expr),
   183  	})
   184  
   185  }
   186  
   187  // VariableName implements the SetOp interface method.
   188  func (u *UserDefinedVariable) VariableName() string {
   189  	return u.Name
   190  }
   191  
   192  // Execute implements the SetOp interface method.
   193  func (u *UserDefinedVariable) Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error {
   194  	value, err := env.Evaluate(u.Expr)
   195  	if err != nil {
   196  		return err
   197  	}
   198  	return vcursor.Session().SetUDV(u.Name, value.Value())
   199  }
   200  
   201  var _ SetOp = (*SysVarIgnore)(nil)
   202  
   203  // MarshalJSON provides the type to SetOp for plan json
   204  func (svi *SysVarIgnore) MarshalJSON() ([]byte, error) {
   205  	return json.Marshal(struct {
   206  		Type string
   207  		SysVarIgnore
   208  	}{
   209  		Type:         "SysVarIgnore",
   210  		SysVarIgnore: *svi,
   211  	})
   212  
   213  }
   214  
   215  // VariableName implements the SetOp interface method.
   216  func (svi *SysVarIgnore) VariableName() string {
   217  	return svi.Name
   218  }
   219  
   220  // Execute implements the SetOp interface method.
   221  func (svi *SysVarIgnore) Execute(context.Context, VCursor, *evalengine.ExpressionEnv) error {
   222  	log.Infof("Ignored inapplicable SET %v = %v", svi.Name, svi.Expr)
   223  	return nil
   224  }
   225  
   226  var _ SetOp = (*SysVarCheckAndIgnore)(nil)
   227  
   228  // MarshalJSON provides the type to SetOp for plan json
   229  func (svci *SysVarCheckAndIgnore) MarshalJSON() ([]byte, error) {
   230  	return json.Marshal(struct {
   231  		Type string
   232  		SysVarCheckAndIgnore
   233  	}{
   234  		Type:                 "SysVarCheckAndIgnore",
   235  		SysVarCheckAndIgnore: *svci,
   236  	})
   237  
   238  }
   239  
   240  // VariableName implements the SetOp interface method
   241  func (svci *SysVarCheckAndIgnore) VariableName() string {
   242  	return svci.Name
   243  }
   244  
   245  // Execute implements the SetOp interface method
   246  func (svci *SysVarCheckAndIgnore) Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error {
   247  	rss, _, err := vcursor.ResolveDestinations(ctx, svci.Keyspace.Name, nil, []key.Destination{svci.TargetDestination})
   248  	if err != nil {
   249  		return err
   250  	}
   251  
   252  	if len(rss) != 1 {
   253  		return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Unexpected error, DestinationKeyspaceID mapping to multiple shards: %v", svci.TargetDestination)
   254  	}
   255  	checkSysVarQuery := fmt.Sprintf("select 1 from dual where @@%s = %s", svci.Name, svci.Expr)
   256  	result, err := execShard(ctx, nil, vcursor, checkSysVarQuery, env.BindVars, rss[0], false /* rollbackOnError */, false /* canAutocommit */)
   257  	if err != nil {
   258  		// Rather than returning the error, we will just log the error
   259  		// as the intention for executing the query it to validate the current setting and eventually ignore it anyways.
   260  		// There is no benefit of returning the error back to client.
   261  		log.Warningf("unable to validate the current settings for '%s': %s", svci.Name, err.Error())
   262  		return nil
   263  	}
   264  	if len(result.Rows) == 0 {
   265  		log.Infof("Ignored inapplicable SET %v = %v", svci.Name, svci.Expr)
   266  	}
   267  	return nil
   268  }
   269  
   270  var _ SetOp = (*SysVarReservedConn)(nil)
   271  
   272  // MarshalJSON provides the type to SetOp for plan json
   273  func (svs *SysVarReservedConn) MarshalJSON() ([]byte, error) {
   274  	return json.Marshal(struct {
   275  		Type string
   276  		SysVarReservedConn
   277  	}{
   278  		Type:               "SysVarSet",
   279  		SysVarReservedConn: *svs,
   280  	})
   281  
   282  }
   283  
   284  // VariableName implements the SetOp interface method
   285  func (svs *SysVarReservedConn) VariableName() string {
   286  	return svs.Name
   287  }
   288  
   289  // Execute implements the SetOp interface method
   290  func (svs *SysVarReservedConn) Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error {
   291  	// For those running on advanced vitess settings.
   292  	if svs.TargetDestination != nil {
   293  		rss, _, err := vcursor.ResolveDestinations(ctx, svs.Keyspace.Name, nil, []key.Destination{svs.TargetDestination})
   294  		if err != nil {
   295  			return err
   296  		}
   297  		vcursor.Session().NeedsReservedConn()
   298  		return svs.execSetStatement(ctx, vcursor, rss, env)
   299  	}
   300  	needReservedConn, err := svs.checkAndUpdateSysVar(ctx, vcursor, env)
   301  	if err != nil {
   302  		return err
   303  	}
   304  	if !needReservedConn {
   305  		// setting ignored, same as underlying datastore
   306  		return nil
   307  	}
   308  	// Update existing shard session with new system variable settings.
   309  	rss := vcursor.Session().ShardSession()
   310  	if len(rss) == 0 {
   311  		return nil
   312  	}
   313  	queries := make([]*querypb.BoundQuery, len(rss))
   314  	for i := 0; i < len(rss); i++ {
   315  		queries[i] = &querypb.BoundQuery{
   316  			Sql:           fmt.Sprintf("set %s = %s", svs.Name, svs.Expr),
   317  			BindVariables: env.BindVars,
   318  		}
   319  	}
   320  	_, errs := vcursor.ExecuteMultiShard(ctx, nil, rss, queries, false /* rollbackOnError */, false /* canAutocommit */)
   321  	return vterrors.Aggregate(errs)
   322  }
   323  
   324  func (svs *SysVarReservedConn) execSetStatement(ctx context.Context, vcursor VCursor, rss []*srvtopo.ResolvedShard, env *evalengine.ExpressionEnv) error {
   325  	queries := make([]*querypb.BoundQuery, len(rss))
   326  	for i := 0; i < len(rss); i++ {
   327  		queries[i] = &querypb.BoundQuery{
   328  			Sql:           fmt.Sprintf("set @@%s = %s", svs.Name, svs.Expr),
   329  			BindVariables: env.BindVars,
   330  		}
   331  	}
   332  	_, errs := vcursor.ExecuteMultiShard(ctx, nil, rss, queries, false /* rollbackOnError */, false /* canAutocommit */)
   333  	return vterrors.Aggregate(errs)
   334  }
   335  
   336  func (svs *SysVarReservedConn) checkAndUpdateSysVar(ctx context.Context, vcursor VCursor, res *evalengine.ExpressionEnv) (bool, error) {
   337  	sysVarExprValidationQuery := fmt.Sprintf("select %s from dual where @@%s != %s", svs.Expr, svs.Name, svs.Expr)
   338  	if svs.Name == "sql_mode" {
   339  		sysVarExprValidationQuery = fmt.Sprintf("select @@%s orig, %s new", svs.Name, svs.Expr)
   340  	}
   341  	rss, _, err := vcursor.ResolveDestinations(ctx, svs.Keyspace.Name, nil, []key.Destination{key.DestinationKeyspaceID{0}})
   342  	if err != nil {
   343  		return false, err
   344  	}
   345  	qr, err := execShard(ctx, nil, vcursor, sysVarExprValidationQuery, res.BindVars, rss[0], false /* rollbackOnError */, false /* canAutocommit */)
   346  	if err != nil {
   347  		return false, err
   348  	}
   349  	changed := len(qr.Rows) > 0
   350  	if !changed {
   351  		return false, nil
   352  	}
   353  
   354  	var value sqltypes.Value
   355  	if svs.Name == "sql_mode" {
   356  		changed, value, err = sqlModeChangedValue(qr)
   357  		if err != nil {
   358  			return false, err
   359  		}
   360  		if !changed {
   361  			return false, nil
   362  		}
   363  	} else {
   364  		value = qr.Rows[0][0]
   365  	}
   366  	buf := new(bytes.Buffer)
   367  	value.EncodeSQL(buf)
   368  	s := buf.String()
   369  	vcursor.Session().SetSysVar(svs.Name, s)
   370  
   371  	// If the condition below is true, we want to use reserved connection instead of SET_VAR query hint.
   372  	// MySQL supports SET_VAR only in MySQL80 and for a limited set of system variables.
   373  	if !svs.SupportSetVar || s == "''" || !vcursor.CanUseSetVar() {
   374  		vcursor.Session().NeedsReservedConn()
   375  		return true, nil
   376  	}
   377  	return false, nil
   378  }
   379  
   380  func sqlModeChangedValue(qr *sqltypes.Result) (bool, sqltypes.Value, error) {
   381  	if len(qr.Fields) != 2 {
   382  		return false, sqltypes.Value{}, nil
   383  	}
   384  	if len(qr.Rows[0]) != 2 {
   385  		return false, sqltypes.Value{}, nil
   386  	}
   387  	orig := qr.Rows[0][0].ToString()
   388  	newVal := qr.Rows[0][1].ToString()
   389  
   390  	origArr := strings.Split(orig, ",")
   391  	// Keep track of if the value is seen or not.
   392  	origMap := map[string]bool{}
   393  	for _, oVal := range origArr {
   394  		// Default is not seen.
   395  		origMap[strings.ToUpper(oVal)] = true
   396  	}
   397  	uniqOrigVal := len(origMap)
   398  	origValSeen := 0
   399  
   400  	changed := false
   401  	newValArr := strings.Split(newVal, ",")
   402  	unsupportedMode := ""
   403  	for _, nVal := range newValArr {
   404  		nVal = strings.ToUpper(nVal)
   405  		for _, mode := range unsupportedSQLModes {
   406  			if mode == nVal {
   407  				unsupportedMode = nVal
   408  				break
   409  			}
   410  		}
   411  		notSeen, exists := origMap[nVal]
   412  		if !exists {
   413  			changed = true
   414  			break
   415  		}
   416  		if exists && notSeen {
   417  			// Value seen. Turn it off
   418  			origMap[nVal] = false
   419  			origValSeen++
   420  		}
   421  	}
   422  	if !changed && uniqOrigVal != origValSeen {
   423  		changed = true
   424  	}
   425  	if changed && unsupportedMode != "" {
   426  		return false, sqltypes.Value{}, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "setting the %s sql_mode is unsupported", unsupportedMode)
   427  	}
   428  
   429  	return changed, qr.Rows[0][1], nil
   430  }
   431  
   432  var _ SetOp = (*SysVarSetAware)(nil)
   433  
   434  // MarshalJSON marshals all the json
   435  func (svss *SysVarSetAware) MarshalJSON() ([]byte, error) {
   436  	return json.Marshal(struct {
   437  		Type string
   438  		Name string
   439  		Expr string
   440  	}{
   441  		Type: "SysVarAware",
   442  		Name: svss.Name,
   443  		Expr: evalengine.FormatExpr(svss.Expr),
   444  	})
   445  }
   446  
   447  // Execute implements the SetOp interface method
   448  func (svss *SysVarSetAware) Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error {
   449  	var err error
   450  	switch svss.Name {
   451  	case sysvars.Autocommit.Name:
   452  		err = svss.setBoolSysVar(ctx, env, vcursor.Session().SetAutocommit)
   453  	case sysvars.ClientFoundRows.Name:
   454  		err = svss.setBoolSysVar(ctx, env, vcursor.Session().SetClientFoundRows)
   455  	case sysvars.SkipQueryPlanCache.Name:
   456  		err = svss.setBoolSysVar(ctx, env, vcursor.Session().SetSkipQueryPlanCache)
   457  	case sysvars.TxReadOnly.Name,
   458  		sysvars.TransactionReadOnly.Name:
   459  		// TODO (4127): This is a dangerous NOP.
   460  		noop := func(context.Context, bool) error { return nil }
   461  		err = svss.setBoolSysVar(ctx, env, noop)
   462  	case sysvars.SQLSelectLimit.Name:
   463  		intValue, err := svss.evalAsInt64(env)
   464  		if err != nil {
   465  			return err
   466  		}
   467  		vcursor.Session().SetSQLSelectLimit(intValue) // nolint:errcheck
   468  	case sysvars.TransactionMode.Name:
   469  		str, err := svss.evalAsString(env)
   470  		if err != nil {
   471  			return err
   472  		}
   473  		out, ok := vtgatepb.TransactionMode_value[strings.ToUpper(str)]
   474  		if !ok {
   475  			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "invalid transaction_mode: %s", str)
   476  		}
   477  		vcursor.Session().SetTransactionMode(vtgatepb.TransactionMode(out))
   478  	case sysvars.Workload.Name:
   479  		str, err := svss.evalAsString(env)
   480  		if err != nil {
   481  			return err
   482  		}
   483  		out, ok := querypb.ExecuteOptions_Workload_value[strings.ToUpper(str)]
   484  		if !ok {
   485  			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "invalid workload: %s", str)
   486  		}
   487  		vcursor.Session().SetWorkload(querypb.ExecuteOptions_Workload(out))
   488  	case sysvars.DDLStrategy.Name:
   489  		str, err := svss.evalAsString(env)
   490  		if err != nil {
   491  			return err
   492  		}
   493  		if _, err := schema.ParseDDLStrategy(str); err != nil {
   494  			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "invalid DDL strategy: %s", str)
   495  		}
   496  		vcursor.Session().SetDDLStrategy(str)
   497  	case sysvars.QueryTimeout.Name:
   498  		queryTimeout, err := svss.evalAsInt64(env)
   499  		if err != nil {
   500  			return err
   501  		}
   502  		vcursor.Session().SetQueryTimeout(queryTimeout)
   503  	case sysvars.SessionEnableSystemSettings.Name:
   504  		err = svss.setBoolSysVar(ctx, env, vcursor.Session().SetSessionEnableSystemSettings)
   505  	case sysvars.Charset.Name, sysvars.Names.Name:
   506  		str, err := svss.evalAsString(env)
   507  		if err != nil {
   508  			return err
   509  		}
   510  		switch strings.ToLower(str) {
   511  		case "", "utf8", "utf8mb4", "latin1", "default":
   512  			// do nothing
   513  			break
   514  		default:
   515  			return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "charset/name %v is not supported", str)
   516  		}
   517  	case sysvars.ReadAfterWriteGTID.Name:
   518  		str, err := svss.evalAsString(env)
   519  		if err != nil {
   520  			return err
   521  		}
   522  		vcursor.Session().SetReadAfterWriteGTID(str)
   523  	case sysvars.ReadAfterWriteTimeOut.Name:
   524  		val, err := svss.evalAsFloat(env)
   525  		if err != nil {
   526  			return err
   527  		}
   528  		vcursor.Session().SetReadAfterWriteTimeout(val)
   529  	case sysvars.SessionTrackGTIDs.Name:
   530  		str, err := svss.evalAsString(env)
   531  		if err != nil {
   532  			return err
   533  		}
   534  		switch strings.ToLower(str) {
   535  		case "off":
   536  			vcursor.Session().SetSessionTrackGTIDs(false)
   537  		case "own_gtid":
   538  			vcursor.Session().SetSessionTrackGTIDs(true)
   539  		default:
   540  			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "variable 'session_track_gtids' can't be set to the value of '%s'", str)
   541  		}
   542  	default:
   543  		return vterrors.NewErrorf(vtrpcpb.Code_NOT_FOUND, vterrors.UnknownSystemVariable, "unknown system variable '%s'", svss.Name)
   544  	}
   545  
   546  	return err
   547  }
   548  
   549  func (svss *SysVarSetAware) evalAsInt64(env *evalengine.ExpressionEnv) (int64, error) {
   550  	value, err := env.Evaluate(svss.Expr)
   551  	if err != nil {
   552  		return 0, err
   553  	}
   554  
   555  	v := value.Value()
   556  	if !v.IsIntegral() {
   557  		return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String())
   558  	}
   559  	intValue, err := v.ToInt64()
   560  	if err != nil {
   561  		return 0, err
   562  	}
   563  	return intValue, nil
   564  }
   565  
   566  func (svss *SysVarSetAware) evalAsFloat(env *evalengine.ExpressionEnv) (float64, error) {
   567  	value, err := env.Evaluate(svss.Expr)
   568  	if err != nil {
   569  		return 0, err
   570  	}
   571  
   572  	v := value.Value()
   573  	floatValue, err := v.ToFloat64()
   574  	if err != nil {
   575  		return 0, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String())
   576  	}
   577  	return floatValue, nil
   578  }
   579  
   580  func (svss *SysVarSetAware) evalAsString(env *evalengine.ExpressionEnv) (string, error) {
   581  	value, err := env.Evaluate(svss.Expr)
   582  	if err != nil {
   583  		return "", err
   584  	}
   585  	v := value.Value()
   586  	if !v.IsText() && !v.IsBinary() {
   587  		return "", vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongTypeForVar, "incorrect argument type to variable '%s': %s", svss.Name, value.Value().Type().String())
   588  	}
   589  
   590  	return v.ToString(), nil
   591  }
   592  
   593  func (svss *SysVarSetAware) setBoolSysVar(ctx context.Context, env *evalengine.ExpressionEnv, setter func(context.Context, bool) error) error {
   594  	value, err := env.Evaluate(svss.Expr)
   595  	if err != nil {
   596  		return err
   597  	}
   598  	boolValue, err := value.ToBooleanStrict()
   599  	if err != nil {
   600  		return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongValueForVar, "variable '%s' can't be set to the value: %s", svss.Name, err.Error())
   601  	}
   602  	return setter(ctx, boolValue)
   603  }
   604  
   605  // VariableName implements the SetOp interface method
   606  func (svss *SysVarSetAware) VariableName() string {
   607  	return svss.Name
   608  }
   609  
   610  var _ SetOp = (*VitessMetadata)(nil)
   611  
   612  func (v *VitessMetadata) Execute(ctx context.Context, vcursor VCursor, env *evalengine.ExpressionEnv) error {
   613  	return vcursor.SetExec(ctx, v.Name, v.Value)
   614  }
   615  
   616  func (v *VitessMetadata) VariableName() string {
   617  	return v.Name
   618  }