@@ -45,6 +45,9 @@ var ErrIntegerOutOfRange = errors.New("integer out of range error")
45
45
// ErrFloatOutOfRange means that a float exceeds the size of the hdb float field.
46
46
var ErrFloatOutOfRange = errors .New ("float out of range error" )
47
47
48
+ // ErrRatConversion means that a conversion to big.Rat was not possible.
49
+ var ErrRatConversion = errors .New ("rat conversion error" )
50
+
48
51
// A ConvertError is returned by conversion methods if a go datatype to hdb datatype conversion fails.
49
52
type ConvertError struct {
50
53
err error
@@ -157,31 +160,19 @@ func convertInteger(tc typeCode, v any, min, max int64) (any, error) { //nolint:
157
160
}
158
161
return i64 , nil
159
162
case uint8 :
160
- u64 := uint64 (v )
161
- if u64 >= 1 << 63 {
162
- return nil , newConvertError (tc , v , ErrUint64OutOfRange )
163
- }
164
- i64 := int64 (u64 )
163
+ i64 := int64 (v )
165
164
if i64 > max || i64 < min {
166
165
return nil , newConvertError (tc , v , ErrIntegerOutOfRange )
167
166
}
168
167
return i64 , nil
169
168
case uint16 :
170
- u64 := uint64 (v )
171
- if u64 >= 1 << 63 {
172
- return nil , newConvertError (tc , v , ErrUint64OutOfRange )
173
- }
174
- i64 := int64 (u64 )
169
+ i64 := int64 (v )
175
170
if i64 > max || i64 < min {
176
171
return nil , newConvertError (tc , v , ErrIntegerOutOfRange )
177
172
}
178
173
return i64 , nil
179
174
case uint32 :
180
- u64 := uint64 (v )
181
- if u64 >= 1 << 63 {
182
- return nil , newConvertError (tc , v , ErrUint64OutOfRange )
183
- }
184
- i64 := int64 (u64 )
175
+ i64 := int64 (v )
185
176
if i64 > max || i64 < min {
186
177
return nil , newConvertError (tc , v , ErrIntegerOutOfRange )
187
178
}
@@ -234,7 +225,13 @@ func convertInteger(tc typeCode, v any, min, max int64) (any, error) { //nolint:
234
225
return nil , newConvertError (tc , v , ErrIntegerOutOfRange )
235
226
}
236
227
return i64 , nil
237
- case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
228
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 :
229
+ i64 := int64 (rv .Uint ())
230
+ if i64 > max || i64 < min {
231
+ return nil , newConvertError (tc , v , ErrIntegerOutOfRange )
232
+ }
233
+ return i64 , nil
234
+ case reflect .Uint64 :
238
235
u64 := rv .Uint ()
239
236
if u64 >= 1 << 63 {
240
237
return nil , newConvertError (tc , v , ErrUint64OutOfRange )
@@ -276,7 +273,12 @@ func convertInteger(tc typeCode, v any, min, max int64) (any, error) { //nolint:
276
273
}
277
274
}
278
275
279
- func convertFloat (tc typeCode , v any , max float64 ) (any , error ) {
276
+ var (
277
+ floatZero = 0.0
278
+ floatOne = 1.0
279
+ )
280
+
281
+ func convertFloat (tc typeCode , v any , max float64 ) (any , error ) { //nolint: gocyclo
280
282
switch v := v .(type ) {
281
283
case float32 :
282
284
f64 := float64 (v )
@@ -289,6 +291,71 @@ func convertFloat(tc typeCode, v any, max float64) (any, error) {
289
291
return nil , newConvertError (tc , v , ErrFloatOutOfRange )
290
292
}
291
293
return v , nil
294
+ case bool :
295
+ if v {
296
+ return floatOne , nil
297
+ }
298
+ return floatZero , nil
299
+ case int :
300
+ f64 := float64 (v )
301
+ if math .Abs (f64 ) > max {
302
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
303
+ }
304
+ return f64 , nil
305
+ case int8 :
306
+ f64 := float64 (v )
307
+ if math .Abs (f64 ) > max {
308
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
309
+ }
310
+ return f64 , nil
311
+ case int16 :
312
+ f64 := float64 (v )
313
+ if math .Abs (f64 ) > max {
314
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
315
+ }
316
+ return f64 , nil
317
+ case int32 :
318
+ f64 := float64 (v )
319
+ if math .Abs (f64 ) > max {
320
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
321
+ }
322
+ return f64 , nil
323
+ case int64 :
324
+ f64 := float64 (v )
325
+ if math .Abs (f64 ) > max {
326
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
327
+ }
328
+ return f64 , nil
329
+ case uint :
330
+ f64 := float64 (v )
331
+ if math .Abs (f64 ) > max {
332
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
333
+ }
334
+ return f64 , nil
335
+ case uint8 :
336
+ f64 := float64 (v )
337
+ if math .Abs (f64 ) > max {
338
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
339
+ }
340
+ return f64 , nil
341
+ case uint16 :
342
+ f64 := float64 (v )
343
+ if math .Abs (f64 ) > max {
344
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
345
+ }
346
+ return f64 , nil
347
+ case uint32 :
348
+ f64 := float64 (v )
349
+ if math .Abs (f64 ) > max {
350
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
351
+ }
352
+ return f64 , nil
353
+ case uint64 :
354
+ f64 := float64 (v )
355
+ if math .Abs (f64 ) > max {
356
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
357
+ }
358
+ return f64 , nil
292
359
case string :
293
360
f64 , err := strconv .ParseFloat (v , 64 )
294
361
if err != nil {
@@ -302,6 +369,23 @@ func convertFloat(tc typeCode, v any, max float64) (any, error) {
302
369
303
370
rv := reflect .ValueOf (v )
304
371
switch rv .Kind () {
372
+ case reflect .Bool :
373
+ if rv .Bool () {
374
+ return floatOne , nil
375
+ }
376
+ return floatZero , nil
377
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
378
+ f64 := float64 (rv .Int ())
379
+ if math .Abs (f64 ) > max {
380
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
381
+ }
382
+ return f64 , nil
383
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
384
+ f64 := float64 (rv .Uint ())
385
+ if math .Abs (f64 ) > max {
386
+ return nil , newConvertError (tc , v , ErrFloatOutOfRange )
387
+ }
388
+ return f64 , nil
305
389
case reflect .Float32 , reflect .Float64 :
306
390
f64 := rv .Float ()
307
391
if math .Abs (f64 ) > max {
@@ -351,24 +435,95 @@ func convertTime(tc typeCode, v any) (any, error) {
351
435
}
352
436
}
353
437
438
+ var (
439
+ ratZero = big .NewRat (0 , 1 )
440
+ ratOne = big .NewRat (1 , 1 )
441
+ )
442
+
354
443
/*
355
444
Currently the min, max check is done during encoding, as the check is expensive and
356
445
we want to avoid doing the conversion twice (convert + encode).
357
446
These checks could be done in convert only, but then we would need a
358
447
struct{m *big.Int, exp int} for decimals as intermediate format.
359
448
360
- We would be able to accept other datatypes as well, like
361
- int??, *big.Int, string, ...
362
- but as the user needs to use Decimal anyway (scan), we go with
363
- *big.Rat only for the time being.
449
+ The conversion does support other types as well (int, *big.Int, string, ...)
450
+ even though the user needs to use Decimal for scanning.
364
451
*/
365
- func convertDecimal (tc typeCode , v any ) (any , error ) {
366
- if v , ok := v .(* big.Rat ); ok {
452
+ func convertDecimal (tc typeCode , v any ) (any , error ) { //nolint: gocyclo
453
+ switch v := v .(type ) {
454
+ case * big.Rat :
367
455
return v , nil
456
+ case * big.Int :
457
+ return new (big.Rat ).SetInt (v ), nil
458
+ case * big.Float :
459
+ r , _ := v .Rat (nil ) // ignore accuracy
460
+ return r , nil
461
+ case bool :
462
+ if v {
463
+ return ratOne , nil
464
+ }
465
+ return ratZero , nil
466
+ case int :
467
+ return new (big.Rat ).SetInt64 (int64 (v )), nil
468
+ case int8 :
469
+ return new (big.Rat ).SetInt64 (int64 (v )), nil
470
+ case int16 :
471
+ return new (big.Rat ).SetInt64 (int64 (v )), nil
472
+ case int32 :
473
+ return new (big.Rat ).SetInt64 (int64 (v )), nil
474
+ case int64 :
475
+ return new (big.Rat ).SetInt64 (v ), nil
476
+ case uint :
477
+ return new (big.Rat ).SetUint64 (uint64 (v )), nil
478
+ case uint8 :
479
+ return new (big.Rat ).SetUint64 (uint64 (v )), nil
480
+ case uint16 :
481
+ return new (big.Rat ).SetUint64 (uint64 (v )), nil
482
+ case uint32 :
483
+ return new (big.Rat ).SetUint64 (uint64 (v )), nil
484
+ case uint64 :
485
+ return new (big.Rat ).SetUint64 (v ), nil
486
+ case float32 :
487
+ r := new (big.Rat ).SetFloat64 (float64 (v ))
488
+ if r == nil {
489
+ return nil , newConvertError (tc , v , ErrRatConversion )
490
+ }
491
+ case float64 :
492
+ r := new (big.Rat ).SetFloat64 (v )
493
+ if r == nil {
494
+ return nil , newConvertError (tc , v , ErrRatConversion )
495
+ }
496
+ case string :
497
+ r , ok := new (big.Rat ).SetString (v )
498
+ if ! ok {
499
+ return nil , newConvertError (tc , v , ErrRatConversion )
500
+ }
501
+ return r , nil
368
502
}
369
503
370
504
rv := reflect .ValueOf (v )
371
505
switch rv .Kind () {
506
+ case reflect .Bool :
507
+ if rv .Bool () {
508
+ return ratOne , nil
509
+ }
510
+ return ratZero , nil
511
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
512
+ return new (big.Rat ).SetInt64 (rv .Int ()), nil
513
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
514
+ return new (big.Rat ).SetUint64 (rv .Uint ()), nil
515
+ case reflect .Float32 , reflect .Float64 :
516
+ r := new (big.Rat ).SetFloat64 (rv .Float ())
517
+ if r == nil {
518
+ return nil , newConvertError (tc , v , ErrRatConversion )
519
+ }
520
+ return r , nil
521
+ case reflect .String :
522
+ r , ok := new (big.Rat ).SetString (rv .String ())
523
+ if ! ok {
524
+ return nil , newConvertError (tc , v , ErrRatConversion )
525
+ }
526
+ return r , nil
372
527
case reflect .Ptr :
373
528
if rv .IsNil () {
374
529
return nil , nil
0 commit comments