Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions datafusion/sql/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

//! SQL Utility Functions

use arrow_schema::{DataType, DECIMAL128_MAX_PRECISION, DECIMAL_DEFAULT_SCALE};
use arrow_schema::{
DataType, DECIMAL128_MAX_PRECISION, DECIMAL256_MAX_PRECISION, DECIMAL_DEFAULT_SCALE,
};
use datafusion_common::tree_node::{Transformed, TreeNode};
use sqlparser::ast::Ident;

Expand Down Expand Up @@ -221,14 +223,17 @@ pub(crate) fn make_decimal_type(
(None, None) => (DECIMAL128_MAX_PRECISION, DECIMAL_DEFAULT_SCALE),
};

// Arrow decimal is i128 meaning 38 maximum decimal digits
if precision == 0
|| precision > DECIMAL128_MAX_PRECISION
|| precision > DECIMAL256_MAX_PRECISION
|| scale.unsigned_abs() > precision
{
plan_err!(
"Decimal(precision = {precision}, scale = {scale}) should satisfy `0 < precision <= 38`, and `scale <= precision`."
"Decimal(precision = {precision}, scale = {scale}) should satisfy `0 < precision <= 76`, and `scale <= precision`."
)
} else if precision > DECIMAL128_MAX_PRECISION
&& precision <= DECIMAL256_MAX_PRECISION
{
Ok(DataType::Decimal256(precision, scale))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

} else {
Ok(DataType::Decimal128(precision, scale))
}
Expand Down
16 changes: 13 additions & 3 deletions datafusion/sql/tests/sql_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ fn cast_to_invalid_decimal_type_precision_0() {
let sql = "SELECT CAST(10 AS DECIMAL(0))";
let err = logical_plan(sql).expect_err("query should have failed");
assert_eq!(
"Error during planning: Decimal(precision = 0, scale = 0) should satisfy `0 < precision <= 38`, and `scale <= precision`.",
"Error during planning: Decimal(precision = 0, scale = 0) should satisfy `0 < precision <= 76`, and `scale <= precision`.",
err.strip_backtrace()
);
}
Expand All @@ -212,9 +212,19 @@ fn cast_to_invalid_decimal_type_precision_gt_38() {
// precision > 38
{
let sql = "SELECT CAST(10 AS DECIMAL(39))";
let plan = "Projection: CAST(Int64(10) AS Decimal256(39, 0))\n EmptyRelation";
quick_test(sql, plan);
}
}

#[test]
fn cast_to_invalid_decimal_type_precision_gt_76() {
// precision > 76
{
let sql = "SELECT CAST(10 AS DECIMAL(79))";
let err = logical_plan(sql).expect_err("query should have failed");
assert_eq!(
"Error during planning: Decimal(precision = 39, scale = 0) should satisfy `0 < precision <= 38`, and `scale <= precision`.",
"Error during planning: Decimal(precision = 79, scale = 0) should satisfy `0 < precision <= 76`, and `scale <= precision`.",
err.strip_backtrace()
);
}
Expand All @@ -227,7 +237,7 @@ fn cast_to_invalid_decimal_type_precision_lt_scale() {
let sql = "SELECT CAST(10 AS DECIMAL(5, 10))";
let err = logical_plan(sql).expect_err("query should have failed");
assert_eq!(
"Error during planning: Decimal(precision = 5, scale = 10) should satisfy `0 < precision <= 38`, and `scale <= precision`.",
"Error during planning: Decimal(precision = 5, scale = 10) should satisfy `0 < precision <= 76`, and `scale <= precision`.",
err.strip_backtrace()
);
}
Expand Down
64 changes: 64 additions & 0 deletions datafusion/sqllogictest/test_files/decimal.slt
Original file line number Diff line number Diff line change
Expand Up @@ -629,3 +629,67 @@ select AVG(column1) from t;

statement ok
drop table t;

statement ok
CREATE EXTERNAL TABLE decimal256_simple (
c1 DECIMAL(50,6) NOT NULL,
c2 DOUBLE NOT NULL,
c3 BIGINT NOT NULL,
c4 BOOLEAN NOT NULL,
c5 DECIMAL(52,7) NOT NULL
)
STORED AS CSV
WITH HEADER ROW
LOCATION '../core/tests/data/decimal_data.csv';

query TT
select arrow_typeof(c1), arrow_typeof(c5) from decimal256_simple limit 1;
----
Decimal256(50, 6) Decimal256(52, 7)

query R rowsort
SELECT c1 from decimal256_simple;
----
0.00001
0.00002
0.00002
0.00003
0.00003
0.00003
0.00004
0.00004
0.00004
0.00004
0.00005
0.00005
0.00005
0.00005
0.00005

query R rowsort
select c1 from decimal256_simple where c1 > 0.000030;
----
0.00004
0.00004
0.00004
0.00004
0.00005
0.00005
0.00005
0.00005
0.00005

query RRIBR rowsort
select * from decimal256_simple where c1 > c5;
----
0.00002 0.000000000002 3 false 0.000019
0.00003 0.000000000003 5 true 0.000011
0.00005 0.000000000005 8 false 0.000033

query TR
select arrow_typeof(avg(c1)), avg(c1) from decimal256_simple;
----
Decimal256(54, 10) 0.0000366666

statement ok
drop table decimal256_simple;