This is an automated email from the ASF dual-hosted git repository.
Dwrite pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new ec84d7d1e7 Allow explicit tables at top-level, e.g. "TABLE emp"
ec84d7d1e7 is described below
commit ec84d7d1e7d686b61f34062a4177ac5f2600be89
Author: Dwrite <[email protected]>
AuthorDate: Tue Oct 20 08:20:04 2026 +0800
Allow explicit tables at top-level, e.g. "TABLE emp"
---
.../java/org/apache/calcite/sql/SqlOrderBy.java | 7 ++-
.../calcite/sql/validate/SqlValidatorImpl.java | 8 ++-
.../java/org/apache/calcite/test/JdbcTest.java | 68 ++++++++++++++++++++++
3 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java
b/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java
index fe22547555..c5da010582 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java
@@ -23,6 +23,8 @@
import java.util.List;
+import static java.util.Objects.requireNonNull;
+
/**
* Parse tree node that represents an {@code ORDER BY} on a query other than a
* {@code SELECT} (e.g. {@code VALUES} or {@code UNION}).
@@ -76,10 +78,10 @@ public SqlOrderBy(SqlParserPos pos, SqlNode query,
SqlNodeList orderList,
@Override public void setOperand(int i, @Nullable SqlNode operand) {
switch (i) {
case 0:
- query = operand;
+ query = requireNonNull(operand, "operand");
break;
case 1:
- orderList = (SqlNodeList) operand;
+ orderList = requireNonNull((SqlNodeList) operand, "orderList");
break;
case 2:
offset = operand;
@@ -91,7 +93,6 @@ public SqlOrderBy(SqlParserPos pos, SqlNode query,
SqlNodeList orderList,
throw new AssertionError(i);
}
}
-
/** Definition of {@code ORDER BY} operator. */
private static class Operator extends SqlSpecialOperator {
private Operator() {
diff --git
a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index fd48733f8c..cb8727f848 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -1265,7 +1265,12 @@ private boolean addOrExpandField(List<SqlNode>
selectItems, Set<String> aliases,
scope = new CatalogScope(scope, ImmutableList.of("CATALOG"));
final SqlNode topNode2 = validateScopedExpression(topNode, scope);
final RelDataType type = getValidatedNodeType(topNode2);
- Util.discard(type);
+ if (topNode2 != topNode) {
+ // The top node was rewritten (for example "TABLE t" becomes
+ // "SELECT * FROM t"). Callers such as Prepare still hold the original
+ // node and ask for its type, so register the type for it as well.
+ setValidatedNodeType(topNode, type);
+ }
return topNode2;
}
@@ -1913,7 +1918,6 @@ && requireNonNull(((SqlNumericLiteral)
node).bigDecimalValue())
type.getFullTypeString()));
}
}
-
/**
* Performs expression rewrites which are always used unconditionally. These
* rewrites massage the expression tree into a standard form so that the
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index d975c5a562..6b81956126 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -9881,6 +9881,74 @@ void checkCalciteSchemaGetSubSchemaMap(boolean cache) {
.returnsUnordered("EMPID=aa");
}
+ /** Tests top-level explicit tables ("TABLE t"), which are equivalent to
+ * "SELECT * FROM t". */
+ @Test void testTopLevelExplicitTable() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table dept")
+ .returnsUnordered(
+ "DEPTNO=10; DNAME=ACCOUNTING; LOC=NEW YORK",
+ "DEPTNO=20; DNAME=RESEARCH; LOC=DALLAS",
+ "DEPTNO=30; DNAME=SALES; LOC=CHICAGO",
+ "DEPTNO=40; DNAME=OPERATIONS; LOC=BOSTON");
+ }
+
+ @Test void testTopLevelExplicitTableOrderBy() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table dept order by deptno desc")
+ .returnsOrdered(
+ "DEPTNO=40; DNAME=OPERATIONS; LOC=BOSTON",
+ "DEPTNO=30; DNAME=SALES; LOC=CHICAGO",
+ "DEPTNO=20; DNAME=RESEARCH; LOC=DALLAS",
+ "DEPTNO=10; DNAME=ACCOUNTING; LOC=NEW YORK");
+ }
+
+ @Test void testTopLevelExplicitTableOrderByOffsetFetch() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table dept order by deptno desc\n"
+ + "offset 1 rows fetch next 2 rows only")
+ .returnsOrdered(
+ "DEPTNO=30; DNAME=SALES; LOC=CHICAGO",
+ "DEPTNO=20; DNAME=RESEARCH; LOC=DALLAS");
+ }
+
+ @Test void testTopLevelExplicitTableQualified() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table dept")
+ .returnsCount(4);
+ }
+
+ /** Control: already worked before the fix. */
+ @Test void testExplicitTableInFrom() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("select * from (table dept)")
+ .returnsCount(4);
+ }
+
+ @Test void testTopLevelExplicitTableUnion() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table dept union all table dept")
+ .returnsCount(8);
+ }
+
+ @Test void testTopLevelExplicitTableInWith() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("with t as (select * from dept) table t")
+ .returnsCount(4);
+ }
+
+ @Test void testExplainTopLevelExplicitTable() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("explain plan for table dept")
+ .returnsCount(1);
+ }
+
+ @Test void testTopLevelExplicitTableNotFound() {
+ CalciteAssert.that().with(CalciteAssert.Config.SCOTT)
+ .query("table nonexistent")
+ .throws_("Object 'NONEXISTENT' not found");
+ }
+
private static String sums(int n, boolean c) {
final StringBuilder b = new StringBuilder();
for (int i = 0; i < n; i++) {