github.com/dolthub/go-mysql-server@v0.18.0/sql/types/system_double.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     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 types
    16  
    17  import (
    18  	"reflect"
    19  	"strconv"
    20  
    21  	"github.com/dolthub/vitess/go/sqltypes"
    22  	"github.com/dolthub/vitess/go/vt/proto/query"
    23  	"github.com/shopspring/decimal"
    24  
    25  	"github.com/dolthub/go-mysql-server/sql"
    26  )
    27  
    28  var systemDoubleValueType = reflect.TypeOf(float64(0))
    29  
    30  // systemDoubleType is an internal double type ONLY for system variables.
    31  type systemDoubleType struct {
    32  	varName    string
    33  	lowerbound float64
    34  	upperbound float64
    35  }
    36  
    37  var _ sql.SystemVariableType = systemDoubleType{}
    38  var _ sql.CollationCoercible = systemDoubleType{}
    39  
    40  // NewSystemDoubleType returns a new systemDoubleType.
    41  func NewSystemDoubleType(varName string, lowerbound, upperbound float64) sql.SystemVariableType {
    42  	return systemDoubleType{varName, lowerbound, upperbound}
    43  }
    44  
    45  // Compare implements Type interface.
    46  func (t systemDoubleType) Compare(a interface{}, b interface{}) (int, error) {
    47  	as, _, err := t.Convert(a)
    48  	if err != nil {
    49  		return 0, err
    50  	}
    51  	bs, _, err := t.Convert(b)
    52  	if err != nil {
    53  		return 0, err
    54  	}
    55  	ai := as.(float64)
    56  	bi := bs.(float64)
    57  
    58  	if ai == bi {
    59  		return 0, nil
    60  	}
    61  	if ai < bi {
    62  		return -1, nil
    63  	}
    64  	return 1, nil
    65  }
    66  
    67  // Convert implements Type interface.
    68  func (t systemDoubleType) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) {
    69  	// String nor nil values are accepted
    70  	switch value := v.(type) {
    71  	case int:
    72  		return t.Convert(float64(value))
    73  	case uint:
    74  		return t.Convert(float64(value))
    75  	case int8:
    76  		return t.Convert(float64(value))
    77  	case uint8:
    78  		return t.Convert(float64(value))
    79  	case int16:
    80  		return t.Convert(float64(value))
    81  	case uint16:
    82  		return t.Convert(float64(value))
    83  	case int32:
    84  		return t.Convert(float64(value))
    85  	case uint32:
    86  		return t.Convert(float64(value))
    87  	case int64:
    88  		return t.Convert(float64(value))
    89  	case uint64:
    90  		return t.Convert(float64(value))
    91  	case float32:
    92  		return t.Convert(float64(value))
    93  	case float64:
    94  		if value >= t.lowerbound && value <= t.upperbound {
    95  			return value, sql.InRange, nil
    96  		}
    97  	case decimal.Decimal:
    98  		f, _ := value.Float64()
    99  		return t.Convert(f)
   100  	case decimal.NullDecimal:
   101  		if value.Valid {
   102  			f, _ := value.Decimal.Float64()
   103  			return t.Convert(f)
   104  		}
   105  	}
   106  
   107  	return nil, sql.OutOfRange, sql.ErrInvalidSystemVariableValue.New(t.varName, v)
   108  }
   109  
   110  // MustConvert implements the Type interface.
   111  func (t systemDoubleType) MustConvert(v interface{}) interface{} {
   112  	value, _, err := t.Convert(v)
   113  	if err != nil {
   114  		panic(err)
   115  	}
   116  	return value
   117  }
   118  
   119  // Equals implements the Type interface.
   120  func (t systemDoubleType) Equals(otherType sql.Type) bool {
   121  	if ot, ok := otherType.(systemDoubleType); ok {
   122  		return t.varName == ot.varName && t.lowerbound == ot.lowerbound && t.upperbound == ot.upperbound
   123  	}
   124  	return false
   125  }
   126  
   127  // MaxTextResponseByteLength implements the Type interface
   128  func (t systemDoubleType) MaxTextResponseByteLength(ctx *sql.Context) uint32 {
   129  	return t.UnderlyingType().MaxTextResponseByteLength(ctx)
   130  }
   131  
   132  // Promote implements the Type interface.
   133  func (t systemDoubleType) Promote() sql.Type {
   134  	return t
   135  }
   136  
   137  // SQL implements Type interface.
   138  func (t systemDoubleType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) {
   139  	if v == nil {
   140  		return sqltypes.NULL, nil
   141  	}
   142  
   143  	v, _, err := t.Convert(v)
   144  	if err != nil {
   145  		return sqltypes.Value{}, err
   146  	}
   147  
   148  	stop := len(dest)
   149  	dest = strconv.AppendFloat(dest, v.(float64), 'f', -1, 64)
   150  	val := dest[stop:]
   151  
   152  	return sqltypes.MakeTrusted(t.Type(), val), nil
   153  }
   154  
   155  // String implements Type interface.
   156  func (t systemDoubleType) String() string {
   157  	return "system_double"
   158  }
   159  
   160  // Type implements Type interface.
   161  func (t systemDoubleType) Type() query.Type {
   162  	return sqltypes.Float64
   163  }
   164  
   165  // ValueType implements Type interface.
   166  func (t systemDoubleType) ValueType() reflect.Type {
   167  	return systemDoubleValueType
   168  }
   169  
   170  // Zero implements Type interface.
   171  func (t systemDoubleType) Zero() interface{} {
   172  	return float64(0)
   173  }
   174  
   175  // CollationCoercibility implements sql.CollationCoercible interface.
   176  func (systemDoubleType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   177  	return sql.Collation_binary, 5
   178  }
   179  
   180  // EncodeValue implements SystemVariableType interface.
   181  func (t systemDoubleType) EncodeValue(val interface{}) (string, error) {
   182  	expectedVal, ok := val.(float64)
   183  	if !ok {
   184  		return "", sql.ErrSystemVariableCodeFail.New(val, t.String())
   185  	}
   186  	return strconv.FormatFloat(expectedVal, 'f', -1, 64), nil
   187  }
   188  
   189  // DecodeValue implements SystemVariableType interface.
   190  func (t systemDoubleType) DecodeValue(val string) (interface{}, error) {
   191  	parsedVal, err := strconv.ParseFloat(val, 64)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	if parsedVal >= t.lowerbound && parsedVal <= t.upperbound {
   196  		return parsedVal, nil
   197  	}
   198  	return nil, sql.ErrSystemVariableCodeFail.New(val, t.String())
   199  }
   200  
   201  func (t systemDoubleType) UnderlyingType() sql.Type {
   202  	return Float64
   203  }