github.com/dolthub/go-mysql-server@v0.18.0/sql/types/tuple.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package types 16 17 import ( 18 "fmt" 19 "reflect" 20 "strings" 21 22 "github.com/dolthub/vitess/go/sqltypes" 23 "github.com/dolthub/vitess/go/vt/proto/query" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 ) 27 28 var tupleValueType = reflect.TypeOf((*[]interface{})(nil)).Elem() 29 30 type TupleType []sql.Type 31 32 var _ sql.Type = TupleType{nil} 33 var _ sql.CollationCoercible = TupleType{nil} 34 35 // CreateTuple returns a new tuple type with the given element types. 36 func CreateTuple(types ...sql.Type) sql.Type { 37 return TupleType(types) 38 } 39 40 func (t TupleType) Compare(a, b interface{}) (int, error) { 41 if hasNulls, res := CompareNulls(a, b); hasNulls { 42 return res, nil 43 } 44 45 a, _, err := t.Convert(a) 46 if err != nil { 47 return 0, err 48 } 49 50 b, _, err = t.Convert(b) 51 if err != nil { 52 return 0, err 53 } 54 55 left := a.([]interface{}) 56 right := b.([]interface{}) 57 for i := range left { 58 cmp, err := t[i].Compare(left[i], right[i]) 59 if err != nil { 60 return 0, err 61 } 62 63 if cmp != 0 { 64 return cmp, nil 65 } 66 } 67 68 return 0, nil 69 } 70 71 func (t TupleType) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) { 72 if v == nil { 73 return nil, sql.InRange, nil 74 } 75 if vals, ok := v.([]interface{}); ok { 76 if len(vals) != len(t) { 77 return nil, sql.OutOfRange, sql.ErrInvalidColumnNumber.New(len(t), len(vals)) 78 } 79 80 var result = make([]interface{}, len(t)) 81 for i, typ := range t { 82 var err error 83 result[i], _, err = typ.Convert(vals[i]) 84 if err != nil { 85 return nil, sql.OutOfRange, err 86 } 87 } 88 89 return result, sql.InRange, nil 90 } 91 return nil, sql.OutOfRange, sql.ErrNotTuple.New(v) 92 } 93 94 func (t TupleType) MustConvert(v interface{}) interface{} { 95 value, _, err := t.Convert(v) 96 if err != nil { 97 panic(err) 98 } 99 return value 100 } 101 102 // Equals implements the Type interface. 103 func (t TupleType) Equals(otherType sql.Type) bool { 104 if ot, ok := otherType.(TupleType); ok && len(t) == len(ot) { 105 for i, tupType := range t { 106 if !tupType.Equals(ot[i]) { 107 return false 108 } 109 } 110 return true 111 } 112 return false 113 } 114 115 // MaxTextResponseByteLength implements the Type interface 116 func (t TupleType) MaxTextResponseByteLength(_ *sql.Context) uint32 { 117 // TupleTypes are never actually sent over the wire directly 118 return 0 119 } 120 121 func (t TupleType) Promote() sql.Type { 122 return t 123 } 124 125 func (t TupleType) SQL(*sql.Context, []byte, interface{}) (sqltypes.Value, error) { 126 return sqltypes.Value{}, fmt.Errorf("unable to convert tuple type to SQL") 127 } 128 129 func (t TupleType) String() string { 130 var elems = make([]string, len(t)) 131 for i, el := range t { 132 elems[i] = el.String() 133 } 134 return fmt.Sprintf("tuple(%s)", strings.Join(elems, ", ")) 135 } 136 137 func (t TupleType) Type() query.Type { 138 return sqltypes.Expression 139 } 140 141 // ValueType implements Type interface. 142 func (t TupleType) ValueType() reflect.Type { 143 return tupleValueType 144 } 145 146 func (t TupleType) Zero() interface{} { 147 zeroes := make([]interface{}, len(t)) 148 for i, tt := range t { 149 zeroes[i] = tt.Zero() 150 } 151 return zeroes 152 } 153 154 // CollationCoercibility implements sql.CollationCoercible interface. 155 func (TupleType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 156 return sql.Collation_binary, 7 157 }