diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index 3431578758510..d8df55d9acec5 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -2678,6 +2678,34 @@ mod tests { ); } + #[test] + fn test_int_decimal_default() { + quick_test( + "SELECT CAST(10 AS DECIMAL)", + "Projection: CAST(Int64(10) AS Decimal(38, 10))\ + \n EmptyRelation", + ); + } + + #[test] + fn test_int_decimal_no_scale() { + quick_test( + "SELECT CAST(10 AS DECIMAL(5))", + "Projection: CAST(Int64(10) AS Decimal(5, 0))\ + \n EmptyRelation", + ); + } + + #[test] + fn test_int_decimal_scale_larger_precision() { + let sql = "SELECT CAST(10 AS DECIMAL(5, 10))"; + let err = logical_plan(sql).expect_err("query should have failed"); + assert_eq!( + r##"Internal("For decimal(precision, scale) precision must be less than or equal to 38 and scale can't be greater than precision. Got (5, 10)")"##, + format!("{:?}", err) + ); + } + #[test] fn select_column_does_not_exist() { let sql = "SELECT doesnotexist FROM person"; diff --git a/datafusion/sql/src/utils.rs b/datafusion/sql/src/utils.rs index 88d0118d286e8..25eec5f5b8df9 100644 --- a/datafusion/sql/src/utils.rs +++ b/datafusion/sql/src/utils.rs @@ -17,7 +17,7 @@ //! SQL Utility Functions -use arrow::datatypes::{DataType, DECIMAL_MAX_PRECISION}; +use arrow::datatypes::{DataType, DECIMAL_DEFAULT_SCALE, DECIMAL_MAX_PRECISION}; use sqlparser::ast::Ident; use datafusion_common::{DataFusionError, Result, ScalarValue}; @@ -447,22 +447,26 @@ pub(crate) fn make_decimal_type( precision: Option, scale: Option, ) -> Result { - match (precision, scale) { - (None, _) | (_, None) => Err(DataFusionError::Internal(format!( - "Decimal(precision, scale) must both be specified, got ({:?}, {:?})", - precision, scale - ))), - (Some(p), Some(s)) => { - // Arrow decimal is i128 meaning 38 maximum decimal digits - if (p as usize) > DECIMAL_MAX_PRECISION || s > p { - Err(DataFusionError::Internal(format!( - "For decimal(precision, scale) precision must be less than or equal to 38 and scale can't be greater than precision. Got ({}, {})", - p, s - ))) - } else { - Ok(DataType::Decimal(p as usize, s as usize)) - } + // postgres like behavior + let (precision, scale) = match (precision, scale) { + (Some(p), Some(s)) => (p as usize, s as usize), + (Some(p), None) => (p as usize, 0), + (None, Some(_)) => { + return Err(DataFusionError::Internal( + "Cannot specify only scale for decimal data type".to_string(), + )) } + (None, None) => (DECIMAL_MAX_PRECISION, DECIMAL_DEFAULT_SCALE), + }; + + // Arrow decimal is i128 meaning 38 maximum decimal digits + if precision > DECIMAL_MAX_PRECISION || scale > precision { + return Err(DataFusionError::Internal(format!( + "For decimal(precision, scale) precision must be less than or equal to 38 and scale can't be greater than precision. Got ({}, {})", + precision, scale + ))); + } else { + Ok(DataType::Decimal(precision, scale)) } }