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++) {

Reply via email to