mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-20 11:22:31 -05:00
PR feedback & changes
This commit is contained in:
committed by
Daylon Wilkins
parent
beeb5fcb8e
commit
c52f790ac1
@@ -1,4 +1,4 @@
|
||||
pk, int, string, boolean, float, uint, uuid
|
||||
0, 0, "asdf", TRUE, 0.0, 0, "00000000-0000-0000-0000-000000000000"
|
||||
1, -1, "qwerty", FALSE, -1.0, 1, "00000000-0000-0000-0000-000000000001"
|
||||
2, 1, "", TRUE, 0.0, 0, "123e4567-e89b-12d3-a456-426655440000"
|
||||
0, 0, "asdf", 1, 0.0, 0, "00000000-0000-0000-0000-000000000000"
|
||||
1, -1, "qwerty", 0, -1.0, 1, "00000000-0000-0000-0000-000000000001"
|
||||
2, 1, "", 1, 0.0, 0, "123e4567-e89b-12d3-a456-426655440000"
|
||||
|
||||
|
@@ -54,7 +54,7 @@ teardown() {
|
||||
[[ "$output" =~ "\`pk\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`int\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`string\` LONGTEXT" ]] || false
|
||||
[[ "$output" =~ "\`boolean\` BIT(1)" ]] || false
|
||||
[[ "$output" =~ "\`boolean\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`float\` DOUBLE" ]] || false
|
||||
[[ "$output" =~ "\`uint\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`uuid\` CHAR(36) CHARACTER SET ascii COLLATE ascii_bin" ]] || false
|
||||
@@ -77,7 +77,7 @@ teardown() {
|
||||
[[ "$output" =~ "\`pk\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`int\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`string\` LONGTEXT" ]] || false
|
||||
[[ "$output" =~ "\`boolean\` BIT(1)" ]] || false
|
||||
[[ "$output" =~ "\`boolean\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`float\` DOUBLE" ]] || false
|
||||
[[ "$output" =~ "\`uint\` BIGINT" ]] || false
|
||||
[[ "$output" =~ "\`uuid\` CHAR(36) CHARACTER SET ascii COLLATE ascii_bin" ]] || false
|
||||
|
||||
28
go/Godeps/LICENSES
generated
28
go/Godeps/LICENSES
generated
@@ -953,34 +953,6 @@ SOFTWARE.
|
||||
= LICENSE 78b3d88d4101969f3415353aea94c9f4cce7ca238b012137e57e0273 =
|
||||
================================================================================
|
||||
|
||||
================================================================================
|
||||
= github.com/araddon/dateparse licensed under: =
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Aaron Raddon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
= LICENSE 99cb99e77c872d66840a2ae14e143620771335a758e6dd7d20f9fb23 =
|
||||
================================================================================
|
||||
|
||||
================================================================================
|
||||
= github.com/asaskevich/govalidator licensed under: =
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/utils/argparser"
|
||||
@@ -142,14 +143,15 @@ func ParseKeyValues(nbf *types.NomsBinFormat, sch schema.Schema, args []string)
|
||||
}
|
||||
}
|
||||
|
||||
convFuncs := make(map[uint64]types.MarshalCallback)
|
||||
convFuncs := make(map[uint64]func(*string) (types.Value, error))
|
||||
err := sch.GetPKCols().Iter(func(tag uint64, col schema.Column) (stop bool, err error) {
|
||||
convFunc, err := doltcore.GetConvFunc(types.StringKind, col.Kind)
|
||||
if err != nil {
|
||||
return false, ColumnError{col.Name, "Conversion from string to " + col.KindString() + "is not defined."}
|
||||
if col.TypeInfo.Equals(typeinfo.StringDefaultType) {
|
||||
convFuncs[tag] = func(v *string) (types.Value, error) {
|
||||
return types.String(*v), nil
|
||||
}
|
||||
} else {
|
||||
convFuncs[tag] = col.TypeInfo.ParseValue
|
||||
}
|
||||
|
||||
convFuncs[tag] = convFunc
|
||||
return false, nil
|
||||
})
|
||||
|
||||
@@ -161,7 +163,7 @@ func ParseKeyValues(nbf *types.NomsBinFormat, sch schema.Schema, args []string)
|
||||
for _, pkMap := range pkMaps {
|
||||
taggedVals := make(row.TaggedValues)
|
||||
for k, v := range pkMap {
|
||||
val, err := convFuncs[k](types.String(v))
|
||||
val, err := convFuncs[k](&v)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -18,11 +18,12 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/table/pipeline"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type FilterFn = func(r row.Row) (matchesFilter bool)
|
||||
@@ -67,14 +68,15 @@ func ParseWhere(sch schema.Schema, whereClause string) (FilterFn, error) {
|
||||
tags = append(tags, curr.Tag)
|
||||
}
|
||||
|
||||
convFunc, err := doltcore.GetConvFunc(types.StringKind, cols[0].Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, err := convFunc(types.String(valStr))
|
||||
if err != nil {
|
||||
return nil, errors.New("unable to convert '" + valStr + "' to " + col.KindString())
|
||||
var val types.Value
|
||||
if cols[0].TypeInfo.Equals(typeinfo.StringDefaultType) {
|
||||
val = types.String(valStr)
|
||||
} else {
|
||||
var err error
|
||||
val, err = cols[0].TypeInfo.ParseValue(&valStr)
|
||||
if err != nil {
|
||||
return nil, errors.New("unable to convert '" + valStr + "' to " + col.TypeInfo.String())
|
||||
}
|
||||
}
|
||||
|
||||
return func(r row.Row) bool {
|
||||
|
||||
@@ -94,7 +94,7 @@ require (
|
||||
|
||||
replace github.com/liquidata-inc/dolt/go/gen/proto/dolt/services/eventsapi => ./gen/proto/dolt/services/eventsapi
|
||||
|
||||
replace github.com/src-d/go-mysql-server => github.com/liquidata-inc/go-mysql-server v0.5.1-0.20200213191913-709d6546a1d8
|
||||
replace github.com/src-d/go-mysql-server => github.com/liquidata-inc/go-mysql-server v0.4.1-0.20200214233634-e82bed780f43
|
||||
|
||||
replace vitess.io/vitess => github.com/liquidata-inc/vitess v0.0.0-20200102230944-f3410911d61f
|
||||
|
||||
|
||||
@@ -341,6 +341,8 @@ github.com/krishicks/yaml-patch v0.0.10/go.mod h1:Sm5TchwZS6sm7RJoyg87tzxm2ZcKzd
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/liquidata-inc/go-mysql-server v0.4.1-0.20200214233634-e82bed780f43 h1:mzDAPBTZBjt+tSRlhQ0pGjIfjGJ0K94JYncn0tAIzIE=
|
||||
github.com/liquidata-inc/go-mysql-server v0.4.1-0.20200214233634-e82bed780f43/go.mod h1:Lh0pg7jnO08HxFm6oj6gtcSTUeeOTu4Spt50Aeo2mes=
|
||||
github.com/liquidata-inc/go-mysql-server v0.5.1-0.20200213191913-709d6546a1d8 h1:ONsKTlbNvi2frCctcqk8mQsQkRgqnf452i1uyhi+HWY=
|
||||
github.com/liquidata-inc/go-mysql-server v0.5.1-0.20200213191913-709d6546a1d8/go.mod h1:Lh0pg7jnO08HxFm6oj6gtcSTUeeOTu4Spt50Aeo2mes=
|
||||
github.com/liquidata-inc/ishell v0.0.0-20190514193646-693241f1f2a0 h1:phMgajKClMUiIr+hF2LGt8KRuUa2Vd2GI1sNgHgSXoU=
|
||||
|
||||
@@ -54,7 +54,7 @@ var testKeyCols = []schema.Column{
|
||||
}
|
||||
var testCols = []schema.Column{
|
||||
{Name: addrColName, Tag: addrColTag, Kind: types.StringKind, IsPartOfPK: false, TypeInfo: typeinfo.StringDefaultType, Constraints: nil},
|
||||
{Name: ageColName, Tag: ageColTag, Kind: types.UintKind, IsPartOfPK: false, TypeInfo: typeinfo.StringDefaultType, Constraints: nil},
|
||||
{Name: ageColName, Tag: ageColTag, Kind: types.UintKind, IsPartOfPK: false, TypeInfo: typeinfo.Uint64Type, Constraints: nil},
|
||||
{Name: titleColName, Tag: titleColTag, Kind: types.StringKind, IsPartOfPK: false, TypeInfo: typeinfo.StringDefaultType, Constraints: nil},
|
||||
{Name: reservedColName, Tag: reservedColTag, Kind: types.StringKind, IsPartOfPK: false, TypeInfo: typeinfo.StringDefaultType, Constraints: nil},
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ package rowconv
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/table/pipeline"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
@@ -56,13 +56,35 @@ func NewRowConverter(mapping *FieldMapping) (*RowConverter, error) {
|
||||
return nil, fmt.Errorf("Could not find column being mapped. src tag: %d, dest tag: %d", srcTag, destTag)
|
||||
}
|
||||
|
||||
convFunc, err := doltcore.GetConvFunc(srcCol.Kind, destCol.Kind)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unsupported conversion from type %s to %s", srcCol.KindString(), destCol.KindString())
|
||||
if srcCol.TypeInfo.Equals(destCol.TypeInfo) {
|
||||
convFuncs[srcTag] = func(v types.Value) (types.Value, error) {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
if destCol.TypeInfo.Equals(typeinfo.StringDefaultType) {
|
||||
convFuncs[srcTag] = func(v types.Value) (types.Value, error) {
|
||||
val, err := srcCol.TypeInfo.FormatValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.String(*val), nil
|
||||
}
|
||||
} else {
|
||||
convFuncs[srcTag] = func(v types.Value) (types.Value, error) {
|
||||
str, err := srcCol.TypeInfo.FormatValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, err := destCol.TypeInfo.ParseValue(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
}
|
||||
|
||||
convFuncs[srcTag] = convFunc
|
||||
}
|
||||
|
||||
return &RowConverter{mapping, false, convFuncs}, nil
|
||||
|
||||
@@ -36,7 +36,6 @@ var srcCols, _ = schema.NewColCollection(
|
||||
schema.NewColumn("inttostr", 4, types.IntKind, false),
|
||||
schema.NewColumn("stringtostr", 5, types.StringKind, false),
|
||||
schema.NewColumn("timestamptostr", 6, types.TimestampKind, false),
|
||||
schema.NewColumn("nulltostr", 7, types.NullKind, false),
|
||||
)
|
||||
|
||||
var srcSch = schema.SchemaFromCols(srcCols)
|
||||
@@ -62,7 +61,6 @@ func TestRowConverter(t *testing.T) {
|
||||
4: types.Int(-1234),
|
||||
5: types.String("string string string"),
|
||||
6: tt,
|
||||
7: types.NullValue,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
@@ -74,11 +72,10 @@ func TestRowConverter(t *testing.T) {
|
||||
0: types.String(id.String()),
|
||||
1: types.String("1.25"),
|
||||
2: types.String("12345678"),
|
||||
3: types.String("true"),
|
||||
3: types.String("1"),
|
||||
4: types.String("-1234"),
|
||||
5: types.String("string string string"),
|
||||
6: types.String(tt.String()),
|
||||
7: types.NullValue,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -44,7 +44,7 @@ var (
|
||||
InvalidTag,
|
||||
types.NullKind,
|
||||
false,
|
||||
typeinfo.NullType,
|
||||
typeinfo.UnknownType,
|
||||
nil,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -79,12 +79,12 @@ func encodeColumn(col schema.Column) encodedColumn {
|
||||
func (nfd encodedColumn) decodeColumn() (schema.Column, error) {
|
||||
var typeInfo typeinfo.TypeInfo
|
||||
var err error
|
||||
if nfd.Kind == "" && nfd.TypeInfo.Type != "" { // new format
|
||||
if nfd.TypeInfo.Type != "" {
|
||||
typeInfo, err = nfd.TypeInfo.decodeTypeInfo()
|
||||
if err != nil {
|
||||
return schema.Column{}, err
|
||||
}
|
||||
} else if nfd.Kind != "" && nfd.TypeInfo.Type == "" { // old format
|
||||
} else if nfd.Kind != "" {
|
||||
typeInfo = typeinfo.FromKind(schema.LwrStrToKind[nfd.Kind])
|
||||
} else {
|
||||
return schema.Column{}, errors.New("cannot decode column due to unknown schema format")
|
||||
|
||||
@@ -29,11 +29,11 @@ const (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Bit, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type bitImpl struct {
|
||||
type bitType struct {
|
||||
sqlBitType sql.BitType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*bitImpl)(nil)
|
||||
var _ TypeInfo = (*bitType)(nil)
|
||||
|
||||
func CreateBitTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if bitStr, ok := params[bitTypeParam_Bits]; ok {
|
||||
@@ -45,14 +45,14 @@ func CreateBitTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bitImpl{sqlBitType}, nil
|
||||
return &bitType{sqlBitType}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create bit type info is missing param "%v"`, bitTypeParam_Bits)
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *bitImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *bitType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Uint); ok {
|
||||
res, err := ti.sqlBitType.Convert(uint64(val))
|
||||
if err != nil {
|
||||
@@ -67,83 +67,102 @@ func (ti *bitImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *bitImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.Uint(artifact), nil
|
||||
func (ti *bitType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
uintVal, err := ti.sqlBitType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := uintVal.(uint64)
|
||||
if ok {
|
||||
return types.Uint(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *bitImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *bitType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*bitImpl); ok {
|
||||
if ti2, ok := other.(*bitType); ok {
|
||||
return ti.sqlBitType.NumberOfBits() == ti2.sqlBitType.NumberOfBits()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *bitType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
uintVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := uintVal.(uint64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
res := strconv.FormatUint(val, 10)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *bitImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *bitType) GetTypeIdentifier() Identifier {
|
||||
return BitTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *bitImpl) GetTypeParams() map[string]string {
|
||||
func (ti *bitType) GetTypeParams() map[string]string {
|
||||
return map[string]string{
|
||||
bitTypeParam_Bits: strconv.FormatInt(int64(ti.sqlBitType.NumberOfBits()), 10),
|
||||
}
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *bitImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *bitType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *bitImpl) NomsKind() types.NomsKind {
|
||||
func (ti *bitType) NomsKind() types.NomsKind {
|
||||
return types.UintKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *bitType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
if val, err := strconv.ParseUint(*str, 10, 64); err == nil {
|
||||
uintVal, err := ti.sqlBitType.Convert(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := uintVal.(uint64); ok {
|
||||
return types.Uint(val), nil
|
||||
}
|
||||
}
|
||||
strVal, err := ti.sqlBitType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(uint64); ok {
|
||||
return types.Uint(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *bitImpl) String() string {
|
||||
func (ti *bitType) String() string {
|
||||
return fmt.Sprintf("Bit(%v)", ti.sqlBitType.NumberOfBits())
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *bitImpl) ToSqlType() sql.Type {
|
||||
func (ti *bitType) ToSqlType() sql.Type {
|
||||
return ti.sqlBitType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *bitImpl) isValid(v interface{}) (artifact uint64, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := ti.sqlBitType.Convert(v)
|
||||
resUint, ok := res.(uint64)
|
||||
return resUint, err == nil && ok
|
||||
}
|
||||
|
||||
@@ -24,14 +24,16 @@ import (
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type boolImpl struct{}
|
||||
type boolType struct {
|
||||
sqlBitType sql.BitType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*boolImpl)(nil)
|
||||
var _ TypeInfo = (*boolType)(nil)
|
||||
|
||||
var BoolType TypeInfo = &boolImpl{}
|
||||
var BoolType TypeInfo = &boolType{sql.MustCreateBitType(1)}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *boolImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *boolType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Bool); ok {
|
||||
if val {
|
||||
return uint64(1), nil
|
||||
@@ -45,162 +47,114 @@ func (ti *boolImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *boolImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
return types.Bool(val), nil
|
||||
case int:
|
||||
return types.Bool(val != 0), nil
|
||||
case int8:
|
||||
return types.Bool(val != 0), nil
|
||||
case int16:
|
||||
return types.Bool(val != 0), nil
|
||||
case int32:
|
||||
return types.Bool(val != 0), nil
|
||||
case int64:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint8:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint16:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint32:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint64:
|
||||
return types.Bool(val != 0), nil
|
||||
case float32:
|
||||
return types.Bool(int64(math.Round(float64(val))) != 0), nil
|
||||
case float64:
|
||||
return types.Bool(int64(math.Round(val)) != 0), nil
|
||||
case string:
|
||||
return types.Bool(artifact != 0), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
return val, nil
|
||||
case types.Int:
|
||||
return types.Bool(val != 0), nil
|
||||
case types.Uint:
|
||||
return types.Bool(val != 0), nil
|
||||
case types.Float:
|
||||
return types.Bool(int64(math.Round(float64(val))) != 0), nil
|
||||
case types.String:
|
||||
return types.Bool(artifact != 0), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
func (ti *boolType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
return types.Bool(val), nil
|
||||
case int:
|
||||
return types.Bool(val != 0), nil
|
||||
case int8:
|
||||
return types.Bool(val != 0), nil
|
||||
case int16:
|
||||
return types.Bool(val != 0), nil
|
||||
case int32:
|
||||
return types.Bool(val != 0), nil
|
||||
case int64:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint8:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint16:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint32:
|
||||
return types.Bool(val != 0), nil
|
||||
case uint64:
|
||||
return types.Bool(val != 0), nil
|
||||
case float32:
|
||||
return types.Bool(int64(math.Round(float64(val))) != 0), nil
|
||||
case float64:
|
||||
return types.Bool(int64(math.Round(val)) != 0), nil
|
||||
case string:
|
||||
b, err := strconv.ParseBool(val)
|
||||
if err == nil {
|
||||
return types.Bool(b), nil
|
||||
}
|
||||
valInt, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" as it is invalid`, ti.String(), val)
|
||||
}
|
||||
return types.Bool(valInt != 0), nil
|
||||
case []byte:
|
||||
return ti.ConvertValueToNomsValue(string(val))
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *boolImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *boolType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*boolImpl)
|
||||
_, ok := other.(*boolType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *boolType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.Bool); ok {
|
||||
res := ""
|
||||
if val {
|
||||
res = "1"
|
||||
} else {
|
||||
res = "0"
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *boolImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *boolType) GetTypeIdentifier() Identifier {
|
||||
return BoolTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *boolImpl) GetTypeParams() map[string]string {
|
||||
func (ti *boolType) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *boolImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *boolType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *boolImpl) NomsKind() types.NomsKind {
|
||||
func (ti *boolType) NomsKind() types.NomsKind {
|
||||
return types.BoolKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *boolType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return ti.ConvertValueToNomsValue(*str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *boolImpl) String() string {
|
||||
func (ti *boolType) String() string {
|
||||
return "Bool"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *boolImpl) ToSqlType() sql.Type {
|
||||
return sql.MustCreateBitType(1)
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *boolImpl) isValid(v interface{}) (artifact int64, ok bool) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case bool:
|
||||
return 0, true
|
||||
case int:
|
||||
return 0, true
|
||||
case int8:
|
||||
return 0, true
|
||||
case int16:
|
||||
return 0, true
|
||||
case int32:
|
||||
return 0, true
|
||||
case int64:
|
||||
return 0, true
|
||||
case uint:
|
||||
return 0, true
|
||||
case uint8:
|
||||
return 0, true
|
||||
case uint16:
|
||||
return 0, true
|
||||
case uint32:
|
||||
return 0, true
|
||||
case uint64:
|
||||
return 0, true
|
||||
case float32:
|
||||
return 0, true
|
||||
case float64:
|
||||
return 0, true
|
||||
case string:
|
||||
b, err := strconv.ParseBool(val)
|
||||
if err == nil {
|
||||
if b {
|
||||
return 1, true
|
||||
}
|
||||
return 0, true
|
||||
}
|
||||
valInt, err := strconv.ParseInt(val, 10, 64)
|
||||
return valInt, err == nil
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
return 0, true
|
||||
case types.Int:
|
||||
return 0, true
|
||||
case types.Uint:
|
||||
return 0, true
|
||||
case types.Float:
|
||||
return 0, true
|
||||
case types.String:
|
||||
b, err := strconv.ParseBool(string(val))
|
||||
if err == nil {
|
||||
if b {
|
||||
return 1, true
|
||||
}
|
||||
return 0, true
|
||||
}
|
||||
valInt, err := strconv.ParseInt(string(val), 10, 64)
|
||||
return valInt, err == nil
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
func (ti *boolType) ToSqlType() sql.Type {
|
||||
return ti.sqlBitType
|
||||
}
|
||||
|
||||
@@ -16,91 +16,54 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
const (
|
||||
datetimeTypeParam_Min = "min"
|
||||
datetimeTypeParam_MinNano = "minnano"
|
||||
datetimeTypeParam_Max = "max"
|
||||
datetimeTypeParam_MaxNano = "maxnano"
|
||||
datetimeTypeParam_DateOnly = "date"
|
||||
datetimeTypeParam_SQL = "sql"
|
||||
datetimeTypeParam_SQL_Date = "date"
|
||||
datetimeTypeParam_SQL_Datetime = "datetime"
|
||||
datetimeTypeParam_SQL_Timestamp = "timestamp"
|
||||
)
|
||||
|
||||
type datetimeImpl struct {
|
||||
Min time.Time
|
||||
Max time.Time
|
||||
DateOnly bool
|
||||
type datetimeType struct {
|
||||
sqlDatetimeType sql.DatetimeType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*datetimeImpl)(nil)
|
||||
var _ TypeInfo = (*datetimeType)(nil)
|
||||
var (
|
||||
DateType = &datetimeType{sql.Date}
|
||||
DatetimeType = &datetimeType{sql.Datetime}
|
||||
TimestampType = &datetimeType{sql.Timestamp}
|
||||
)
|
||||
|
||||
func CreateDatetimeTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
var minInt int64
|
||||
var minNanoInt int64
|
||||
var err error
|
||||
if minStr, ok := params[datetimeTypeParam_Min]; ok {
|
||||
minInt, err = strconv.ParseInt(minStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if sqlType, ok := params[datetimeTypeParam_SQL]; ok {
|
||||
switch sqlType {
|
||||
case datetimeTypeParam_SQL_Date:
|
||||
return DateType, nil
|
||||
case datetimeTypeParam_SQL_Datetime:
|
||||
return DatetimeType, nil
|
||||
case datetimeTypeParam_SQL_Timestamp:
|
||||
return TimestampType, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`create datetime type info has invalid param "%v"`, sqlType)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create datetime type info is missing param "%v"`, datetimeTypeParam_Min)
|
||||
return nil, fmt.Errorf(`create datetime type info is missing param "%v"`, datetimeTypeParam_SQL)
|
||||
}
|
||||
if minNanoStr, ok := params[datetimeTypeParam_MinNano]; ok {
|
||||
minNanoInt, err = strconv.ParseInt(minNanoStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var maxInt int64
|
||||
var maxNanoInt int64
|
||||
if maxStr, ok := params[datetimeTypeParam_Max]; ok {
|
||||
maxInt, err = strconv.ParseInt(maxStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create datetime type info is missing param "%v"`, datetimeTypeParam_Max)
|
||||
}
|
||||
if maxNanoStr, ok := params[datetimeTypeParam_MaxNano]; ok {
|
||||
maxNanoInt, err = strconv.ParseInt(maxNanoStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var dateOnly bool
|
||||
if _, ok := params[datetimeTypeParam_DateOnly]; ok {
|
||||
dateOnly = true
|
||||
}
|
||||
ti := &datetimeImpl{time.Unix(minInt, minNanoInt), time.Unix(maxInt, maxNanoInt), dateOnly}
|
||||
if dateOnly {
|
||||
ti.Min = ti.Min.Truncate(24 * time.Hour)
|
||||
ti.Max = ti.Max.Truncate(24 * time.Hour)
|
||||
}
|
||||
if ti.Min.After(ti.Max) || ti.Min.Equal(ti.Max) {
|
||||
return nil, fmt.Errorf("create datetime type info has min >= max which is disallowed")
|
||||
}
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *datetimeType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
//TODO: handle the zero value as a special case that is valid for all ranges
|
||||
if val, ok := v.(types.Timestamp); ok {
|
||||
t := time.Time(val).UTC()
|
||||
if ti.DateOnly {
|
||||
t = t.Truncate(24 * time.Hour)
|
||||
}
|
||||
if (t.After(ti.Min) && t.Before(ti.Max)) || t.Equal(ti.Min) || t.Equal(ti.Max) {
|
||||
return t, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert time "%v" to value`, ti.String(), t.String())
|
||||
return ti.sqlDatetimeType.Convert(time.Time(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -109,148 +72,108 @@ func (ti *datetimeImpl) ConvertNomsValueToValue(v types.Value) (interface{}, err
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
func (ti *datetimeType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
//TODO: handle the zero value as a special case that is valid for all ranges
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case string:
|
||||
return types.Timestamp(artifact), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case time.Time:
|
||||
return types.Timestamp(artifact), nil
|
||||
case types.String:
|
||||
return types.Timestamp(artifact), nil
|
||||
case types.Timestamp:
|
||||
return types.Timestamp(artifact), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
timeVal, err := ti.sqlDatetimeType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := timeVal.(time.Time)
|
||||
if ok {
|
||||
return types.Timestamp(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *datetimeType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*datetimeImpl); ok {
|
||||
return ti.Min.Equal(ti2.Min) && ti.Max.Equal(ti2.Max)
|
||||
if ti2, ok := other.(*datetimeType); ok {
|
||||
return ti.sqlDatetimeType.Type() == ti2.sqlDatetimeType.Type()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *datetimeType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
timeVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := timeVal.(time.Time)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
if ti.sqlDatetimeType.Type() == sqltypes.Date {
|
||||
res := val.Format(sql.DateLayout)
|
||||
return &res, nil
|
||||
} else {
|
||||
res := val.Format(sql.TimestampDatetimeLayout)
|
||||
return &res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *datetimeType) GetTypeIdentifier() Identifier {
|
||||
return DatetimeTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) GetTypeParams() map[string]string {
|
||||
params := map[string]string{
|
||||
datetimeTypeParam_Min: strconv.FormatInt(ti.Min.Unix(), 10),
|
||||
datetimeTypeParam_Max: strconv.FormatInt(ti.Max.Unix(), 10),
|
||||
func (ti *datetimeType) GetTypeParams() map[string]string {
|
||||
sqlParam := ""
|
||||
switch ti.sqlDatetimeType.Type() {
|
||||
case sqltypes.Date:
|
||||
sqlParam = datetimeTypeParam_SQL_Date
|
||||
case sqltypes.Datetime:
|
||||
sqlParam = datetimeTypeParam_SQL_Datetime
|
||||
case sqltypes.Timestamp:
|
||||
sqlParam = datetimeTypeParam_SQL_Timestamp
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown datetime type info sql type "%v"`, ti.sqlDatetimeType.Type().String()))
|
||||
}
|
||||
if ti.DateOnly {
|
||||
params[datetimeTypeParam_DateOnly] = ""
|
||||
}
|
||||
return params
|
||||
return map[string]string{datetimeTypeParam_SQL: sqlParam}
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *datetimeType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) NomsKind() types.NomsKind {
|
||||
func (ti *datetimeType) NomsKind() types.NomsKind {
|
||||
return types.TimestampKind
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) String() string {
|
||||
dateOnly := ""
|
||||
if ti.DateOnly {
|
||||
dateOnly = ", DateOnly"
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *datetimeType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return fmt.Sprintf(`Datetime(Min: "%v", Max: "%v"%v)`, ti.Min.String(), ti.Max.String(), dateOnly)
|
||||
strVal, err := ti.sqlDatetimeType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(time.Time); ok {
|
||||
return types.Timestamp(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *datetimeType) String() string {
|
||||
return fmt.Sprintf(`Datetime(SQL: "%v")`, ti.sqlDatetimeType.String())
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *datetimeImpl) ToSqlType() sql.Type {
|
||||
if ti.DateOnly {
|
||||
return sql.Date
|
||||
}
|
||||
minTimestamp := sql.Timestamp.MinimumTime()
|
||||
maxTimestamp := sql.Timestamp.MaximumTime()
|
||||
if (ti.Min.Equal(minTimestamp) || ti.Min.After(minTimestamp)) && (ti.Max.Equal(maxTimestamp) || ti.Max.Before(maxTimestamp)) {
|
||||
return sql.Timestamp
|
||||
}
|
||||
return sql.Datetime
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *datetimeImpl) isValid(v interface{}) (artifact time.Time, ok bool) {
|
||||
//TODO: handle the zero value as a special case that is valid for all ranges
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return time.Time{}, true
|
||||
case string:
|
||||
for _, format := range sql.TimestampDatetimeLayouts {
|
||||
if t, err := time.Parse(format, val); err == nil {
|
||||
t = t.UTC()
|
||||
if ti.DateOnly {
|
||||
t = t.Truncate(24 * time.Hour)
|
||||
}
|
||||
if (t.After(ti.Min) && t.Before(ti.Max)) || t.Equal(ti.Min) || t.Equal(ti.Max) {
|
||||
return t, true
|
||||
}
|
||||
return time.Time{}, false
|
||||
}
|
||||
}
|
||||
return time.Time{}, false
|
||||
case types.Null:
|
||||
return time.Time{}, true
|
||||
case time.Time:
|
||||
val = val.UTC()
|
||||
if ti.DateOnly {
|
||||
val = val.Truncate(24 * time.Hour)
|
||||
}
|
||||
if (val.After(ti.Min) && val.Before(ti.Max)) || val.Equal(ti.Min) || val.Equal(ti.Max) {
|
||||
return val, true
|
||||
}
|
||||
return time.Time{}, false
|
||||
case types.String:
|
||||
valStr := string(val)
|
||||
for _, format := range sql.TimestampDatetimeLayouts {
|
||||
if t, err := time.Parse(format, valStr); err == nil {
|
||||
t = t.UTC()
|
||||
if ti.DateOnly {
|
||||
t = t.Truncate(24 * time.Hour)
|
||||
}
|
||||
if (t.After(ti.Min) && t.Before(ti.Max)) || t.Equal(ti.Min) || t.Equal(ti.Max) {
|
||||
return t, true
|
||||
}
|
||||
return time.Time{}, false
|
||||
}
|
||||
}
|
||||
return time.Time{}, false
|
||||
case types.Timestamp:
|
||||
t := time.Time(val).UTC()
|
||||
if ti.DateOnly {
|
||||
t = t.Truncate(24 * time.Hour)
|
||||
}
|
||||
if (t.After(ti.Min) && t.Before(ti.Max)) || t.Equal(ti.Min) || t.Equal(ti.Max) {
|
||||
return t, true
|
||||
}
|
||||
return time.Time{}, false
|
||||
default:
|
||||
return time.Time{}, false
|
||||
}
|
||||
func (ti *datetimeType) ToSqlType() sql.Type {
|
||||
return ti.sqlDatetimeType
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ const (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Decimal, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type decimalImpl struct {
|
||||
type decimalType struct {
|
||||
sqlDecimalType sql.DecimalType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*decimalImpl)(nil)
|
||||
var _ TypeInfo = (*decimalType)(nil)
|
||||
|
||||
func CreateDecimalTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
var precision uint8
|
||||
@@ -61,11 +61,11 @@ func CreateDecimalTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &decimalImpl{sqlDecimalType}, nil
|
||||
return &decimalType{sqlDecimalType}, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *decimalImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *decimalType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := ti.sqlDecimalType.Convert(string(val))
|
||||
if err != nil {
|
||||
@@ -80,36 +80,56 @@ func (ti *decimalImpl) ConvertNomsValueToValue(v types.Value) (interface{}, erro
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *decimalImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.String(artifact), nil
|
||||
func (ti *decimalType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
strVal, err := ti.sqlDecimalType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *decimalImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *decimalType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*decimalImpl); ok {
|
||||
if ti2, ok := other.(*decimalType); ok {
|
||||
return ti.sqlDecimalType.Precision() == ti2.sqlDecimalType.Precision() &&
|
||||
ti.sqlDecimalType.Scale() == ti2.sqlDecimalType.Scale()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *decimalType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
strVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return &val, nil
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *decimalImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *decimalType) GetTypeIdentifier() Identifier {
|
||||
return DecimalTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *decimalImpl) GetTypeParams() map[string]string {
|
||||
func (ti *decimalType) GetTypeParams() map[string]string {
|
||||
return map[string]string{
|
||||
decimalTypeParam_Precision: strconv.FormatUint(uint64(ti.sqlDecimalType.Precision()), 10),
|
||||
decimalTypeParam_Scale: strconv.FormatUint(uint64(ti.sqlDecimalType.Scale()), 10),
|
||||
@@ -117,48 +137,37 @@ func (ti *decimalImpl) GetTypeParams() map[string]string {
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *decimalImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *decimalType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *decimalImpl) NomsKind() types.NomsKind {
|
||||
func (ti *decimalType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *decimalType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlDecimalType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *decimalImpl) String() string {
|
||||
func (ti *decimalType) String() string {
|
||||
return fmt.Sprintf("Decimal(%v, %v)", ti.sqlDecimalType.Precision(), ti.sqlDecimalType.Scale())
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *decimalImpl) ToSqlType() sql.Type {
|
||||
func (ti *decimalType) ToSqlType() sql.Type {
|
||||
return ti.sqlDecimalType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *decimalImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := ti.sqlDecimalType.Convert(v)
|
||||
resStr, ok := res.(string)
|
||||
return resStr, err == nil && ok
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ const (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Enum, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type enumImpl struct {
|
||||
type enumType struct {
|
||||
sqlEnumType sql.EnumType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*enumImpl)(nil)
|
||||
var _ TypeInfo = (*enumType)(nil)
|
||||
|
||||
func CreateEnumTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
var collation sql.Collation
|
||||
@@ -62,11 +62,11 @@ func CreateEnumTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &enumImpl{sqlEnumType}, nil
|
||||
return &enumType{sqlEnumType}, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *enumImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *enumType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := ti.sqlEnumType.Convert(string(val))
|
||||
if err != nil {
|
||||
@@ -81,23 +81,27 @@ func (ti *enumImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *enumImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.String(artifact), nil
|
||||
func (ti *enumType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
strVal, err := ti.sqlEnumType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *enumImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *enumType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*enumImpl); ok && ti.sqlEnumType.NumberOfElements() == ti2.sqlEnumType.NumberOfElements() {
|
||||
if ti2, ok := other.(*enumType); ok && ti.sqlEnumType.NumberOfElements() == ti2.sqlEnumType.NumberOfElements() {
|
||||
tiVals := ti.sqlEnumType.Values()
|
||||
ti2Vals := ti2.sqlEnumType.Values()
|
||||
for i := range tiVals {
|
||||
@@ -110,13 +114,29 @@ func (ti *enumImpl) Equals(other TypeInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *enumType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
strVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return &val, nil
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *enumImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *enumType) GetTypeIdentifier() Identifier {
|
||||
return EnumTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *enumImpl) GetTypeParams() map[string]string {
|
||||
func (ti *enumType) GetTypeParams() map[string]string {
|
||||
var sb strings.Builder
|
||||
enc := gob.NewEncoder(&sb)
|
||||
err := enc.Encode(ti.sqlEnumType.Values())
|
||||
@@ -131,48 +151,37 @@ func (ti *enumImpl) GetTypeParams() map[string]string {
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *enumImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *enumType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *enumImpl) NomsKind() types.NomsKind {
|
||||
func (ti *enumType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *enumType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlEnumType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *enumImpl) String() string {
|
||||
func (ti *enumType) String() string {
|
||||
return fmt.Sprintf(`Enum(Collation: %v, Values: %v)`, ti.sqlEnumType.Collation().String(), strings.Join(ti.sqlEnumType.Values(), ", "))
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *enumImpl) ToSqlType() sql.Type {
|
||||
func (ti *enumType) ToSqlType() sql.Type {
|
||||
return ti.sqlEnumType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *enumImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := ti.sqlEnumType.Convert(v)
|
||||
resStr, ok := res.(string)
|
||||
return resStr, err == nil && ok
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
@@ -27,27 +27,27 @@ import (
|
||||
type FloatWidth int8
|
||||
|
||||
const (
|
||||
FloatWidth32 FloatWidth = 32
|
||||
FloatWidth64 FloatWidth = 64
|
||||
floatTypeParam_Width = "width"
|
||||
floatTypeParam_Width = "width"
|
||||
floatTypeParam_Width_32 = "32"
|
||||
floatTypeParam_Width_64 = "64"
|
||||
)
|
||||
|
||||
type floatImpl struct {
|
||||
Width FloatWidth
|
||||
type floatType struct {
|
||||
sqlFloatType sql.NumberType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*floatImpl)(nil)
|
||||
var _ TypeInfo = (*floatType)(nil)
|
||||
var (
|
||||
Float32Type TypeInfo = &floatImpl{FloatWidth32}
|
||||
Float64Type TypeInfo = &floatImpl{FloatWidth64}
|
||||
Float32Type = &floatType{sql.Float32}
|
||||
Float64Type = &floatType{sql.Float64}
|
||||
)
|
||||
|
||||
func CreateFloatTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if width, ok := params[floatTypeParam_Width]; ok {
|
||||
switch width {
|
||||
case "32":
|
||||
case floatTypeParam_Width_32:
|
||||
return Float32Type, nil
|
||||
case "64":
|
||||
case floatTypeParam_Width_64:
|
||||
return Float64Type, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`create float type info has "%v" param with value "%v"`, floatTypeParam_Width, width)
|
||||
@@ -57,16 +57,9 @@ func CreateFloatTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *floatImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *floatType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Float); ok {
|
||||
switch ti.Width {
|
||||
case FloatWidth32:
|
||||
return float32(val), nil
|
||||
case FloatWidth64:
|
||||
return float64(val), nil
|
||||
default:
|
||||
panic(fmt.Errorf(`float width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
return ti.sqlFloatType.Convert(float64(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -75,176 +68,107 @@ func (ti *floatImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *floatImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
if val {
|
||||
return types.Float(1), nil
|
||||
}
|
||||
return types.Float(0), nil
|
||||
case int:
|
||||
return types.Float(val), nil
|
||||
case int8:
|
||||
return types.Float(val), nil
|
||||
case int16:
|
||||
return types.Float(val), nil
|
||||
case int32:
|
||||
return types.Float(val), nil
|
||||
case int64:
|
||||
return types.Float(val), nil
|
||||
case uint:
|
||||
return types.Float(val), nil
|
||||
case uint8:
|
||||
return types.Float(val), nil
|
||||
case uint16:
|
||||
return types.Float(val), nil
|
||||
case uint32:
|
||||
return types.Float(val), nil
|
||||
case uint64:
|
||||
return types.Float(val), nil
|
||||
case float32:
|
||||
return types.Float(val), nil
|
||||
case float64:
|
||||
return types.Float(val), nil
|
||||
case string:
|
||||
return types.Float(artifact), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
if val {
|
||||
return types.Float(1), nil
|
||||
}
|
||||
return types.Float(0), nil
|
||||
case types.Int:
|
||||
return types.Float(val), nil
|
||||
case types.Uint:
|
||||
return types.Float(val), nil
|
||||
case types.Float:
|
||||
return val, nil
|
||||
case types.String:
|
||||
return types.Float(artifact), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *floatType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
fltVal, err := ti.sqlFloatType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := fltVal.(type) {
|
||||
case float32:
|
||||
return types.Float(val), nil
|
||||
case float64:
|
||||
return types.Float(val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *floatImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *floatType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*floatImpl); ok {
|
||||
return ti.Width == ti2.Width
|
||||
if ti2, ok := other.(*floatType); ok {
|
||||
return ti.sqlFloatType.Type() == ti2.sqlFloatType.Type()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *floatType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fltVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := fltVal.(type) {
|
||||
case float32:
|
||||
res := strconv.FormatFloat(float64(val), 'f', -1, 64)
|
||||
return &res, nil
|
||||
case float64:
|
||||
res := strconv.FormatFloat(val, 'f', -1, 64)
|
||||
return &res, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *floatImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *floatType) GetTypeIdentifier() Identifier {
|
||||
return FloatTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *floatImpl) GetTypeParams() map[string]string {
|
||||
return map[string]string{floatTypeParam_Width: strconv.Itoa(int(ti.Width))}
|
||||
func (ti *floatType) GetTypeParams() map[string]string {
|
||||
sqlParam := ""
|
||||
switch ti.sqlFloatType.Type() {
|
||||
case sqltypes.Float32:
|
||||
sqlParam = floatTypeParam_Width_32
|
||||
case sqltypes.Float64:
|
||||
sqlParam = floatTypeParam_Width_64
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown float type info sql type "%v"`, ti.sqlFloatType.Type().String()))
|
||||
}
|
||||
return map[string]string{floatTypeParam_Width: sqlParam}
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *floatImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *floatType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *floatImpl) NomsKind() types.NomsKind {
|
||||
func (ti *floatType) NomsKind() types.NomsKind {
|
||||
return types.FloatKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *floatType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return ti.ConvertValueToNomsValue(*str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *floatImpl) String() string {
|
||||
switch ti.Width {
|
||||
case FloatWidth32:
|
||||
func (ti *floatType) String() string {
|
||||
switch ti.sqlFloatType.Type() {
|
||||
case sqltypes.Float32:
|
||||
return "Float32"
|
||||
case FloatWidth64:
|
||||
case sqltypes.Float64:
|
||||
return "Float64"
|
||||
default:
|
||||
panic(fmt.Errorf(`float width "%v" is not valid`, ti.Width))
|
||||
panic(fmt.Errorf(`unknown float type info sql type "%v"`, ti.sqlFloatType.Type().String()))
|
||||
}
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *floatImpl) ToSqlType() sql.Type {
|
||||
switch ti.Width {
|
||||
case FloatWidth32:
|
||||
return sql.Float32
|
||||
case FloatWidth64:
|
||||
return sql.Float64
|
||||
default:
|
||||
panic(fmt.Errorf(`float width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *floatImpl) isValid(v interface{}) (artifact float64, ok bool) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case bool:
|
||||
return 0, true
|
||||
case int:
|
||||
return 0, true
|
||||
case int8:
|
||||
return 0, true
|
||||
case int16:
|
||||
return 0, true
|
||||
case int32:
|
||||
return 0, true
|
||||
case int64:
|
||||
return 0, true
|
||||
case uint:
|
||||
return 0, true
|
||||
case uint8:
|
||||
return 0, true
|
||||
case uint16:
|
||||
return 0, true
|
||||
case uint32:
|
||||
return 0, true
|
||||
case uint64:
|
||||
return 0, true
|
||||
case float32:
|
||||
return 0, true
|
||||
case float64:
|
||||
if ti.Width == FloatWidth32 {
|
||||
return 0, val >= -math.MaxFloat32 && val <= math.MaxFloat32
|
||||
}
|
||||
return 0, true
|
||||
case string:
|
||||
fltVal, err := strconv.ParseFloat(val, 64)
|
||||
return fltVal, err == nil
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
return 0, true
|
||||
case types.Int:
|
||||
return 0, true
|
||||
case types.Uint:
|
||||
return 0, true
|
||||
case types.Float:
|
||||
if ti.Width == FloatWidth32 {
|
||||
return 0, val >= -math.MaxFloat32 && val <= math.MaxFloat32
|
||||
}
|
||||
return 0, true
|
||||
case types.String:
|
||||
fltVal, err := strconv.ParseFloat(string(val), 64)
|
||||
return fltVal, err == nil
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
func (ti *floatType) ToSqlType() sql.Type {
|
||||
return ti.sqlFloatType
|
||||
}
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
package typeinfo
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
@@ -26,16 +24,18 @@ import (
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type inlineBlobImpl struct{}
|
||||
type inlineBlobType struct {
|
||||
sqlBinaryType sql.StringType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*inlineBlobImpl)(nil)
|
||||
var _ TypeInfo = (*inlineBlobType)(nil)
|
||||
|
||||
var InlineBlobType TypeInfo = &inlineBlobImpl{}
|
||||
var InlineBlobType = &inlineBlobType{sql.MustCreateBinary(sqltypes.VarBinary, math.MaxUint16)}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *inlineBlobType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.InlineBlob); ok {
|
||||
return strings.ToUpper(hex.EncodeToString(val)), nil
|
||||
return string(val), nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -44,86 +44,91 @@ func (ti *inlineBlobImpl) ConvertNomsValueToValue(v types.Value) (interface{}, e
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if _, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case []byte:
|
||||
return types.InlineBlob(val), nil
|
||||
case string:
|
||||
return types.InlineBlob(val), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.InlineBlob:
|
||||
return val, nil
|
||||
case types.String:
|
||||
return types.InlineBlob(val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *inlineBlobType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
strVal, err := ti.sqlBinaryType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.InlineBlob(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *inlineBlobType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*inlineBlobImpl)
|
||||
_, ok := other.(*inlineBlobType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *inlineBlobType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.InlineBlob); ok {
|
||||
convVal, err := ti.ConvertNomsValueToValue(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, ok := convVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *inlineBlobType) GetTypeIdentifier() Identifier {
|
||||
return InlineBlobTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) GetTypeParams() map[string]string {
|
||||
func (ti *inlineBlobType) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *inlineBlobType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) NomsKind() types.NomsKind {
|
||||
func (ti *inlineBlobType) NomsKind() types.NomsKind {
|
||||
return types.InlineBlobKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *inlineBlobType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlBinaryType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.InlineBlob(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) String() string {
|
||||
func (ti *inlineBlobType) String() string {
|
||||
return "InlineBlob"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *inlineBlobImpl) ToSqlType() sql.Type {
|
||||
return sql.MustCreateBinary(sqltypes.VarBinary, math.MaxUint16)
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *inlineBlobImpl) isValid(v interface{}) (artifact []byte, ok bool) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return nil, true
|
||||
case []byte:
|
||||
return nil, len(val) <= math.MaxUint16
|
||||
case string:
|
||||
return nil, len(val) <= math.MaxUint16
|
||||
case types.Null:
|
||||
return nil, true
|
||||
case types.InlineBlob:
|
||||
return nil, len(val) <= math.MaxUint16
|
||||
case types.String:
|
||||
return nil, len(val) <= math.MaxUint16
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
func (ti *inlineBlobType) ToSqlType() sql.Type {
|
||||
return ti.sqlBinaryType
|
||||
}
|
||||
|
||||
@@ -16,55 +16,48 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type IntWidth int8
|
||||
|
||||
const (
|
||||
IntWidth8 IntWidth = 8
|
||||
IntWidth16 IntWidth = 16
|
||||
IntWidth24 IntWidth = 24
|
||||
IntWidth32 IntWidth = 32
|
||||
IntWidth64 IntWidth = 64
|
||||
intTypeParams_Width = "width"
|
||||
intTypeParams_Width_8 = "8"
|
||||
intTypeParams_Width_16 = "16"
|
||||
intTypeParams_Width_24 = "24"
|
||||
intTypeParams_Width_32 = "32"
|
||||
intTypeParams_Width_64 = "64"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxInt24 = 1<<23 - 1
|
||||
MinInt24 = -1 << 23
|
||||
intTypeParams_Width = "width"
|
||||
)
|
||||
|
||||
type intImpl struct {
|
||||
Width IntWidth
|
||||
type intType struct {
|
||||
sqlIntType sql.NumberType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*intImpl)(nil)
|
||||
var _ TypeInfo = (*intType)(nil)
|
||||
var (
|
||||
Int8Type TypeInfo = &intImpl{IntWidth8}
|
||||
Int16Type TypeInfo = &intImpl{IntWidth16}
|
||||
Int24Type TypeInfo = &intImpl{IntWidth24}
|
||||
Int32Type TypeInfo = &intImpl{IntWidth32}
|
||||
Int64Type TypeInfo = &intImpl{IntWidth64}
|
||||
Int8Type = &intType{sql.Int8}
|
||||
Int16Type = &intType{sql.Int16}
|
||||
Int24Type = &intType{sql.Int24}
|
||||
Int32Type = &intType{sql.Int32}
|
||||
Int64Type = &intType{sql.Int64}
|
||||
)
|
||||
|
||||
func CreateIntTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if width, ok := params[intTypeParams_Width]; ok {
|
||||
switch width {
|
||||
case "8":
|
||||
case intTypeParams_Width_8:
|
||||
return Int8Type, nil
|
||||
case "16":
|
||||
case intTypeParams_Width_16:
|
||||
return Int16Type, nil
|
||||
case "24":
|
||||
case intTypeParams_Width_24:
|
||||
return Int24Type, nil
|
||||
case "32":
|
||||
case intTypeParams_Width_32:
|
||||
return Int32Type, nil
|
||||
case "64":
|
||||
case intTypeParams_Width_64:
|
||||
return Int64Type, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`create int type info has "%v" param with value "%v"`, intTypeParams_Width, width)
|
||||
@@ -74,22 +67,9 @@ func CreateIntTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *intImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *intType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Int); ok {
|
||||
switch ti.Width {
|
||||
case IntWidth8:
|
||||
return int8(val), nil
|
||||
case IntWidth16:
|
||||
return int16(val), nil
|
||||
case IntWidth24:
|
||||
return int32(val), nil
|
||||
case IntWidth32:
|
||||
return int32(val), nil
|
||||
case IntWidth64:
|
||||
return int64(val), nil
|
||||
default:
|
||||
panic(fmt.Errorf(`int width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
return ti.sqlIntType.Convert(int64(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -98,204 +78,129 @@ func (ti *intImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *intImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
if val {
|
||||
return types.Int(1), nil
|
||||
}
|
||||
return types.Int(0), nil
|
||||
case int:
|
||||
return types.Int(val), nil
|
||||
case int8:
|
||||
return types.Int(val), nil
|
||||
case int16:
|
||||
return types.Int(val), nil
|
||||
case int32:
|
||||
return types.Int(val), nil
|
||||
case int64:
|
||||
return types.Int(val), nil
|
||||
case uint:
|
||||
return types.Int(val), nil
|
||||
case uint8:
|
||||
return types.Int(val), nil
|
||||
case uint16:
|
||||
return types.Int(val), nil
|
||||
case uint32:
|
||||
return types.Int(val), nil
|
||||
case uint64:
|
||||
return types.Int(val), nil
|
||||
case float32:
|
||||
return types.Int(val), nil
|
||||
case float64:
|
||||
return types.Int(val), nil
|
||||
case string:
|
||||
return types.Int(artifact), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
if val {
|
||||
return types.Int(1), nil
|
||||
}
|
||||
return types.Int(0), nil
|
||||
case types.Int:
|
||||
return val, nil
|
||||
case types.Uint:
|
||||
return types.Int(val), nil
|
||||
case types.Float:
|
||||
return types.Int(val), nil
|
||||
case types.String:
|
||||
return types.Int(artifact), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *intType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
intVal, err := ti.sqlIntType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := intVal.(type) {
|
||||
case int8:
|
||||
return types.Int(val), nil
|
||||
case int16:
|
||||
return types.Int(val), nil
|
||||
case int32:
|
||||
return types.Int(val), nil
|
||||
case int64:
|
||||
return types.Int(val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *intImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *intType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*intImpl); ok {
|
||||
return ti.Width == ti2.Width
|
||||
if ti2, ok := other.(*intType); ok {
|
||||
return ti.sqlIntType.Type() == ti2.sqlIntType.Type()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *intType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
intVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := intVal.(type) {
|
||||
case int8:
|
||||
res := strconv.FormatInt(int64(val), 10)
|
||||
return &res, nil
|
||||
case int16:
|
||||
res := strconv.FormatInt(int64(val), 10)
|
||||
return &res, nil
|
||||
case int32:
|
||||
res := strconv.FormatInt(int64(val), 10)
|
||||
return &res, nil
|
||||
case int64:
|
||||
res := strconv.FormatInt(val, 10)
|
||||
return &res, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *intImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *intType) GetTypeIdentifier() Identifier {
|
||||
return IntTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *intImpl) GetTypeParams() map[string]string {
|
||||
return map[string]string{intTypeParams_Width: strconv.Itoa(int(ti.Width))}
|
||||
func (ti *intType) GetTypeParams() map[string]string {
|
||||
sqlParam := ""
|
||||
switch ti.sqlIntType.Type() {
|
||||
case sqltypes.Int8:
|
||||
sqlParam = intTypeParams_Width_8
|
||||
case sqltypes.Int16:
|
||||
sqlParam = intTypeParams_Width_16
|
||||
case sqltypes.Int24:
|
||||
sqlParam = intTypeParams_Width_24
|
||||
case sqltypes.Int32:
|
||||
sqlParam = intTypeParams_Width_32
|
||||
case sqltypes.Int64:
|
||||
sqlParam = intTypeParams_Width_64
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown int type info sql type "%v"`, ti.sqlIntType.Type().String()))
|
||||
}
|
||||
return map[string]string{intTypeParams_Width: sqlParam}
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *intImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *intType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *intImpl) NomsKind() types.NomsKind {
|
||||
func (ti *intType) NomsKind() types.NomsKind {
|
||||
return types.IntKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *intType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return ti.ConvertValueToNomsValue(*str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *intImpl) String() string {
|
||||
switch ti.Width {
|
||||
case IntWidth8:
|
||||
func (ti *intType) String() string {
|
||||
switch ti.sqlIntType.Type() {
|
||||
case sqltypes.Int8:
|
||||
return "Int8"
|
||||
case IntWidth16:
|
||||
case sqltypes.Int16:
|
||||
return "Int16"
|
||||
case IntWidth24:
|
||||
case sqltypes.Int24:
|
||||
return "Int24"
|
||||
case IntWidth32:
|
||||
case sqltypes.Int32:
|
||||
return "Int32"
|
||||
case IntWidth64:
|
||||
case sqltypes.Int64:
|
||||
return "Int64"
|
||||
default:
|
||||
panic(fmt.Errorf(`int width "%v" is not valid`, ti.Width))
|
||||
panic(fmt.Errorf(`unknown int type info sql type "%v"`, ti.sqlIntType.Type().String()))
|
||||
}
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *intImpl) ToSqlType() sql.Type {
|
||||
switch ti.Width {
|
||||
case IntWidth8:
|
||||
return sql.Int8
|
||||
case IntWidth16:
|
||||
return sql.Int16
|
||||
case IntWidth24:
|
||||
return sql.Int24
|
||||
case IntWidth32:
|
||||
return sql.Int32
|
||||
case IntWidth64:
|
||||
return sql.Int64
|
||||
default:
|
||||
panic(fmt.Errorf(`int width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *intImpl) isValid(v interface{}) (artifact int64, ok bool) {
|
||||
var minValue int64
|
||||
var maxValue int64
|
||||
switch ti.Width {
|
||||
case IntWidth8:
|
||||
minValue = math.MinInt8
|
||||
maxValue = math.MaxInt8
|
||||
case IntWidth16:
|
||||
minValue = math.MinInt16
|
||||
maxValue = math.MaxInt16
|
||||
case IntWidth24:
|
||||
minValue = MinInt24
|
||||
maxValue = MaxInt24
|
||||
case IntWidth32:
|
||||
minValue = math.MinInt32
|
||||
maxValue = math.MaxInt32
|
||||
case IntWidth64:
|
||||
minValue = math.MinInt64
|
||||
maxValue = math.MaxInt64
|
||||
default:
|
||||
panic(fmt.Errorf(`int width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case bool:
|
||||
return 0, true
|
||||
case int:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case int8:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case int16:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case int32:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case int64:
|
||||
return 0, val >= minValue && val <= maxValue
|
||||
case uint:
|
||||
return 0, int64(val) <= maxValue
|
||||
case uint8:
|
||||
return 0, int64(val) <= maxValue
|
||||
case uint16:
|
||||
return 0, int64(val) <= maxValue
|
||||
case uint32:
|
||||
return 0, int64(val) <= maxValue
|
||||
case uint64:
|
||||
return 0, val <= uint64(maxValue)
|
||||
case float32:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case float64:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case string:
|
||||
intVal, err := strconv.ParseInt(val, 10, 64)
|
||||
return intVal, err == nil
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
return 0, true
|
||||
case types.Int:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case types.Uint:
|
||||
return 0, uint64(val) <= uint64(maxValue)
|
||||
case types.Float:
|
||||
return 0, int64(val) >= minValue && int64(val) <= maxValue
|
||||
case types.String:
|
||||
intVal, err := strconv.ParseInt(string(val), 10, 64)
|
||||
return intVal, err == nil
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
func (ti *intType) ToSqlType() sql.Type {
|
||||
return ti.sqlIntType
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright 2020 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package typeinfo
|
||||
|
||||
import (
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type nullImpl struct{}
|
||||
|
||||
var _ TypeInfo = (*nullImpl)(nil)
|
||||
|
||||
var NullType TypeInfo = &nullImpl{}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *nullImpl) ConvertNomsValueToValue(types.Value) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *nullImpl) ConvertValueToNomsValue(interface{}) (types.Value, error) {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *nullImpl) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*nullImpl)
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *nullImpl) GetTypeIdentifier() Identifier {
|
||||
return NullTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *nullImpl) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *nullImpl) IsValid(interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *nullImpl) NomsKind() types.NomsKind {
|
||||
return types.NullKind
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *nullImpl) String() string {
|
||||
return "Null"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *nullImpl) ToSqlType() sql.Type {
|
||||
return sql.Null
|
||||
}
|
||||
@@ -31,11 +31,11 @@ const (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Set, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type setImpl struct {
|
||||
type setType struct {
|
||||
sqlSetType sql.SetType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*setImpl)(nil)
|
||||
var _ TypeInfo = (*setType)(nil)
|
||||
|
||||
func CreateSetTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
var collation sql.Collation
|
||||
@@ -62,11 +62,11 @@ func CreateSetTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &setImpl{sqlSetType}, nil
|
||||
return &setType{sqlSetType}, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *setImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *setType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := ti.sqlSetType.Convert(string(val))
|
||||
if err != nil {
|
||||
@@ -81,23 +81,27 @@ func (ti *setImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *setImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.String(artifact), nil
|
||||
func (ti *setType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlSetType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *setImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *setType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*setImpl); ok && ti.sqlSetType.NumberOfElements() == ti2.sqlSetType.NumberOfElements() {
|
||||
if ti2, ok := other.(*setType); ok && ti.sqlSetType.NumberOfElements() == ti2.sqlSetType.NumberOfElements() {
|
||||
tiVals := ti.sqlSetType.Values()
|
||||
ti2Vals := ti2.sqlSetType.Values()
|
||||
for i := range tiVals {
|
||||
@@ -110,13 +114,29 @@ func (ti *setImpl) Equals(other TypeInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *setType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
strVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return &val, nil
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *setImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *setType) GetTypeIdentifier() Identifier {
|
||||
return SetTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *setImpl) GetTypeParams() map[string]string {
|
||||
func (ti *setType) GetTypeParams() map[string]string {
|
||||
var sb strings.Builder
|
||||
enc := gob.NewEncoder(&sb)
|
||||
err := enc.Encode(ti.sqlSetType.Values())
|
||||
@@ -131,48 +151,37 @@ func (ti *setImpl) GetTypeParams() map[string]string {
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *setImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *setType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *setImpl) NomsKind() types.NomsKind {
|
||||
func (ti *setType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *setType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlSetType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *setImpl) String() string {
|
||||
func (ti *setType) String() string {
|
||||
return fmt.Sprintf(`Set(Collation: %v, Values: %v)`, ti.sqlSetType.Collation().String(), strings.Join(ti.sqlSetType.Values(), ","))
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *setImpl) ToSqlType() sql.Type {
|
||||
func (ti *setType) ToSqlType() sql.Type {
|
||||
return ti.sqlSetType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *setImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := ti.sqlSetType.Convert(v)
|
||||
resStr, ok := res.(string)
|
||||
return resStr, err == nil && ok
|
||||
}
|
||||
|
||||
@@ -24,20 +24,19 @@ import (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Time, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type timeImpl struct{}
|
||||
type timeType struct {
|
||||
sqlTimeType sql.TimeType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*timeImpl)(nil)
|
||||
var _ TypeInfo = (*timeType)(nil)
|
||||
|
||||
var TimeType TypeInfo = &timeImpl{}
|
||||
var TimeType = &timeType{sql.Time}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *timeImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *timeType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
//TODO: expose the MySQL type's microsecond implementation and persist that to disk? Enables sorting
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := sql.Time.Convert(string(val))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`"%v" cannot convert "%v" to value`, ti.String(), val)
|
||||
}
|
||||
return res, nil
|
||||
return string(val), nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -46,79 +45,84 @@ func (ti *timeImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *timeImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.String(artifact), nil
|
||||
func (ti *timeType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlTimeType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *timeImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *timeType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*timeImpl)
|
||||
_, ok := other.(*timeType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *timeType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res := string(val)
|
||||
return &res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *timeImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *timeType) GetTypeIdentifier() Identifier {
|
||||
return TimeTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *timeImpl) GetTypeParams() map[string]string {
|
||||
func (ti *timeType) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *timeImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *timeType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *timeImpl) NomsKind() types.NomsKind {
|
||||
func (ti *timeType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *timeType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlTimeType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *timeImpl) String() string {
|
||||
func (ti *timeType) String() string {
|
||||
return "Time"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *timeImpl) ToSqlType() sql.Type {
|
||||
return sql.Time
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *timeImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := sql.Time.Convert(v)
|
||||
resStr, ok := res.(string)
|
||||
return resStr, err == nil && ok
|
||||
func (ti *timeType) ToSqlType() sql.Type {
|
||||
return ti.sqlTimeType
|
||||
}
|
||||
|
||||
@@ -22,19 +22,23 @@ import (
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type tupleImpl struct{}
|
||||
type tupleType struct{}
|
||||
|
||||
var _ TypeInfo = (*tupleImpl)(nil)
|
||||
var _ TypeInfo = (*tupleType)(nil)
|
||||
|
||||
var TupleType TypeInfo = &tupleImpl{}
|
||||
// This is for internal use only. Used in merge conflicts.
|
||||
var TupleType = &tupleType{}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *tupleImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *tupleType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if _, ok := v.(types.Null); ok {
|
||||
return nil, nil
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *tupleImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
func (ti *tupleType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if tVal, ok := v.(types.Value); ok {
|
||||
return tVal, nil
|
||||
}
|
||||
@@ -45,26 +49,31 @@ func (ti *tupleImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *tupleImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *tupleType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*tupleImpl)
|
||||
_, ok := other.(*tupleType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *tupleType) FormatValue(v types.Value) (*string, error) {
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *tupleImpl) GetTypeIdentifier() Identifier {
|
||||
return TupleIdentifier
|
||||
func (ti *tupleType) GetTypeIdentifier() Identifier {
|
||||
return TupleTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *tupleImpl) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
func (ti *tupleType) GetTypeParams() map[string]string {
|
||||
panic("cannot persist tuple type")
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *tupleImpl) IsValid(v interface{}) bool {
|
||||
func (ti *tupleType) IsValid(v types.Value) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
@@ -73,16 +82,21 @@ func (ti *tupleImpl) IsValid(v interface{}) bool {
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *tupleImpl) NomsKind() types.NomsKind {
|
||||
func (ti *tupleType) NomsKind() types.NomsKind {
|
||||
return types.TupleKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *tupleType) ParseValue(str *string) (types.Value, error) {
|
||||
return nil, fmt.Errorf(`"%v" cannot parse strings`, ti.String())
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *tupleImpl) String() string {
|
||||
func (ti *tupleType) String() string {
|
||||
return "Tuple"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *tupleImpl) ToSqlType() sql.Type {
|
||||
return sql.LongText
|
||||
func (ti *tupleType) ToSqlType() sql.Type {
|
||||
panic("we should never be calling the SQL type on a Tuple column")
|
||||
}
|
||||
|
||||
@@ -35,10 +35,9 @@ const (
|
||||
FloatTypeIdentifier Identifier = "float"
|
||||
InlineBlobTypeIdentifier Identifier = "inlineblob"
|
||||
IntTypeIdentifier Identifier = "int"
|
||||
NullTypeIdentifier Identifier = "null"
|
||||
SetTypeIdentifier Identifier = "set"
|
||||
TimeTypeIdentifier Identifier = "time"
|
||||
TupleIdentifier Identifier = "tuple"
|
||||
TupleTypeIdentifier Identifier = "tuple"
|
||||
UintTypeIdentifier Identifier = "uint"
|
||||
UuidTypeIdentifier Identifier = "uuid"
|
||||
VarBinaryTypeIdentifier Identifier = "varbinary"
|
||||
@@ -56,10 +55,9 @@ var Identifiers = map[Identifier]struct{}{
|
||||
FloatTypeIdentifier: {},
|
||||
InlineBlobTypeIdentifier: {},
|
||||
IntTypeIdentifier: {},
|
||||
NullTypeIdentifier: {},
|
||||
SetTypeIdentifier: {},
|
||||
TimeTypeIdentifier: {},
|
||||
TupleIdentifier: {},
|
||||
TupleTypeIdentifier: {},
|
||||
UintTypeIdentifier: {},
|
||||
UuidTypeIdentifier: {},
|
||||
VarBinaryTypeIdentifier: {},
|
||||
@@ -80,6 +78,9 @@ type TypeInfo interface {
|
||||
// Equals returns whether the given TypeInfo is equivalent to this TypeInfo.
|
||||
Equals(other TypeInfo) bool
|
||||
|
||||
// FormatValue returns the stringified version of the value.
|
||||
FormatValue(v types.Value) (*string, error)
|
||||
|
||||
// GetTypeIdentifier returns an identifier for this type used for serialization.
|
||||
GetTypeIdentifier() Identifier
|
||||
|
||||
@@ -88,11 +89,14 @@ type TypeInfo interface {
|
||||
GetTypeParams() map[string]string
|
||||
|
||||
// IsValid takes in a value (go or Noms) and returns whether the value is valid for this type.
|
||||
IsValid(v interface{}) bool
|
||||
IsValid(v types.Value) bool
|
||||
|
||||
// NomsKind returns the NomsKind that best matches this TypeInfo.
|
||||
NomsKind() types.NomsKind
|
||||
|
||||
// ParseValue parses a string and returns a go value that represents it according to this type.
|
||||
ParseValue(str *string) (types.Value, error)
|
||||
|
||||
// ToSqlType returns the TypeInfo as a sql.Type. If an exact match is able to be made then that is
|
||||
// the one returned, otherwise the sql.Type is the closest match possible.
|
||||
ToSqlType() sql.Type
|
||||
@@ -105,7 +109,7 @@ type TypeInfo interface {
|
||||
func FromSqlType(sqlType sql.Type) (TypeInfo, error) {
|
||||
switch sqlType.Type() {
|
||||
case sqltypes.Null:
|
||||
return NullType, nil
|
||||
return UnknownType, nil
|
||||
case sqltypes.Int8:
|
||||
return Int8Type, nil
|
||||
case sqltypes.Int16:
|
||||
@@ -131,114 +135,103 @@ func FromSqlType(sqlType sql.Type) (TypeInfo, error) {
|
||||
case sqltypes.Float64:
|
||||
return Float64Type, nil
|
||||
case sqltypes.Timestamp:
|
||||
datetimeType, ok := sqlType.(sql.DatetimeType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "DatetimeTypeIdentifier" from SQL basetype "Timestamp"`)
|
||||
}
|
||||
return &datetimeImpl{
|
||||
Min: datetimeType.MinimumTime(),
|
||||
Max: datetimeType.MaximumTime(),
|
||||
DateOnly: false,
|
||||
}, nil
|
||||
return TimestampType, nil
|
||||
case sqltypes.Date:
|
||||
datetimeType, ok := sqlType.(sql.DatetimeType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "DatetimeTypeIdentifier" from SQL basetype "Date"`)
|
||||
}
|
||||
return &datetimeImpl{
|
||||
Min: datetimeType.MinimumTime(),
|
||||
Max: datetimeType.MaximumTime(),
|
||||
DateOnly: true,
|
||||
}, nil
|
||||
return DateType, nil
|
||||
case sqltypes.Time:
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
return TimeType, nil
|
||||
case sqltypes.Datetime:
|
||||
datetimeType, ok := sqlType.(sql.DatetimeType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "DatetimeTypeIdentifier" from SQL basetype "Datetime"`)
|
||||
}
|
||||
return &datetimeImpl{
|
||||
Min: datetimeType.MinimumTime(),
|
||||
Max: datetimeType.MaximumTime(),
|
||||
DateOnly: false,
|
||||
}, nil
|
||||
return DatetimeType, nil
|
||||
case sqltypes.Year:
|
||||
return YearType, nil
|
||||
case sqltypes.Decimal:
|
||||
decimalType, ok := sqlType.(sql.DecimalType)
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
decimalSQLType, ok := sqlType.(sql.DecimalType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "DecimalTypeIdentifier" from SQL basetype "Decimal"`)
|
||||
}
|
||||
return &decimalImpl{decimalType}, nil
|
||||
return &decimalType{decimalSQLType}, nil
|
||||
case sqltypes.Text:
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "Text"`)
|
||||
}
|
||||
return &varStringImpl{
|
||||
stringType.Collation(),
|
||||
stringType.MaxCharacterLength(),
|
||||
false,
|
||||
true,
|
||||
}, nil
|
||||
return &varStringType{stringType}, nil
|
||||
case sqltypes.Blob:
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "Blob"`)
|
||||
}
|
||||
return &varBinaryImpl{stringType.MaxByteLength(), false, true}, nil
|
||||
return &varBinaryType{stringType}, nil
|
||||
case sqltypes.VarChar:
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "VarChar"`)
|
||||
}
|
||||
return &varStringImpl{
|
||||
stringType.Collation(),
|
||||
stringType.MaxCharacterLength(),
|
||||
false,
|
||||
false,
|
||||
}, nil
|
||||
return &varStringType{stringType}, nil
|
||||
case sqltypes.VarBinary:
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "VarBinary"`)
|
||||
}
|
||||
return &varBinaryImpl{stringType.MaxByteLength(), false, false}, nil
|
||||
return &varBinaryType{stringType}, nil
|
||||
case sqltypes.Char:
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "Char"`)
|
||||
}
|
||||
return &varStringImpl{
|
||||
stringType.Collation(),
|
||||
stringType.MaxCharacterLength(),
|
||||
true,
|
||||
false,
|
||||
}, nil
|
||||
return &varStringType{stringType}, nil
|
||||
case sqltypes.Binary:
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
stringType, ok := sqlType.(sql.StringType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "StringType" from SQL basetype "Binary"`)
|
||||
}
|
||||
return &varBinaryImpl{stringType.MaxByteLength(), true, false}, nil
|
||||
return &varBinaryType{stringType}, nil
|
||||
case sqltypes.Bit:
|
||||
bitType, ok := sqlType.(sql.BitType)
|
||||
bitSQLType, ok := sqlType.(sql.BitType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "BitTypeIdentifier" from SQL basetype "Bit"`)
|
||||
}
|
||||
return &bitImpl{bitType}, nil
|
||||
return &bitType{bitSQLType}, nil
|
||||
case sqltypes.Enum:
|
||||
enumType, ok := sqlType.(sql.EnumType)
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
enumSQLType, ok := sqlType.(sql.EnumType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "EnumTypeIdentifier" from SQL basetype "Enum"`)
|
||||
}
|
||||
return &enumImpl{enumType}, nil
|
||||
return &enumType{enumSQLType}, nil
|
||||
case sqltypes.Set:
|
||||
setType, ok := sqlType.(sql.SetType)
|
||||
//TODO: determine the storage format
|
||||
if fmt.Sprintf("a") != "" { // always evaluates to true, compiler won't complain about unreachable code
|
||||
return nil, fmt.Errorf(`"%v" has not yet been implemented`, sqlType.String())
|
||||
}
|
||||
setSQLType, ok := sqlType.(sql.SetType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`expected "SetTypeIdentifier" from SQL basetype "Set"`)
|
||||
}
|
||||
return &setImpl{setType}, nil
|
||||
return &setType{setSQLType}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`no type info can be created from SQL base type "%v"`, sqlType.String())
|
||||
}
|
||||
@@ -263,13 +256,11 @@ func FromTypeParams(id Identifier, params map[string]string) (TypeInfo, error) {
|
||||
return InlineBlobType, nil
|
||||
case IntTypeIdentifier:
|
||||
return CreateIntTypeFromParams(params)
|
||||
case NullTypeIdentifier:
|
||||
return NullType, nil
|
||||
case SetTypeIdentifier:
|
||||
return CreateSetTypeFromParams(params)
|
||||
case TimeTypeIdentifier:
|
||||
return TimeType, nil
|
||||
case TupleIdentifier:
|
||||
case TupleTypeIdentifier:
|
||||
return TupleType, nil
|
||||
case UintTypeIdentifier:
|
||||
return CreateUintTypeFromParams(params)
|
||||
@@ -298,18 +289,11 @@ func FromKind(kind types.NomsKind) TypeInfo {
|
||||
case types.IntKind:
|
||||
return Int64Type
|
||||
case types.NullKind:
|
||||
return NullType
|
||||
return UnknownType
|
||||
case types.StringKind:
|
||||
return StringDefaultType
|
||||
case types.TimestampKind:
|
||||
// Here we set it to the limits of the SQL Datetime type just so conversions
|
||||
// between the two types are straightforward. This is an arbitrary decision and
|
||||
// this can definitely be widened later if we decide to.
|
||||
return &datetimeImpl{
|
||||
sql.Datetime.MinimumTime(),
|
||||
sql.Datetime.MaximumTime(),
|
||||
false,
|
||||
}
|
||||
return DatetimeType
|
||||
case types.TupleKind:
|
||||
return TupleType
|
||||
case types.UintKind:
|
||||
|
||||
@@ -16,54 +16,48 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type UintWidth int8
|
||||
|
||||
const (
|
||||
UintWidth8 UintWidth = 8
|
||||
UintWidth16 UintWidth = 16
|
||||
UintWidth24 UintWidth = 24
|
||||
UintWidth32 UintWidth = 32
|
||||
UintWidth64 UintWidth = 64
|
||||
uintTypeParam_Width = "width"
|
||||
uintTypeParam_Width = "width"
|
||||
uintTypeParam_Width_8 = "8"
|
||||
uintTypeParam_Width_16 = "16"
|
||||
uintTypeParam_Width_24 = "24"
|
||||
uintTypeParam_Width_32 = "32"
|
||||
uintTypeParam_Width_64 = "64"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxUint24 = 1 << 24
|
||||
)
|
||||
|
||||
type uintImpl struct {
|
||||
Width UintWidth
|
||||
type uintType struct {
|
||||
sqlUintType sql.NumberType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*uintImpl)(nil)
|
||||
var _ TypeInfo = (*uintType)(nil)
|
||||
var (
|
||||
Uint8Type TypeInfo = &uintImpl{UintWidth8}
|
||||
Uint16Type TypeInfo = &uintImpl{UintWidth16}
|
||||
Uint24Type TypeInfo = &uintImpl{UintWidth24}
|
||||
Uint32Type TypeInfo = &uintImpl{UintWidth32}
|
||||
Uint64Type TypeInfo = &uintImpl{UintWidth64}
|
||||
Uint8Type = &uintType{sql.Uint8}
|
||||
Uint16Type = &uintType{sql.Uint16}
|
||||
Uint24Type = &uintType{sql.Uint24}
|
||||
Uint32Type = &uintType{sql.Uint32}
|
||||
Uint64Type = &uintType{sql.Uint64}
|
||||
)
|
||||
|
||||
func CreateUintTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
if width, ok := params[uintTypeParam_Width]; ok {
|
||||
switch width {
|
||||
case "8":
|
||||
case uintTypeParam_Width_8:
|
||||
return Uint8Type, nil
|
||||
case "16":
|
||||
case uintTypeParam_Width_16:
|
||||
return Uint16Type, nil
|
||||
case "24":
|
||||
case uintTypeParam_Width_24:
|
||||
return Uint24Type, nil
|
||||
case "32":
|
||||
case uintTypeParam_Width_32:
|
||||
return Uint32Type, nil
|
||||
case "64":
|
||||
case uintTypeParam_Width_64:
|
||||
return Uint64Type, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`create uint type info has "%v" param with value "%v"`, uintTypeParam_Width, width)
|
||||
@@ -73,22 +67,9 @@ func CreateUintTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *uintImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *uintType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Uint); ok {
|
||||
switch ti.Width {
|
||||
case UintWidth8:
|
||||
return uint8(val), nil
|
||||
case UintWidth16:
|
||||
return uint16(val), nil
|
||||
case UintWidth24:
|
||||
return uint32(val), nil
|
||||
case UintWidth32:
|
||||
return uint32(val), nil
|
||||
case UintWidth64:
|
||||
return uint64(val), nil
|
||||
default:
|
||||
panic(fmt.Errorf(`uint width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
return ti.sqlUintType.Convert(uint64(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -97,198 +78,129 @@ func (ti *uintImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *uintImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
if val {
|
||||
return types.Uint(1), nil
|
||||
}
|
||||
return types.Uint(0), nil
|
||||
case int:
|
||||
return types.Uint(val), nil
|
||||
case int8:
|
||||
return types.Uint(val), nil
|
||||
case int16:
|
||||
return types.Uint(val), nil
|
||||
case int32:
|
||||
return types.Uint(val), nil
|
||||
case int64:
|
||||
return types.Uint(val), nil
|
||||
case uint:
|
||||
return types.Uint(val), nil
|
||||
case uint8:
|
||||
return types.Uint(val), nil
|
||||
case uint16:
|
||||
return types.Uint(val), nil
|
||||
case uint32:
|
||||
return types.Uint(val), nil
|
||||
case uint64:
|
||||
return types.Uint(val), nil
|
||||
case float32:
|
||||
return types.Uint(val), nil
|
||||
case float64:
|
||||
return types.Uint(val), nil
|
||||
case string:
|
||||
return types.Uint(artifact), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
if val {
|
||||
return types.Uint(1), nil
|
||||
}
|
||||
return types.Uint(0), nil
|
||||
case types.Int:
|
||||
return types.Uint(val), nil
|
||||
case types.Uint:
|
||||
return val, nil
|
||||
case types.Float:
|
||||
return types.Uint(val), nil
|
||||
case types.String:
|
||||
return types.Uint(artifact), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *uintType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
uintVal, err := ti.sqlUintType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := uintVal.(type) {
|
||||
case uint8:
|
||||
return types.Uint(val), nil
|
||||
case uint16:
|
||||
return types.Uint(val), nil
|
||||
case uint32:
|
||||
return types.Uint(val), nil
|
||||
case uint64:
|
||||
return types.Uint(val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *uintImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *uintType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*uintImpl); ok {
|
||||
return ti.Width == ti2.Width
|
||||
if ti2, ok := other.(*uintType); ok {
|
||||
return ti.sqlUintType.Type() == ti2.sqlUintType.Type()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *uintType) FormatValue(v types.Value) (*string, error) {
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
uintVal, err := ti.ConvertNomsValueToValue(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch val := uintVal.(type) {
|
||||
case uint8:
|
||||
res := strconv.FormatUint(uint64(val), 10)
|
||||
return &res, nil
|
||||
case uint16:
|
||||
res := strconv.FormatUint(uint64(val), 10)
|
||||
return &res, nil
|
||||
case uint32:
|
||||
res := strconv.FormatUint(uint64(val), 10)
|
||||
return &res, nil
|
||||
case uint64:
|
||||
res := strconv.FormatUint(val, 10)
|
||||
return &res, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *uintImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *uintType) GetTypeIdentifier() Identifier {
|
||||
return UintTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *uintImpl) GetTypeParams() map[string]string {
|
||||
return map[string]string{uintTypeParam_Width: strconv.Itoa(int(ti.Width))}
|
||||
func (ti *uintType) GetTypeParams() map[string]string {
|
||||
sqlParam := ""
|
||||
switch ti.sqlUintType.Type() {
|
||||
case sqltypes.Uint8:
|
||||
sqlParam = uintTypeParam_Width_8
|
||||
case sqltypes.Uint16:
|
||||
sqlParam = uintTypeParam_Width_16
|
||||
case sqltypes.Uint24:
|
||||
sqlParam = uintTypeParam_Width_24
|
||||
case sqltypes.Uint32:
|
||||
sqlParam = uintTypeParam_Width_32
|
||||
case sqltypes.Uint64:
|
||||
sqlParam = uintTypeParam_Width_64
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown uint type info sql type "%v"`, ti.sqlUintType.Type().String()))
|
||||
}
|
||||
return map[string]string{uintTypeParam_Width: sqlParam}
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *uintImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *uintType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *uintImpl) NomsKind() types.NomsKind {
|
||||
func (ti *uintType) NomsKind() types.NomsKind {
|
||||
return types.UintKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *uintType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return ti.ConvertValueToNomsValue(*str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *uintImpl) String() string {
|
||||
switch ti.Width {
|
||||
case UintWidth8:
|
||||
func (ti *uintType) String() string {
|
||||
switch ti.sqlUintType.Type() {
|
||||
case sqltypes.Uint8:
|
||||
return "Uint8"
|
||||
case UintWidth16:
|
||||
case sqltypes.Uint16:
|
||||
return "Uint16"
|
||||
case UintWidth24:
|
||||
case sqltypes.Uint24:
|
||||
return "Uint24"
|
||||
case UintWidth32:
|
||||
case sqltypes.Uint32:
|
||||
return "Uint32"
|
||||
case UintWidth64:
|
||||
case sqltypes.Uint64:
|
||||
return "Uint64"
|
||||
default:
|
||||
panic(fmt.Errorf(`uint width "%v" is not valid`, ti.Width))
|
||||
panic(fmt.Errorf(`unknown uint type info sql type "%v"`, ti.sqlUintType.Type().String()))
|
||||
}
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *uintImpl) ToSqlType() sql.Type {
|
||||
switch ti.Width {
|
||||
case UintWidth8:
|
||||
return sql.Uint8
|
||||
case UintWidth16:
|
||||
return sql.Uint16
|
||||
case UintWidth24:
|
||||
return sql.Uint24
|
||||
case UintWidth32:
|
||||
return sql.Uint32
|
||||
case UintWidth64:
|
||||
return sql.Uint64
|
||||
default:
|
||||
panic(fmt.Errorf(`uint width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *uintImpl) isValid(v interface{}) (artifact uint64, ok bool) {
|
||||
var maxValue uint64
|
||||
switch ti.Width {
|
||||
case UintWidth8:
|
||||
maxValue = math.MaxUint8
|
||||
case UintWidth16:
|
||||
maxValue = math.MaxUint16
|
||||
case UintWidth24:
|
||||
maxValue = MaxUint24
|
||||
case UintWidth32:
|
||||
maxValue = math.MaxUint32
|
||||
case UintWidth64:
|
||||
maxValue = math.MaxUint64
|
||||
default:
|
||||
panic(fmt.Errorf(`uint width "%v" is not valid`, ti.Width))
|
||||
}
|
||||
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case bool:
|
||||
return 0, true
|
||||
case int:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case int8:
|
||||
return 0, val >= 0
|
||||
case int16:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case int32:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case int64:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case uint:
|
||||
return 0, uint64(val) <= maxValue
|
||||
case uint8:
|
||||
return 0, uint64(val) <= maxValue
|
||||
case uint16:
|
||||
return 0, uint64(val) <= maxValue
|
||||
case uint32:
|
||||
return 0, uint64(val) <= maxValue
|
||||
case uint64:
|
||||
return 0, val <= maxValue
|
||||
case float32:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case float64:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case string:
|
||||
uintVal, err := strconv.ParseUint(val, 10, 64)
|
||||
return uintVal, err == nil
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
return 0, true
|
||||
case types.Int:
|
||||
return 0, int64(val) >= 0 && uint64(val) <= maxValue
|
||||
case types.Uint:
|
||||
return 0, uint64(val) <= maxValue
|
||||
case types.Float:
|
||||
return 0, val >= 0 && uint64(val) <= maxValue
|
||||
case types.String:
|
||||
uintVal, err := strconv.ParseUint(string(val), 10, 64)
|
||||
return uintVal, err == nil
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
func (ti *uintType) ToSqlType() sql.Type {
|
||||
return ti.sqlUintType
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ func (ti *unknownImpl) Equals(TypeInfo) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *unknownImpl) FormatValue(types.Value) (*string, error) {
|
||||
return nil, fmt.Errorf(`"Unknown" cannot convert any Noms value to a string`)
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *unknownImpl) GetTypeIdentifier() Identifier {
|
||||
return UnknownTypeIdentifier
|
||||
@@ -50,11 +55,11 @@ func (ti *unknownImpl) GetTypeIdentifier() Identifier {
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *unknownImpl) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
panic("cannot persist unknown type")
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *unknownImpl) IsValid(v interface{}) bool {
|
||||
func (ti *unknownImpl) IsValid(types.Value) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -63,6 +68,11 @@ func (ti *unknownImpl) NomsKind() types.NomsKind {
|
||||
return types.UnknownKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *unknownImpl) ParseValue(*string) (types.Value, error) {
|
||||
return nil, fmt.Errorf(`"Unknown" cannot convert any strings to a Noms value`)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *unknownImpl) String() string {
|
||||
return "Unknown"
|
||||
|
||||
@@ -24,14 +24,16 @@ import (
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type uuidImpl struct{}
|
||||
type uuidType struct {
|
||||
sqlCharType sql.StringType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*uuidImpl)(nil)
|
||||
var _ TypeInfo = (*uuidType)(nil)
|
||||
|
||||
var UuidType TypeInfo = &uuidImpl{}
|
||||
var UuidType = &uuidType{sql.MustCreateString(sqltypes.Char, 36, sql.Collation_ascii_bin)}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *uuidImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *uuidType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.UUID); ok {
|
||||
return val.String(), nil
|
||||
}
|
||||
@@ -42,88 +44,83 @@ func (ti *uuidImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *uuidImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case string:
|
||||
return types.UUID(artifact), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case uuid.UUID:
|
||||
return types.UUID(val), nil
|
||||
case types.String:
|
||||
return types.UUID(artifact), nil
|
||||
case types.UUID:
|
||||
return val, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
func (ti *uuidType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case string:
|
||||
valUuid, err := uuid.Parse(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.UUID(valUuid), err
|
||||
case uuid.UUID:
|
||||
return types.UUID(val), nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *uuidImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *uuidType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*uuidImpl)
|
||||
_, ok := other.(*uuidType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *uuidType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.UUID); ok {
|
||||
res := val.String()
|
||||
return &res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *uuidImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *uuidType) GetTypeIdentifier() Identifier {
|
||||
return UuidTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *uuidImpl) GetTypeParams() map[string]string {
|
||||
func (ti *uuidType) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *uuidImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *uuidType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *uuidImpl) NomsKind() types.NomsKind {
|
||||
func (ti *uuidType) NomsKind() types.NomsKind {
|
||||
return types.UUIDKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *uuidType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
uuidVal, err := uuid.Parse(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.UUID(uuidVal), nil
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *uuidImpl) String() string {
|
||||
func (ti *uuidType) String() string {
|
||||
return "Uuid"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *uuidImpl) ToSqlType() sql.Type {
|
||||
return sql.MustCreateString(sqltypes.Char, 36, sql.Collation_ascii_bin)
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *uuidImpl) isValid(v interface{}) (artifact uuid.UUID, ok bool) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return uuid.UUID{}, true
|
||||
case string:
|
||||
valUuid, err := uuid.Parse(val)
|
||||
return valUuid, err == nil
|
||||
case types.Null:
|
||||
return uuid.UUID{}, true
|
||||
case uuid.UUID:
|
||||
return val, true
|
||||
case types.String:
|
||||
valUuid, err := uuid.Parse(string(val))
|
||||
return valUuid, err == nil
|
||||
case types.UUID:
|
||||
return uuid.UUID(val), true
|
||||
default:
|
||||
return uuid.UUID{}, false
|
||||
}
|
||||
func (ti *uuidType) ToSqlType() sql.Type {
|
||||
return ti.sqlCharType
|
||||
}
|
||||
|
||||
@@ -25,50 +25,59 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
varBinaryTypeParam_Length = "length"
|
||||
varBinaryTypeParam_PadBytes = "pad"
|
||||
varBinaryTypeParam_IsSqlBlob = "blob"
|
||||
varBinaryTypeParam_Length = "length"
|
||||
varBinaryTypeParam_SQL = "sql"
|
||||
varBinaryTypeParam_SQL_Binary = "bin"
|
||||
varBinaryTypeParam_SQL_VarBinary = "varbin"
|
||||
varBinaryTypeParam_SQL_Blob = "blob"
|
||||
)
|
||||
|
||||
// As a type, this is modeled more after MySQL's story for binary data. There, it's treated
|
||||
// as a string that is interpreted as raw bytes, rather than as a bespoke data structure,
|
||||
// and thus this is mirrored here in its implementation. This will minimize any differences
|
||||
// that could arise.
|
||||
type varBinaryImpl struct {
|
||||
MaxLength int64
|
||||
PadBytes bool
|
||||
IsSqlBlob bool // When converting to a SQL type, this ensures a distinction between BLOB and VARBINARY
|
||||
type varBinaryType struct {
|
||||
sqlBinaryType sql.StringType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*varBinaryImpl)(nil)
|
||||
var _ TypeInfo = (*varBinaryType)(nil)
|
||||
|
||||
func CreateVarBinaryTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
ti := &varBinaryImpl{}
|
||||
var length int64
|
||||
var err error
|
||||
if lengthStr, ok := params[varBinaryTypeParam_Length]; ok {
|
||||
ti.MaxLength, err = strconv.ParseInt(lengthStr, 10, 64)
|
||||
length, err = strconv.ParseInt(lengthStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create varbinary type info is missing param "%v"`, varBinaryTypeParam_Length)
|
||||
}
|
||||
if _, ok := params[varBinaryTypeParam_PadBytes]; ok {
|
||||
ti.PadBytes = true
|
||||
if sqlStr, ok := params[varBinaryTypeParam_SQL]; ok {
|
||||
var sqlType sql.StringType
|
||||
switch sqlStr {
|
||||
case varBinaryTypeParam_SQL_Binary:
|
||||
sqlType, err = sql.CreateBinary(sqltypes.Binary, length)
|
||||
case varBinaryTypeParam_SQL_VarBinary:
|
||||
sqlType, err = sql.CreateBinary(sqltypes.VarBinary, length)
|
||||
case varBinaryTypeParam_SQL_Blob:
|
||||
sqlType, err = sql.CreateBinary(sqltypes.Blob, length)
|
||||
default:
|
||||
return nil, fmt.Errorf(`create varbinary type info has "%v" param with value "%v"`, varBinaryTypeParam_SQL, sqlStr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &varBinaryType{sqlType}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create varbinary type info is missing param "%v"`, varBinaryTypeParam_SQL)
|
||||
}
|
||||
if _, ok := params[varBinaryTypeParam_IsSqlBlob]; ok {
|
||||
ti.IsSqlBlob = true
|
||||
}
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *varBinaryType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
if ti.PadBytes {
|
||||
return ti.padBytes(string(val)), nil
|
||||
}
|
||||
return string(val), nil
|
||||
return ti.sqlBinaryType.Convert(string(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -77,221 +86,117 @@ func (ti *varBinaryImpl) ConvertNomsValueToValue(v types.Value) (interface{}, er
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
if val {
|
||||
return types.String("1"), nil
|
||||
}
|
||||
return types.String("0"), nil
|
||||
case int:
|
||||
return types.String(artifact), nil
|
||||
case int8:
|
||||
return types.String(artifact), nil
|
||||
case int16:
|
||||
return types.String(artifact), nil
|
||||
case int32:
|
||||
return types.String(artifact), nil
|
||||
case int64:
|
||||
return types.String(artifact), nil
|
||||
case uint:
|
||||
return types.String(artifact), nil
|
||||
case uint8:
|
||||
return types.String(artifact), nil
|
||||
case uint16:
|
||||
return types.String(artifact), nil
|
||||
case uint32:
|
||||
return types.String(artifact), nil
|
||||
case uint64:
|
||||
return types.String(artifact), nil
|
||||
case float32:
|
||||
return types.String(artifact), nil
|
||||
case float64:
|
||||
return types.String(artifact), nil
|
||||
case string:
|
||||
if ti.PadBytes {
|
||||
return types.String(ti.padBytes(val)), nil
|
||||
}
|
||||
return types.String(val), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
if val {
|
||||
return types.String("1"), nil
|
||||
}
|
||||
return types.String("0"), nil
|
||||
case types.Int:
|
||||
return types.String(artifact), nil
|
||||
case types.Uint:
|
||||
return types.String(artifact), nil
|
||||
case types.Float:
|
||||
return types.String(artifact), nil
|
||||
case types.String:
|
||||
if ti.PadBytes {
|
||||
return types.String(ti.padBytes(string(val))), nil
|
||||
}
|
||||
return val, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *varBinaryType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlBinaryType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *varBinaryType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*varBinaryImpl); ok {
|
||||
return ti.MaxLength == ti2.MaxLength && ti.PadBytes == ti2.PadBytes
|
||||
if ti2, ok := other.(*varBinaryType); ok {
|
||||
return ti.sqlBinaryType.MaxCharacterLength() == ti2.sqlBinaryType.MaxCharacterLength() &&
|
||||
ti.sqlBinaryType.Type() == ti2.sqlBinaryType.Type()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *varBinaryType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := ti.sqlBinaryType.Convert(string(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resStr, ok := res.(string); ok {
|
||||
return &resStr, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *varBinaryType) GetTypeIdentifier() Identifier {
|
||||
return VarBinaryTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) GetTypeParams() map[string]string {
|
||||
func (ti *varBinaryType) GetTypeParams() map[string]string {
|
||||
typeParams := map[string]string{
|
||||
varBinaryTypeParam_Length: strconv.FormatInt(ti.MaxLength, 10),
|
||||
varBinaryTypeParam_Length: strconv.FormatInt(ti.sqlBinaryType.MaxCharacterLength(), 10),
|
||||
}
|
||||
if ti.PadBytes {
|
||||
typeParams[varBinaryTypeParam_PadBytes] = ""
|
||||
}
|
||||
if ti.IsSqlBlob {
|
||||
typeParams[varBinaryTypeParam_IsSqlBlob] = ""
|
||||
switch ti.sqlBinaryType.Type() {
|
||||
case sqltypes.Binary:
|
||||
typeParams[varBinaryTypeParam_SQL] = varBinaryTypeParam_SQL_Binary
|
||||
case sqltypes.VarBinary:
|
||||
typeParams[varBinaryTypeParam_SQL] = varBinaryTypeParam_SQL_VarBinary
|
||||
case sqltypes.Blob:
|
||||
typeParams[varBinaryTypeParam_SQL] = varBinaryTypeParam_SQL_Blob
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown varbinary type info sql type "%v"`, ti.sqlBinaryType.Type().String()))
|
||||
}
|
||||
return typeParams
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *varBinaryType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) NomsKind() types.NomsKind {
|
||||
func (ti *varBinaryType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *varBinaryType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlBinaryType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := strVal.(string); ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) String() string {
|
||||
additionalText := ""
|
||||
if ti.PadBytes {
|
||||
additionalText = ", PadBytes"
|
||||
func (ti *varBinaryType) String() string {
|
||||
sqlType := ""
|
||||
switch ti.sqlBinaryType.Type() {
|
||||
case sqltypes.Binary:
|
||||
sqlType = "Binary"
|
||||
case sqltypes.VarBinary:
|
||||
sqlType = "VarBinary"
|
||||
case sqltypes.Blob:
|
||||
sqlType = "Blob"
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown varbinary type info sql type "%v"`, ti.sqlBinaryType.Type().String()))
|
||||
}
|
||||
if ti.IsSqlBlob {
|
||||
additionalText = ", SqlBlob"
|
||||
}
|
||||
return fmt.Sprintf(`VarBinary(%v%v)`, ti.MaxLength, additionalText)
|
||||
return fmt.Sprintf(`VarBinary(%v, SQL: %v)`, ti.sqlBinaryType.MaxCharacterLength(), sqlType)
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *varBinaryImpl) ToSqlType() sql.Type {
|
||||
// Binary is the only type that pads bytes.
|
||||
if ti.PadBytes {
|
||||
sqlType, err := sql.CreateBinary(sqltypes.Binary, ti.MaxLength)
|
||||
if err == nil {
|
||||
return sqlType
|
||||
}
|
||||
}
|
||||
if !ti.IsSqlBlob {
|
||||
sqlType, err := sql.CreateBinary(sqltypes.VarBinary, ti.MaxLength)
|
||||
if err == nil {
|
||||
return sqlType
|
||||
}
|
||||
}
|
||||
// The SQL type has a max character limit
|
||||
maxLength := ti.MaxLength
|
||||
if maxLength > sql.LongBlob.MaxCharacterLength() {
|
||||
maxLength = sql.LongBlob.MaxCharacterLength()
|
||||
}
|
||||
sqlType, err := sql.CreateBinary(sqltypes.Blob, maxLength)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sqlType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *varBinaryImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case bool:
|
||||
return "", ti.MaxLength >= 1
|
||||
case int:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int8:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int16:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int32:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int64:
|
||||
strVal := strconv.FormatInt(val, 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint8:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint16:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint32:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint64:
|
||||
strVal := strconv.FormatUint(val, 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case float32:
|
||||
strVal := strconv.FormatFloat(float64(val), 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case float64:
|
||||
strVal := strconv.FormatFloat(val, 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case string:
|
||||
return "", int64(len(val)) <= ti.MaxLength
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
return "", ti.MaxLength >= 1
|
||||
case types.Int:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.Uint:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.Float:
|
||||
strVal := strconv.FormatFloat(float64(val), 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.String:
|
||||
return "", int64(len(val)) <= ti.MaxLength
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
// padBytes pads a string with zero bytes if the string length is less than the max length.
|
||||
func (ti *varBinaryImpl) padBytes(v string) string {
|
||||
if int64(len(v)) < ti.MaxLength {
|
||||
return string(append([]byte(v), make([]byte, ti.MaxLength-int64(len(v)))...))
|
||||
}
|
||||
return v
|
||||
func (ti *varBinaryType) ToSqlType() sql.Type {
|
||||
return ti.sqlBinaryType
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
"vitess.io/vitess/go/sqltypes"
|
||||
@@ -27,32 +27,27 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
varStringTypeParam_Collate = "collate"
|
||||
varStringTypeParam_Length = "length"
|
||||
varStringTypeParam_RemoveTrailingSpaces = "rts"
|
||||
varStringTypeParam_IsSqlText = "text"
|
||||
varStringTypeParam_Collate = "collate"
|
||||
varStringTypeParam_Length = "length"
|
||||
varStringTypeParam_SQL = "sql"
|
||||
varStringTypeParam_SQL_Char = "char"
|
||||
varStringTypeParam_SQL_VarChar = "varchar"
|
||||
varStringTypeParam_SQL_Text = "text"
|
||||
)
|
||||
|
||||
type varStringImpl struct {
|
||||
Collation sql.Collation
|
||||
MaxLength int64
|
||||
RemoveTrailingSpaces bool
|
||||
IsSqlText bool // When converting to a SQL type, this ensures a distinction between TEXT and VARCHAR
|
||||
type varStringType struct {
|
||||
sqlStringType sql.StringType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*varStringImpl)(nil)
|
||||
var StringDefaultType TypeInfo = &varStringImpl{
|
||||
sql.Collation_Default,
|
||||
math.MaxUint32,
|
||||
false,
|
||||
true,
|
||||
}
|
||||
var _ TypeInfo = (*varStringType)(nil)
|
||||
var StringDefaultType = &varStringType{sql.CreateLongText(sql.Collation_Default)}
|
||||
|
||||
func CreateVarStringTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
ti := &varStringImpl{}
|
||||
var length int64
|
||||
var collation sql.Collation
|
||||
var err error
|
||||
if collationStr, ok := params[varStringTypeParam_Collate]; ok {
|
||||
ti.Collation, err = sql.ParseCollation(nil, &collationStr, false)
|
||||
collation, err = sql.ParseCollation(nil, &collationStr, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,26 +55,46 @@ func CreateVarStringTypeFromParams(params map[string]string) (TypeInfo, error) {
|
||||
return nil, fmt.Errorf(`create varstring type info is missing param "%v"`, varStringTypeParam_Collate)
|
||||
}
|
||||
if maxLengthStr, ok := params[varStringTypeParam_Length]; ok {
|
||||
ti.MaxLength, err = strconv.ParseInt(maxLengthStr, 10, 64)
|
||||
length, err = strconv.ParseInt(maxLengthStr, 10, 64)
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create varstring type info is missing param "%v"`, varStringTypeParam_Length)
|
||||
}
|
||||
if _, ok := params[varStringTypeParam_RemoveTrailingSpaces]; ok {
|
||||
ti.RemoveTrailingSpaces = true
|
||||
if sqlStr, ok := params[varStringTypeParam_SQL]; ok {
|
||||
var sqlType sql.StringType
|
||||
switch sqlStr {
|
||||
case varStringTypeParam_SQL_Char:
|
||||
sqlType, err = sql.CreateString(sqltypes.Char, length, collation)
|
||||
case varStringTypeParam_SQL_VarChar:
|
||||
sqlType, err = sql.CreateString(sqltypes.VarChar, length, collation)
|
||||
case varStringTypeParam_SQL_Text:
|
||||
sqlType, err = sql.CreateString(sqltypes.Text, length, collation)
|
||||
default:
|
||||
return nil, fmt.Errorf(`create varstring type info has "%v" param with value "%v"`, varStringTypeParam_SQL, sqlStr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &varStringType{sqlType}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf(`create varstring type info is missing param "%v"`, varStringTypeParam_Length)
|
||||
}
|
||||
if _, ok := params[varStringTypeParam_IsSqlText]; ok {
|
||||
ti.IsSqlText = true
|
||||
}
|
||||
return ti, nil
|
||||
}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *varStringImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *varStringType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
if ti.RemoveTrailingSpaces {
|
||||
return strings.TrimRight(string(val), " "), nil
|
||||
strVal, err := ti.sqlStringType.Convert(string(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return string(val), nil
|
||||
res, ok := strVal.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
if ti.sqlStringType.Type() == sqltypes.Char {
|
||||
res = strings.TrimRightFunc(res, unicode.IsSpace)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -88,215 +103,112 @@ func (ti *varStringImpl) ConvertNomsValueToValue(v types.Value) (interface{}, er
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *varStringImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return types.NullValue, nil
|
||||
case bool:
|
||||
if val {
|
||||
return types.String("1"), nil
|
||||
}
|
||||
return types.String("0"), nil
|
||||
case int:
|
||||
return types.String(artifact), nil
|
||||
case int8:
|
||||
return types.String(artifact), nil
|
||||
case int16:
|
||||
return types.String(artifact), nil
|
||||
case int32:
|
||||
return types.String(artifact), nil
|
||||
case int64:
|
||||
return types.String(artifact), nil
|
||||
case uint:
|
||||
return types.String(artifact), nil
|
||||
case uint8:
|
||||
return types.String(artifact), nil
|
||||
case uint16:
|
||||
return types.String(artifact), nil
|
||||
case uint32:
|
||||
return types.String(artifact), nil
|
||||
case uint64:
|
||||
return types.String(artifact), nil
|
||||
case float32:
|
||||
return types.String(artifact), nil
|
||||
case float64:
|
||||
return types.String(artifact), nil
|
||||
case string:
|
||||
if ti.RemoveTrailingSpaces {
|
||||
return types.String(strings.TrimRight(val, " ")), nil
|
||||
}
|
||||
return types.String(val), nil
|
||||
case types.Null:
|
||||
return types.NullValue, nil
|
||||
case types.Bool:
|
||||
if val {
|
||||
return types.String("1"), nil
|
||||
}
|
||||
return types.String("0"), nil
|
||||
case types.Int:
|
||||
return types.String(artifact), nil
|
||||
case types.Uint:
|
||||
return types.String(artifact), nil
|
||||
case types.Float:
|
||||
return types.String(artifact), nil
|
||||
case types.String:
|
||||
if ti.RemoveTrailingSpaces {
|
||||
return types.String(strings.TrimRight(string(val), " ")), nil
|
||||
}
|
||||
return val, nil
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%v" has falsely evaluated value "%v" of type "%T" as valid`, ti.String(), val, val)
|
||||
}
|
||||
func (ti *varStringType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
strVal, err := ti.sqlStringType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := strVal.(string)
|
||||
if ok {
|
||||
return types.String(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *varStringImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *varStringType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
if ti2, ok := other.(*varStringImpl); ok {
|
||||
return *ti == *ti2
|
||||
if ti2, ok := other.(*varStringType); ok {
|
||||
return ti.sqlStringType.MaxCharacterLength() == ti2.sqlStringType.MaxCharacterLength() &&
|
||||
ti.sqlStringType.Type() == ti2.sqlStringType.Type() &&
|
||||
ti.sqlStringType.Collation() == ti2.sqlStringType.Collation()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *varStringType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.String); ok {
|
||||
res, err := ti.ConvertNomsValueToValue(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resStr, ok := res.(string); ok {
|
||||
return &resStr, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *varStringImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *varStringType) GetTypeIdentifier() Identifier {
|
||||
return VarStringTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *varStringImpl) GetTypeParams() map[string]string {
|
||||
func (ti *varStringType) GetTypeParams() map[string]string {
|
||||
typeParams := map[string]string{
|
||||
varStringTypeParam_Collate: ti.Collation.String(),
|
||||
varStringTypeParam_Length: strconv.FormatInt(ti.MaxLength, 10),
|
||||
varStringTypeParam_Collate: ti.sqlStringType.Collation().String(),
|
||||
varStringTypeParam_Length: strconv.FormatInt(ti.sqlStringType.MaxCharacterLength(), 10),
|
||||
}
|
||||
if ti.RemoveTrailingSpaces {
|
||||
typeParams[varStringTypeParam_RemoveTrailingSpaces] = ""
|
||||
}
|
||||
if ti.IsSqlText {
|
||||
typeParams[varStringTypeParam_IsSqlText] = ""
|
||||
switch ti.sqlStringType.Type() {
|
||||
case sqltypes.Char:
|
||||
typeParams[varStringTypeParam_SQL] = varStringTypeParam_SQL_Char
|
||||
case sqltypes.VarChar:
|
||||
typeParams[varStringTypeParam_SQL] = varStringTypeParam_SQL_VarChar
|
||||
case sqltypes.Text:
|
||||
typeParams[varStringTypeParam_SQL] = varStringTypeParam_SQL_Text
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown varstring type info sql type "%v"`, ti.sqlStringType.Type().String()))
|
||||
}
|
||||
return typeParams
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *varStringImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *varStringType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *varStringImpl) NomsKind() types.NomsKind {
|
||||
func (ti *varStringType) NomsKind() types.NomsKind {
|
||||
return types.StringKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *varStringType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return ti.ConvertValueToNomsValue(*str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *varStringImpl) String() string {
|
||||
additionalText := ""
|
||||
if ti.RemoveTrailingSpaces {
|
||||
additionalText = ", RemoveTrailingSpaces"
|
||||
func (ti *varStringType) String() string {
|
||||
sqlType := ""
|
||||
switch ti.sqlStringType.Type() {
|
||||
case sqltypes.Char:
|
||||
sqlType = "Char"
|
||||
case sqltypes.VarChar:
|
||||
sqlType = "VarChar"
|
||||
case sqltypes.Text:
|
||||
sqlType = "Text"
|
||||
default:
|
||||
panic(fmt.Errorf(`unknown varstring type info sql type "%v"`, ti.sqlStringType.Type().String()))
|
||||
}
|
||||
if ti.IsSqlText {
|
||||
additionalText = ", SqlText"
|
||||
}
|
||||
return fmt.Sprintf(`VarString(%v, %v%v)`, ti.Collation.String(), ti.MaxLength, additionalText)
|
||||
return fmt.Sprintf(`VarString(%v, %v, SQL: %v)`, ti.sqlStringType.Collation().String(), ti.sqlStringType.MaxCharacterLength(), sqlType)
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *varStringImpl) ToSqlType() sql.Type {
|
||||
// Char is the only type that removes trailing spaces
|
||||
if ti.RemoveTrailingSpaces {
|
||||
sqlType, err := sql.CreateString(sqltypes.Char, ti.MaxLength, ti.Collation)
|
||||
if err == nil {
|
||||
return sqlType
|
||||
}
|
||||
}
|
||||
if !ti.IsSqlText {
|
||||
sqlType, err := sql.CreateString(sqltypes.VarChar, ti.MaxLength, ti.Collation)
|
||||
if err == nil {
|
||||
return sqlType
|
||||
}
|
||||
}
|
||||
// The SQL type has a max character limit
|
||||
maxLength := ti.MaxLength
|
||||
if maxLength > sql.LongText.MaxCharacterLength() {
|
||||
maxLength = sql.LongText.MaxCharacterLength()
|
||||
}
|
||||
sqlType, err := sql.CreateString(sqltypes.Text, maxLength, ti.Collation)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sqlType
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *varStringImpl) isValid(v interface{}) (artifact string, ok bool) {
|
||||
//TODO: handle collations
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return "", true
|
||||
case bool:
|
||||
return "", ti.MaxLength >= 1
|
||||
case int:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int8:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int16:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int32:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case int64:
|
||||
strVal := strconv.FormatInt(val, 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint8:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint16:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint32:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case uint64:
|
||||
strVal := strconv.FormatUint(val, 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case float32:
|
||||
strVal := strconv.FormatFloat(float64(val), 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case float64:
|
||||
strVal := strconv.FormatFloat(val, 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case string:
|
||||
return "", int64(len(val)) <= ti.MaxLength
|
||||
case types.Null:
|
||||
return "", true
|
||||
case types.Bool:
|
||||
return "", ti.MaxLength >= 1
|
||||
case types.Int:
|
||||
strVal := strconv.FormatInt(int64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.Uint:
|
||||
strVal := strconv.FormatUint(uint64(val), 10)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.Float:
|
||||
strVal := strconv.FormatFloat(float64(val), 'g', -1, 64)
|
||||
return strVal, int64(len(strVal)) <= ti.MaxLength
|
||||
case types.String:
|
||||
return "", int64(len(val)) <= ti.MaxLength
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
func (ti *varStringType) ToSqlType() sql.Type {
|
||||
return ti.sqlStringType
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package typeinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/src-d/go-mysql-server/sql"
|
||||
|
||||
@@ -24,20 +25,18 @@ import (
|
||||
|
||||
// This is a dolt implementation of the MySQL type Year, thus most of the functionality
|
||||
// within is directly reliant on the go-mysql-server implementation.
|
||||
type yearImpl struct{}
|
||||
type yearType struct {
|
||||
sqlYearType sql.YearType
|
||||
}
|
||||
|
||||
var _ TypeInfo = (*yearImpl)(nil)
|
||||
var _ TypeInfo = (*yearType)(nil)
|
||||
|
||||
var YearType TypeInfo = &yearImpl{}
|
||||
var YearType = &yearType{sql.Year}
|
||||
|
||||
// ConvertNomsValueToValue implements TypeInfo interface.
|
||||
func (ti *yearImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
func (ti *yearType) ConvertNomsValueToValue(v types.Value) (interface{}, error) {
|
||||
if val, ok := v.(types.Int); ok {
|
||||
res, err := sql.Year.Convert(int16(val))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`"%v" cannot convert year "%v" to value`, ti.String(), val)
|
||||
}
|
||||
return res, nil
|
||||
return ti.sqlYearType.Convert(int64(val))
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
@@ -46,79 +45,92 @@ func (ti *yearImpl) ConvertNomsValueToValue(v types.Value) (interface{}, error)
|
||||
}
|
||||
|
||||
// ConvertValueToNomsValue implements TypeInfo interface.
|
||||
func (ti *yearImpl) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if artifact, ok := ti.isValid(v); ok {
|
||||
switch v.(type) {
|
||||
case nil, types.Null:
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return types.Int(artifact), nil
|
||||
func (ti *yearType) ConvertValueToNomsValue(v interface{}) (types.Value, error) {
|
||||
if v == nil {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert value "%v" of type "%T" as it is invalid`, ti.String(), v, v)
|
||||
intVal, err := ti.sqlYearType.Convert(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := intVal.(int16)
|
||||
if ok {
|
||||
return types.Int(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
|
||||
// Equals implements TypeInfo interface.
|
||||
func (ti *yearImpl) Equals(other TypeInfo) bool {
|
||||
func (ti *yearType) Equals(other TypeInfo) bool {
|
||||
if other == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := other.(*yearImpl)
|
||||
_, ok := other.(*yearType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// FormatValue implements TypeInfo interface.
|
||||
func (ti *yearType) FormatValue(v types.Value) (*string, error) {
|
||||
if val, ok := v.(types.Int); ok {
|
||||
convVal, err := ti.ConvertNomsValueToValue(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, ok := convVal.(int16)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`"%v" has unexpectedly encountered a value of type "%T" from embedded type`, ti.String(), v)
|
||||
}
|
||||
res := strconv.FormatInt(int64(val), 10)
|
||||
return &res, nil
|
||||
}
|
||||
if _, ok := v.(types.Null); ok || v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert NomsKind "%v" to a string`, ti.String(), v.Kind())
|
||||
}
|
||||
|
||||
// GetTypeIdentifier implements TypeInfo interface.
|
||||
func (ti *yearImpl) GetTypeIdentifier() Identifier {
|
||||
func (ti *yearType) GetTypeIdentifier() Identifier {
|
||||
return YearTypeIdentifier
|
||||
}
|
||||
|
||||
// GetTypeParams implements TypeInfo interface.
|
||||
func (ti *yearImpl) GetTypeParams() map[string]string {
|
||||
func (ti *yearType) GetTypeParams() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid implements TypeInfo interface.
|
||||
func (ti *yearImpl) IsValid(v interface{}) bool {
|
||||
_, ok := ti.isValid(v)
|
||||
return ok
|
||||
func (ti *yearType) IsValid(v types.Value) bool {
|
||||
_, err := ti.ConvertNomsValueToValue(v)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// NomsKind implements TypeInfo interface.
|
||||
func (ti *yearImpl) NomsKind() types.NomsKind {
|
||||
func (ti *yearType) NomsKind() types.NomsKind {
|
||||
return types.IntKind
|
||||
}
|
||||
|
||||
// ParseValue implements TypeInfo interface.
|
||||
func (ti *yearType) ParseValue(str *string) (types.Value, error) {
|
||||
if str == nil || *str == "" {
|
||||
return types.NullValue, nil
|
||||
}
|
||||
intVal, err := ti.sqlYearType.Convert(*str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if val, ok := intVal.(int16); ok {
|
||||
return types.Int(val), nil
|
||||
}
|
||||
return nil, fmt.Errorf(`"%v" cannot convert the string "%v" to a value`, ti.String(), str)
|
||||
}
|
||||
|
||||
// String implements TypeInfo interface.
|
||||
func (ti *yearImpl) String() string {
|
||||
func (ti *yearType) String() string {
|
||||
return "Year"
|
||||
}
|
||||
|
||||
// ToSqlType implements TypeInfo interface.
|
||||
func (ti *yearImpl) ToSqlType() sql.Type {
|
||||
return sql.Year
|
||||
}
|
||||
|
||||
// isValid is an internal implementation for the TypeInfo interface function IsValid.
|
||||
// Some validity checks process the value into its final form, which may be returned
|
||||
// as an artifact so that a value doesn't need to be processed twice in some scenarios.
|
||||
func (ti *yearImpl) isValid(v interface{}) (artifact int16, ok bool) {
|
||||
// convert some Noms values to their standard golang equivalents, except Null
|
||||
switch val := v.(type) {
|
||||
case nil:
|
||||
return 0, true
|
||||
case types.Null:
|
||||
return 0, true
|
||||
case types.Bool:
|
||||
v = bool(val)
|
||||
case types.Int:
|
||||
v = int64(val)
|
||||
case types.Uint:
|
||||
v = uint64(val)
|
||||
case types.Float:
|
||||
v = float64(val)
|
||||
case types.String:
|
||||
v = string(val)
|
||||
}
|
||||
res, err := sql.Year.Convert(v)
|
||||
resInt, ok := res.(int16)
|
||||
return resInt, err == nil && ok
|
||||
func (ti *yearType) ToSqlType() sql.Type {
|
||||
return ti.sqlYearType
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
const doubleQuot = `"`
|
||||
@@ -283,25 +284,16 @@ func valueAsSqlString(value types.Value) (string, error) {
|
||||
return "FALSE", nil
|
||||
}
|
||||
case types.UUIDKind:
|
||||
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
str, _ := convFn(value)
|
||||
return doubleQuot + string(str.(types.String)) + doubleQuot, nil
|
||||
return doubleQuot + uuid.UUID(value.(types.UUID)).String() + doubleQuot, nil
|
||||
case types.StringKind:
|
||||
s := string(value.(types.String))
|
||||
s = strings.ReplaceAll(s, doubleQuot, "\\\"")
|
||||
return doubleQuot + s + doubleQuot, nil
|
||||
default:
|
||||
convFn, err := doltcore.GetConvFunc(value.Kind(), types.StringKind)
|
||||
str, err := typeinfo.FromKind(value.Kind()).FormatValue(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
str, err := convFn(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(str.(types.String)), nil
|
||||
return *str, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sql
|
||||
|
||||
import (
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
var DoltToSQLType = map[types.NomsKind]string{
|
||||
types.StringKind: VARCHAR + "(1024)", // we don't actually enforce string lengths, but mysql requires them
|
||||
types.BoolKind: BOOL,
|
||||
types.FloatKind: FLOAT_TYPE,
|
||||
types.IntKind: INT,
|
||||
types.UintKind: INT + " " + UNSIGNED,
|
||||
types.UUIDKind: UUID,
|
||||
}
|
||||
|
||||
// TypeConversionFn is a function that converts one noms value to another of a different type in a guaranteed fashion,
|
||||
// i.e. any conversion that could possibly fail (e.g. string -> int) are not allowed. Only SQL-safe conversions are
|
||||
// allowed, even if they are guaranteed to be safe, so that e.g. there is no way to convert a numeric type to a string.
|
||||
// These kinds of conversions must be explicit in SQL.
|
||||
type TypeConversionFn func(types.Value) types.Value
|
||||
|
||||
var convFuncMap = map[types.NomsKind]map[types.NomsKind]TypeConversionFn{
|
||||
types.StringKind: {
|
||||
types.StringKind: identityConvFunc,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.UUIDKind: {
|
||||
types.UUIDKind: identityConvFunc,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.UintKind: {
|
||||
types.UintKind: identityConvFunc,
|
||||
types.IntKind: convUintToInt,
|
||||
types.FloatKind: convUintToFloat,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.IntKind: {
|
||||
types.UintKind: convIntToUint,
|
||||
types.IntKind: identityConvFunc,
|
||||
types.FloatKind: convIntToFloat,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.FloatKind: {
|
||||
types.FloatKind: identityConvFunc,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.BoolKind: {
|
||||
types.BoolKind: identityConvFunc,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
types.NullKind: {
|
||||
types.StringKind: convToNullFunc,
|
||||
types.UUIDKind: convToNullFunc,
|
||||
types.UintKind: convToNullFunc,
|
||||
types.IntKind: convToNullFunc,
|
||||
types.FloatKind: convToNullFunc,
|
||||
types.BoolKind: convToNullFunc,
|
||||
types.NullKind: convToNullFunc,
|
||||
},
|
||||
}
|
||||
|
||||
// GetTypeConversionFn takes in a source kind and a destination kind and returns a TypeConversionFn which can convert
|
||||
// values of the source kind to values of the destination kind in a type-safe manner, or nil if no such conversion is
|
||||
// possible.
|
||||
func GetTypeConversionFn(srcKind, destKind types.NomsKind) TypeConversionFn {
|
||||
var convFunc TypeConversionFn
|
||||
if destKindMap, ok := convFuncMap[srcKind]; ok {
|
||||
convFunc = destKindMap[destKind]
|
||||
}
|
||||
|
||||
return convFunc
|
||||
}
|
||||
|
||||
func identityConvFunc(value types.Value) types.Value {
|
||||
return value
|
||||
}
|
||||
|
||||
var convToNullFunc = func(types.Value) types.Value {
|
||||
return nil
|
||||
}
|
||||
|
||||
func convUintToInt(val types.Value) types.Value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := uint64(val.(types.Uint))
|
||||
return types.Int(int64(n))
|
||||
}
|
||||
|
||||
func convUintToFloat(val types.Value) types.Value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := uint64(val.(types.Uint))
|
||||
return types.Float(float64(n))
|
||||
}
|
||||
|
||||
func convIntToUint(val types.Value) types.Value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := int64(val.(types.Int))
|
||||
return types.Uint(uint64(n))
|
||||
}
|
||||
|
||||
func convIntToFloat(val types.Value) types.Value {
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
n := int64(val.(types.Int))
|
||||
return types.Float(float64(n))
|
||||
}
|
||||
@@ -121,15 +121,11 @@ func TestCreateTable(t *testing.T) {
|
||||
c10 tinytext comment 'tag:10',
|
||||
c11 mediumtext comment 'tag:11',
|
||||
c12 longtext comment 'tag:12',
|
||||
c13 tinyblob comment 'tag:13',
|
||||
c14 blob comment 'tag:14',
|
||||
c15 longblob comment 'tag:15',
|
||||
c16 char(5) comment 'tag:16',
|
||||
c17 varchar(255) comment 'tag:17',
|
||||
c18 varchar(80) comment 'tag:18',
|
||||
c19 float comment 'tag:19',
|
||||
c20 double comment 'tag:20',
|
||||
c21 decimal(10,5) comment 'tag:21',
|
||||
c22 int unsigned comment 'tag:22',
|
||||
c23 tinyint unsigned comment 'tag:23',
|
||||
c24 smallint unsigned comment 'tag:24',
|
||||
@@ -149,15 +145,15 @@ func TestCreateTable(t *testing.T) {
|
||||
schemaNewColumn(t, "c10", 10, sql.TinyText, false),
|
||||
schemaNewColumn(t, "c11", 11, sql.MediumText, false),
|
||||
schemaNewColumn(t, "c12", 12, sql.LongText, false),
|
||||
schemaNewColumn(t, "c13", 13, sql.TinyBlob, false),
|
||||
schemaNewColumn(t, "c14", 14, sql.Blob, false),
|
||||
schemaNewColumn(t, "c15", 15, sql.LongBlob, false),
|
||||
//schemaNewColumn(t, "c13", 13, sql.TinyBlob, false),
|
||||
//schemaNewColumn(t, "c14", 14, sql.Blob, false),
|
||||
//schemaNewColumn(t, "c15", 15, sql.LongBlob, false),
|
||||
schemaNewColumn(t, "c16", 16, sql.MustCreateStringWithDefaults(sqltypes.Char, 5), false),
|
||||
schemaNewColumn(t, "c17", 17, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false),
|
||||
schemaNewColumn(t, "c18", 18, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
|
||||
schemaNewColumn(t, "c19", 19, sql.Float32, false),
|
||||
schemaNewColumn(t, "c20", 20, sql.Float64, false),
|
||||
schemaNewColumn(t, "c21", 21, sql.MustCreateDecimalType(10, 5), false),
|
||||
//schemaNewColumn(t, "c21", 21, sql.MustCreateDecimalType(10, 5), false),
|
||||
schemaNewColumn(t, "c22", 22, sql.Uint32, false),
|
||||
schemaNewColumn(t, "c23", 23, sql.Uint8, false),
|
||||
schemaNewColumn(t, "c24", 24, sql.Uint16, false),
|
||||
@@ -501,8 +497,6 @@ func TestAddColumn(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyAndChangeColumn(t *testing.T) {
|
||||
// This worked previously as LONGTEXT & VARCHAR(80) are both LONGTEXT to dolt, so it thought there was no change
|
||||
t.Skip("We don't yet support column type changes")
|
||||
tests := []struct {
|
||||
name string
|
||||
query string
|
||||
@@ -512,11 +506,11 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "alter modify column reorder middle",
|
||||
query: "alter table people modify column first_name varchar(80) not null after last_name",
|
||||
query: "alter table people modify column first_name longtext not null after last_name",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schemaNewColumn(t, "first_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
schema.NewColumn("age", AgeTag, types.IntKind, false),
|
||||
schema.NewColumn("rating", RatingTag, types.FloatKind, false),
|
||||
@@ -527,9 +521,9 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter modify column reorder first",
|
||||
query: "alter table people modify column first_name varchar(80) not null first",
|
||||
query: "alter table people modify column first_name longtext not null first",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schemaNewColumn(t, "first_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
@@ -542,10 +536,10 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter modify column drop null constraint",
|
||||
query: "alter table people modify column first_name varchar(80) null",
|
||||
query: "alter table people modify column first_name longtext null",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schemaNewColumn(t, "first_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
|
||||
schema.NewColumn("first_name", FirstNameTag, types.StringKind, false),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
schema.NewColumn("age", AgeTag, types.IntKind, false),
|
||||
@@ -557,11 +551,11 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter change column rename and reorder",
|
||||
query: "alter table people change first_name christian_name varchar(80) not null after last_name",
|
||||
query: "alter table people change first_name christian_name longtext not null after last_name",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schemaNewColumn(t, "christian_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("christian_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
schema.NewColumn("age", AgeTag, types.IntKind, false),
|
||||
schema.NewColumn("rating", RatingTag, types.FloatKind, false),
|
||||
@@ -572,9 +566,9 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter change column rename and reorder first",
|
||||
query: "alter table people change column first_name christian_name varchar(80) not null first",
|
||||
query: "alter table people change column first_name christian_name longtext not null first",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schemaNewColumn(t, "christian_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("christian_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
@@ -587,10 +581,10 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter change column drop null constraint",
|
||||
query: "alter table people change column first_name first_name varchar(80) null",
|
||||
query: "alter table people change column first_name first_name longtext null",
|
||||
expectedSchema: dtestutils.CreateSchema(
|
||||
schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
|
||||
schemaNewColumn(t, "first_name", FirstNameTag, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
|
||||
schema.NewColumn("first_name", FirstNameTag, types.StringKind, false),
|
||||
schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
|
||||
schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
|
||||
schema.NewColumn("age", AgeTag, types.IntKind, false),
|
||||
@@ -602,17 +596,17 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter modify column change tag",
|
||||
query: "alter table people modify column first_name varchar(80) not null comment 'tag:100'",
|
||||
query: "alter table people modify column first_name longtext not null comment 'tag:100'",
|
||||
expectedErr: "A column with the name first_name already exists",
|
||||
},
|
||||
{
|
||||
name: "alter modify column not null with type mismatch in default",
|
||||
query: "alter table people modify rating float default 'not a number'",
|
||||
query: "alter table people modify rating double default 'not a number'",
|
||||
expectedErr: "incompatible type for default value",
|
||||
},
|
||||
{
|
||||
name: "alter modify column with tag conflict",
|
||||
query: "alter table people modify rating float default 1.0 comment 'tag:1'",
|
||||
query: "alter table people modify rating double default 1.0 comment 'tag:1'",
|
||||
expectedErr: "A column with the name rating already exists",
|
||||
},
|
||||
{
|
||||
@@ -622,7 +616,7 @@ func TestModifyAndChangeColumn(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "alter modify column not null, existing null values",
|
||||
query: "alter table people modify num_episodes int unsigned not null",
|
||||
query: "alter table people modify num_episodes bigint unsigned not null",
|
||||
expectedErr: "cannot change column to NOT NULL",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package doltcore
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
// StringToValue takes a string and a NomsKind and tries to convert the string to a noms Value.
|
||||
func StringToValue(s string, kind types.NomsKind) (types.Value, error) {
|
||||
if !types.IsPrimitiveKind(kind) || kind == types.BlobKind {
|
||||
return nil, errors.New("Only primitive type support")
|
||||
}
|
||||
|
||||
emptyStringType := types.KindToType[types.StringKind]
|
||||
|
||||
marshalFunc, err := emptyStringType.GetMarshalFunc(kind)
|
||||
if err != nil {
|
||||
panic("Unsupported type " + kind.String())
|
||||
}
|
||||
|
||||
return marshalFunc(types.String(s))
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package doltcore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
type strToNomsTypeTests struct {
|
||||
s string
|
||||
k types.NomsKind
|
||||
expVal types.Value
|
||||
expErr bool
|
||||
}
|
||||
|
||||
var tests = []strToNomsTypeTests{
|
||||
{"test string", types.StringKind, types.String("test string"), false},
|
||||
{"1.3294398", types.FloatKind, types.Float(1.3294398), false},
|
||||
{"-3294398", types.FloatKind, types.Float(-3294398), false},
|
||||
{"TRuE", types.BoolKind, types.Bool(true), false},
|
||||
{"False", types.BoolKind, types.Bool(false), false},
|
||||
{"-123456", types.IntKind, types.Int(-123456), false},
|
||||
{"123456", types.IntKind, types.Int(123456), false},
|
||||
{"0.123", types.IntKind, types.Int(0), false},
|
||||
{".123", types.IntKind, types.Int(0), false},
|
||||
{"-0.123", types.IntKind, types.Int(0), false},
|
||||
{"-.123", types.IntKind, types.Int(0), false},
|
||||
{"100000000000", types.UintKind, types.Uint(100000000000), false},
|
||||
{"0", types.UintKind, types.Uint(0), false},
|
||||
{
|
||||
"01234567-89ab-cdef-FEDC-BA9876543210",
|
||||
types.UUIDKind,
|
||||
types.UUID([16]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}),
|
||||
false},
|
||||
{"0", types.UintKind, types.Uint(0), false},
|
||||
{"", types.NullKind, types.NullValue, false},
|
||||
{
|
||||
"61626364656667",
|
||||
types.InlineBlobKind,
|
||||
types.InlineBlob([]byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67}),
|
||||
false},
|
||||
{
|
||||
"61D184E19083F09D95AB",
|
||||
types.InlineBlobKind,
|
||||
types.InlineBlob([]byte{0x61, 0xd1, 0x84, 0xe1, 0x90, 0x83, 0xf0, 0x9d, 0x95, 0xab}),
|
||||
false},
|
||||
|
||||
{"test failure", types.FloatKind, nil, true},
|
||||
{"test failure", types.BoolKind, nil, true},
|
||||
{"test failure", types.IntKind, nil, true},
|
||||
{"0xdeadbeef", types.IntKind, nil, true},
|
||||
{"test failure", types.UintKind, nil, true},
|
||||
{"-1", types.UintKind, nil, true},
|
||||
{"0123456789abcdeffedcba9876543210abc", types.UUIDKind, nil, true},
|
||||
{"0", types.UUIDKind, nil, true},
|
||||
}
|
||||
|
||||
func TestStrConversion(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
val, err := StringToValue(test.s, test.k)
|
||||
|
||||
if (err != nil) != test.expErr {
|
||||
t.Errorf("Conversion of \"%s\" returned unexpected error: %v", test.s, err)
|
||||
}
|
||||
|
||||
if err == nil && !val.Equals(test.expVal) {
|
||||
t.Errorf("Conversion of \"%s\" returned unexpected error: %v", test.s, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
"github.com/bcicen/jstream"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/encoding"
|
||||
@@ -146,31 +145,9 @@ func (r *JSONReader) convToRow(rowMap map[string]interface{}) (row.Row, error) {
|
||||
return nil, fmt.Errorf("column %s not found in schema", k)
|
||||
}
|
||||
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
f, err := doltcore.GetConvFunc(types.IntKind, col.Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taggedVals[col.Tag], _ = f(types.Int(val))
|
||||
case string:
|
||||
f, err := doltcore.GetConvFunc(types.StringKind, col.Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taggedVals[col.Tag], _ = f(types.String(val))
|
||||
case bool:
|
||||
f, err := doltcore.GetConvFunc(types.BoolKind, col.Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taggedVals[col.Tag], _ = f(types.Bool(val))
|
||||
case float64:
|
||||
f, err := doltcore.GetConvFunc(types.FloatKind, col.Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
taggedVals[col.Tag], _ = f(types.Float(val))
|
||||
switch v.(type) {
|
||||
case int, string, bool, float64:
|
||||
taggedVals[col.Tag], _ = col.TypeInfo.ConvertValueToNomsValue(v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
|
||||
"github.com/tealeg/xlsx"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
@@ -62,7 +61,7 @@ func decodeXLSXRows(nbf *types.NomsBinFormat, xlData [][][]string, sch schema.Sc
|
||||
return nil, errors.New(v + "is not a valid column")
|
||||
}
|
||||
valString := dataVals[i+1][k]
|
||||
taggedVals[col.Tag], err = doltcore.StringToValue(valString, col.Kind)
|
||||
taggedVals[col.Tag], err = col.TypeInfo.ParseValue(&valString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/row"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/table/untyped"
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
@@ -43,10 +43,14 @@ func TestDecodeXLSXRows(t *testing.T) {
|
||||
}
|
||||
|
||||
taggedVals := make(row.TaggedValues, sch.GetAllCols().Size())
|
||||
taggedVals[uint64(0)], _ = doltcore.StringToValue("1", types.StringKind)
|
||||
taggedVals[uint64(1)], _ = doltcore.StringToValue("osheiza", types.StringKind)
|
||||
taggedVals[uint64(2)], _ = doltcore.StringToValue("otori", types.StringKind)
|
||||
taggedVals[uint64(3)], _ = doltcore.StringToValue("24", types.StringKind)
|
||||
str := "1"
|
||||
taggedVals[uint64(0)], _ = typeinfo.StringDefaultType.ParseValue(&str)
|
||||
str = "osheiza"
|
||||
taggedVals[uint64(1)], _ = typeinfo.StringDefaultType.ParseValue(&str)
|
||||
str = "otori"
|
||||
taggedVals[uint64(2)], _ = typeinfo.StringDefaultType.ParseValue(&str)
|
||||
str = "24"
|
||||
taggedVals[uint64(3)], _ = typeinfo.StringDefaultType.ParseValue(&str)
|
||||
|
||||
newRow, err := row.New(types.Format_7_18, sch, taggedVals)
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package doltcore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
// GetConvFunc takes in a source kind and a destination kind and returns a MarshalCallback which can convert values of the
|
||||
// source kind to values of the destination kind.
|
||||
func GetConvFunc(srcKind, destKind types.NomsKind) (types.MarshalCallback, error) {
|
||||
if emptyVal, ok := types.KindToType[srcKind]; ok && emptyVal != nil {
|
||||
return emptyVal.GetMarshalFunc(destKind)
|
||||
}
|
||||
return nil, fmt.Errorf("%v does not have an associated Value implementation", srcKind)
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package doltcore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
const (
|
||||
zeroUUIDStr = "00000000-0000-0000-0000-000000000000"
|
||||
)
|
||||
|
||||
var zeroUUID = uuid.Must(uuid.Parse(zeroUUIDStr))
|
||||
|
||||
func TestConv(t *testing.T) {
|
||||
tests := []struct {
|
||||
input types.Value
|
||||
expectedOut types.Value
|
||||
expectFunc bool
|
||||
expectErr bool
|
||||
}{
|
||||
{types.String("test"), types.String("test"), true, false},
|
||||
{types.String(""), types.String(""), true, false},
|
||||
{types.String(`""`), types.String(`""`), true, false},
|
||||
{types.String(zeroUUIDStr), types.UUID(zeroUUID), true, false},
|
||||
{types.String("10"), types.Uint(10), true, false},
|
||||
{types.String("-101"), types.Int(-101), true, false},
|
||||
{types.String("3.25"), types.Float(3.25), true, false},
|
||||
{types.String("true"), types.Bool(true), true, false},
|
||||
{types.String("61D184E19083F09D95AB"), types.InlineBlob([]byte{0x61, 0xd1, 0x84, 0xe1, 0x90, 0x83, 0xf0, 0x9d, 0x95, 0xab}),
|
||||
true, false},
|
||||
{types.String("1970/12/31"),
|
||||
types.Timestamp(time.Date(1970, 12, 31, 0, 0, 0, 0, time.UTC)),
|
||||
true, false},
|
||||
{types.String("anything"), types.NullValue, true, false},
|
||||
|
||||
{types.UUID(zeroUUID), types.String(zeroUUIDStr), true, false},
|
||||
{types.UUID(zeroUUID), types.UUID(zeroUUID), true, false},
|
||||
{types.UUID(zeroUUID), types.Uint(0), false, false},
|
||||
{types.UUID(zeroUUID), types.Int(0), false, false},
|
||||
{types.UUID(zeroUUID), types.Float(0), false, false},
|
||||
{types.UUID(zeroUUID), types.Bool(false), false, false},
|
||||
{types.UUID(zeroUUID), types.InlineBlob{}, false, false},
|
||||
{types.UUID(zeroUUID), types.Timestamp{}, false, false},
|
||||
{types.UUID(zeroUUID), types.NullValue, true, false},
|
||||
|
||||
{types.Uint(10), types.String("10"), true, false},
|
||||
{types.Uint(100), types.UUID(zeroUUID), false, false},
|
||||
{types.Uint(1000), types.Uint(1000), true, false},
|
||||
{types.Uint(10000), types.Int(10000), true, false},
|
||||
{types.Uint(100000), types.Float(100000), true, false},
|
||||
{types.Uint(1000000), types.Bool(true), true, false},
|
||||
{types.Uint(10000000), types.InlineBlob{}, false, false},
|
||||
{types.Uint(100000000), types.Timestamp(time.Unix(100000000, 0).UTC()), true, false},
|
||||
{types.Uint(1000000000), types.NullValue, true, false},
|
||||
|
||||
{types.Int(-10), types.String("-10"), true, false},
|
||||
{types.Int(-100), types.UUID(zeroUUID), false, false},
|
||||
{types.Int(1000), types.Uint(1000), true, false},
|
||||
{types.Int(-10000), types.Int(-10000), true, false},
|
||||
{types.Int(-100000), types.Float(-100000), true, false},
|
||||
{types.Int(-1000000), types.Bool(true), true, false},
|
||||
{types.Int(-10000000), types.InlineBlob{}, false, false},
|
||||
{types.Int(-100000000), types.Timestamp(time.Unix(-100000000, 0).UTC()), true, false},
|
||||
{types.Int(-1000000000), types.NullValue, true, false},
|
||||
|
||||
{types.Float(1.5), types.String("1.5"), true, false},
|
||||
{types.Float(10.5), types.UUID(zeroUUID), false, false},
|
||||
{types.Float(100.5), types.Uint(100), true, false},
|
||||
{types.Float(1000.5), types.Int(1000), true, false},
|
||||
{types.Float(10000.5), types.Float(10000.5), true, false},
|
||||
{types.Float(100000.5), types.Bool(true), true, false},
|
||||
{types.Float(1000000.5), types.InlineBlob{}, false, false},
|
||||
{types.Float(10000000.5), types.Timestamp(time.Unix(10000000, 500000000).UTC()), true, false},
|
||||
{types.Float(100000000.5), types.NullValue, true, false},
|
||||
|
||||
{types.Bool(true), types.String("true"), true, false},
|
||||
{types.Bool(false), types.UUID(zeroUUID), false, false},
|
||||
{types.Bool(true), types.Uint(1), true, false},
|
||||
{types.Bool(false), types.Int(0), true, false},
|
||||
{types.Bool(true), types.Float(1), true, false},
|
||||
{types.Bool(false), types.Bool(false), true, false},
|
||||
{types.Bool(false), types.InlineBlob{}, false, true},
|
||||
{types.Bool(false), types.Timestamp{}, false, true},
|
||||
{types.Bool(true), types.NullValue, true, false},
|
||||
|
||||
{types.InlineBlob([]byte{0x61, 0xd1, 0x84, 0xe1, 0x90, 0x83, 0xf0, 0x9d, 0x95, 0xab}),
|
||||
types.String("61D184E19083F09D95AB"), true, false},
|
||||
{types.InlineBlob([]byte{}), types.UUID(zeroUUID), false, false},
|
||||
{types.InlineBlob([]byte{}), types.Uint(1583200922), false, false},
|
||||
{types.InlineBlob([]byte{}), types.Int(1901502183), false, false},
|
||||
{types.InlineBlob([]byte{}), types.Float(2219803444.4), false, false},
|
||||
{types.InlineBlob([]byte{}), types.Bool(false), false, true},
|
||||
{types.InlineBlob([]byte{1, 10, 100}), types.InlineBlob([]byte{1, 10, 100}), true, false},
|
||||
{types.InlineBlob([]byte{}), types.NullValue, true, false},
|
||||
|
||||
{types.Timestamp(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
types.String("2000-01-01 00:00:00 +0000"), true, false},
|
||||
{types.Timestamp(time.Date(2010, 2, 2, 1, 1, 1, 0, time.UTC)),
|
||||
types.UUID(zeroUUID), false, false},
|
||||
{types.Timestamp(time.Date(2020, 3, 3, 2, 2, 2, 0, time.UTC)),
|
||||
types.Uint(1583200922), true, false},
|
||||
{types.Timestamp(time.Date(2030, 4, 4, 3, 3, 3, 0, time.UTC)),
|
||||
types.Int(1901502183), true, false},
|
||||
{types.Timestamp(time.Date(2040, 5, 5, 4, 4, 4, 400000000, time.UTC)),
|
||||
types.Float(2219803444.4), true, false},
|
||||
{types.Timestamp(time.Date(2050, 6, 6, 5, 5, 5, 0, time.UTC)),
|
||||
types.Bool(false), false, true},
|
||||
{types.Timestamp(time.Date(2060, 7, 7, 6, 6, 6, 678912345, time.UTC)),
|
||||
types.Timestamp(time.Unix(2856405966, 678912345).UTC()), true, false},
|
||||
{types.Timestamp(time.Date(2070, 8, 8, 7, 7, 7, 0, time.UTC)),
|
||||
types.NullValue, true, false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
convFunc, err := GetConvFunc(test.input.Kind(), test.expectedOut.Kind())
|
||||
|
||||
if convFunc == nil && err != nil && test.expectFunc == true {
|
||||
t.Error("Did not receive conversion function for conversion from", test.input.Kind(), "to", test.expectedOut.Kind())
|
||||
} else if convFunc != nil {
|
||||
if test.expectFunc == false {
|
||||
t.Error("Incorrectly received conversion function for conversion from", test.input.Kind(), "to", test.expectedOut.Kind())
|
||||
continue
|
||||
}
|
||||
|
||||
result, err := convFunc(test.input)
|
||||
|
||||
if (err != nil) != test.expectErr {
|
||||
t.Error("input:", test.input, "expected err:", test.expectErr, "actual err:", err != nil)
|
||||
}
|
||||
|
||||
if !test.expectedOut.Equals(result) {
|
||||
t.Error("input:", test.input, "expected result:", test.expectedOut, "actual result:", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var convertibleTypes = []types.NomsKind{types.StringKind, types.UUIDKind, types.UintKind, types.IntKind, types.FloatKind, types.BoolKind, types.InlineBlobKind}
|
||||
|
||||
func TestNullConversion(t *testing.T) {
|
||||
for _, srcKind := range convertibleTypes {
|
||||
for _, destKind := range convertibleTypes {
|
||||
convFunc, err := GetConvFunc(srcKind, destKind)
|
||||
|
||||
if convFunc != nil && err == nil {
|
||||
res, err := convFunc(nil)
|
||||
|
||||
if res != nil || err != nil {
|
||||
t.Error("null conversion failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/sql"
|
||||
"github.com/liquidata-inc/dolt/go/libraries/doltcore/schema/typeinfo"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/types"
|
||||
)
|
||||
|
||||
@@ -171,10 +172,7 @@ func getSQLHeader(cols []*SeedColumn, tableName, format string) string {
|
||||
colStr = fmt.Sprintf("%s COMMENT 'tag:%d'", colStr, i)
|
||||
|
||||
// translate noms type
|
||||
sqlType, ok := sql.DoltToSQLType[col.Type]
|
||||
if !ok {
|
||||
log.Fatalf("unable to format sql string, unknown noms to sql conversion for type %v \n", col.Type)
|
||||
}
|
||||
sqlType := typeinfo.FromKind(col.Type).ToSqlType().String()
|
||||
|
||||
schema = append(schema, fmt.Sprintf(colStr, col.Name, strings.ToUpper(sqlType)))
|
||||
}
|
||||
|
||||
@@ -476,10 +476,6 @@ func readBlob(ctx context.Context, r io.Reader, vrw ValueReadWriter) (Blob, erro
|
||||
return newBlob(seq), nil
|
||||
}
|
||||
|
||||
func (Blob) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(BlobKind, targetKind)
|
||||
}
|
||||
|
||||
func (b Blob) readFrom(nbf *NomsBinFormat, bnr *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -95,65 +95,6 @@ func (b Bool) skip(nbf *NomsBinFormat, bnr *binaryNomsReader) {
|
||||
bnr.skipUint8()
|
||||
}
|
||||
|
||||
func (Bool) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case BoolKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
b := val.(Bool)
|
||||
if b {
|
||||
return Float(1), nil
|
||||
}
|
||||
return Float(0), nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
b := val.(Bool)
|
||||
if b {
|
||||
return Int(1), nil
|
||||
}
|
||||
return Int(0), nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
b := val.(Bool)
|
||||
if b {
|
||||
return String("true"), nil
|
||||
}
|
||||
return String("false"), nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
b := val.(Bool)
|
||||
if b {
|
||||
return Uint(1), nil
|
||||
}
|
||||
return Uint(0), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(BoolKind, targetKind)
|
||||
}
|
||||
|
||||
func (b Bool) HumanReadableString() string {
|
||||
return strconv.FormatBool(bool(b))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ package types
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/hash"
|
||||
)
|
||||
@@ -95,73 +94,6 @@ func (v Float) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipFloat(nbf)
|
||||
}
|
||||
|
||||
func (Float) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case BoolKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fl := float64(val.(Float))
|
||||
return Bool(fl != 0), nil
|
||||
}, nil
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fl := float64(val.(Float))
|
||||
return Int(int(fl)), nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fl := float64(val.(Float))
|
||||
str := strconv.FormatFloat(fl, 'f', -1, 64)
|
||||
return String(str), nil
|
||||
}, nil
|
||||
case TimestampKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fl := float64(val.(Float))
|
||||
// If Float is too large, we'll clamp it to the max time representable
|
||||
// There are comparison issues for times too large, so "200000000-12-31 23:59:59 UTC" seems like a reasonable maximum.
|
||||
if fl > 6311328264403199 {
|
||||
fl = 6311328264403199
|
||||
// I could not find anything pointing to a minimum allowed time, so "-200000000-01-01 00:00:00 UTC" seems reasonable
|
||||
} else if fl < -6311452567219200 {
|
||||
fl = -6311452567219200
|
||||
}
|
||||
// We treat a Float as seconds and nanoseconds, unlike integers which are just seconds
|
||||
seconds := int64(fl)
|
||||
nanoseconds := int64((fl - float64(seconds)) * float64(time.Second/time.Nanosecond))
|
||||
return Timestamp(time.Unix(seconds, nanoseconds).UTC()), nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
fl := float64(val.(Float))
|
||||
return Uint(uint64(fl)), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(FloatKind, targetKind)
|
||||
}
|
||||
|
||||
func (v Float) HumanReadableString() string {
|
||||
return strconv.FormatFloat(float64(v), 'g', -1, 64)
|
||||
}
|
||||
|
||||
@@ -102,28 +102,6 @@ func (v InlineBlob) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipBytes(size)
|
||||
}
|
||||
|
||||
func (InlineBlob) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case InlineBlobKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return String(strings.ToUpper(hex.EncodeToString(val.(InlineBlob)))), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(InlineBlobKind, targetKind)
|
||||
}
|
||||
|
||||
func (v InlineBlob) HumanReadableString() string {
|
||||
return strings.ToUpper(hex.EncodeToString(v))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ package types
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/hash"
|
||||
)
|
||||
@@ -96,69 +95,6 @@ func (v Int) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipInt()
|
||||
}
|
||||
|
||||
func (Int) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case BoolKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := int64(val.(Int))
|
||||
return Bool(n != 0), nil
|
||||
}, nil
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := int64(val.(Int))
|
||||
return Float(float64(n)), nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := int64(val.(Int))
|
||||
str := strconv.FormatInt(n, 10)
|
||||
return String(str), nil
|
||||
}, nil
|
||||
case TimestampKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := int64(val.(Int))
|
||||
// There are comparison issues for times too large, so "200000000-12-31 23:59:59 UTC" seems like a reasonable maximum.
|
||||
if n > 6311328264403199 {
|
||||
n = 6311328264403199
|
||||
// I could not find anything pointing to a minimum allowed time, so "-200000000-01-01 00:00:00" seems reasonable
|
||||
} else if n < -6311452567219200 {
|
||||
n = -6311452567219200
|
||||
}
|
||||
return Timestamp(time.Unix(n, 0).UTC()), nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := int64(val.(Int))
|
||||
return Uint(uint64(n)), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(IntKind, targetKind)
|
||||
}
|
||||
|
||||
func (v Int) HumanReadableString() string {
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
}
|
||||
|
||||
@@ -429,10 +429,6 @@ func newEmptyListSequenceChunker(ctx context.Context, vrw ValueReadWriter) (*seq
|
||||
return newEmptySequenceChunker(ctx, vrw, makeListLeafChunkFn(vrw), newIndexedMetaSequenceChunkFn(ListKind, vrw), hashValueBytes)
|
||||
}
|
||||
|
||||
func (List) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(ListKind, targetKind)
|
||||
}
|
||||
|
||||
func (l List) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -562,10 +562,6 @@ func newEmptyMapSequenceChunker(ctx context.Context, vrw ValueReadWriter) (*sequ
|
||||
return newEmptySequenceChunker(ctx, vrw, makeMapLeafChunkFn(vrw), newOrderedMetaSequenceChunkFn(MapKind, vrw), mapHashValueBytes)
|
||||
}
|
||||
|
||||
func (Map) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(MapKind, targetKind)
|
||||
}
|
||||
|
||||
func (m Map) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2019 Liquidata, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ConversionError struct {
|
||||
fromKind NomsKind
|
||||
toKind NomsKind
|
||||
err error
|
||||
}
|
||||
|
||||
// CreateConversionError creates a special kind of error to return during issues with marshalling values.
|
||||
func CreateConversionError(sourceKind NomsKind, targetKind NomsKind, err error) ConversionError {
|
||||
return ConversionError{
|
||||
fromKind: sourceKind,
|
||||
toKind: targetKind,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateNoConversionError creates a special kind of error to return when no marshal function is provided.
|
||||
func CreateNoConversionError(sourceKind NomsKind, targetKind NomsKind) ConversionError {
|
||||
return ConversionError{
|
||||
fromKind: sourceKind,
|
||||
toKind: targetKind,
|
||||
err: errors.New("no marshalling function found"),
|
||||
}
|
||||
}
|
||||
|
||||
func (ce ConversionError) Error() string {
|
||||
toKindStr := KindToString[ce.toKind]
|
||||
fromKindStr := KindToString[ce.fromKind]
|
||||
return fmt.Sprint("error converting", fromKindStr, "to", toKindStr, ": ", ce.err.Error())
|
||||
}
|
||||
@@ -88,12 +88,6 @@ func (v Null) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
|
||||
func (v Null) skip(nbf *NomsBinFormat, b *binaryNomsReader) {}
|
||||
|
||||
func (Null) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v Null) HumanReadableString() string {
|
||||
return "null_value"
|
||||
}
|
||||
|
||||
@@ -205,10 +205,6 @@ func (r Ref) isSameTargetType(other Ref) bool {
|
||||
return bytes.Equal(targetTypeBytes, otherTargetTypeBytes)
|
||||
}
|
||||
|
||||
func (Ref) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(RefKind, targetKind)
|
||||
}
|
||||
|
||||
func (r Ref) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -354,10 +354,6 @@ func newEmptySetSequenceChunker(ctx context.Context, vrw ValueReadWriter) (*sequ
|
||||
return newEmptySequenceChunker(ctx, vrw, makeSetLeafChunkFn(vrw), newOrderedMetaSequenceChunkFn(SetKind, vrw), hashValueBytes)
|
||||
}
|
||||
|
||||
func (Set) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(SetKind, targetKind)
|
||||
}
|
||||
|
||||
func (s Set) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -23,15 +23,9 @@ package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/hash"
|
||||
)
|
||||
@@ -122,143 +116,6 @@ func parseNumber(s String) (isNegative bool, decPos int, err error) {
|
||||
return isNegative, decPos, nil
|
||||
}
|
||||
|
||||
func (String) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case BoolKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
b, err := strconv.ParseBool(strings.ToLower(string(s)))
|
||||
if err != nil {
|
||||
return Bool(false), CreateConversionError(s.Kind(), BoolKind, err)
|
||||
}
|
||||
return Bool(b), nil
|
||||
}, nil
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
f, err := strconv.ParseFloat(string(s), 64)
|
||||
if err != nil {
|
||||
return Float(math.NaN()), CreateConversionError(s.Kind(), FloatKind, err)
|
||||
}
|
||||
return Float(f), nil
|
||||
}, nil
|
||||
case InlineBlobKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
data, err := hex.DecodeString(string(s))
|
||||
if err != nil {
|
||||
return InlineBlob{}, CreateConversionError(s.Kind(), InlineBlobKind, err)
|
||||
}
|
||||
return InlineBlob(data), nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
isNegative, decPos, err := parseNumber(s)
|
||||
if err != nil {
|
||||
b, boolErr := strconv.ParseBool(string(s))
|
||||
if boolErr == nil {
|
||||
if b {
|
||||
return Int(1), nil
|
||||
}
|
||||
return Int(0), nil
|
||||
}
|
||||
return Int(0), CreateConversionError(s.Kind(), IntKind, err)
|
||||
}
|
||||
if decPos == 0 || (decPos == 1 && isNegative) {
|
||||
return Int(0), nil
|
||||
}
|
||||
if decPos != -1 {
|
||||
s = s[:decPos]
|
||||
}
|
||||
n, err := strconv.ParseInt(string(s), 10, 64)
|
||||
if err != nil {
|
||||
return Int(0), CreateConversionError(s.Kind(), IntKind, err)
|
||||
}
|
||||
return Int(n), nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case TimestampKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
t, err := dateparse.ParseStrict(string(s))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Timestamp(t), nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
n, err := strconv.ParseUint(string(s), 10, 64)
|
||||
if err != nil {
|
||||
return Uint(0), CreateConversionError(s.Kind(), UintKind, err)
|
||||
}
|
||||
return Uint(n), nil
|
||||
}, nil
|
||||
case UUIDKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
s := val.(String)
|
||||
if len(s) == 0 {
|
||||
return NullValue, nil
|
||||
}
|
||||
u, err := uuid.Parse(string(s))
|
||||
if err != nil {
|
||||
return UUID(u), CreateConversionError(s.Kind(), UUIDKind, err)
|
||||
}
|
||||
return UUID(u), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(StringKind, targetKind)
|
||||
}
|
||||
|
||||
func (s String) HumanReadableString() string {
|
||||
return strconv.Quote(string(s))
|
||||
}
|
||||
|
||||
@@ -656,10 +656,6 @@ func verifyStructName(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (Struct) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(StructKind, targetKind)
|
||||
}
|
||||
|
||||
func (s Struct) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
const (
|
||||
timestampNumBytes = 15
|
||||
timestampFormat = "2006-01-02 15:04:05.999999999 -0700"
|
||||
timestampFormat = "2006-01-02 15:04:05.999999"
|
||||
)
|
||||
|
||||
type Timestamp time.Time
|
||||
@@ -105,59 +105,8 @@ func (v Timestamp) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipBytes(timestampNumBytes)
|
||||
}
|
||||
|
||||
func (Timestamp) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
t := time.Time(val.(Timestamp))
|
||||
seconds := t.Unix()
|
||||
// Since Float allows decimals, we represent the nanoseconds as a decimal
|
||||
nanoseconds := t.Nanosecond()
|
||||
combination := float64(seconds) + (float64(nanoseconds) / float64(time.Second/time.Nanosecond))
|
||||
return Float(combination), nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
t := time.Time(val.(Timestamp))
|
||||
return Int(t.Unix()), nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
t := val.(Timestamp)
|
||||
return String(t.String()), nil
|
||||
}, nil
|
||||
case TimestampKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
t := time.Time(val.(Timestamp))
|
||||
return Uint(t.Unix()), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(TimestampKind, targetKind)
|
||||
}
|
||||
|
||||
func (v Timestamp) String() string {
|
||||
return time.Time(v).Format(timestampFormat)
|
||||
return time.Time(v).UTC().Format(timestampFormat)
|
||||
}
|
||||
|
||||
func (v Timestamp) HumanReadableString() string {
|
||||
|
||||
@@ -496,10 +496,6 @@ func (t Tuple) fieldsToMap() (map[Value]Value, error) {
|
||||
return valMap, nil
|
||||
}
|
||||
|
||||
func (Tuple) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(TupleKind, targetKind)
|
||||
}
|
||||
|
||||
func (t Tuple) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -189,10 +189,6 @@ func indexOfType(t *Type, tl []*Type) (uint32, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (*Type) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
return nil, CreateNoConversionError(TypeKind, targetKind)
|
||||
}
|
||||
|
||||
func (t *Type) readFrom(nbf *NomsBinFormat, b *binaryNomsReader) (Value, error) {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ package types
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/liquidata-inc/dolt/go/store/hash"
|
||||
)
|
||||
@@ -97,66 +96,6 @@ func (v Uint) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipUint()
|
||||
}
|
||||
|
||||
func (Uint) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case BoolKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := uint64(val.(Uint))
|
||||
return Bool(n != 0), nil
|
||||
}, nil
|
||||
case FloatKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := uint64(val.(Uint))
|
||||
return Float(float64(n)), nil
|
||||
}, nil
|
||||
case IntKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := uint64(val.(Uint))
|
||||
return Int(int64(n)), nil
|
||||
}, nil
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := uint64(val.(Uint))
|
||||
str := strconv.FormatUint(n, 10)
|
||||
return String(str), nil
|
||||
}, nil
|
||||
case TimestampKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n := uint64(val.(Uint))
|
||||
// There are comparison issues for times too large, so "200000000-12-31 23:59:59 UTC" seems like a reasonable maximum.
|
||||
if n > 6311328264403199 {
|
||||
n = 6311328264403199
|
||||
}
|
||||
return Timestamp(time.Unix(int64(n), 0).UTC()), nil
|
||||
}, nil
|
||||
case UintKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(UintKind, targetKind)
|
||||
}
|
||||
|
||||
func (v Uint) HumanReadableString() string {
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
||||
|
||||
@@ -103,28 +103,6 @@ func (v UUID) skip(nbf *NomsBinFormat, b *binaryNomsReader) {
|
||||
b.skipBytes(uuidNumBytes)
|
||||
}
|
||||
|
||||
func (UUID) GetMarshalFunc(targetKind NomsKind) (MarshalCallback, error) {
|
||||
switch targetKind {
|
||||
case NullKind:
|
||||
return func(Value) (Value, error) {
|
||||
return NullValue, nil
|
||||
}, nil
|
||||
case StringKind:
|
||||
return func(val Value) (Value, error) {
|
||||
if val == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return String(val.(UUID).String()), nil
|
||||
}, nil
|
||||
case UUIDKind:
|
||||
return func(val Value) (Value, error) {
|
||||
return val, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, CreateNoConversionError(UUIDKind, targetKind)
|
||||
}
|
||||
|
||||
func (v UUID) String() string {
|
||||
return uuid.UUID(v).String()
|
||||
}
|
||||
|
||||
@@ -110,10 +110,6 @@ type Value interface {
|
||||
// chunked then this will return the refs of th sub trees of the prolly-tree.
|
||||
WalkRefs(*NomsBinFormat, RefCallback) error
|
||||
|
||||
// GetMarshalFunc takes in a Kind and returns a function that accepts a Value of the calling type.
|
||||
// The returned function then marshals the given type into the given Kind.
|
||||
GetMarshalFunc(NomsKind) (MarshalCallback, error)
|
||||
|
||||
// HumanReadableString returns a human-readable string version of this Value (not meant for re-parsing)
|
||||
HumanReadableString() string
|
||||
|
||||
|
||||
Reference in New Issue
Block a user