Skip to content

Commit

Permalink
Merge #47483
Browse files Browse the repository at this point in the history
47483: sql: fix casting of negative datums to decimals r=rytaft a=rytaft

Prior to this commit, when negative intervals, timestamps, and timestamptzs
were cast to decimals, the result was incorrect. The problem was due to the
fact that for these negative values, `Decimal.Coeff.neg` was being set to true,
while `Decimal.Negative` was false. As explained in the comment in `decimal.go`,
"Coeff must be positive. If it is negative results may be incorrect and apd
may panic."

This commit fixes the problem by setting `Decimal.Negative` to true and
`Decimal.Coeff.neg` to false when casting negative datums to decimals.

Fixes #47327

Release note (bug fix): Fixed incorrect results that could occur when
casting negative intervals or timestamps to type decimal.

Co-authored-by: Rebecca Taft <[email protected]>
  • Loading branch information
craig[bot] and rytaft committed Apr 14, 2020
2 parents 18b0247 + 633302d commit 761708f
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/cast
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,20 @@ CREATE TABLE t2 AS SELECT 18446744073709551616::FLOAT AS f

statement error pgcode 22003 integer out of range
SELECT f::int FROM t2

# Regression test for #47327. Test that negative intervals are correctly
# cast to a decimal.
statement ok
CREATE TABLE t0(c0 DECIMAL UNIQUE); INSERT INTO t0(c0) VALUES(0);

statement ok
CREATE TABLE t1(c0 DECIMAL); INSERT INTO t1(c0) VALUES(0);

# Both of these queries should return no rows.
query T
SELECT t0.c0 FROM t0 WHERE t0.c0 BETWEEN t0.c0 AND INTERVAL '-1'::DECIMAL
----

query T
SELECT t1.c0 FROM t1 WHERE t1.c0 BETWEEN t1.c0 AND INTERVAL '-1'::DECIMAL
----
14 changes: 14 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/scalar
Original file line number Diff line number Diff line change
Expand Up @@ -751,3 +751,17 @@ root · · ("array
└── scan · · (a, b) ·
· table t@primary · ·
· spans FULL SCAN · ·

# Regression test for #47327. The span should have an end value of -1.
statement ok
CREATE TABLE t0(c0 DECIMAL UNIQUE); INSERT INTO t0(c0) VALUES(0);

query TTTTT
EXPLAIN (VERBOSE) SELECT t0.c0 FROM t0 WHERE t0.c0 BETWEEN t0.c0 AND INTERVAL '-1'::DECIMAL
----
· distributed false · ·
· vectorized true · ·
scan · · (c0) ·
· table t0@t0_c0_key · ·
· spans /!NULL-/-1/PrefixEnd · ·
· filter c0 >= c0 · ·
11 changes: 11 additions & 0 deletions pkg/sql/sem/tree/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2983,6 +2983,11 @@ func TimestampToDecimal(ts hlc.Timestamp) *DDecimal {
val.Mul(val, big10E10)
val.Add(val, big.NewInt(int64(ts.Logical)))

// val must be positive. If it was set to a negative value above,
// transfer the sign to res.Negative.
res.Negative = val.Sign() < 0
val.Abs(val)

// Shift 10 decimals to the right, so that the logical
// field appears as fractional part.
res.Decimal.Exponent = -10
Expand Down Expand Up @@ -3494,6 +3499,12 @@ func PerformCast(ctx *EvalContext, d Datum, t *types.T) (Datum, error) {
return nil, err
}
if !unset {
// dd.Coeff must be positive. If it was set to a negative value
// above, transfer the sign to dd.Negative.
if dd.Coeff.Sign() < 0 {
dd.Negative = true
dd.Coeff.Abs(&dd.Coeff)
}
err = LimitDecimalWidth(&dd.Decimal, int(t.Precision()), int(t.Scale()))
return &dd, err
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/sql/sem/tree/testdata/eval/cast
Original file line number Diff line number Diff line change
Expand Up @@ -1054,3 +1054,19 @@ eval
'0101000000000000000000F03F000000000000F03F'::geometry::geography
----
'0101000020E6100000000000000000F03F000000000000F03F'

# Test that decimals are correctly cast when the original value is negative.
eval
'-2020-10-10'::timestamp::decimal
----
-125887824000.000000

eval
'-2020-10-10-2020 10:10:00.11111111111111111'::timestamptz::decimal
----
-125887714199.888889

eval
'-10'::interval::decimal
----
-10.000000000

0 comments on commit 761708f

Please sign in to comment.