-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(go/adbc/driver/snowflake): handling of integer values sent for NUMBER columns #1267
Changes from 6 commits
9948ea3
60bad0d
d4fc953
befa948
b7fe32e
d1074d7
10a677a
2354164
a517521
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,20 +101,36 @@ func getTransformer(sc *arrow.Schema, ld gosnowflake.ArrowStreamLoader, useHighP | |
} | ||
f.Type = dt | ||
transformers[i] = func(ctx context.Context, a arrow.Array) (arrow.Array, error) { | ||
return compute.CastArray(ctx, a, compute.SafeCastOptions(dt)) | ||
return integerToDecimal128(ctx, a, dt) | ||
} | ||
} else { | ||
if srcMeta.Scale != 0 { | ||
f.Type = arrow.PrimitiveTypes.Float64 | ||
transformers[i] = func(ctx context.Context, a arrow.Array) (arrow.Array, error) { | ||
result, err := compute.Divide(ctx, compute.ArithmeticOptions{NoCheckOverflow: true}, | ||
&compute.ArrayDatum{Value: a.Data()}, | ||
compute.NewDatum(math.Pow10(int(srcMeta.Scale)))) | ||
if err != nil { | ||
return nil, err | ||
// For precisions of 16, 17 and 18, a conversion from int64 to float64 fails with an error | ||
// So for these precisions, we instead convert first to a decimal128 and then to a float64. | ||
Comment on lines
+109
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the error? Should those precisions instead work and we should push a fix upstream to the Arrow lib? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message is "invalid: integer value 99999999999999999 not in range: -9007199254740992 to 9007199254740992". I do think that it makes sense to allow a lossy conversion in Arrow from int64 to float64 and that would avoid the need for this special case. This may require some design work in Arrow -- for instance, having the Divide kernel take a CastOptions or adding AllowFloatTruncate to ArithmeticOptions. |
||
if srcMeta.Precision > 15 && srcMeta.Precision < 19 { | ||
transformers[i] = func(ctx context.Context, a arrow.Array) (arrow.Array, error) { | ||
result, err := integerToDecimal128(ctx, a, &arrow.Decimal128Type{ | ||
Precision: int32(srcMeta.Precision), | ||
Scale: int32(srcMeta.Scale), | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return compute.CastArray(ctx, result, compute.UnsafeCastOptions(f.Type)) | ||
} | ||
} else { | ||
// For precisions less than 16, we can simply scale the integer value appropriately | ||
transformers[i] = func(ctx context.Context, a arrow.Array) (arrow.Array, error) { | ||
result, err := compute.Divide(ctx, compute.ArithmeticOptions{NoCheckOverflow: true}, | ||
&compute.ArrayDatum{Value: a.Data()}, | ||
compute.NewDatum(math.Pow10(int(srcMeta.Scale)))) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer result.Release() | ||
return result.(*compute.ArrayDatum).MakeArray(), nil | ||
} | ||
defer result.Release() | ||
return result.(*compute.ArrayDatum).MakeArray(), nil | ||
} | ||
} else { | ||
f.Type = arrow.PrimitiveTypes.Int64 | ||
|
@@ -266,6 +282,24 @@ func getTransformer(sc *arrow.Schema, ld gosnowflake.ArrowStreamLoader, useHighP | |
return out, getRecTransformer(out, transformers) | ||
} | ||
|
||
func integerToDecimal128(ctx context.Context, a arrow.Array, dt *arrow.Decimal128Type) (arrow.Array, error) { | ||
// We can't do a cast directly into the destination type because the numbers we get from Snowflake | ||
// are scaled integers. So not only would the cast produce the wrong value, it also risks producing | ||
// an error of precisions which e.g. can't hold every int64. To work around these problems, we instead | ||
// cast into a decimal type of a precision and scale which we know will hold all values and won't | ||
// require scaling, We then substitute the type on this array with the actual return type. | ||
Comment on lines
+286
to
+290
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hate this so much, but it makes sense that we have to do this because of how snowflake works. |
||
|
||
dt0 := &arrow.Decimal128Type{ | ||
Precision: int32(20), | ||
Scale: int32(0), | ||
} | ||
result, err := compute.CastArray(ctx, a, compute.SafeCastOptions(dt0)) | ||
if err == nil { | ||
result.Data().Reset(dt, result.Data().Len(), result.Data().Buffers(), result.Data().Children(), result.Data().NullN(), result.Data().Offset()) | ||
} | ||
return result, err | ||
CurtHagenlocher marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
func rowTypesToArrowSchema(ctx context.Context, ld gosnowflake.ArrowStreamLoader, useHighPrecision bool) (*arrow.Schema, error) { | ||
var loc *time.Location | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is great behavior for the driver, but it is the current behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment here as to why the resulting value is equal to the low bits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind filing an issue to update this? It sounds like we must error here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #1277