github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/convert_test.go (about) 1 // Copyright 2020-2021 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 expression 16 17 import ( 18 "math" 19 "testing" 20 "time" 21 22 "github.com/shopspring/decimal" 23 "github.com/stretchr/testify/require" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 "github.com/dolthub/go-mysql-server/sql/types" 27 ) 28 29 func TestConvert(t *testing.T) { 30 tests := []struct { 31 name string 32 row sql.Row 33 expression sql.Expression 34 castTo string 35 typeLength int 36 typeScale int 37 expected interface{} 38 expectedErr bool 39 }{ 40 { 41 name: "convert int32 to signed", 42 row: nil, 43 expression: NewLiteral(int32(1), types.Int32), 44 castTo: ConvertToSigned, 45 expected: int64(1), 46 expectedErr: false, 47 }, 48 { 49 name: "convert int32 to unsigned", 50 row: nil, 51 expression: NewLiteral(int32(-5), types.Int32), 52 castTo: ConvertToUnsigned, 53 expected: uint64(math.MaxUint64 - 4), 54 expectedErr: false, 55 }, 56 { 57 name: "convert int32 to float", 58 row: nil, 59 expression: NewLiteral(int32(-5), types.Int32), 60 castTo: ConvertToFloat, 61 expected: float32(-5.0), 62 expectedErr: false, 63 }, 64 { 65 name: "convert int32 to double", 66 row: nil, 67 expression: NewLiteral(int32(-5), types.Int32), 68 castTo: ConvertToDouble, 69 expected: -5.0, 70 expectedErr: false, 71 }, 72 { 73 name: "convert string to signed", 74 row: nil, 75 expression: NewLiteral("-3", types.LongText), 76 castTo: ConvertToSigned, 77 expected: int64(-3), 78 expectedErr: false, 79 }, 80 { 81 name: "convert string to unsigned", 82 row: nil, 83 expression: NewLiteral("-3", types.LongText), 84 castTo: ConvertToUnsigned, 85 expected: uint64(18446744073709551613), 86 expectedErr: false, 87 }, 88 { 89 name: "convert string to double", 90 row: nil, 91 expression: NewLiteral("-3.123", types.LongText), 92 castTo: ConvertToDouble, 93 expected: -3.123, 94 expectedErr: false, 95 }, 96 { 97 name: "convert string to decimal with precision/scale constraints", 98 row: nil, 99 expression: NewLiteral("10.123456", types.LongText), 100 typeLength: 4, 101 typeScale: 2, 102 castTo: ConvertToDecimal, 103 expected: "10.12", 104 expectedErr: false, 105 }, 106 { 107 name: "convert int to string", 108 row: nil, 109 expression: NewLiteral(-3, types.Int32), 110 castTo: ConvertToChar, 111 expected: "-3", 112 expectedErr: false, 113 }, 114 { 115 name: "convert int to string with length constraint", 116 row: nil, 117 expression: NewLiteral(-3, types.Int32), 118 castTo: ConvertToChar, 119 typeLength: 1, 120 expected: "-", 121 expectedErr: false, 122 }, 123 { 124 name: "convert int to string with length constraint larger than value", 125 row: nil, 126 expression: NewLiteral(-3, types.Int32), 127 castTo: ConvertToChar, 128 typeLength: 10, 129 expected: "-3", 130 expectedErr: false, 131 }, 132 { 133 name: "impossible conversion string to unsigned", 134 row: nil, 135 expression: NewLiteral("hello", types.LongText), 136 castTo: ConvertToUnsigned, 137 expected: uint64(0), 138 expectedErr: false, 139 }, 140 { 141 name: "impossible conversion string to signed", 142 row: nil, 143 castTo: ConvertToSigned, 144 expression: NewLiteral("A", types.LongText), 145 expected: int64(0), 146 expectedErr: false, 147 }, 148 { 149 name: "impossible conversion string to double", 150 row: nil, 151 castTo: ConvertToDouble, 152 expression: NewLiteral("A", types.LongText), 153 expected: 0.0, 154 expectedErr: false, 155 }, 156 { 157 name: "string to datetime", 158 row: nil, 159 expression: NewLiteral("2017-12-12", types.LongText), 160 castTo: ConvertToDatetime, 161 expected: time.Date(2017, time.December, 12, 0, 0, 0, 0, time.UTC), 162 expectedErr: false, 163 }, 164 { 165 name: "impossible conversion string to datetime", 166 row: nil, 167 castTo: ConvertToDatetime, 168 expression: NewLiteral(1, types.Int32), 169 expected: nil, 170 expectedErr: false, 171 }, 172 { 173 name: "string to date", 174 row: nil, 175 castTo: ConvertToDate, 176 expression: NewLiteral("2017-12-12 11:12:13", types.Int32), 177 expected: time.Date(2017, time.December, 12, 0, 0, 0, 0, time.UTC), 178 expectedErr: false, 179 }, 180 { 181 name: "impossible conversion string to date", 182 row: nil, 183 castTo: ConvertToDate, 184 expression: NewLiteral(1, types.Int32), 185 expected: nil, 186 expectedErr: false, 187 }, 188 { 189 name: "float to binary", 190 row: nil, 191 castTo: ConvertToBinary, 192 expression: NewLiteral(float64(-2.3), types.Float64), 193 expected: []byte("-2.3"), 194 expectedErr: false, 195 }, 196 { 197 name: "float to binary with length restriction", 198 row: nil, 199 castTo: ConvertToBinary, 200 typeLength: 3, 201 expression: NewLiteral(float64(-2.3), types.Float64), 202 expected: []byte("-2."), 203 expectedErr: false, 204 }, 205 { 206 name: "float to char with length restriction", 207 row: nil, 208 castTo: ConvertToChar, 209 typeLength: 4, 210 expression: NewLiteral(10.56789, types.Float32), 211 expected: "10.5", 212 expectedErr: false, 213 }, 214 { 215 name: "float to char with length restriction larger than value", 216 row: nil, 217 castTo: ConvertToChar, 218 typeLength: 40, 219 expression: NewLiteral(10.56789, types.Float32), 220 expected: "10.56789", 221 expectedErr: false, 222 }, 223 { 224 name: "string to json", 225 row: nil, 226 castTo: ConvertToJSON, 227 expression: NewLiteral(`{"a":2}`, types.LongText), 228 expected: types.MustJSON(`{"a":2}`), 229 expectedErr: false, 230 }, 231 { 232 name: "int to json", 233 row: nil, 234 castTo: ConvertToJSON, 235 expression: NewLiteral(2, types.Int32), 236 expected: types.JSONDocument{Val: float64(2)}, 237 expectedErr: false, 238 }, 239 { 240 name: "impossible conversion string to json", 241 row: nil, 242 castTo: ConvertToJSON, 243 expression: NewLiteral("3>2", types.LongText), 244 expected: nil, 245 expectedErr: true, 246 }, 247 { 248 name: "bool to signed", 249 row: nil, 250 castTo: ConvertToSigned, 251 expression: NewLiteral(true, types.Boolean), 252 expected: int64(1), 253 expectedErr: false, 254 }, 255 { 256 name: "bool to datetime", 257 row: nil, 258 castTo: ConvertToDatetime, 259 expression: NewLiteral(true, types.Boolean), 260 expected: nil, 261 expectedErr: false, 262 }, 263 } 264 265 for _, test := range tests { 266 t.Run(test.name, func(t *testing.T) { 267 require := require.New(t) 268 convert := NewConvertWithLengthAndScale(test.expression, test.castTo, test.typeLength, test.typeScale) 269 val, err := convert.Eval(sql.NewEmptyContext(), test.row) 270 if test.expectedErr { 271 require.Error(err) 272 } else { 273 require.NoError(err) 274 } 275 276 // Convert any Decimal values to strings for easier comparison (same as we do for engine tests) 277 if d, ok := val.(decimal.Decimal); ok { 278 val = d.String() 279 } 280 281 require.Equal(test.expected, val) 282 }) 283 } 284 }