You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/04/11 05:13:53 UTC
(datafusion) 01/01: fix(sql): return planner error for malformed typed literals (#21454)
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch gh-readonly-queue/main/pr-21454-540d8ecd5fc5ad07cb7ca5d77df9eb45f5da290e
in repository https://gitbox.apache.org/repos/asf/datafusion.git
commit 374806c3ed7ec6b60b8a9ae9d05009bb9d81cd89
Author: Asish Kumar <87...@users.noreply.github.com>
AuthorDate: Sat Apr 11 10:43:33 2026 +0530
fix(sql): return planner error for malformed typed literals (#21454)
## Which issue does this PR close?
- Closes #21431.
## Rationale for this change
Planning a malformed typed literal such as `time 17542368000000000`
currently panics in `datafusion-sql` because the planner assumes every
`TypedString` payload is string-backed and calls
`into_string().unwrap()`.
Invalid SQL should surface as a normal planner error rather than
aborting the planning path.
## What changes are included in this PR?
- Replace the `unwrap()` in the `SQLExpr::TypedString` planning path
with explicit validation.
- Return a planner error when the typed literal payload is not
string-backed.
- Add a regression test covering the invalid `TIME` typed literal
reported in the issue.
## Are these changes tested?
- `cargo test -p datafusion-sql`
## Are there any user-facing changes?
Users now receive a planner error for malformed typed literals instead
of a panic.
Signed-off-by: Asish Kumar <of...@gmail.com>
Co-authored-by: Jonah Gao <jo...@msn.com>
---
datafusion/sql/src/expr/mod.rs | 17 +++++++++++++----
datafusion/sql/tests/sql_integration.rs | 24 ++++++++++++++++++++++--
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs
index fefbf134bd..d599373f0a 100644
--- a/datafusion/sql/src/expr/mod.rs
+++ b/datafusion/sql/src/expr/mod.rs
@@ -306,10 +306,19 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
data_type,
value,
uses_odbc_syntax: _,
- }) => Ok(Expr::Cast(Cast::new_from_field(
- Box::new(lit(value.into_string().unwrap())),
- self.convert_data_type_to_field(&data_type)?,
- ))),
+ }) => {
+ let value = match value.into_string() {
+ Some(value) => value,
+ None => {
+ return plan_err!("Typed literal requires a string payload");
+ }
+ };
+
+ Ok(Expr::Cast(Cast::new_from_field(
+ Box::new(lit(value)),
+ self.convert_data_type_to_field(&data_type)?,
+ )))
+ }
SQLExpr::IsNull(expr) => Ok(Expr::IsNull(Box::new(
self.sql_expr_to_logical_expr(*expr, schema, planner_context)?,
diff --git a/datafusion/sql/tests/sql_integration.rs b/datafusion/sql/tests/sql_integration.rs
index 2c2c7eac8b..574468f4b1 100644
--- a/datafusion/sql/tests/sql_integration.rs
+++ b/datafusion/sql/tests/sql_integration.rs
@@ -26,7 +26,7 @@ use std::vec;
use arrow::datatypes::{TimeUnit::Nanosecond, *};
use common::MockContextProvider;
-use datafusion_common::{DataFusionError, Result, assert_contains};
+use datafusion_common::{DFSchema, DataFusionError, Result, assert_contains};
use datafusion_expr::{
ColumnarValue, CreateIndex, DdlStatement, ScalarFunctionArgs, ScalarUDF,
ScalarUDFImpl, Signature, Volatility, col, logical_plan::LogicalPlan,
@@ -35,7 +35,7 @@ use datafusion_expr::{
use datafusion_functions::{string, unicode};
use datafusion_sql::{
parser::DFParser,
- planner::{NullOrdering, ParserOptions, SqlToRel},
+ planner::{NullOrdering, ParserOptions, PlannerContext, SqlToRel},
};
use crate::common::{CustomExprPlanner, CustomTypePlanner, MockSessionState};
@@ -52,6 +52,7 @@ use datafusion_functions_window::{rank::rank_udwf, row_number::row_number_udwf};
use insta::{allow_duplicates, assert_snapshot};
use rstest::rstest;
use sqlparser::dialect::{Dialect, GenericDialect, HiveDialect, MySqlDialect};
+use sqlparser::parser::Parser;
mod cases;
mod common;
@@ -254,6 +255,25 @@ fn within_group_rejected_for_non_ordered_set_udaf() {
);
}
+#[test]
+fn typed_literal_without_string_payload_returns_error() {
+ let sql_expr = Parser::new(&GenericDialect {})
+ .try_with_sql("time 17542368000000000")
+ .unwrap()
+ .parse_expr()
+ .unwrap();
+ let context = MockContextProvider {
+ state: MockSessionState::default(),
+ };
+ let sql_to_rel = SqlToRel::new(&context);
+
+ let err = sql_to_rel
+ .sql_to_expr(sql_expr, &DFSchema::empty(), &mut PlannerContext::new())
+ .expect_err("planning invalid typed literals should return an error");
+
+ assert_contains!(err.to_string(), "Typed literal requires a string payload");
+}
+
#[test]
fn parse_ident_normalization_5() {
let sql = "SELECT AGE FROM PERSON";
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org