github.com/dolthub/go-mysql-server@v0.18.0/sql/types/year.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  	"time"
    21  
    22  	"github.com/dolthub/vitess/go/sqltypes"
    23  	"github.com/dolthub/vitess/go/vt/proto/query"
    24  	"github.com/shopspring/decimal"
    25  	"gopkg.in/src-d/go-errors.v1"
    26  
    27  	"github.com/dolthub/go-mysql-server/sql"
    28  )
    29  
    30  var (
    31  	Year sql.YearType = YearType_{}
    32  
    33  	ErrConvertingToYear = errors.NewKind("value %v is not a valid Year")
    34  
    35  	yearValueType = reflect.TypeOf(int16(0))
    36  )
    37  
    38  type YearType_ struct{}
    39  
    40  // Compare implements Type interface.
    41  func (t YearType_) Compare(a interface{}, b interface{}) (int, error) {
    42  	if hasNulls, res := CompareNulls(a, b); hasNulls {
    43  		return res, nil
    44  	}
    45  
    46  	as, _, err := t.Convert(a)
    47  	if err != nil {
    48  		return 0, err
    49  	}
    50  	bs, _, err := t.Convert(b)
    51  	if err != nil {
    52  		return 0, err
    53  	}
    54  	ai := as.(int16)
    55  	bi := bs.(int16)
    56  
    57  	if ai == bi {
    58  		return 0, nil
    59  	}
    60  	if ai < bi {
    61  		return -1, nil
    62  	}
    63  	return 1, nil
    64  }
    65  
    66  // Convert implements Type interface.
    67  func (t YearType_) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) {
    68  	if v == nil {
    69  		return nil, sql.InRange, nil
    70  	}
    71  
    72  	switch value := v.(type) {
    73  	case int:
    74  		return t.Convert(int64(value))
    75  	case uint:
    76  		return t.Convert(int64(value))
    77  	case int8:
    78  		return t.Convert(int64(value))
    79  	case uint8:
    80  		return t.Convert(int64(value))
    81  	case int16:
    82  		return t.Convert(int64(value))
    83  	case uint16:
    84  		return t.Convert(int64(value))
    85  	case int32:
    86  		return t.Convert(int64(value))
    87  	case uint32:
    88  		return t.Convert(int64(value))
    89  	case int64:
    90  		if value == 0 {
    91  			return int16(0), sql.InRange, nil
    92  		}
    93  		if value >= 1 && value <= 69 {
    94  			return int16(value + 2000), sql.InRange, nil
    95  		}
    96  		if value >= 70 && value <= 99 {
    97  			return int16(value + 1900), sql.InRange, nil
    98  		}
    99  		if value >= 1901 && value <= 2155 {
   100  			return int16(value), sql.InRange, nil
   101  		}
   102  	case uint64:
   103  		return t.Convert(int64(value))
   104  	case float32:
   105  		return t.Convert(int64(value))
   106  	case float64:
   107  		return t.Convert(int64(value))
   108  	case decimal.Decimal:
   109  		return t.Convert(value.IntPart())
   110  	case decimal.NullDecimal:
   111  		if !value.Valid {
   112  			return nil, sql.InRange, nil
   113  		}
   114  		return t.Convert(value.Decimal.IntPart())
   115  	case string:
   116  		valueLength := len(value)
   117  		if valueLength == 1 || valueLength == 2 || valueLength == 4 {
   118  			i, err := strconv.ParseInt(value, 10, 64)
   119  			if err != nil {
   120  				return nil, sql.OutOfRange, err
   121  			}
   122  			if i == 0 {
   123  				return int16(2000), sql.InRange, nil
   124  			}
   125  			return t.Convert(i)
   126  		}
   127  	case time.Time:
   128  		year := value.Year()
   129  		if year == 0 || (year >= 1901 && year <= 2155) {
   130  			return int16(year), sql.InRange, nil
   131  		}
   132  	}
   133  
   134  	return nil, sql.InRange, ErrConvertingToYear.New(v)
   135  }
   136  
   137  // MustConvert implements the Type interface.
   138  func (t YearType_) MustConvert(v interface{}) interface{} {
   139  	value, _, err := t.Convert(v)
   140  	if err != nil {
   141  		panic(err)
   142  	}
   143  	return value
   144  }
   145  
   146  // Equals implements the Type interface.
   147  func (t YearType_) Equals(otherType sql.Type) bool {
   148  	_, ok := otherType.(YearType_)
   149  	return ok
   150  }
   151  
   152  // MaxTextResponseByteLength implements the Type interface
   153  func (t YearType_) MaxTextResponseByteLength(_ *sql.Context) uint32 {
   154  	return 4
   155  }
   156  
   157  // Promote implements the Type interface.
   158  func (t YearType_) Promote() sql.Type {
   159  	return t
   160  }
   161  
   162  // SQL implements Type interface.
   163  func (t YearType_) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) {
   164  	if v == nil {
   165  		return sqltypes.NULL, nil
   166  	}
   167  
   168  	v, _, err := t.Convert(v)
   169  	if err != nil {
   170  		return sqltypes.Value{}, err
   171  	}
   172  
   173  	stop := len(dest)
   174  	dest = strconv.AppendInt(dest, int64(v.(int16)), 10)
   175  	val := dest[stop:]
   176  
   177  	return sqltypes.MakeTrusted(sqltypes.Year, val), nil
   178  }
   179  
   180  // String implements Type interface.
   181  func (t YearType_) String() string {
   182  	return "year"
   183  }
   184  
   185  // Type implements Type interface.
   186  func (t YearType_) Type() query.Type {
   187  	return sqltypes.Year
   188  }
   189  
   190  // ValueType implements Type interface.
   191  func (t YearType_) ValueType() reflect.Type {
   192  	return yearValueType
   193  }
   194  
   195  // Zero implements Type interface.
   196  func (t YearType_) Zero() interface{} {
   197  	return int16(0)
   198  }
   199  
   200  // CollationCoercibility implements sql.CollationCoercible interface.
   201  func (YearType_) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   202  	return sql.Collation_binary, 5
   203  }