1/* 2Copyright 2014 SAP SE 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package driver 18 19import ( 20 "database/sql/driver" 21 "errors" 22 "fmt" 23 "math" 24 "reflect" 25 "time" 26 27 p "github.com/SAP/go-hdb/internal/protocol" 28) 29 30const ( 31 minTinyint = 0 32 maxTinyint = math.MaxUint8 33 minSmallint = math.MinInt16 34 maxSmallint = math.MaxInt16 35 minInteger = math.MinInt32 36 maxInteger = math.MaxInt32 37 minBigint = math.MinInt64 38 maxBigint = math.MaxInt64 39 maxReal = math.MaxFloat32 40 maxDouble = math.MaxFloat64 41) 42 43// ErrIntegerOutOfRange means that an integer exceeds the size of the hdb integer field. 44var ErrIntegerOutOfRange = errors.New("integer out of range error") 45 46// ErrFloatOutOfRange means that a float exceeds the size of the hdb float field. 47var ErrFloatOutOfRange = errors.New("float out of range error") 48 49var typeOfTime = reflect.TypeOf((*time.Time)(nil)).Elem() 50var typeOfBytes = reflect.TypeOf((*[]byte)(nil)).Elem() 51 52func checkNamedValue(prmFieldSet *p.ParameterFieldSet, nv *driver.NamedValue) error { 53 idx := nv.Ordinal - 1 54 55 if idx >= prmFieldSet.NumInputField() { 56 return nil 57 } 58 59 f := prmFieldSet.Field(idx) 60 dt := f.TypeCode().DataType() 61 62 value, err := convertNamedValue(idx, f, dt, nv.Value) 63 64 if err != nil { 65 return err 66 } 67 68 nv.Value = value 69 return nil 70} 71 72func convertNamedValue(idx int, f *p.ParameterField, dt p.DataType, v driver.Value) (driver.Value, error) { 73 var err error 74 75 // let fields with own Value converter convert themselves first (e.g. NullInt64, ...) 76 if _, ok := v.(driver.Valuer); ok { 77 if v, err = driver.DefaultParameterConverter.ConvertValue(v); err != nil { 78 return nil, err 79 } 80 } 81 82 switch dt { 83 84 default: 85 return nil, fmt.Errorf("convert named value datatype error: %[1]d - %[1]s", dt) 86 87 case p.DtTinyint: 88 return convertNvInteger(v, minTinyint, maxTinyint) 89 90 case p.DtSmallint: 91 return convertNvInteger(v, minSmallint, maxSmallint) 92 93 case p.DtInteger: 94 return convertNvInteger(v, minInteger, maxInteger) 95 96 case p.DtBigint: 97 return convertNvInteger(v, minBigint, maxBigint) 98 99 case p.DtReal: 100 return convertNvFloat(v, maxReal) 101 102 case p.DtDouble: 103 return convertNvFloat(v, maxDouble) 104 105 case p.DtTime: 106 return convertNvTime(v) 107 108 case p.DtDecimal: 109 return convertNvDecimal(v) 110 111 case p.DtString: 112 return convertNvString(v) 113 114 case p.DtBytes: 115 return convertNvBytes(v) 116 117 case p.DtLob: 118 return convertNvLob(idx, f, v) 119 120 } 121} 122 123// integer types 124func convertNvInteger(v interface{}, min, max int64) (driver.Value, error) { 125 126 if v == nil { 127 return v, nil 128 } 129 130 rv := reflect.ValueOf(v) 131 switch rv.Kind() { 132 133 // bool is represented in HDB as tinyint 134 case reflect.Bool: 135 return rv.Bool(), nil 136 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 137 i64 := rv.Int() 138 if i64 > max || i64 < min { 139 return nil, ErrIntegerOutOfRange 140 } 141 return i64, nil 142 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 143 u64 := rv.Uint() 144 if u64 > uint64(max) { 145 return nil, ErrIntegerOutOfRange 146 } 147 return int64(u64), nil 148 case reflect.Ptr: 149 // indirect pointers 150 if rv.IsNil() { 151 return nil, nil 152 } 153 return convertNvInteger(rv.Elem().Interface(), min, max) 154 } 155 156 return nil, fmt.Errorf("unsupported integer conversion type error %[1]T %[1]v", v) 157} 158 159// float types 160func convertNvFloat(v interface{}, max float64) (driver.Value, error) { 161 162 if v == nil { 163 return v, nil 164 } 165 166 rv := reflect.ValueOf(v) 167 switch rv.Kind() { 168 169 case reflect.Float32, reflect.Float64: 170 f64 := rv.Float() 171 if math.Abs(f64) > max { 172 return nil, ErrFloatOutOfRange 173 } 174 return f64, nil 175 case reflect.Ptr: 176 // indirect pointers 177 if rv.IsNil() { 178 return nil, nil 179 } 180 return convertNvFloat(rv.Elem().Interface(), max) 181 } 182 183 return nil, fmt.Errorf("unsupported float conversion type error %[1]T %[1]v", v) 184} 185 186// time 187func convertNvTime(v interface{}) (driver.Value, error) { 188 189 if v == nil { 190 return nil, nil 191 } 192 193 switch v := v.(type) { 194 195 case time.Time: 196 return v, nil 197 } 198 199 rv := reflect.ValueOf(v) 200 201 switch rv.Kind() { 202 203 case reflect.Ptr: 204 // indirect pointers 205 if rv.IsNil() { 206 return nil, nil 207 } 208 return convertNvTime(rv.Elem().Interface()) 209 } 210 211 if rv.Type().ConvertibleTo(typeOfTime) { 212 tv := rv.Convert(typeOfTime) 213 return tv.Interface().(time.Time), nil 214 } 215 216 return nil, fmt.Errorf("unsupported time conversion type error %[1]T %[1]v", v) 217} 218 219// decimal 220func convertNvDecimal(v interface{}) (driver.Value, error) { 221 222 if v == nil { 223 return nil, nil 224 } 225 226 if v, ok := v.([]byte); ok { 227 return v, nil 228 } 229 230 return nil, fmt.Errorf("unsupported decimal conversion type error %[1]T %[1]v", v) 231} 232 233// string 234func convertNvString(v interface{}) (driver.Value, error) { 235 236 if v == nil { 237 return v, nil 238 } 239 240 switch v := v.(type) { 241 242 case string, []byte: 243 return v, nil 244 } 245 246 rv := reflect.ValueOf(v) 247 248 switch rv.Kind() { 249 250 case reflect.String: 251 return rv.String(), nil 252 253 case reflect.Slice: 254 if rv.Type() == typeOfBytes { 255 return rv.Bytes(), nil 256 } 257 258 case reflect.Ptr: 259 // indirect pointers 260 if rv.IsNil() { 261 return nil, nil 262 } 263 return convertNvString(rv.Elem().Interface()) 264 } 265 266 if rv.Type().ConvertibleTo(typeOfBytes) { 267 bv := rv.Convert(typeOfBytes) 268 return bv.Interface().([]byte), nil 269 } 270 271 return nil, fmt.Errorf("unsupported character conversion type error %[1]T %[1]v", v) 272} 273 274// bytes 275func convertNvBytes(v interface{}) (driver.Value, error) { 276 277 if v == nil { 278 return v, nil 279 } 280 281 if v, ok := v.([]byte); ok { 282 return v, nil 283 } 284 285 rv := reflect.ValueOf(v) 286 287 switch rv.Kind() { 288 289 case reflect.Slice: 290 if rv.Type() == typeOfBytes { 291 return rv.Bytes(), nil 292 } 293 294 case reflect.Ptr: 295 // indirect pointers 296 if rv.IsNil() { 297 return nil, nil 298 } 299 return convertNvBytes(rv.Elem().Interface()) 300 } 301 302 if rv.Type().ConvertibleTo(typeOfBytes) { 303 bv := rv.Convert(typeOfBytes) 304 return bv.Interface().([]byte), nil 305 } 306 307 return nil, fmt.Errorf("unsupported bytes conversion type error %[1]T %[1]v", v) 308} 309 310// Lob 311func convertNvLob(idx int, f *p.ParameterField, v interface{}) (driver.Value, error) { 312 313 if v == nil { 314 return v, nil 315 } 316 317 switch v := v.(type) { 318 case Lob: 319 if v.rd == nil { 320 return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v) 321 } 322 f.SetLobReader(v.rd) 323 return fmt.Sprintf("<lob %d", idx), nil 324 case *Lob: 325 if v.rd == nil { 326 return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v) 327 } 328 f.SetLobReader(v.rd) 329 return fmt.Sprintf("<lob %d", idx), nil 330 case NullLob: 331 if !v.Valid { 332 return nil, nil 333 } 334 if v.Lob.rd == nil { 335 return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v) 336 } 337 f.SetLobReader(v.Lob.rd) 338 return fmt.Sprintf("<lob %d", idx), nil 339 case *NullLob: 340 if !v.Valid { 341 return nil, nil 342 } 343 if v.Lob.rd == nil { 344 return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v) 345 } 346 f.SetLobReader(v.Lob.rd) 347 return fmt.Sprintf("<lob %d", idx), nil 348 } 349 350 rv := reflect.ValueOf(v) 351 352 switch rv.Kind() { 353 354 case reflect.Ptr: 355 // indirect pointers 356 if rv.IsNil() { 357 return nil, nil 358 } 359 return convertNvLob(idx, f, rv.Elem().Interface()) 360 } 361 362 return nil, fmt.Errorf("unsupported lob conversion type error %[1]T %[1]v", v) 363} 364