This is an automated email from the ASF dual-hosted git repository.
gengliang pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 23e272b1cbb6 [SPARK-55694][SQL] Block constraints in CTAS/RTAS at
parser level
23e272b1cbb6 is described below
commit 23e272b1cbb670a129472f626417259ccfafdade
Author: Yan Yan <[email protected]>
AuthorDate: Wed Feb 25 11:20:49 2026 -0800
[SPARK-55694][SQL] Block constraints in CTAS/RTAS at parser level
### What changes were proposed in this pull request?
The grammar accepts constraint specifications (PRIMARY KEY, UNIQUE, CHECK,
FOREIGN KEY) in CREATE TABLE AS SELECT and REPLACE TABLE AS SELECT, but the
execution layer silently drops them. Neither the ANSI SQL standard nor
PostgreSQL supports this syntax - the SQL standard makes table element lists
and AS subquery clauses mutually exclusive. Block this at the parser level,
consistent with existing CTAS/RTAS checks for schema columns and partition
column types.
### Why are the changes needed?
Explicitly throw exception for an unsupported case for clarity
### Does this PR introduce _any_ user-facing change?
No
### How was this patch tested?
unit test
### Was this patch authored or co-authored using generative AI tooling?
Co-Authored-By: Claude Opus 4.6 <noreplyanthropic.com>
Closes #54454 from yyanyy/block-ctas-constraints.
Authored-by: Yan Yan <[email protected]>
Signed-off-by: Gengliang Wang <[email protected]>
(cherry picked from commit 38a75333db72896318177e241b9d0a45d5b99c7b)
Signed-off-by: Gengliang Wang <[email protected]>
---
.../spark/sql/catalyst/parser/AstBuilder.scala | 10 ++++++++
.../execution/command/PlanResolutionSuite.scala | 30 ++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
index 9adc755730f5..6649568a00b2 100644
---
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
+++
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/AstBuilder.scala
@@ -5125,6 +5125,11 @@ class AstBuilder extends DataTypeAstBuilder
"Partition column types may not be specified in Create Table As
Select (CTAS)",
ctx)
+ case Some(_) if constraints.nonEmpty =>
+ operationNotAllowed(
+ "Constraints may not be specified in a Create Table As Select
(CTAS) statement",
+ ctx)
+
case Some(query) =>
CreateTableAsSelect(identifier, partitioning, query, tableSpec,
Map.empty, ifNotExists)
@@ -5204,6 +5209,11 @@ class AstBuilder extends DataTypeAstBuilder
"Partition column types may not be specified in Replace Table As
Select (RTAS)",
ctx)
+ case Some(_) if constraints.nonEmpty =>
+ operationNotAllowed(
+ "Constraints may not be specified in a Replace Table As Select
(RTAS) statement",
+ ctx)
+
case Some(query) =>
ReplaceTableAsSelect(identifier, partitioning, query, tableSpec,
writeOptions = Map.empty, orCreate = orCreate)
diff --git
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala
index 8e5ee1644f9c..af2efd426b17 100644
---
a/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala
+++
b/sql/core/src/test/scala/org/apache/spark/sql/execution/command/PlanResolutionSuite.scala
@@ -2968,6 +2968,36 @@ class PlanResolutionSuite extends SharedSparkSession
with AnalysisTest {
ExpectedContext(fragment = sql2, start = 0, stop = 61))
}
+ test("CTAS statement with constraints") {
+ Seq(
+ "CONSTRAINT pk PRIMARY KEY (id)",
+ "CONSTRAINT uk UNIQUE (id)",
+ "CONSTRAINT ck CHECK (id > 0)"
+ ).foreach { constraintDef =>
+ val sql = s"CREATE TABLE ctas1 ($constraintDef) AS SELECT 1 AS id"
+ assertUnsupported(
+ sql,
+ Map("message" ->
+ "Constraints may not be specified in a Create Table As Select (CTAS)
statement"),
+ ExpectedContext(fragment = sql, start = 0, stop = sql.length - 1))
+ }
+ }
+
+ test("RTAS statement with constraints") {
+ Seq(
+ "CONSTRAINT pk PRIMARY KEY (id)",
+ "CONSTRAINT uk UNIQUE (id)",
+ "CONSTRAINT ck CHECK (id > 0)"
+ ).foreach { constraintDef =>
+ val sql = s"REPLACE TABLE rtas1 ($constraintDef) AS SELECT 1 AS id"
+ assertUnsupported(
+ sql,
+ Map("message" ->
+ "Constraints may not be specified in a Replace Table As Select
(RTAS) statement"),
+ ExpectedContext(fragment = sql, start = 0, stop = sql.length - 1))
+ }
+ }
+
test("create table - basic") {
val query = "CREATE TABLE my_table (id int, name string)"
val (desc, allowExisting) = extractTableDesc(query)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]