github.com/team-ide/go-dialect@v1.9.20/vitess/sqltypes/bind_variables.go (about)

     1  /*
     2  Copyright 2019 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 sqltypes
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"strconv"
    24  
    25  	"google.golang.org/protobuf/proto"
    26  
    27  	querypb "github.com/team-ide/go-dialect/vitess/query"
    28  )
    29  
    30  type DecimalFloat float64
    31  
    32  var (
    33  	// BvSchemaName is bind variable to be sent down to vttablet for schema name.
    34  	BvSchemaName = "__vtschemaname"
    35  
    36  	// BvReplaceSchemaName is bind variable to be sent down to vttablet to replace schema name.
    37  	BvReplaceSchemaName = "__replacevtschemaname"
    38  
    39  	// NullBindVariable is a bindvar with NULL value.
    40  	NullBindVariable = &querypb.BindVariable{Type: querypb.Type_NULL_TYPE}
    41  )
    42  
    43  // ValueToProto converts Value to a *querypb.Value.
    44  func ValueToProto(v Value) *querypb.Value {
    45  	return &querypb.Value{Type: v.typ, Value: v.val}
    46  }
    47  
    48  // ProtoToValue converts a *querypb.Value to a Value.
    49  func ProtoToValue(v *querypb.Value) Value {
    50  	return MakeTrusted(v.Type, v.Value)
    51  }
    52  
    53  // BuildBindVariables builds a map[string]*querypb.BindVariable from a map[string]interface{}.
    54  func BuildBindVariables(in map[string]interface{}) (map[string]*querypb.BindVariable, error) {
    55  	if len(in) == 0 {
    56  		return nil, nil
    57  	}
    58  
    59  	out := make(map[string]*querypb.BindVariable, len(in))
    60  	for k, v := range in {
    61  		bv, err := BuildBindVariable(v)
    62  		if err != nil {
    63  			return nil, fmt.Errorf("%s: %v", k, err)
    64  		}
    65  		out[k] = bv
    66  	}
    67  	return out, nil
    68  }
    69  
    70  // HexNumBindVariable converts bytes representing a hex number to a bind var.
    71  func HexNumBindVariable(v []byte) *querypb.BindVariable {
    72  	return ValueBindVariable(NewHexNum(v))
    73  }
    74  
    75  // HexValBindVariable converts bytes representing a hex encoded string to a bind var.
    76  func HexValBindVariable(v []byte) *querypb.BindVariable {
    77  	return ValueBindVariable(NewHexVal(v))
    78  }
    79  
    80  // Int8BindVariable converts an int8 to a bind var.
    81  func Int8BindVariable(v int8) *querypb.BindVariable {
    82  	return ValueBindVariable(NewInt8(v))
    83  }
    84  
    85  // Int32BindVariable converts an int32 to a bind var.
    86  func Int32BindVariable(v int32) *querypb.BindVariable {
    87  	return ValueBindVariable(NewInt32(v))
    88  }
    89  
    90  // BoolBindVariable converts an bool to a int64 bind var.
    91  func BoolBindVariable(v bool) *querypb.BindVariable {
    92  	if v {
    93  		return Int64BindVariable(1)
    94  	}
    95  	return Int64BindVariable(0)
    96  }
    97  
    98  // Int64BindVariable converts an int64 to a bind var.
    99  func Int64BindVariable(v int64) *querypb.BindVariable {
   100  	return ValueBindVariable(NewInt64(v))
   101  }
   102  
   103  // Uint64BindVariable converts a uint64 to a bind var.
   104  func Uint64BindVariable(v uint64) *querypb.BindVariable {
   105  	return ValueBindVariable(NewUint64(v))
   106  }
   107  
   108  // Float64BindVariable converts a float64 to a bind var.
   109  func Float64BindVariable(v float64) *querypb.BindVariable {
   110  	return ValueBindVariable(NewFloat64(v))
   111  }
   112  
   113  func DecimalBindVariable(v DecimalFloat) *querypb.BindVariable {
   114  	f := strconv.FormatFloat(float64(v), 'f', -1, 64)
   115  	return ValueBindVariable(NewDecimal(f))
   116  }
   117  
   118  // StringBindVariable converts a string to a bind var.
   119  func StringBindVariable(v string) *querypb.BindVariable {
   120  	return ValueBindVariable(NewVarChar(v))
   121  }
   122  
   123  // BytesBindVariable converts a []byte to a bind var.
   124  func BytesBindVariable(v []byte) *querypb.BindVariable {
   125  	return &querypb.BindVariable{Type: VarBinary, Value: v}
   126  }
   127  
   128  // ValueBindVariable converts a Value to a bind var.
   129  func ValueBindVariable(v Value) *querypb.BindVariable {
   130  	return &querypb.BindVariable{Type: v.typ, Value: v.val}
   131  }
   132  
   133  // BuildBindVariable builds a *querypb.BindVariable from a valid input type.
   134  func BuildBindVariable(v interface{}) (*querypb.BindVariable, error) {
   135  	switch v := v.(type) {
   136  	case string:
   137  		return StringBindVariable(v), nil
   138  	case []byte:
   139  		return BytesBindVariable(v), nil
   140  	case bool:
   141  		if v {
   142  			return Int8BindVariable(1), nil
   143  		}
   144  		return Int8BindVariable(0), nil
   145  	case int:
   146  		return &querypb.BindVariable{
   147  			Type:  querypb.Type_INT64,
   148  			Value: strconv.AppendInt(nil, int64(v), 10),
   149  		}, nil
   150  	case int64:
   151  		return Int64BindVariable(v), nil
   152  	case uint64:
   153  		return Uint64BindVariable(v), nil
   154  	case DecimalFloat:
   155  		return DecimalBindVariable(v), nil
   156  	case float64:
   157  		return Float64BindVariable(v), nil
   158  	case nil:
   159  		return NullBindVariable, nil
   160  	case Value:
   161  		return ValueBindVariable(v), nil
   162  	case *querypb.BindVariable:
   163  		return v, nil
   164  	case []interface{}:
   165  		bv := &querypb.BindVariable{
   166  			Type:   querypb.Type_TUPLE,
   167  			Values: make([]*querypb.Value, len(v)),
   168  		}
   169  		values := make([]querypb.Value, len(v))
   170  		for i, lv := range v {
   171  			lbv, err := BuildBindVariable(lv)
   172  			if err != nil {
   173  				return nil, err
   174  			}
   175  			values[i].Type = lbv.Type
   176  			values[i].Value = lbv.Value
   177  			bv.Values[i] = &values[i]
   178  		}
   179  		return bv, nil
   180  	case []string:
   181  		bv := &querypb.BindVariable{
   182  			Type:   querypb.Type_TUPLE,
   183  			Values: make([]*querypb.Value, len(v)),
   184  		}
   185  		values := make([]querypb.Value, len(v))
   186  		for i, lv := range v {
   187  			values[i].Type = querypb.Type_VARCHAR
   188  			values[i].Value = []byte(lv)
   189  			bv.Values[i] = &values[i]
   190  		}
   191  		return bv, nil
   192  	case [][]byte:
   193  		bv := &querypb.BindVariable{
   194  			Type:   querypb.Type_TUPLE,
   195  			Values: make([]*querypb.Value, len(v)),
   196  		}
   197  		values := make([]querypb.Value, len(v))
   198  		for i, lv := range v {
   199  			values[i].Type = querypb.Type_VARBINARY
   200  			values[i].Value = lv
   201  			bv.Values[i] = &values[i]
   202  		}
   203  		return bv, nil
   204  	case []int:
   205  		bv := &querypb.BindVariable{
   206  			Type:   querypb.Type_TUPLE,
   207  			Values: make([]*querypb.Value, len(v)),
   208  		}
   209  		values := make([]querypb.Value, len(v))
   210  		for i, lv := range v {
   211  			values[i].Type = querypb.Type_INT64
   212  			values[i].Value = strconv.AppendInt(nil, int64(lv), 10)
   213  			bv.Values[i] = &values[i]
   214  		}
   215  		return bv, nil
   216  	case []int64:
   217  		bv := &querypb.BindVariable{
   218  			Type:   querypb.Type_TUPLE,
   219  			Values: make([]*querypb.Value, len(v)),
   220  		}
   221  		values := make([]querypb.Value, len(v))
   222  		for i, lv := range v {
   223  			values[i].Type = querypb.Type_INT64
   224  			values[i].Value = strconv.AppendInt(nil, lv, 10)
   225  			bv.Values[i] = &values[i]
   226  		}
   227  		return bv, nil
   228  	case []uint64:
   229  		bv := &querypb.BindVariable{
   230  			Type:   querypb.Type_TUPLE,
   231  			Values: make([]*querypb.Value, len(v)),
   232  		}
   233  		values := make([]querypb.Value, len(v))
   234  		for i, lv := range v {
   235  			values[i].Type = querypb.Type_UINT64
   236  			values[i].Value = strconv.AppendUint(nil, lv, 10)
   237  			bv.Values[i] = &values[i]
   238  		}
   239  		return bv, nil
   240  	case []float64:
   241  		bv := &querypb.BindVariable{
   242  			Type:   querypb.Type_TUPLE,
   243  			Values: make([]*querypb.Value, len(v)),
   244  		}
   245  		values := make([]querypb.Value, len(v))
   246  		for i, lv := range v {
   247  			values[i].Type = querypb.Type_FLOAT64
   248  			values[i].Value = strconv.AppendFloat(nil, lv, 'g', -1, 64)
   249  			bv.Values[i] = &values[i]
   250  		}
   251  		return bv, nil
   252  	case []Value:
   253  		bv := &querypb.BindVariable{
   254  			Type:   querypb.Type_TUPLE,
   255  			Values: make([]*querypb.Value, len(v)),
   256  		}
   257  		values := make([]querypb.Value, len(v))
   258  		for i, lv := range v {
   259  			lbv, err := BuildBindVariable(lv)
   260  			if err != nil {
   261  				return nil, err
   262  			}
   263  			values[i].Type = lbv.Type
   264  			values[i].Value = lbv.Value
   265  			bv.Values[i] = &values[i]
   266  		}
   267  		return bv, nil
   268  	}
   269  	return nil, fmt.Errorf("type %T not supported as bind var: %v", v, v)
   270  }
   271  
   272  // ValidateBindVariables validates a map[string]*querypb.BindVariable.
   273  func ValidateBindVariables(bv map[string]*querypb.BindVariable) error {
   274  	for k, v := range bv {
   275  		if err := ValidateBindVariable(v); err != nil {
   276  			return fmt.Errorf("%s: %v", k, err)
   277  		}
   278  	}
   279  	return nil
   280  }
   281  
   282  // ValidateBindVariable returns an error if the bind variable has inconsistent
   283  // fields.
   284  func ValidateBindVariable(bv *querypb.BindVariable) error {
   285  	if bv == nil {
   286  		return errors.New("bind variable is nil")
   287  	}
   288  
   289  	if bv.Type == querypb.Type_TUPLE {
   290  		if len(bv.Values) == 0 {
   291  			return errors.New("empty tuple is not allowed")
   292  		}
   293  		for _, val := range bv.Values {
   294  			if val.Type == querypb.Type_TUPLE {
   295  				return errors.New("tuple not allowed inside another tuple")
   296  			}
   297  			if err := ValidateBindVariable(&querypb.BindVariable{Type: val.Type, Value: val.Value}); err != nil {
   298  				return err
   299  			}
   300  		}
   301  		return nil
   302  	}
   303  
   304  	// If NewValue succeeds, the value is valid.
   305  	_, err := NewValue(bv.Type, bv.Value)
   306  	return err
   307  }
   308  
   309  // BindVariableToValue converts a bind var into a Value.
   310  func BindVariableToValue(bv *querypb.BindVariable) (Value, error) {
   311  	if bv.Type == querypb.Type_TUPLE {
   312  		return NULL, errors.New("cannot convert a TUPLE bind var into a value")
   313  	}
   314  	return MakeTrusted(bv.Type, bv.Value), nil
   315  }
   316  
   317  // BindVariablesEqual compares two maps of bind variables.
   318  // For protobuf messages we have to use "proto.Equal".
   319  func BindVariablesEqual(x, y map[string]*querypb.BindVariable) bool {
   320  	return proto.Equal(&querypb.BoundQuery{BindVariables: x}, &querypb.BoundQuery{BindVariables: y})
   321  }
   322  
   323  // CopyBindVariables returns a shallow-copy of the given bindVariables map.
   324  func CopyBindVariables(bindVariables map[string]*querypb.BindVariable) map[string]*querypb.BindVariable {
   325  	result := make(map[string]*querypb.BindVariable, len(bindVariables))
   326  	for key, value := range bindVariables {
   327  		result[key] = value
   328  	}
   329  	return result
   330  }
   331  
   332  // FormatBindVariables returns a string representation of the
   333  // bind variables.
   334  //
   335  // If full is false, then large string or tuple values are truncated
   336  // to only print the lengths.
   337  //
   338  // If asJson is true, then the resulting string is a valid JSON
   339  // representation, otherwise it is the golang printed map representation.
   340  func FormatBindVariables(bindVariables map[string]*querypb.BindVariable, full, asJSON bool) string {
   341  	var out map[string]*querypb.BindVariable
   342  	if full {
   343  		out = bindVariables
   344  	} else {
   345  		// NOTE(szopa): I am getting rid of potentially large bind
   346  		// variables.
   347  		out = make(map[string]*querypb.BindVariable)
   348  		for k, v := range bindVariables {
   349  			if IsIntegral(v.Type) || IsFloat(v.Type) {
   350  				out[k] = v
   351  			} else if v.Type == querypb.Type_TUPLE {
   352  				out[k] = StringBindVariable(fmt.Sprintf("%v items", len(v.Values)))
   353  			} else {
   354  				out[k] = StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value)))
   355  			}
   356  		}
   357  	}
   358  
   359  	if asJSON {
   360  		var buf bytes.Buffer
   361  		buf.WriteString("{")
   362  		first := true
   363  		for k, v := range out {
   364  			if !first {
   365  				buf.WriteString(", ")
   366  			} else {
   367  				first = false
   368  			}
   369  			if IsIntegral(v.Type) || IsFloat(v.Type) {
   370  				fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value))
   371  			} else {
   372  				fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value))
   373  			}
   374  		}
   375  		buf.WriteString("}")
   376  		return buf.String()
   377  	}
   378  
   379  	return fmt.Sprintf("%v", out)
   380  }