IMPALA-4813: Round on divide and multiply Address rounding on divide and multiply when results are truncated.
Testing: Manually ran some divides that should overflow, then added the results to the test. Made the decimal-test use rounding behavior by default, and now the error margin of the test has decreased. Initial perf results: Multiply is totall uninteresting so far, all implementations return the same values in the same time: +-------------------------+-----------------------------------+ | sum(l_quantity * l_tax) | sum(l_extendedprice * l_discount) | +-------------------------+-----------------------------------+ | 61202493.3700 | 114698450836.4234 | +-------------------------+-----------------------------------+ Fetched 1 row(s) in 1.13s Divide shows no regression from prior with DECIMAL_V2 off: +-----------------------------+-----------------------------------+ | sum(l_quantity / l_tax) | sum(l_extendedprice / l_discount) | +-----------------------------+-----------------------------------+ | 46178777464.523809516381723 | 61076151920731.010714279183910 | +-----------------------------+-----------------------------------+ before: Fetched 1 row(s) in 13.08s after: Fetched 1 row(s) in 13.06s And with DECIMAL_V2 on: +-----------------------------+-----------------------------------+ | sum(l_quantity / l_tax) | sum(l_extendedprice / l_discount) | +-----------------------------+-----------------------------------+ | 46178777464.523809523847285 | 61076151920731.010714285714202 | +-----------------------------+-----------------------------------+ Fetched 1 row(s) in 16.06s So the performance regression is not as bad as expected. Still, divide performance could use some work. Change-Id: Ie6bfcbe37555b74598d409c6f84f06b0ae5c4312 Reviewed-on: http://gerrit.cloudera.org:8080/6132 Reviewed-by: Dan Hecht <[email protected]> Tested-by: Impala Public Jenkins Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/c87ab35a Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/c87ab35a Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/c87ab35a Branch: refs/heads/master Commit: c87ab35af18d93b5f5e31b6adc0b20bc1ecf165a Parents: c463796 Author: Zach Amsden <[email protected]> Authored: Fri Feb 24 00:55:38 2017 +0000 Committer: Impala Public Jenkins <[email protected]> Committed: Thu Mar 2 20:12:05 2017 +0000 ---------------------------------------------------------------------- be/src/exprs/aggregate-functions-ir.cc | 3 +- be/src/exprs/decimal-operators-ir.cc | 18 +- be/src/exprs/expr-test.cc | 377 +++++++++++- be/src/runtime/decimal-test.cc | 613 ++++++++++--------- be/src/runtime/decimal-value.h | 81 +-- be/src/runtime/decimal-value.inline.h | 107 +++- be/src/runtime/types.cc | 7 + be/src/runtime/types.h | 12 + be/src/util/bit-util-test.cc | 28 + be/src/util/bit-util.h | 25 +- be/src/util/string-parser.h | 6 - .../queries/QueryTest/decimal-exprs.test | 16 +- 12 files changed, 864 insertions(+), 429 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/c87ab35a/be/src/exprs/aggregate-functions-ir.cc ---------------------------------------------------------------------- diff --git a/be/src/exprs/aggregate-functions-ir.cc b/be/src/exprs/aggregate-functions-ir.cc index 6c8c781..10a775d 100644 --- a/be/src/exprs/aggregate-functions-ir.cc +++ b/be/src/exprs/aggregate-functions-ir.cc @@ -447,8 +447,9 @@ DecimalVal AggregateFunctions::DecimalAvgGetValue(FunctionContext* ctx, int sum_scale = ctx->impl()->GetConstFnAttr(FunctionContextImpl::ARG_TYPE_SCALE, 0); bool is_nan = false; bool overflow = false; + bool round = ctx->impl()->GetConstFnAttr(FunctionContextImpl::DECIMAL_V2); Decimal16Value result = sum.Divide<int128_t>(sum_scale, count, 0 /* count's scale */, - output_precision, output_scale, &is_nan, &overflow); + output_precision, output_scale, round, &is_nan, &overflow); if (UNLIKELY(is_nan)) return DecimalVal::null(); if (UNLIKELY(overflow)) { ctx->AddWarning("Avg computation overflowed, returning NULL"); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/c87ab35a/be/src/exprs/decimal-operators-ir.cc ---------------------------------------------------------------------- diff --git a/be/src/exprs/decimal-operators-ir.cc b/be/src/exprs/decimal-operators-ir.cc index 6ea48f7..e502dda 100644 --- a/be/src/exprs/decimal-operators-ir.cc +++ b/be/src/exprs/decimal-operators-ir.cc @@ -679,20 +679,22 @@ BooleanVal DecimalOperators::CastToBooleanVal( ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \ int return_scale = \ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \ + bool round = \ + ctx->impl()->GetConstFnAttr(FunctionContextImpl::DECIMAL_V2); \ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE)) { \ case 4: { \ Decimal4Value x_val = GetDecimal4Value(x, x_size, &overflow); \ Decimal4Value y_val = GetDecimal4Value(y, y_size, &overflow); \ Decimal4Value result = x_val.OP_FN<int32_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &overflow); \ - DCHECK(!overflow) << "Cannot overflow except with Decimal17Value"; \ + return_precision, return_scale, round, &overflow); \ + DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \ return DecimalVal(result.value()); \ } \ case 8: { \ Decimal8Value x_val = GetDecimal8Value(x, x_size, &overflow); \ Decimal8Value y_val = GetDecimal8Value(y, y_size, &overflow); \ Decimal8Value result = x_val.OP_FN<int64_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &overflow); \ + return_precision, return_scale, round, &overflow); \ DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \ return DecimalVal(result.value()); \ } \ @@ -700,7 +702,7 @@ BooleanVal DecimalOperators::CastToBooleanVal( Decimal16Value x_val = GetDecimal16Value(x, x_size, &overflow); \ Decimal16Value y_val = GetDecimal16Value(y, y_size, &overflow); \ Decimal16Value result = x_val.OP_FN<int128_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &overflow); \ + return_precision, return_scale, round, &overflow); \ RETURN_IF_OVERFLOW(ctx, overflow, DecimalVal); \ return DecimalVal(result.value()); \ } \ @@ -724,12 +726,14 @@ BooleanVal DecimalOperators::CastToBooleanVal( ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_PRECISION); \ int return_scale = \ ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SCALE); \ + bool round = \ + ctx->impl()->GetConstFnAttr(FunctionContextImpl::DECIMAL_V2); \ switch (ctx->impl()->GetConstFnAttr(FunctionContextImpl::RETURN_TYPE_SIZE)) { \ case 4: { \ Decimal4Value x_val = GetDecimal4Value(x, x_size, &overflow); \ Decimal4Value y_val = GetDecimal4Value(y, y_size, &overflow); \ Decimal4Value result = x_val.OP_FN<int32_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &is_nan, &overflow); \ + return_precision, return_scale, round, &is_nan, &overflow); \ DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \ if (is_nan) return DecimalVal::null(); \ return DecimalVal(result.value()); \ @@ -738,7 +742,7 @@ BooleanVal DecimalOperators::CastToBooleanVal( Decimal8Value x_val = GetDecimal8Value(x, x_size, &overflow); \ Decimal8Value y_val = GetDecimal8Value(y, y_size, &overflow); \ Decimal8Value result = x_val.OP_FN<int64_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &is_nan, &overflow); \ + return_precision, return_scale, round, &is_nan, &overflow); \ DCHECK(!overflow) << "Cannot overflow except with Decimal16Value"; \ if (is_nan) return DecimalVal::null(); \ return DecimalVal(result.value()); \ @@ -747,7 +751,7 @@ BooleanVal DecimalOperators::CastToBooleanVal( Decimal16Value x_val = GetDecimal16Value(x, x_size, &overflow); \ Decimal16Value y_val = GetDecimal16Value(y, y_size, &overflow); \ Decimal16Value result = x_val.OP_FN<int128_t>(x_scale, y_val, y_scale, \ - return_precision, return_scale, &is_nan, &overflow); \ + return_precision, return_scale, round, &is_nan, &overflow); \ RETURN_IF_OVERFLOW(ctx, overflow, DecimalVal); \ if (is_nan) return DecimalVal::null(); \ return DecimalVal(result.value()); \ http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/c87ab35a/be/src/exprs/expr-test.cc ---------------------------------------------------------------------- diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc index e9dbd76..604644e 100644 --- a/be/src/exprs/expr-test.cc +++ b/be/src/exprs/expr-test.cc @@ -1387,23 +1387,380 @@ DecimalTestCase decimal_cases[] = { 10000000000ll * 10000000000ll * 10000000000ll, 38, 6 }}}, { "cast(98765432109876543210 as decimal(20,0)) / " "cast(98765432109876543211 as decimal(20,0))", - {{ false, 0, 38, 0 }, - { false, 999999999999999999, 38, 18 }}}, + {{ false, 0, 38, 0 }, + { false, 1000000000000000000, 38, 18 }}}, { "cast(111111.1111 as decimal(20, 10)) / cast(.7777 as decimal(38, 38))", {{ true, 0, 38, 38 }, - { false, 142871429985, 38, 6 }}}, + { false, 142871429986, 38, 6 }}}, { "2.0 / 3.0", {{ false, 6666, 6, 4}, - { false, 666666, 8, 6}}}, + { false, 666667, 8, 6}}}, { "-2.0 / 3.0", {{ false, -6666, 6, 4}, - { false, -666666, 8, 6}}}, + { false, -666667, 8, 6}}}, { "2.0 / -3.0", {{ false, -6666, 6, 4}, - { false, -666666, 8, 6}}}, + { false, -666667, 8, 6}}}, { "-2.0 / -3.0", {{ false, 6666, 6, 4}, - { false, 666666, 8, 6}}}, + { false, 666667, 8, 6}}}, + // Test divide rounding + { "10.10 / 3.0", + {{ false, 336666, 8, 5 }, + { false, 3366667, 9, 6 }}}, + { "cast(-10.10 as decimal(4,2)) / 3.0", // XXX JIRA: IMPALA-4877 + {{ false, -336666, 8, 5 }, + { false, -3366667, 9, 6 }}}, + { "10.10 / 20.3", + {{ false, 497536, 9, 6 }, + { false, 497537, 9, 6 }}}, + { "10.10 / -20.3", + {{ false, -497536, 9, 6 }, + { false, -497537, 9, 6 }}}, + // N.B. - Google and python both insist that 999999.998 / 999 is 1001.000999 + // However, multiplying the result back, 999 * 1001.000998999 gives the + // original value exactly, while their answer does not, 999 * 10001.000999 = + // 999999.998001. The same issue comes up many times during the following + // computations. Division is hard, let's go shopping. + { "cast(999999.998 as decimal(9,3)) / 999", + {{ false, 1001000998998, 15, 9 }, + { false, 1001000998999, 15, 9 }}}, + { "cast(999.999998 as decimal(9,3)) / 999", + {{ false, 1001000000, 15, 9 }, + { false, 1001001001, 15, 9 }}}, + { "cast(999.999998 as decimal(9,6)) / 999", + {{ false, 1001000998998, 15, 12 }, + { false, 1001000998999, 15, 12 }}}, + { "cast(0.999999998 as decimal(9,6)) / 999", + {{ false, 1001000000, 15, 12 }, + { false, 1001001001, 15, 12 }}}, + { "cast(0.999999998 as decimal(9,9)) / 999", + {{ false, 1001000998998, 15, 15 }, + { false, 1001000998999, 15, 15 }}}, + { "cast(-999999.998 as decimal(9,3)) / 999", + {{ false, -1001000998998, 15, 9 }, + { false, -1001000998999, 15, 9 }}}, + { "cast(-999.999998 as decimal(9,3)) / 999", + {{ false, -1001000000, 15, 9 }, + { false, -1001001001, 15, 9 }}}, + { "cast(-999.999998 as decimal(9,6)) / 999", + {{ false, -1001000998998, 15, 12 }, + { false, -1001000998999, 15, 12 }}}, + { "cast(-0.999999998 as decimal(9,6)) / 999", + {{ false, -1001000000, 15, 12 }, + { false, -1001001001, 15, 12 }}}, + { "cast(-0.999999998 as decimal(9,9)) / 999", + {{ false, -1001000998998, 15, 15 }, + { false, -1001000998999, 15, 15 }}}, + { "cast(-999999.998 as decimal(9,3)) / -999", + {{ false, 1001000998998, 15, 9 }, + { false, 1001000998999, 15, 9 }}}, + { "cast(-999.999998 as decimal(9,3)) / -999", + {{ false, 1001000000, 15, 9 }, + { false, 1001001001, 15, 9 }}}, + { "cast(-999.999998 as decimal(9,6)) / -999", + {{ false, 1001000998998, 15, 12 }, + { false, 1001000998999, 15, 12 }}}, + { "cast(-0.999999998 as decimal(9,6)) / -999", + {{ false, 1001000000, 15, 12 }, + { false, 1001001001, 15, 12 }}}, + { "cast(-0.999999998 as decimal(9,9)) / -999", + {{ false, 1001000998998, 15, 15 }, + { false, 1001000998999, 15, 15 }}}, + { "cast(999999.998 as decimal(9,3)) / -999", + {{ false, -1001000998998, 15, 9 }, + { false, -1001000998999, 15, 9 }}}, + { "cast(999.999998 as decimal(9,3)) / -999", + {{ false, -1001000000, 15, 9 }, + { false, -1001001001, 15, 9 }}}, + { "cast(999.999998 as decimal(9,6)) / -999", + {{ false, -1001000998998, 15, 12 }, + { false, -1001000998999, 15, 12 }}}, + { "cast(0.999999998 as decimal(9,6)) / -999", + {{ false, -1001000000, 15, 12 }, + { false, -1001001001, 15, 12 }}}, + { "cast(0.999999998 as decimal(9,9)) / -999", + {{ false, -1001000998998, 15, 15 }, + { false, -1001000998999, 15, 15 }}}, + { "cast(999.999998 as decimal(9,3)) / 999999999", + {{ false, 99999900, 20, 14 }, + { false, 100000000, 20, 14 }}}, + { "cast(999.999998 as decimal(9,6)) / 999999999", + {{ false, 99999999899, 20, 17 }, + { false, 99999999900, 20, 17 }}}, + { "cast(0.999999998 as decimal(9,6)) / 999999999", + {{ false, 99999900, 20, 17 }, + { false, 100000000, 20, 17 }}}, + { "cast(0.999999998 as decimal(9,9)) / 999999999", + {{ false, 99999999899, 20, 20 }, + { false, 99999999900, 20, 20 }}}, + { "cast(-999999.998 as decimal(9,3)) / 999999999", + {{ false, -99999999899, 20, 14 }, + { false, -99999999900, 20, 14 }}}, + { "cast(-999.999998 as decimal(9,3)) / 999999999", + {{ false, -99999900, 20, 14 }, + { false, -100000000, 20, 14 }}}, + { "cast(-999.999998 as decimal(9,6)) / 999999999", + {{ false, -99999999899, 20, 17 }, + { false, -99999999900, 20, 17 }}}, + { "cast(-0.999999998 as decimal(9,6)) / 999999999", + {{ false, -99999900, 20, 17 }, + { false, -100000000, 20, 17 }}}, + { "cast(-0.999999998 as decimal(9,9)) / 999999999", + {{ false, -99999999899, 20, 20 }, + { false, -99999999900, 20, 20 }}}, + { "cast(-999999.998 as decimal(9,3)) / 999999999", + {{ false, -99999999899, 20, 14 }, + { false, -99999999900, 20, 14 }}}, + { "cast(-999.999998 as decimal(9,3)) / 999999999", + {{ false, -99999900, 20, 14 }, + { false, -100000000, 20, 14 }}}, + { "cast(-999.999998 as decimal(9,6)) / 999999999", + {{ false, -99999999899, 20, 17 }, + { false, -99999999900, 20, 17 }}}, + { "cast(-0.999999998 as decimal(9,6)) / 999999999", + {{ false, -99999900, 20, 17 }, + { false, -100000000, 20, 17 }}}, + { "cast(-0.999999998 as decimal(9,9)) / 999999999", + {{ false, -99999999899, 20, 20 }, + { false, -99999999900, 20, 20 }}}, + { "cast(999999.998 as decimal(9,3)) / -999999999", + {{ false, -99999999899, 20, 14 }, + { false, -99999999900, 20, 14 }}}, + { "cast(999.999998 as decimal(9,3)) / -999999999", + {{ false, -99999900, 20, 14 }, + { false, -100000000, 20, 14 }}}, + { "cast(999.999998 as decimal(9,6)) / -999999999", + {{ false, -99999999899, 20, 17 }, + { false, -99999999900, 20, 17 }}}, + { "cast(0.999999998 as decimal(9,6)) / -999999999", + {{ false, -99999900, 20, 17 }, + { false, -100000000, 20, 17 }}}, + { "cast(0.999999998 as decimal(9,9)) / -999999999", + {{ false, -99999999899, 20, 20 }, + { false, -99999999900, 20, 20 }}}, + { "17014118346046923173168730371588.410/17014118346046923173168730371588.410", + {{ false, 1000, 38, 3 }, + { false, 1000000, 38, 6 }}}, + { "17014118346046923173168730371588.410/17014118346046923173168730371588.409", + {{ false, 1000, 38, 3 }, + { false, 1000000, 38, 6 }}}, + { "17014118346046923173168730371588.410/34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 1, 38, 6 }}}, + { "17014118346046923173168730371588.410/34028236692093846346337460743176820001", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "17014118346046923173168730371588.410/51042355038140769519506191114765230000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "17014118346046923173168730371588.410/10208471007628153903901238222953046343", + {{ false, 0, 38, 3 }, + { false, 2, 38, 6 }}}, + { "170141183460469231731687303715884.10/34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, 5, 38, 6 }}}, + { "170141183460469231731687303715884.10/34028236692093846346337460743176820001", + {{ false, 0, 38, 2 }, + { false, 5, 38, 6 }}}, + { "170141183460469231731687303715884.10/51042355038140769519506191114765230000", + {{ false, 0, 38, 2 }, + { false, 3, 38, 6 }}}, + { "170141183460469231731687303715884.10/10208471007628153903901238222953046343", + {{ false, 0, 38, 2 }, + { false, 17, 38, 6 }}}, + { "1701411834604692317316873037158841.0/34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, 50, 38, 6 }}}, + { "1701411834604692317316873037158841.0/34028236692093846346337460743176820001", + {{ false, 0, 38, 1 }, + { false, 50, 38, 6 }}}, + { "1701411834604692317316873037158841.0/51042355038140769519506191114765229999", + {{ false, 0, 38, 1 }, + { false, 33, 38, 6 }}}, + { "1701411834604692317316873037158841.0/10208471007628153903901238222953046343", + {{ false, 0, 38, 1 }, + { false, 167, 38, 6 }}}, + { "17014118346046923173168730371588410/34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, 500, 38, 6 }}}, + { "17014118346046923173168730371588410/34028236692093846346337460743176820001", + {{ false, 0, 38, 0 }, + { false, 500, 38, 6 }}}, + { "17014118346046923173168730371588410/51042355038140769519506191114765229999", + {{ false, 0, 38, 0 }, + { false, 333, 38, 6 }}}, + { "17014118346046923173168730371588410/10208471007628153903901238222953046343", + {{ false, 0, 38, 0 }, + { false, 1667, 38, 6 }}}, + { "17014118346046923173168730371588410/3402823669209384634633746074317682000.0", + {{ false, 0, 38, 1 }, + { false, 5000, 38, 6 }}}, + { "17014118346046923173168730371588410/3402823669209384634633746074317682000.1", + {{ false, 0, 38, 1 }, + { false, 5000, 38, 6 }}}, + { "17014118346046923173168730371588410/5104235503814076951950619111476522999.9", + {{ false, 0, 38, 1 }, + { false, 3333, 38, 6 }}}, + { "17014118346046923173168730371588410/1020847100762815390390123822295304634.3", + {{ false, 0, 38, 1 }, + { false, 16667, 38, 6 }}}, + { "15014118346046923173168730371588.410/34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "150141183460469231731687303715884.10/34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, 4, 38, 6 }}}, + { "1501411834604692317316873037158841.0/34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, 44, 38, 6 }}}, + { "15014118346046923173168730371588410/34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, 441, 38, 6 }}}, + { "16014118346046923173168730371588.410/34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "160141183460469231731687303715884.10/34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, 5, 38, 6 }}}, + { "1601411834604692317316873037158841.0/34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, 47, 38, 6 }}}, + { "16014118346046923173168730371588410/34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, 471, 38, 6 }}}, + { "16014118346046923173168730371588410/3402823669209384634633746074317682000", + {{ false, 0, 38, 0 }, + { false, 4706, 38, 6 }}}, + { "18014118346046923173168730371588.410/34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 1, 38, 6 }}}, + { "180141183460469231731687303715884.10/34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, 5, 38, 6 }}}, + { "1801411834604692317316873037158841.0/34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, 53, 38, 6 }}}, + { "18014118346046923173168730371588410/34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, 529, 38, 6 }}}, + { "18014118346046923173168730371588410/3402823669209384634633746074317682000", + {{ false, 0, 38, 0 }, + { false, 5294, 38, 6 }}}, + { "18014118346046923173168730371588410/340282366920938463463374607431768200", + {{ false, 0, 38, 0 }, + { false, 52939, 38, 6 }}}, + { "17014118346046923173168730371588.410/-17014118346046923173168730371588.410", + {{ false, -1000, 38, 3 }, + { false, -1000000, 38, 6 }}}, + { "17014118346046923173168730371588.410/-17014118346046923173168730371588.409", + {{ false, -1000, 38, 3 }, + { false, -1000000, 38, 6 }}}, + { "17014118346046923173168730371588.410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, -1, 38, 6 }}}, + { "17014118346046923173168730371588.410/-34028236692093846346337460743176820001", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "17014118346046923173168730371588.410/-51042355038140769519506191114765230000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "17014118346046923173168730371588.410/-10208471007628153903901238222953046343", + {{ false, 0, 38, 3 }, + { false, -2, 38, 6 }}}, + { "170141183460469231731687303715884.10/-34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, -5, 38, 6 }}}, + { "170141183460469231731687303715884.10/-34028236692093846346337460743176820001", + {{ false, 0, 38, 2 }, + { false, -5, 38, 6 }}}, + { "170141183460469231731687303715884.10/-51042355038140769519506191114765230000", + {{ false, 0, 38, 2 }, + { false, -3, 38, 6 }}}, + { "170141183460469231731687303715884.10/-10208471007628153903901238222953046343", + {{ false, 0, 38, 2 }, + { false, -17, 38, 6 }}}, + { "1701411834604692317316873037158841.0/-34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, -50, 38, 6 }}}, + { "1701411834604692317316873037158841.0/-34028236692093846346337460743176820001", + {{ false, 0, 38, 1 }, + { false, -50, 38, 6 }}}, + { "1701411834604692317316873037158841.0/-51042355038140769519506191114765229999", + {{ false, 0, 38, 1 }, + { false, -33, 38, 6 }}}, + { "1701411834604692317316873037158841.0/-10208471007628153903901238222953046343", + {{ false, 0, 38, 1 }, + { false, -167, 38, 6 }}}, + { "17014118346046923173168730371588410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, -500, 38, 6 }}}, + { "17014118346046923173168730371588410/-34028236692093846346337460743176820001", + {{ false, 0, 38, 0 }, + { false, -500, 38, 6 }}}, + { "17014118346046923173168730371588410/-51042355038140769519506191114765229999", + {{ false, 0, 38, 0 }, + { false, -333, 38, 6 }}}, + { "17014118346046923173168730371588410/-10208471007628153903901238222953046343", + {{ false, 0, 38, 0 }, + { false, -1667, 38, 6 }}}, + { "17014118346046923173168730371588410/-3402823669209384634633746074317682000.0", + {{ false, 0, 38, 1 }, + { false, -5000, 38, 6 }}}, + { "17014118346046923173168730371588410/-3402823669209384634633746074317682000.1", + {{ false, 0, 38, 1 }, + { false, -5000, 38, 6 }}}, + { "17014118346046923173168730371588410/-5104235503814076951950619111476522999.9", + {{ false, 0, 38, 1 }, + { false, -3333, 38, 6 }}}, + { "17014118346046923173168730371588410/-1020847100762815390390123822295304634.3", + {{ false, 0, 38, 1 }, + { false, -16667, 38, 6 }}}, + { "15014118346046923173168730371588.410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "150141183460469231731687303715884.10/-34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, -4, 38, 6 }}}, + { "1501411834604692317316873037158841.0/-34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, -44, 38, 6 }}}, + { "15014118346046923173168730371588410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, -441, 38, 6 }}}, + { "16014118346046923173168730371588.410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, 0, 38, 6 }}}, + { "160141183460469231731687303715884.10/-34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, -5, 38, 6 }}}, + { "1601411834604692317316873037158841.0/-34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, -47, 38, 6 }}}, + { "16014118346046923173168730371588410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, -471, 38, 6 }}}, + { "16014118346046923173168730371588410/-3402823669209384634633746074317682000", + {{ false, 0, 38, 0 }, + { false, -4706, 38, 6 }}}, + { "18014118346046923173168730371588.410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 3 }, + { false, -1, 38, 6 }}}, + { "180141183460469231731687303715884.10/-34028236692093846346337460743176820000", + {{ false, 0, 38, 2 }, + { false, -5, 38, 6 }}}, + { "1801411834604692317316873037158841.0/-34028236692093846346337460743176820000", + {{ false, 0, 38, 1 }, + { false, -53, 38, 6 }}}, + { "18014118346046923173168730371588410/-34028236692093846346337460743176820000", + {{ false, 0, 38, 0 }, + { false, -529, 38, 6 }}}, + { "18014118346046923173168730371588410/-3402823669209384634633746074317682000", + {{ false, 0, 38, 0 }, + { false, -5294, 38, 6 }}}, + { "18014118346046923173168730371588410/-340282366920938463463374607431768200", + {{ false, 0, 38, 0 }, + { false, -52939, 38, 6 }}}, // Test modulo operator { "cast(1.23 as decimal(8,2)) % cast(1 as decimal(10,3))", {{ false, 230, 9, 3 }}}, { "cast(1 as decimal(38,0)) % cast(.2 as decimal(38,1))", {{ false, 0, 38, 1 }}}, @@ -1595,6 +1952,12 @@ DecimalTestCase decimal_cases[] = { { "cast(cast(-9223372036854775809.0 AS bigint) AS decimal(30,0))", {{ false, 9223372036854775807, 30, 0 }, // BUG: JIRA: IMPALA-865 { true, 0, 30, 0 }}}, + { "cast(cast(cast(pow(1, -38) as decimal(38,38)) as bigint) as decimal(18,10))", + {{ false, 0, 18, 10 }, + { false, 10000000000, 18, 10 }}}, + { "cast(cast(cast(-pow(1, -38) as decimal(38,38)) as bigint) as decimal(18,10))", + {{ false, 0, 18, 10 }, + { false, -10000000000, 18, 10 }}}, // Test CAST FLOAT -> DECIMAL { "cast(cast(power(10, 3) - power(10, -1) as float) as decimal(4,1))", {{ false, 9999, 4, 1 }}}, http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/c87ab35a/be/src/runtime/decimal-test.cc ---------------------------------------------------------------------- diff --git a/be/src/runtime/decimal-test.cc b/be/src/runtime/decimal-test.cc index 6bcd34d..190ee39 100644 --- a/be/src/runtime/decimal-test.cc +++ b/be/src/runtime/decimal-test.cc @@ -34,7 +34,7 @@ using std::min; namespace impala { // Compare decimal result against double. -static const double MAX_ERROR = 0.0001; +static const double MAX_ERROR = 0.00005; template <typename T> void VerifyEquals(const DecimalValue<T>& t1, const DecimalValue<T>& t2) { @@ -45,11 +45,11 @@ void VerifyEquals(const DecimalValue<T>& t1, const DecimalValue<T>& t2) { } template <typename T> -void VerifyParse(const string& s, const ColumnType& t, +void VerifyParse(const string& s, int precision, int scale, const DecimalValue<T>& expected_val, StringParser::ParseResult expected_result) { StringParser::ParseResult parse_result; DecimalValue<T> val = StringParser::StringToDecimal<T>( - s.c_str(), s.size(), t, &parse_result); + s.c_str(), s.size(), precision, scale, &parse_result); EXPECT_EQ(expected_result, parse_result) << "Failed test string: " << s; if (expected_result == StringParser::PARSE_SUCCESS || expected_result == StringParser::PARSE_UNDERFLOW) { @@ -58,31 +58,30 @@ void VerifyParse(const string& s, const ColumnType& t, } template<typename T> -void VerifyToString(const T& decimal, const ColumnType& t, const string& expected) { - EXPECT_EQ(decimal.ToString(t), expected); +void VerifyToString(const T& decimal, int precision, int scale, const string& expected) { + EXPECT_EQ(decimal.ToString(precision, scale), expected); } -void StringToAllDecimals(const string& s, const ColumnType& t, int32_t val, +void StringToAllDecimals(const string& s, int precision, int scale, int32_t val, StringParser::ParseResult result) { - VerifyParse(s, t, Decimal4Value(val), result); - VerifyParse(s, t, Decimal8Value(val), result); - VerifyParse(s, t, Decimal16Value(val), result); + VerifyParse(s, precision, scale, Decimal4Value(val), result); + VerifyParse(s, precision, scale, Decimal8Value(val), result); + VerifyParse(s, precision, scale, Decimal16Value(val), result); } TEST(IntToDecimal, Basic) { Decimal16Value d16; bool overflow = false; - d16 = Decimal16Value::FromInt(ColumnType::CreateDecimalType(27, 18), -25559, &overflow); + d16 = Decimal16Value::FromInt(27, 18, -25559, &overflow); EXPECT_FALSE(overflow); - VerifyToString(d16, ColumnType::CreateDecimalType(27, 18), "-25559.000000000000000000"); + VerifyToString(d16, 27, 18, "-25559.000000000000000000"); - d16 = Decimal16Value::FromInt(ColumnType::CreateDecimalType(36, 29), 32130, &overflow); + d16 = Decimal16Value::FromInt(36, 29, 32130, &overflow); EXPECT_FALSE(overflow); - VerifyToString(d16, ColumnType::CreateDecimalType(36, 29), - "32130.00000000000000000000000000000"); + VerifyToString(d16, 36, 29, "32130.00000000000000000000000000000"); - d16 = Decimal16Value::FromInt(ColumnType::CreateDecimalType(38, 38), 1, &overflow); + d16 = Decimal16Value::FromInt(38, 38, 1, &overflow); EXPECT_TRUE(overflow); // Smaller decimal types can't overflow here since the FE should never generate @@ -90,363 +89,335 @@ TEST(IntToDecimal, Basic) { } TEST(DoubleToDecimal, Basic) { - ColumnType t1 = ColumnType::CreateDecimalType(9, 0); - ColumnType t2 = ColumnType::CreateDecimalType(10, 5); - ColumnType t3 = ColumnType::CreateDecimalType(10, 10); - ColumnType t4 = ColumnType::CreateDecimalType(1, 0); - ColumnType t5 = ColumnType::CreateDecimalType(1, 1); - Decimal4Value d4; Decimal8Value d8; Decimal16Value d16; bool overflow = false; - d4 = Decimal4Value::FromDouble(t1, 1.9, true, &overflow); + d4 = Decimal4Value::FromDouble(9, 0, 1.9, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 2); - VerifyToString(d4, t1, "2"); + VerifyToString(d4, 9, 0, "2"); - d4 = Decimal4Value::FromDouble(t1, 1.9, false, &overflow); + d4 = Decimal4Value::FromDouble(9, 0, 1.9, false, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 1); - VerifyToString(d4, t1, "1"); + VerifyToString(d4, 9, 0, "1"); - d4 = Decimal4Value::FromDouble(t4, 1, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 1); - VerifyToString(d4, t4, "1"); + VerifyToString(d4, 1, 0, "1"); - d4 = Decimal4Value::FromDouble(t4, 0, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 0, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 0); - VerifyToString(d4, t4, "0"); + VerifyToString(d4, 1, 0, "0"); - d4 = Decimal4Value::FromDouble(t4, 9.9, false, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 9.9, false, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 9); - VerifyToString(d4, t4, "9"); + VerifyToString(d4, 1, 0, "9"); - d4 = Decimal4Value::FromDouble(t4, 9.9, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 9.9, true, &overflow); EXPECT_TRUE(overflow); overflow = false; - d4 = Decimal4Value::FromDouble(t4, -1, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, -1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), -1); - VerifyToString(d4, t4, "-1"); + VerifyToString(d4, 1, 0, "-1"); - d4 = Decimal4Value::FromDouble(t4, -9.9, false, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, -9.9, false, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), -9); - VerifyToString(d4, t4, "-9"); + VerifyToString(d4, 1, 0, "-9"); - d4 = Decimal4Value::FromDouble(t4, -9.9, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, -9.9, true, &overflow); EXPECT_TRUE(overflow); overflow = false; - d4 = Decimal4Value::FromDouble(t5, 0.1, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 1, 0.1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 1); - VerifyToString(d4, t5, "0.1"); + VerifyToString(d4, 1, 1, "0.1"); - d4 = Decimal4Value::FromDouble(t5, 0.0, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 1, 0.0, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 0); - VerifyToString(d4, t5, "0.0"); + VerifyToString(d4, 1, 1, "0.0"); - d4 = Decimal4Value::FromDouble(t5, -0.1, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 1, -0.1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), -1); - VerifyToString(d4, t5, "-0.1"); + VerifyToString(d4, 1, 1, "-0.1"); overflow = false; - d8 = Decimal8Value::FromDouble(t2, -100.1, true, &overflow); + d8 = Decimal8Value::FromDouble(10, 5, -100.1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d8.value(), -10010000); - VerifyToString(d8, t2, "-100.10000"); + VerifyToString(d8, 10, 5, "-100.10000"); overflow = false; - d16 = Decimal16Value::FromDouble(t3, -0.1, true, &overflow); + d16 = Decimal16Value::FromDouble(10, 10, -0.1, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d16.value(), -1000000000); - VerifyToString(d16, t3, "-0.1000000000"); + VerifyToString(d16, 10, 10, "-0.1000000000"); // Test overflow overflow = false; - Decimal4Value::FromDouble(t1, 999999999.123, false, &overflow); + Decimal4Value::FromDouble(9, 0, 999999999.123, false, &overflow); EXPECT_FALSE(overflow); overflow = false; - Decimal4Value::FromDouble(t1, 1234567890.1, false, &overflow); + Decimal4Value::FromDouble(9, 0, 1234567890.1, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal8Value::FromDouble(t1, -1234567890.123, false, &overflow); + Decimal8Value::FromDouble(9, 0, -1234567890.123, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal8Value::FromDouble(t2, 99999.1234567, false, &overflow); + Decimal8Value::FromDouble(10, 5, 99999.1234567, false, &overflow); EXPECT_FALSE(overflow); overflow = false; - Decimal8Value::FromDouble(t2, 100000.1, false, &overflow); + Decimal8Value::FromDouble(10, 5, 100000.1, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal8Value::FromDouble(t2, -123456.123, false, &overflow); + Decimal8Value::FromDouble(10, 5, -123456.123, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - d16 = Decimal16Value::FromDouble(t3, 0.1234, true, &overflow); + d16 = Decimal16Value::FromDouble(10, 10, 0.1234, true, &overflow); EXPECT_FALSE(overflow); - VerifyToString(d16, t3, "0.1234000000"); + VerifyToString(d16, 10, 10, "0.1234000000"); overflow = false; - Decimal16Value::FromDouble(t3, 1.1, true, &overflow); + Decimal16Value::FromDouble(10, 10, 1.1, true, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal16Value::FromDouble(t3, -1.1, true, &overflow); + Decimal16Value::FromDouble(10, 10, -1.1, true, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal16Value::FromDouble(t3, 0.99999999999, false, &overflow); + Decimal16Value::FromDouble(10, 10, 0.99999999999, false, &overflow); EXPECT_FALSE(overflow); overflow = false; - Decimal16Value::FromDouble(t3, 0.99999999999, true, &overflow); + Decimal16Value::FromDouble(10, 10, 0.99999999999, true, &overflow); EXPECT_TRUE(overflow); overflow = false; - Decimal16Value::FromDouble(t3, -0.99999999999, false, &overflow); + Decimal16Value::FromDouble(10, 10, -0.99999999999, false, &overflow); EXPECT_FALSE(overflow); overflow = false; - Decimal16Value::FromDouble(t3, -0.99999999999, true, &overflow); + Decimal16Value::FromDouble(10, 10, -0.99999999999, true, &overflow); EXPECT_TRUE(overflow); overflow = false; // Test half rounding behavior - d4 = Decimal4Value::FromDouble(t4, 0.499999999, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 0.499999999, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 0); - VerifyToString(d4, t4, "0"); + VerifyToString(d4, 1, 0, "0"); - d4 = Decimal4Value::FromDouble(t4, 0.5, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, 0.5, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 1); - VerifyToString(d4, t4, "1"); + VerifyToString(d4, 1, 0, "1"); - d4 = Decimal4Value::FromDouble(t4, -0.499999999, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, -0.499999999, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), 0); - VerifyToString(d4, t4, "0"); + VerifyToString(d4, 1, 0, "0"); - d4 = Decimal4Value::FromDouble(t4, -0.5, true, &overflow); + d4 = Decimal4Value::FromDouble(1, 0, -0.5, true, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(d4.value(), -1); - VerifyToString(d4, t4, "-1"); + VerifyToString(d4, 1, 0, "-1"); } TEST(StringToDecimal, Basic) { - ColumnType t1 = ColumnType::CreateDecimalType(10, 0); - ColumnType t2 = ColumnType::CreateDecimalType(10, 2); - ColumnType t3 = ColumnType::CreateDecimalType(2, 0); - ColumnType t4 = ColumnType::CreateDecimalType(10, 5); - - StringToAllDecimals(" 1234", t1, 1234, StringParser::PARSE_SUCCESS); - StringToAllDecimals("", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals(" ", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals(" 0 0 ", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("0 0", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("++0", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("--0", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("..0", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("0..", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals(".0.", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("0.0.", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("0-", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("0+", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("X", t1, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("+", t3, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("-", t3, 0, StringParser::PARSE_FAILURE); - - StringToAllDecimals("1234", t1, 1234, StringParser::PARSE_SUCCESS); - StringToAllDecimals("1234", t2, 123400, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-1234", t2, -123400, StringParser::PARSE_SUCCESS); - StringToAllDecimals("123", t3, 123, StringParser::PARSE_OVERFLOW); - StringToAllDecimals(" 12 ", t3, 12, StringParser::PARSE_SUCCESS); - StringToAllDecimals("000", t3, 0, StringParser::PARSE_SUCCESS); - StringToAllDecimals(" . ", t3, 0, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-.", t3, 0, StringParser::PARSE_SUCCESS); - StringToAllDecimals("1.", t3, 1, StringParser::PARSE_SUCCESS); - StringToAllDecimals(".1", t2, 10, StringParser::PARSE_SUCCESS); - StringToAllDecimals("00012.3", t2, 1230, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-00012.3", t2, -1230, StringParser::PARSE_SUCCESS); - - StringToAllDecimals("123.45", t2, 12345, StringParser::PARSE_SUCCESS); - StringToAllDecimals(".45", t2, 45, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-.45", t2, -45, StringParser::PARSE_SUCCESS); - StringToAllDecimals(" 123.4 ", t4, 12340000, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-123.45", t4, -12345000, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-123.456", t2, -12345, StringParser::PARSE_UNDERFLOW); - - StringToAllDecimals("e", t3, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("E", t3, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals("+E", t3, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals(".E", t3, 0, StringParser::PARSE_FAILURE); - StringToAllDecimals(" 0 e 0 ", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("0e 0", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("0e1.0", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("0e1.", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("0e.1", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("0ee0", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("e1", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("1e", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("1.1.0e0", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("1e1.0", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("1..1e1", t1, 100, StringParser::PARSE_FAILURE); - StringToAllDecimals("1e9999999999999999999", t1, 100, StringParser::PARSE_OVERFLOW); - - StringToAllDecimals(" 1e0 ", t2, 100, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-1e0", t2, -100, StringParser::PARSE_SUCCESS); - StringToAllDecimals("1e-0", t2, 100, StringParser::PARSE_SUCCESS); - StringToAllDecimals(" 1e2 ", t2, 10000, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-1e-2", t2, -1, StringParser::PARSE_SUCCESS); - StringToAllDecimals(".011e3 ", t3, 11, StringParser::PARSE_SUCCESS); - StringToAllDecimals(".00011e5 ", t3, 11, StringParser::PARSE_SUCCESS); - StringToAllDecimals("110e-1 ", t3, 11, StringParser::PARSE_UNDERFLOW); - StringToAllDecimals("1.10e1 ", t3, 11, StringParser::PARSE_UNDERFLOW); - StringToAllDecimals("1.10e3 ", t3, 11, StringParser::PARSE_OVERFLOW); + StringToAllDecimals(" 1234", 10, 0, 1234, StringParser::PARSE_SUCCESS); + StringToAllDecimals("", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals(" ", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals(" 0 0 ", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("0 0", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("++0", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("--0", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("..0", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("0..", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals(".0.", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("0.0.", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("0-", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("0+", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("X", 10, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("+", 2, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("-", 2, 0, 0, StringParser::PARSE_FAILURE); + + StringToAllDecimals("1234", 10, 0, 1234, StringParser::PARSE_SUCCESS); + StringToAllDecimals("1234", 10, 2, 123400, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-1234", 10, 2, -123400, StringParser::PARSE_SUCCESS); + StringToAllDecimals("123", 2, 0, 123, StringParser::PARSE_OVERFLOW); + StringToAllDecimals(" 12 ", 2, 0, 12, StringParser::PARSE_SUCCESS); + StringToAllDecimals("000", 2, 0, 0, StringParser::PARSE_SUCCESS); + StringToAllDecimals(" . ", 2, 0, 0, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-.", 2, 0, 0, StringParser::PARSE_SUCCESS); + StringToAllDecimals("1.", 2, 0, 1, StringParser::PARSE_SUCCESS); + StringToAllDecimals(".1", 10, 2, 10, StringParser::PARSE_SUCCESS); + StringToAllDecimals("00012.3", 10, 2, 1230, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-00012.3", 10, 2, -1230, StringParser::PARSE_SUCCESS); + + StringToAllDecimals("123.45", 10, 2, 12345, StringParser::PARSE_SUCCESS); + StringToAllDecimals(".45", 10, 2, 45, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-.45", 10, 2, -45, StringParser::PARSE_SUCCESS); + StringToAllDecimals(" 123.4 ", 10, 5, 12340000, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-123.45", 10, 5, -12345000, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-123.456", 10, 2, -12345, StringParser::PARSE_UNDERFLOW); + + StringToAllDecimals("e", 2, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("E", 2, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals("+E", 2, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals(".E", 2, 0, 0, StringParser::PARSE_FAILURE); + StringToAllDecimals(" 0 e 0 ", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("0e 0", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("0e1.0", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("0e1.", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("0e.1", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("0ee0", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("e1", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("1e", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("1.1.0e0", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("1e1.0", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("1..1e1", 10, 0, 100, StringParser::PARSE_FAILURE); + StringToAllDecimals("1e9999999999999999999", 10, 0, 100, StringParser::PARSE_OVERFLOW); + + StringToAllDecimals(" 1e0 ", 10, 2, 100, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-1e0", 10, 2, -100, StringParser::PARSE_SUCCESS); + StringToAllDecimals("1e-0", 10, 2, 100, StringParser::PARSE_SUCCESS); + StringToAllDecimals(" 1e2 ", 10, 2, 10000, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-1e-2", 10, 2, -1, StringParser::PARSE_SUCCESS); + StringToAllDecimals(".011e3 ", 2, 0, 11, StringParser::PARSE_SUCCESS); + StringToAllDecimals(".00011e5 ", 2, 0, 11, StringParser::PARSE_SUCCESS); + StringToAllDecimals("110e-1 ", 2, 0, 11, StringParser::PARSE_UNDERFLOW); + StringToAllDecimals("1.10e1 ", 2, 0, 11, StringParser::PARSE_UNDERFLOW); + StringToAllDecimals("1.10e3 ", 2, 0, 11, StringParser::PARSE_OVERFLOW); } TEST(StringToDecimal, LargeDecimals) { - ColumnType t1 = ColumnType::CreateDecimalType(1, 0); - ColumnType t2 = ColumnType::CreateDecimalType(10, 10); - ColumnType t3 = ColumnType::CreateDecimalType(8, 3); - - StringToAllDecimals("1", t1, 1, StringParser::PARSE_SUCCESS); - StringToAllDecimals("-1", t1, -1, StringParser::PARSE_SUCCESS); - StringToAllDecimals(".1", t1, 0, StringParser::PARSE_UNDERFLOW); - StringToAllDecimals("10", t1, 10, StringParser::PARSE_OVERFLOW); - StringToAllDecimals("-10", t1, -10, StringParser::PARSE_OVERFLOW); + StringToAllDecimals("1", 1, 0, 1, StringParser::PARSE_SUCCESS); + StringToAllDecimals("-1", 1, 0, -1, StringParser::PARSE_SUCCESS); + StringToAllDecimals(".1", 1, 0, 0, StringParser::PARSE_UNDERFLOW); + StringToAllDecimals("10", 1, 0, 10, StringParser::PARSE_OVERFLOW); + StringToAllDecimals("-10", 1, 0, -10, StringParser::PARSE_OVERFLOW); - VerifyParse(".1234567890", t2, + VerifyParse(".1234567890", 10, 10, Decimal8Value(1234567890L), StringParser::PARSE_SUCCESS); - VerifyParse("-.1234567890", t2, + VerifyParse("-.1234567890", 10, 10, Decimal8Value(-1234567890L), StringParser::PARSE_SUCCESS); - VerifyParse(".12345678900", t2, + VerifyParse(".12345678900", 10, 10, Decimal8Value(1234567890L), StringParser::PARSE_UNDERFLOW); - VerifyParse("-.12345678900", t2, + VerifyParse("-.12345678900", 10, 10, Decimal8Value(-1234567890L), StringParser::PARSE_UNDERFLOW); - VerifyParse(".1234567890", t2, + VerifyParse(".1234567890", 10, 10, Decimal16Value(1234567890L), StringParser::PARSE_SUCCESS); - VerifyParse("-.1234567890", t2, + VerifyParse("-.1234567890", 10, 10, Decimal16Value(-1234567890L), StringParser::PARSE_SUCCESS); - VerifyParse(".12345678900", t2, + VerifyParse(".12345678900", 10, 10, Decimal16Value(1234567890L), StringParser::PARSE_UNDERFLOW); - VerifyParse("-.12345678900", t2, + VerifyParse("-.12345678900", 10, 10, Decimal16Value(-1234567890L), StringParser::PARSE_UNDERFLOW); // Up to 8 digits with 5 before the decimal and 3 after. - VerifyParse("12345.678", t3, + VerifyParse("12345.678", 8, 3, Decimal8Value(12345678L), StringParser::PARSE_SUCCESS); - VerifyParse("-12345.678", t3, + VerifyParse("-12345.678", 8, 3, Decimal8Value(-12345678L), StringParser::PARSE_SUCCESS); - VerifyParse("123456.78", t3, + VerifyParse("123456.78", 8, 3, Decimal8Value(12345678L), StringParser::PARSE_OVERFLOW); - VerifyParse("1234.5678", t3, + VerifyParse("1234.5678", 8, 3, Decimal8Value(1234567L), StringParser::PARSE_UNDERFLOW); - VerifyParse("12345.678", t3, + VerifyParse("12345.678", 8, 3, Decimal16Value(12345678L), StringParser::PARSE_SUCCESS); - VerifyParse("-12345.678", t3, + VerifyParse("-12345.678", 8, 3, Decimal16Value(-12345678L), StringParser::PARSE_SUCCESS); - VerifyParse("123456.78", t3, + VerifyParse("123456.78", 8, 3, Decimal16Value(12345678L), StringParser::PARSE_OVERFLOW); - VerifyParse("1234.5678", t3, + VerifyParse("1234.5678", 8, 3, Decimal16Value(1234567L), StringParser::PARSE_UNDERFLOW); // Test max unscaled value for each of the decimal types. - VerifyParse("999999999", ColumnType::CreateDecimalType(9, 0), + VerifyParse("999999999", 9, 0, Decimal4Value(999999999), StringParser::PARSE_SUCCESS); - VerifyParse("99999.9999", ColumnType::CreateDecimalType(9, 4), + VerifyParse("99999.9999", 9, 4, Decimal4Value(999999999), StringParser::PARSE_SUCCESS); - VerifyParse("0.999999999", ColumnType::CreateDecimalType(9, 9), + VerifyParse("0.999999999", 9, 9, Decimal4Value(999999999), StringParser::PARSE_SUCCESS); - VerifyParse("-999999999", ColumnType::CreateDecimalType(9, 0), + VerifyParse("-999999999", 9, 0, Decimal4Value(-999999999), StringParser::PARSE_SUCCESS); - VerifyParse("-99999.9999", ColumnType::CreateDecimalType(9, 4), + VerifyParse("-99999.9999", 9, 4, Decimal4Value(-999999999), StringParser::PARSE_SUCCESS); - VerifyParse("-0.999999999", ColumnType::CreateDecimalType(9, 9), + VerifyParse("-0.999999999", 9, 9, Decimal4Value(-999999999), StringParser::PARSE_SUCCESS); - VerifyParse("1000000000", ColumnType::CreateDecimalType(9, 0), + VerifyParse("1000000000", 9, 0, Decimal4Value(0), StringParser::PARSE_OVERFLOW); - VerifyParse("-1000000000", ColumnType::CreateDecimalType(9, 0), + VerifyParse("-1000000000", 9, 0, Decimal4Value(0), StringParser::PARSE_OVERFLOW); - VerifyParse("999999999999999999", ColumnType::CreateDecimalType(18, 0), + VerifyParse("999999999999999999", 18, 0, Decimal8Value(999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse("999999.999999999999", ColumnType::CreateDecimalType(18, 12), + VerifyParse("999999.999999999999", 18, 12, Decimal8Value(999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse(".999999999999999999", ColumnType::CreateDecimalType(18, 18), + VerifyParse(".999999999999999999", 18, 18, Decimal8Value(999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse("-999999999999999999", ColumnType::CreateDecimalType(18, 0), + VerifyParse("-999999999999999999", 18, 0, Decimal8Value(-999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse("-999999.999999999999", ColumnType::CreateDecimalType(18, 12), + VerifyParse("-999999.999999999999", 18, 12, Decimal8Value(-999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse("-.999999999999999999", ColumnType::CreateDecimalType(18, 18), + VerifyParse("-.999999999999999999", 18, 18, Decimal8Value(-999999999999999999ll), StringParser::PARSE_SUCCESS); - VerifyParse("1000000000000000000", ColumnType::CreateDecimalType(18, 0), + VerifyParse("1000000000000000000", 18, 0, Decimal8Value(0), StringParser::PARSE_OVERFLOW); - VerifyParse("01000000000000000000", ColumnType::CreateDecimalType(18, 0), + VerifyParse("01000000000000000000", 18, 0, Decimal8Value(0), StringParser::PARSE_OVERFLOW); int128_t result = DecimalUtil::MAX_UNSCALED_DECIMAL16; VerifyParse("99999999999999999999999999999999999999", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(result), StringParser::PARSE_SUCCESS); + 38, 0, Decimal16Value(result), StringParser::PARSE_SUCCESS); VerifyParse("99999999999999999999999999999999999999e1", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(result), StringParser::PARSE_OVERFLOW); + 38, 0, Decimal16Value(result), StringParser::PARSE_OVERFLOW); VerifyParse("999999999999999999999999999999999999990e-1", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(result), StringParser::PARSE_UNDERFLOW); + 38, 0, Decimal16Value(result), StringParser::PARSE_UNDERFLOW); VerifyParse("999999999999999999999999999999999.99999", - ColumnType::CreateDecimalType(38, 5), - Decimal16Value(result), StringParser::PARSE_SUCCESS); + 38, 5, Decimal16Value(result), StringParser::PARSE_SUCCESS); VerifyParse(".99999999999999999999999999999999999999", - ColumnType::CreateDecimalType(38, 38), - Decimal16Value(result), StringParser::PARSE_SUCCESS); + 38, 38, Decimal16Value(result), StringParser::PARSE_SUCCESS); VerifyParse("-99999999999999999999999999999999999999", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(-result), StringParser::PARSE_SUCCESS); + 38, 0, Decimal16Value(-result), StringParser::PARSE_SUCCESS); VerifyParse("-999999999999999999999999999999999.99999", - ColumnType::CreateDecimalType(38, 5), - Decimal16Value(-result), StringParser::PARSE_SUCCESS); + 38, 5, Decimal16Value(-result), StringParser::PARSE_SUCCESS); VerifyParse("-.99999999999999999999999999999999999999", - ColumnType::CreateDecimalType(38, 38), - Decimal16Value(-result), StringParser::PARSE_SUCCESS); + 38, 38, Decimal16Value(-result), StringParser::PARSE_SUCCESS); VerifyParse("-.99999999999999999999999999999999999999e1", - ColumnType::CreateDecimalType(38, 38), - Decimal16Value(-result), StringParser::PARSE_OVERFLOW); + 38, 38, Decimal16Value(-result), StringParser::PARSE_OVERFLOW); VerifyParse("-.999999999999999999999999999999999999990e-1", - ColumnType::CreateDecimalType(38, 38), - Decimal16Value(-result / 10), StringParser::PARSE_UNDERFLOW); + 38, 38, Decimal16Value(-result / 10), StringParser::PARSE_UNDERFLOW); VerifyParse("-.999999999999999999999999999999999999990000000000000000e-20", - ColumnType::CreateDecimalType(38, 38), + 38, 38, Decimal16Value(-result / DecimalUtil::GetScaleMultiplier<int128_t>(20)), StringParser::PARSE_UNDERFLOW); VerifyParse("100000000000000000000000000000000000000", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(0), StringParser::PARSE_OVERFLOW); + 38, 0, Decimal16Value(0), StringParser::PARSE_OVERFLOW); VerifyParse("-100000000000000000000000000000000000000", - ColumnType::CreateDecimalType(38, 0), - Decimal16Value(0), StringParser::PARSE_OVERFLOW); + 38, 0, Decimal16Value(0), StringParser::PARSE_OVERFLOW); } TEST(DecimalTest, Overflow) { bool overflow = false; - ColumnType t1 = ColumnType::CreateDecimalType(38, 0); Decimal16Value result; Decimal16Value d_max(DecimalUtil::MAX_UNSCALED_DECIMAL16); @@ -456,157 +427,155 @@ TEST(DecimalTest, Overflow) { // Adding same sign overflow = false; - d_max.Add<int128_t>(t1, one, t1, 38, 0, &overflow); + d_max.Add<int128_t>(0, one, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - one.Add<int128_t>(t1, d_max, t1, 38, 0, &overflow); + one.Add<int128_t>(0, d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - d_max.Add<int128_t>(t1, d_max, t1, 38, 0, &overflow); + d_max.Add<int128_t>(0, d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - result = d_max.Add<int128_t>(t1, zero, t1, 38, 0, &overflow); + result = d_max.Add<int128_t>(0, zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value()); // Subtracting same sign overflow = false; - result = d_max.Subtract<int128_t>(t1, one, t1, 38, 0, &overflow); + result = d_max.Subtract<int128_t>(0, one, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); overflow = false; EXPECT_TRUE(result.value() == d_max.value() - 1); - result = one.Subtract<int128_t>(t1, d_max, t1, 38, 0, &overflow); + result = one.Subtract<int128_t>(0, d_max, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); overflow = false; EXPECT_TRUE(result.value() == -(d_max.value() - 1)); - result = d_max.Subtract<int128_t>(t1, d_max, t1, 38, 0, &overflow); + result = d_max.Subtract<int128_t>(0, d_max, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); overflow = false; EXPECT_TRUE(result.value() == 0); - result = d_max.Subtract<int128_t>(t1, zero, t1, 38, 0, &overflow); + result = d_max.Subtract<int128_t>(0, zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value()); // Adding different sign overflow = false; - result = d_max.Add<int128_t>(t1, -one, t1, 38, 0, &overflow); + result = d_max.Add<int128_t>(0, -one, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value() - 1); overflow = false; - result = one.Add<int128_t>(t1, -d_max, t1, 38, 0, &overflow); + result = one.Add<int128_t>(0, -d_max, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == -(d_max.value() - 1)); overflow = false; - result = d_max.Add<int128_t>(t1, -d_max, t1, 38, 0, &overflow); + result = d_max.Add<int128_t>(0, -d_max, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == 0); overflow = false; - result = d_max.Add<int128_t>(t1, -zero, t1, 38, 0, &overflow); + result = d_max.Add<int128_t>(0, -zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value()); // Subtracting different sign overflow = false; - d_max.Subtract<int128_t>(t1, -one, t1, 38, 0, &overflow); + d_max.Subtract<int128_t>(0, -one, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); - one.Subtract<int128_t>(t1, -d_max, t1, 38, 0, &overflow); + one.Subtract<int128_t>(0, -d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - d_max.Subtract<int128_t>(t1, -d_max, t1, 38, 0, &overflow); + d_max.Subtract<int128_t>(0, -d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - result = d_max.Subtract<int128_t>(t1, -zero, t1, 38, 0, &overflow); + result = d_max.Subtract<int128_t>(0, -zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value()); // Multiply overflow = false; - result = d_max.Multiply<int128_t>(t1, one, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, one, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == d_max.value()); overflow = false; - result = d_max.Multiply<int128_t>(t1, -one, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, -one, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == -d_max.value()); overflow = false; - result = d_max.Multiply<int128_t>(t1, two, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, two, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - result = d_max.Multiply<int128_t>(t1, -two, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, -two, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - result = d_max.Multiply<int128_t>(t1, d_max, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); overflow = false; - result = d_max.Multiply<int128_t>(t1, -d_max, t1, 38, 0, &overflow); + result = d_max.Multiply<int128_t>(0, -d_max, 0, 38, 0, false, &overflow); EXPECT_TRUE(overflow); // Multiply by 0 overflow = false; - result = zero.Multiply<int128_t>(t1, one, t1, 38, 0, &overflow); + result = zero.Multiply<int128_t>(0, one, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == 0); overflow = false; - result = one.Multiply<int128_t>(t1, zero, t1, 38, 0, &overflow); + result = one.Multiply<int128_t>(0, zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == 0); overflow = false; - result = zero.Multiply<int128_t>(t1, zero, t1, 38, 0, &overflow); + result = zero.Multiply<int128_t>(0, zero, 0, 38, 0, false, &overflow); EXPECT_FALSE(overflow); EXPECT_TRUE(result.value() == 0); // Adding any value with scale to (38, 0) will overflow if the most significant // digit is set. - ColumnType t2 = ColumnType::CreateDecimalType(1, 1); overflow = false; - result = d_max.Add<int128_t>(t1, zero, t2, 38, 1, &overflow); + result = d_max.Add<int128_t>(0, zero, 1, 38, 1, false, &overflow); EXPECT_TRUE(overflow); // Add 37 9's (with scale 0) Decimal16Value d3(DecimalUtil::MAX_UNSCALED_DECIMAL16 / 10); overflow = false; - result = d3.Add<int128_t>(t1, zero, t2, 38, 1, &overflow); + result = d3.Add<int128_t>(0, zero, 1, 38, 1, false, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(result.value(), DecimalUtil::MAX_UNSCALED_DECIMAL16 - 9); overflow = false; - result = d3.Add<int128_t>(t1, one, t2, 38, 1, &overflow); + result = d3.Add<int128_t>(0, one, 1, 38, 1, false, &overflow); EXPECT_FALSE(overflow); EXPECT_EQ(result.value(), DecimalUtil::MAX_UNSCALED_DECIMAL16 - 8); // Mod overflow = false; bool is_nan; - ColumnType t3 = ColumnType::CreateDecimalType(38, 20); - result = d3.Mod<int128_t>(t1, d3, t3, 38, 20, &is_nan, &overflow); + result = d3.Mod<int128_t>(0, d3, 20, 38, 20, false, &is_nan, &overflow); EXPECT_TRUE(overflow); EXPECT_FALSE(is_nan); overflow = false; - result = d3.Mod<int128_t>(t1, two, t1, 38, 0, &is_nan, &overflow); + result = d3.Mod<int128_t>(0, two, 0, 38, 0, false, &is_nan, &overflow); EXPECT_FALSE(overflow); EXPECT_FALSE(is_nan); EXPECT_EQ(result.value(), DecimalUtil::MAX_UNSCALED_DECIMAL16 % 2); - result = d3.Mod<int128_t>(t1, zero, t2, 38, 1, &is_nan, &overflow); + result = d3.Mod<int128_t>(0, zero, 1, 38, 1, false, &is_nan, &overflow); EXPECT_TRUE(is_nan); } @@ -618,20 +587,20 @@ TEST(DecimalTest, MultiplyScaleOverflow) { bool overflow = false; Decimal16Value x(1); Decimal16Value y(3); - ColumnType max_scale = ColumnType::CreateDecimalType(38, 38); + int max_scale = 38; // x = 0.<37 zeroes>1. y = 0.<37 zeroes>3 The result should be 0.<74 zeroes>3. // Since this can't be represented, the result will truncate to 0. - Decimal16Value result = x.Multiply<int128_t>(max_scale, y, max_scale, 38, 38, &overflow); + Decimal16Value result = x.Multiply<int128_t>(max_scale, y, max_scale, 38, 38, false, &overflow); EXPECT_TRUE(result.value() == 0); EXPECT_FALSE(overflow); - ColumnType scale_1 = ColumnType::CreateDecimalType(1, 1); - ColumnType scale_37 = ColumnType::CreateDecimalType(38, 37); + int scale_1 = 1; + int scale_37 = 37; // x = 0.<36 zeroes>1, y = 0.3 // The result should be 0.<37 zeroes>11, which would require scale = 39. // The truncated version should 0.<37 zeroes>3. - result = x.Multiply<int128_t>(scale_37, y, scale_1, 38, 38, &overflow); + result = x.Multiply<int128_t>(scale_37, y, scale_1, 38, 38, false, &overflow); EXPECT_TRUE(result.value() == 3); EXPECT_FALSE(overflow); } @@ -646,7 +615,8 @@ enum Op { // Implementation of decimal rules. This is handled in the planner in the normal // execution paths. -ColumnType GetResultType(const ColumnType& t1, const ColumnType& t2, Op op) { +ColumnType GetResultType(const ColumnType& t1, const ColumnType& t2, Op op, bool v2) { + // TODO: Implement V2 result types switch (op) { case ADD: case SUBTRACT: @@ -658,10 +628,17 @@ ColumnType GetResultType(const ColumnType& t1, const ColumnType& t2, Op op) { return ColumnType::CreateDecimalType( t1.precision + t2.precision, t1.scale + t2.scale); case DIVIDE: - return ColumnType::CreateDecimalType( - min(38, + if (v2) { + int result_scale = + max(ColumnType::MIN_ADJUSTED_SCALE, t1.scale + t2.precision + 1); + int result_precision =t1.precision - t1.scale + t2.scale + result_scale; + return ColumnType::CreateAdjustedDecimalType(result_precision, result_scale); + } else { + return ColumnType::CreateDecimalType( + min(ColumnType::MAX_PRECISION, t1.precision - t1.scale + t2.scale + max(4, t1.scale + t2.precision + 1)), - max(4, t1.scale + t2.precision + 1)); + min(ColumnType::MAX_PRECISION, max(4, t1.scale + t2.precision + 1))); + } case MOD: return ColumnType::CreateDecimalType( min(t1.precision - t1.scale, t2.precision - t2.scale) + max(t1.scale, t2.scale), @@ -672,47 +649,65 @@ ColumnType GetResultType(const ColumnType& t1, const ColumnType& t2, Op op) { } } +TEST(DecimalResultTypes, Basic) { + ColumnType t1 = ColumnType::CreateDecimalType(38, 10); + ColumnType t2 = ColumnType::CreateDecimalType(38, 38); + ColumnType t3 = ColumnType::CreateDecimalType(38, 0); + + auto r1 = GetResultType(t1, t2, DIVIDE, true); + EXPECT_EQ(r1.precision, 38); + EXPECT_EQ(r1.scale, 6); + + auto r2 = GetResultType(t1, t3, DIVIDE, true); + EXPECT_EQ(r2.precision, 38); + EXPECT_EQ(r2.scale, 10); + + auto r3 = GetResultType(t1, t2, DIVIDE, false); + EXPECT_EQ(r3.precision, 38); + EXPECT_EQ(r3.scale, 38); +} + template<typename T> void VerifyFuzzyEquals(const T& actual, const ColumnType& t, - double expected, bool overflow) { - double actual_d = actual.ToDouble(t); + double expected, bool overflow, double max_error = MAX_ERROR) { + double actual_d = actual.ToDouble(t.scale); EXPECT_FALSE(overflow); - EXPECT_TRUE(fabs(actual_d - expected) < MAX_ERROR) + EXPECT_TRUE(fabs(actual_d - expected) < max_error) << actual_d << " != " << expected; } TEST(DecimalArithmetic, Basic) { ColumnType t1 = ColumnType::CreateDecimalType(5, 4); ColumnType t2 = ColumnType::CreateDecimalType(8, 3); - ColumnType t1_plus_2 = GetResultType(t1, t2, ADD); - ColumnType t1_times_2 = GetResultType(t1, t2, MULTIPLY); + ColumnType t1_plus_2 = GetResultType(t1, t2, ADD, false); + ColumnType t1_times_2 = GetResultType(t1, t2, MULTIPLY, false); Decimal4Value d1(123456789); Decimal4Value d2(23456); Decimal4Value d3(-23456); - double d1_double = d1.ToDouble(t1); - double d2_double = d2.ToDouble(t2); - double d3_double = d3.ToDouble(t2); + double d1_double = d1.ToDouble(t1.scale); + double d2_double = d2.ToDouble(t2.scale); + double d3_double = d3.ToDouble(t2.scale); bool overflow = false; // TODO: what's the best way to author a bunch of tests like this? VerifyFuzzyEquals(d1.Add<int64_t>( - t1, d2, t2, t1_plus_2.precision, t1_plus_2.scale, &overflow), + t1.scale, d2, t2.scale, t1_plus_2.precision, t1_plus_2.scale, false, &overflow), t1_plus_2, d1_double + d2_double, overflow); VerifyFuzzyEquals(d1.Add<int64_t>( - t1, d3, t2, t1_plus_2.precision, t1_plus_2.scale, &overflow), + t1.scale, d3, t2.scale, t1_plus_2.precision, t1_plus_2.scale, false, &overflow), t1_plus_2, d1_double + d3_double, overflow); VerifyFuzzyEquals(d1.Subtract<int64_t>( - t1, d2, t2, t1_plus_2.precision, t1_plus_2.scale, &overflow), + t1.scale, d2, t2.scale, t1_plus_2.precision, t1_plus_2.scale, false, &overflow), t1_plus_2, d1_double - d2_double, overflow); VerifyFuzzyEquals(d1.Subtract<int64_t>( - t1, d3, t2, t1_plus_2.precision, t1_plus_2.scale, &overflow), + t1.scale, d3, t2.scale, t1_plus_2.precision, t1_plus_2.scale, false, &overflow), t1_plus_2, d1_double - d3_double, overflow); VerifyFuzzyEquals(d1.Multiply<int128_t>( - t1, d2, t2, t1_times_2.precision, t1_times_2.scale, &overflow), + t1.scale, d2, t2.scale, t1_times_2.precision, t1_times_2.scale, false, &overflow), t1_times_2, d1_double * d2_double, overflow); VerifyFuzzyEquals(d1.Multiply<int64_t>( - t1, d3, t2, t1_times_2.precision, t1_times_2.scale, &overflow), + t1.scale, d3, t2.scale, t1_times_2.precision, t1_times_2.scale, false, &overflow), t1_times_2, d1_double * d3_double, overflow); } @@ -725,25 +720,27 @@ TEST(DecimalArithmetic, Divide) { for (int numerator_s = 0; numerator_s <= numerator_p; ++numerator_s) { for (int denominator_p = 1; denominator_p <= 3; ++denominator_p) { for (int denominator_s = 0; denominator_s <= denominator_p; ++denominator_s) { - ColumnType t1 = ColumnType::CreateDecimalType(numerator_p, numerator_s); - ColumnType t2 = ColumnType::CreateDecimalType(denominator_p, denominator_s); - ColumnType t3 = GetResultType(t1, t2, DIVIDE); - bool is_nan = false; - bool is_overflow = false; - Decimal8Value r = x.Divide<int64_t>( - t1, y, t2, t3.precision, t3.scale, &is_nan, &is_overflow); - double approx_x = x.ToDouble(t1); - double approx_y = y.ToDouble(t2); - double approx_r = r.ToDouble(t3); - double expected_r = approx_x / approx_y; - - EXPECT_FALSE(is_nan); - EXPECT_FALSE(is_overflow); - if (fabs(approx_r - expected_r) > MAX_ERROR) { - LOG(ERROR) << approx_r << " " << expected_r; - LOG(ERROR) << x.ToString(t1) << "/" << y.ToString(t2) - << "=" << r.ToString(t3); - EXPECT_TRUE(false); + for (int v2: { 0, 1 }) { + ColumnType t1 = ColumnType::CreateDecimalType(numerator_p, numerator_s); + ColumnType t2 = ColumnType::CreateDecimalType(denominator_p, denominator_s); + ColumnType t3 = GetResultType(t1, t2, DIVIDE, v2); + bool is_nan = false; + bool is_overflow = false; + Decimal8Value r = x.Divide<int64_t>( + t1.scale, y, t2.scale, t3.precision, t3.scale, true, &is_nan, &is_overflow); + double approx_x = x.ToDouble(t1.scale); + double approx_y = y.ToDouble(t2.scale); + double approx_r = r.ToDouble(t3.scale); + double expected_r = approx_x / approx_y; + + EXPECT_FALSE(is_nan); + EXPECT_FALSE(is_overflow); + if (fabs(approx_r - expected_r) > MAX_ERROR) { + LOG(ERROR) << approx_r << " " << expected_r; + LOG(ERROR) << x.ToString(t1) << "/" << y.ToString(t2) + << "=" << r.ToString(t3); + EXPECT_TRUE(false); + } } } } @@ -752,19 +749,18 @@ TEST(DecimalArithmetic, Divide) { // Divide by 0 bool is_nan = false; bool is_overflow = false; - Decimal8Value r = x.Divide<int64_t>(ColumnType::CreateDecimalType(10, 0), - Decimal4Value(0), ColumnType::CreateDecimalType(2,0), 38, 4, &is_nan, &is_overflow); + Decimal8Value r = x.Divide<int64_t>(0, Decimal4Value(0), 0, 38, 4, true, + &is_nan, &is_overflow); EXPECT_TRUE(is_nan) << "Expected NaN, got: " << r; EXPECT_FALSE(is_overflow); // In this case, we are dividing large precision decimals meaning the resulting // decimal underflows. The resulting type is (38,38). - ColumnType t4 = ColumnType::CreateDecimalType(38, 4); Decimal16Value x2(53994500); Decimal16Value y2(5399450); is_nan = false; is_overflow = false; - x2.Divide<int128_t>(t4, y2, t4, 38, 38, &is_nan, &is_overflow); + x2.Divide<int128_t>(4, y2, 4, 38, 38, true, &is_nan, &is_overflow); EXPECT_TRUE(is_overflow); EXPECT_FALSE(is_nan); } @@ -772,7 +768,7 @@ TEST(DecimalArithmetic, Divide) { TEST(DecimalArithmetic, DivideLargeScales) { ColumnType t1 = ColumnType::CreateDecimalType(38, 8); ColumnType t2 = ColumnType::CreateDecimalType(20, 0); - ColumnType t3 = GetResultType(t1, t2, DIVIDE); + ColumnType t3 = GetResultType(t1, t2, DIVIDE, false); StringParser::ParseResult result; const char* data = "319391280635.61476055"; Decimal16Value x = @@ -780,15 +776,16 @@ TEST(DecimalArithmetic, DivideLargeScales) { Decimal16Value y(10000); bool is_nan = false; bool is_overflow = false; - Decimal16Value r = - x.Divide<int128_t>(t1, y, t2, t3.precision, t3.scale, &is_nan, &is_overflow); - VerifyToString(r, t3, "31939128.06356147605500000000000000000"); + Decimal16Value r = x.Divide<int128_t>(t1.scale, y, t2.scale, t3.precision, t3.scale, + true, &is_nan, &is_overflow); + VerifyToString(r, t3.precision, t3.scale, "31939128.06356147605500000000000000000"); EXPECT_FALSE(is_nan); EXPECT_FALSE(is_overflow); y = -y; - r = x.Divide<int128_t>(t1, y, t2, t3.precision, t3.scale, &is_nan, &is_overflow); - VerifyToString(r, t3, "-31939128.06356147605500000000000000000"); + r = x.Divide<int128_t>(t1.scale, y, t2.scale, t3.precision, t3.scale, true, + &is_nan, &is_overflow); + VerifyToString(r, t3.precision, t3.scale, "-31939128.06356147605500000000000000000"); EXPECT_FALSE(is_nan); EXPECT_FALSE(is_overflow); } @@ -826,32 +823,36 @@ TEST(DecimalArithmetic, RandTesting) { DecimalValue<int64_t> dec2 = RandDecimal<int64_t>(p2); ColumnType t1 = ColumnType::CreateDecimalType(p1, s1); ColumnType t2 = ColumnType::CreateDecimalType(p2, s2); - double t1_d = dec1.ToDouble(t1); - double t2_d = dec2.ToDouble(t2); + double t1_d = dec1.ToDouble(s1); + double t2_d = dec2.ToDouble(s2); - ColumnType add_t = GetResultType(t1, t2, ADD); + ColumnType add_t = GetResultType(t1, t2, ADD, false); bool overflow = false; VerifyFuzzyEquals(dec1.Add<int64_t>( - t1, dec2, t2, add_t.precision, add_t.scale, &overflow), + t1.scale, dec2, t2.scale, add_t.precision, add_t.scale, false, &overflow), add_t, t1_d + t2_d, overflow); VerifyFuzzyEquals(dec1.Subtract<int64_t>( - t1, dec2, t2, add_t.precision, add_t.scale, &overflow), + t1.scale, dec2, t2.scale, add_t.precision, add_t.scale, false, &overflow), add_t, t1_d - t2_d, overflow); + if (overflow) continue; + #if 0 - TODO: doubles are not precise enough for this - ColumnType multiply_t = GetResultType(t1, t2, MULTIPLY); - ColumnType divide_t = GetResultType(t1, t2, DIVIDE); - // double is too imprecise to generate the right result. - // TODO: compare against the ground truth using the multi precision float library. + // multiply V2 result type not implemented yet + ColumnType multiply_t = GetResultType(t1, t2, MULTIPLY, true); VerifyFuzzyEquals(dec1.Multiply<int64_t>( - t1, dec2, t2, multiply_t.scale), multiply_t, t1_d * t2_d); - if (dec2.value() != 0) { - VerifyFuzzyEquals(dec1.Divide<int64_t>( - t1, dec2, t2, divide_t.scale), divide_t, t1_d / t2_d); - } + t1.scale, dec2, t2.scale, multiply_t.scale), multiply_t, t1_d * t2_d); #endif - + // With rounding, we should be able to get much closer to real values + ColumnType divide_t = GetResultType(t1, t2, DIVIDE, true); + bool is_nan = false; + overflow = false; + auto result = dec1.Divide<int128_t>(t1.scale, dec2, t2.scale, divide_t.precision, + divide_t.scale, true, &is_nan, &overflow); + if (!is_nan && !overflow) + VerifyFuzzyEquals(result, divide_t, t1_d / t2_d, false, + pow(10, divide_t.precision - divide_t.scale - 6)); + EXPECT_EQ(is_nan, dec2.value() == 0); EXPECT_EQ(dec1.Compare(t1.scale, dec2, t2.scale), DoubleCompare(t1_d, t2_d)); EXPECT_TRUE(dec1.Compare(t1.scale, dec1, t1.scale) == 0); EXPECT_TRUE(dec2.Compare(t2.scale, dec2, t2.scale) == 0); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/c87ab35a/be/src/runtime/decimal-value.h ---------------------------------------------------------------------- diff --git a/be/src/runtime/decimal-value.h b/be/src/runtime/decimal-value.h index 23c8c6f..88ec2e3 100644 --- a/be/src/runtime/decimal-value.h +++ b/be/src/runtime/decimal-value.h @@ -60,10 +60,6 @@ class DecimalValue { bool round, bool* overflow); /// Assigns *result as a decimal. - static inline DecimalValue FromInt(const ColumnType& t, int64_t d, bool* overflow) { - return FromInt(t.precision, t.scale, d, overflow); - } - static inline DecimalValue FromInt(int precision, int scale, int64_t d, bool* overflow); /// The overloaded operators assume that this and other have the same scale. They are @@ -102,11 +98,6 @@ class DecimalValue { /// Returns a new decimal scaled by from src_type to dst_type. /// e.g. If this value was 1100 at scale 3 and the dst_type had scale two, the /// result would be 110. (In both cases representing the decimal 1.1). - inline DecimalValue ScaleTo(const ColumnType& src_type, const ColumnType& dst_type, - bool* overflow) const { - return ScaleTo(src_type.scale, dst_type.scale, dst_type.precision, overflow); - } - inline DecimalValue ScaleTo(int src_scale, int dst_scale, int dst_precision, bool* overflow) const; @@ -119,71 +110,33 @@ class DecimalValue { /// not valid. /// RESULT_T needs to be larger than T to avoid overflow issues. template<typename RESULT_T> - inline DecimalValue<RESULT_T> Add(const ColumnType& this_type, - const DecimalValue& other, const ColumnType& other_type, int result_precision, - int result_scale, bool* overflow) const { - return Add<RESULT_T>(this_type.scale, other, other_type.scale, result_precision, - result_scale, overflow); - } - - template<typename RESULT_T> inline DecimalValue<RESULT_T> Add(int this_scale, const DecimalValue& other, - int other_scale, int result_precision, int result_scale, bool* overflow) const; - - template<typename RESULT_T> - inline DecimalValue<RESULT_T> Subtract(const ColumnType& this_type, - const DecimalValue& other, const ColumnType& other_type, int result_precision, - int result_scale, bool* overflow) const { - return Add<RESULT_T>(this_type, -other, other_type, result_precision, - result_scale, overflow); - } + int other_scale, int result_precision, int result_scale, bool round, + bool* overflow) const; template<typename RESULT_T> inline DecimalValue<RESULT_T> Subtract(int this_scale, const DecimalValue& other, - int other_scale, int result_precision, int result_scale, bool* overflow) const { + int other_scale, int result_precision, int result_scale, bool round, + bool* overflow) const { return Add<RESULT_T>(this_scale, -other, other_scale, result_precision, - result_scale, overflow); - } - - template<typename RESULT_T> - inline DecimalValue<RESULT_T> Multiply(const ColumnType& this_type, - const DecimalValue& other, const ColumnType& other_type, int result_precision, - int result_scale, bool* overflow) const { - return Multiply<RESULT_T>(this_type.scale, other, other_type.scale, result_precision, - result_scale, overflow); + result_scale, round, overflow); } template<typename RESULT_T> inline DecimalValue<RESULT_T> Multiply(int this_scale, const DecimalValue& other, - int other_scale, int result_precision, int result_scale, bool* overflow) const; - - /// is_nan is set to true if 'other' is 0. The value returned is undefined. - template<typename RESULT_T> - inline DecimalValue<RESULT_T> Divide(const ColumnType& this_type, - const DecimalValue& other, const ColumnType& other_type, int result_precision, - int result_scale, bool* is_nan, bool* overflow) const { - return Divide<RESULT_T>(this_type.scale, other, other_type.scale, result_precision, - result_scale, is_nan, overflow); - } - - template<typename RESULT_T> - inline DecimalValue<RESULT_T> Divide(int this_scale, const DecimalValue& other, - int other_scale, int result_precision, int result_scale, bool* is_nan, + int other_scale, int result_precision, int result_scale, bool round, bool* overflow) const; /// is_nan is set to true if 'other' is 0. The value returned is undefined. template<typename RESULT_T> - inline DecimalValue<RESULT_T> Mod(const ColumnType& this_type, - const DecimalValue& other, const ColumnType& other_type, int result_precision, - int result_scale, bool* is_nan, bool* overflow) const { - return Mod<RESULT_T>(this_type.scale, other, other_type.scale, result_precision, - result_scale, is_nan, overflow); - } + inline DecimalValue<RESULT_T> Divide(int this_scale, const DecimalValue& other, + int other_scale, int result_precision, int result_scale, bool round, + bool* is_nan, bool* overflow) const; template<typename RESULT_T> inline DecimalValue<RESULT_T> Mod(int this_scale, const DecimalValue& other, - int other_scale, int result_precision, int result_scale, bool* is_nan, - bool* overflow) const; + int other_scale, int result_precision, int result_scale, bool round, + bool* is_nan, bool* overflow) const; /// Compares this and other. Returns 0 if equal, < 0 if this < other and > 0 if /// this > other. @@ -215,17 +168,9 @@ class DecimalValue { inline T& value() { return value_; } /// Returns the value of the decimal before the decimal point. - inline const T whole_part(const ColumnType& t) const { - return whole_part(t.scale); - } - inline const T whole_part(int scale) const; /// Returns the value of the decimal after the decimal point. - inline const T fractional_part(const ColumnType& t) const { - return fractional_part(t.scale); - } - inline const T fractional_part(int scale) const; /// Returns the value as an integer, setting overflow to true on overflow, @@ -236,10 +181,6 @@ class DecimalValue { inline typename RESULT_T::underlying_type_t ToInt(int scale, bool* overflow) const; /// Returns an approximate double for this decimal. - inline double ToDouble(const ColumnType& type) const { - return ToDouble(type.scale); - } - inline double ToDouble(int scale) const; inline uint32_t Hash(int seed = 0) const;
