This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new c89cb70781 Add Explicit Error Handling for Unsupported SQL `FETCH`
Clause in Planner and CLI (#18691)
c89cb70781 is described below
commit c89cb70781dd3e8c52f7cbfff51c2b850900a132
Author: kosiew <[email protected]>
AuthorDate: Mon Dec 1 16:16:32 2025 +0800
Add Explicit Error Handling for Unsupported SQL `FETCH` Clause in Planner
and CLI (#18691)
## Which issue does this PR close?
* Closes #17716.
## Rationale for this change
The `FETCH NEXT` clause was being parsed without triggering an error,
resulting in the CLI executing queries containing unsupported SQL
syntax. This could mislead users into believing the feature is supported
and undermine SQL correctness guarantees. Adding explicit handling
ensures unsupported syntax fails fast with a clear and consistent error
message.
## What changes are included in this PR?
* Added explicit detection of the `FETCH` clause in `SqlToRel` and
return a `not_impl_err!` when encountered.
* Updated CLI integration tests to include a snapshot verifying that the
CLI now returns an error when `FETCH` is used.
* Added a SQL integration test confirming that the planner correctly
rejects `FETCH`.
* Updated user documentation to note that DataFusion does not currently
support the SQL `FETCH` clause.
## Are these changes tested?
Yes. The PR includes:
* A new CLI integration test snapshot validating the error message.
* A new SQL integration test (`fetch_clause_is_not_supported`) verifying
planner behavior.
## Are there any user-facing changes?
Yes. Queries using the SQL `FETCH` clause will now produce a clear error
instead of executing unexpectedly. Documentation has been updated to
reflect this behavior.
## LLM-generated code disclosure
This pull request includes code that was generated with assistance from
LLM.
All LLM-generated code in this PR has been manually reviewed and tested.
---
datafusion/sql/src/query.rs | 31 +++++++++++++++++++++------
datafusion/sql/tests/sql_integration.rs | 7 ++++++
datafusion/sqllogictest/test_files/errors.slt | 5 +++++
3 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/datafusion/sql/src/query.rs b/datafusion/sql/src/query.rs
index d316550f4d..6a9267a9a5 100644
--- a/datafusion/sql/src/query.rs
+++ b/datafusion/sql/src/query.rs
@@ -46,17 +46,34 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
let mut query_plan_context = outer_planner_context.clone();
let planner_context = &mut query_plan_context;
- if let Some(with) = query.with {
+ let Query {
+ with,
+ body,
+ order_by,
+ limit_clause,
+ fetch,
+ locks: _,
+ for_clause: _,
+ settings: _,
+ format_clause: _,
+ pipe_operators,
+ } = query;
+
+ if fetch.is_some() {
+ return not_impl_err!("FETCH clause is not supported yet");
+ }
+
+ if let Some(with) = with {
self.plan_with_clause(with, planner_context)?;
}
- let set_expr = *query.body;
+ let set_expr = *body;
let plan = match set_expr {
SetExpr::Select(mut select) => {
let select_into = select.into.take();
let plan =
- self.select_to_plan(*select, query.order_by,
planner_context)?;
- let plan = self.limit(plan, query.limit_clause,
planner_context)?;
+ self.select_to_plan(*select, order_by.clone(),
planner_context)?;
+ let plan = self.limit(plan, limit_clause.clone(),
planner_context)?;
// Process the `SELECT INTO` after `LIMIT`.
self.select_into(plan, select_into)
}
@@ -69,7 +86,7 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
let _guard = StackGuard::new(256 * 1024);
self.set_expr_to_plan(other, planner_context)
}?;
- let oby_exprs = to_order_by_exprs(query.order_by)?;
+ let oby_exprs = to_order_by_exprs(order_by)?;
let order_by_rex = self.order_by_to_sort_expr(
oby_exprs,
plan.schema(),
@@ -78,11 +95,11 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
None,
)?;
let plan = self.order_by(plan, order_by_rex)?;
- self.limit(plan, query.limit_clause, planner_context)
+ self.limit(plan, limit_clause, planner_context)
}
}?;
- self.pipe_operators(plan, query.pipe_operators, planner_context)
+ self.pipe_operators(plan, pipe_operators, planner_context)
}
/// Apply pipe operators to a plan
diff --git a/datafusion/sql/tests/sql_integration.rs
b/datafusion/sql/tests/sql_integration.rs
index 7615891be3..c52b09afce 100644
--- a/datafusion/sql/tests/sql_integration.rs
+++ b/datafusion/sql/tests/sql_integration.rs
@@ -3971,6 +3971,13 @@ Limit: skip=3, fetch=5
);
}
+#[test]
+fn fetch_clause_is_not_supported() {
+ let sql = "SELECT 1 FETCH NEXT 1 ROW ONLY";
+ let err = logical_plan(sql).unwrap_err();
+ assert_contains!(err.to_string(), "FETCH clause is not supported yet");
+}
+
#[test]
fn test_offset_before_limit() {
let sql = "select id from person where person.id > 100 OFFSET 3 LIMIT 5;";
diff --git a/datafusion/sqllogictest/test_files/errors.slt
b/datafusion/sqllogictest/test_files/errors.slt
index 41f747df5b..22430774bb 100644
--- a/datafusion/sqllogictest/test_files/errors.slt
+++ b/datafusion/sqllogictest/test_files/errors.slt
@@ -74,6 +74,11 @@ statement error DataFusion error: Error during planning:
Unsupported compound id
SELECT COUNT(*) FROM
way.too.many.namespaces.as.ident.prefixes.aggregate_test_100
+# fetch_clause_not_supported
+statement error FETCH clause is not supported yet
+SELECT 1 FETCH NEXT 1 ROW ONLY
+
+
#
# Wrong scalar function signature
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]