Skip to content

Commit 984a2ec

Browse files
committed
[SPARK-52142][SQL] Display table constraints in SHOW CREATE TABLE COMMAND
### What changes were proposed in this pull request? Display table constraints in the SHOW CREATE TABLE COMMAND ### Why are the changes needed? Displaying table constraints is expected for the SHOW CREATE TABLE COMMAND ### 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? No Closes #51541 from gengliangwang/showCreateTable. Authored-by: Gengliang Wang <[email protected]> Signed-off-by: Gengliang Wang <[email protected]>
1 parent 3d99b0b commit 984a2ec

File tree

8 files changed

+117
-49
lines changed

8 files changed

+117
-49
lines changed

sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/constraints/BaseConstraint.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ public boolean rely() {
6363

6464
@Override
6565
public String toDDL() {
66+
// The validation status is not included in the DDL output as it's not part of
67+
// the Spark SQL syntax for constraints.
6668
return String.format(
67-
"CONSTRAINT %s %s %s %s %s",
69+
"CONSTRAINT %s %s %s %s",
6870
name,
6971
definition(),
7072
enforced ? "ENFORCED" : "NOT ENFORCED",
71-
validationStatus,
7273
rely ? "RELY" : "NORELY");
7374
}
7475

sql/catalyst/src/test/scala/org/apache/spark/sql/connector/catalog/ConstraintSuite.scala

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class ConstraintSuite extends SparkFunSuite {
3333
.validationStatus(ValidationStatus.VALID)
3434
.rely(true)
3535
.build()
36-
assert(con1.toDDL == "CONSTRAINT con1 CHECK (id > 10) ENFORCED VALID RELY")
36+
assert(con1.toDDL == "CONSTRAINT con1 CHECK (id > 10) ENFORCED RELY")
37+
assert(con1.validationStatus() == ValidationStatus.VALID)
3738

3839
val con2 = Constraint.check("con2")
3940
.predicate(
@@ -46,7 +47,8 @@ class ConstraintSuite extends SparkFunSuite {
4647
.validationStatus(ValidationStatus.VALID)
4748
.rely(true)
4849
.build()
49-
assert(con2.toDDL == "CONSTRAINT con2 CHECK (a.`b.c`.d = 1) NOT ENFORCED VALID RELY")
50+
assert(con2.toDDL == "CONSTRAINT con2 CHECK (a.`b.c`.d = 1) NOT ENFORCED RELY")
51+
assert(con2.validationStatus() == ValidationStatus.VALID)
5052

5153
val con3 = Constraint.check("con3")
5254
.predicateSql("a.b.c <=> 1")
@@ -60,10 +62,12 @@ class ConstraintSuite extends SparkFunSuite {
6062
.validationStatus(ValidationStatus.INVALID)
6163
.rely(false)
6264
.build()
63-
assert(con3.toDDL == "CONSTRAINT con3 CHECK (a.b.c <=> 1) NOT ENFORCED INVALID NORELY")
65+
assert(con3.toDDL == "CONSTRAINT con3 CHECK (a.b.c <=> 1) NOT ENFORCED NORELY")
66+
assert(con3.validationStatus() == ValidationStatus.INVALID)
6467

6568
val con4 = Constraint.check("con4").predicateSql("a = 1").build()
66-
assert(con4.toDDL == "CONSTRAINT con4 CHECK (a = 1) ENFORCED UNVALIDATED NORELY")
69+
assert(con4.toDDL == "CONSTRAINT con4 CHECK (a = 1) ENFORCED NORELY")
70+
assert(con4.validationStatus() == ValidationStatus.UNVALIDATED)
6771
}
6872

6973
test("UNIQUE constraint toDDL") {
@@ -74,7 +78,8 @@ class ConstraintSuite extends SparkFunSuite {
7478
.validationStatus(ValidationStatus.UNVALIDATED)
7579
.rely(true)
7680
.build()
77-
assert(con1.toDDL == "CONSTRAINT con1 UNIQUE (a.b.c, d) NOT ENFORCED UNVALIDATED RELY")
81+
assert(con1.toDDL == "CONSTRAINT con1 UNIQUE (a.b.c, d) NOT ENFORCED RELY")
82+
assert(con1.validationStatus() == ValidationStatus.UNVALIDATED)
7883

7984
val con2 = Constraint.unique(
8085
"con2",
@@ -83,7 +88,8 @@ class ConstraintSuite extends SparkFunSuite {
8388
.validationStatus(ValidationStatus.VALID)
8489
.rely(true)
8590
.build()
86-
assert(con2.toDDL == "CONSTRAINT con2 UNIQUE (`a.b`.x.y, d) NOT ENFORCED VALID RELY")
91+
assert(con2.toDDL == "CONSTRAINT con2 UNIQUE (`a.b`.x.y, d) NOT ENFORCED RELY")
92+
assert(con2.validationStatus() == ValidationStatus.VALID)
8793
}
8894

8995
test("PRIMARY KEY constraint toDDL") {
@@ -94,7 +100,8 @@ class ConstraintSuite extends SparkFunSuite {
94100
.validationStatus(ValidationStatus.VALID)
95101
.rely(true)
96102
.build()
97-
assert(pk1.toDDL == "CONSTRAINT pk1 PRIMARY KEY (a.b.c, d) ENFORCED VALID RELY")
103+
assert(pk1.toDDL == "CONSTRAINT pk1 PRIMARY KEY (a.b.c, d) ENFORCED RELY")
104+
assert(pk1.validationStatus() == ValidationStatus.VALID)
98105

99106
val pk2 = Constraint.primaryKey(
100107
"pk2",
@@ -103,7 +110,8 @@ class ConstraintSuite extends SparkFunSuite {
103110
.validationStatus(ValidationStatus.INVALID)
104111
.rely(false)
105112
.build()
106-
assert(pk2.toDDL == "CONSTRAINT pk2 PRIMARY KEY (`x.y`.z, id) NOT ENFORCED INVALID NORELY")
113+
assert(pk2.toDDL == "CONSTRAINT pk2 PRIMARY KEY (`x.y`.z, id) NOT ENFORCED NORELY")
114+
assert(pk2.validationStatus() == ValidationStatus.INVALID)
107115
}
108116

109117
test("FOREIGN KEY constraint toDDL") {
@@ -118,7 +126,8 @@ class ConstraintSuite extends SparkFunSuite {
118126
.build()
119127
assert(fk1.toDDL == "CONSTRAINT fk1 FOREIGN KEY (col1, col2) " +
120128
"REFERENCES schema.table (ref_col1, ref_col2) " +
121-
"ENFORCED VALID RELY")
129+
"ENFORCED RELY")
130+
assert(fk1.validationStatus() == ValidationStatus.VALID)
122131

123132
val fk2 = Constraint.foreignKey(
124133
"fk2",
@@ -131,6 +140,7 @@ class ConstraintSuite extends SparkFunSuite {
131140
.build()
132141
assert(fk2.toDDL == "CONSTRAINT fk2 FOREIGN KEY (`x.y`.z) " +
133142
"REFERENCES other_table (other_id) " +
134-
"NOT ENFORCED INVALID NORELY")
143+
"NOT ENFORCED NORELY")
144+
assert(fk2.validationStatus() == ValidationStatus.INVALID)
135145
}
136146
}

sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/v2/ShowCreateTableExec.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ case class ShowCreateTableExec(
6565
private def showTableDataColumns(table: Table, builder: StringBuilder): Unit = {
6666
import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._
6767
val columns = CharVarcharUtils.getRawSchema(table.columns.asSchema, conf).fields.map(_.toDDL)
68-
builder ++= concatByMultiLines(columns)
68+
val constraints = table.constraints().map(_.toDDL)
69+
builder ++= concatByMultiLines(columns ++ constraints)
6970
}
7071

7172
private def showTableUsing(table: Table, builder: StringBuilder): Unit = {

sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/CheckConstraintSuite.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,20 +134,20 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
134134
val constraint = getCheckConstraint(table)
135135
assert(constraint.name() == "c1")
136136
assert(constraint.toDDL ==
137-
"CONSTRAINT c1 CHECK (from_json(j, 'a INT').a > 1) ENFORCED VALID NORELY")
137+
"CONSTRAINT c1 CHECK (from_json(j, 'a INT').a > 1) ENFORCED NORELY")
138138
assert(constraint.predicateSql() == "from_json(j, 'a INT').a > 1")
139139
assert(constraint.predicate() == null)
140140
}
141141
}
142142

143143
def getConstraintCharacteristics(): Seq[(String, String)] = {
144144
Seq(
145-
("", s"ENFORCED VALID NORELY"),
146-
("NORELY", s"ENFORCED VALID NORELY"),
147-
("RELY", s"ENFORCED VALID RELY"),
148-
("ENFORCED", s"ENFORCED VALID NORELY"),
149-
("ENFORCED NORELY", s"ENFORCED VALID NORELY"),
150-
("ENFORCED RELY", s"ENFORCED VALID RELY")
145+
("", s"ENFORCED NORELY"),
146+
("NORELY", s"ENFORCED NORELY"),
147+
("RELY", s"ENFORCED RELY"),
148+
("ENFORCED", s"ENFORCED NORELY"),
149+
("ENFORCED NORELY", s"ENFORCED NORELY"),
150+
("ENFORCED RELY", s"ENFORCED RELY")
151151
)
152152
}
153153

@@ -176,7 +176,7 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
176176
val constraint = getCheckConstraint(table)
177177
assert(constraint.name() == "c1")
178178
assert(constraint.toDDL ==
179-
s"CONSTRAINT c1 CHECK (LENGTH(name) > 0) ENFORCED VALID NORELY")
179+
s"CONSTRAINT c1 CHECK (LENGTH(name) > 0) ENFORCED NORELY")
180180
assert(constraint.predicateSql() == "LENGTH(name) > 0")
181181
}
182182
}
@@ -258,7 +258,7 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
258258
val constraint = getCheckConstraint(table)
259259
assert(constraint.name() == "valid_positive_num")
260260
assert(constraint.toDDL ==
261-
"CONSTRAINT valid_positive_num CHECK (s.num >= -1) ENFORCED VALID NORELY")
261+
"CONSTRAINT valid_positive_num CHECK (s.num >= -1) ENFORCED NORELY")
262262
}
263263
}
264264

@@ -288,7 +288,7 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
288288
val constraint = getCheckConstraint(table)
289289
assert(constraint.name() == "valid_map_val")
290290
assert(constraint.toDDL ==
291-
"CONSTRAINT valid_map_val CHECK (m['a'] >= -1) ENFORCED VALID NORELY")
291+
"CONSTRAINT valid_map_val CHECK (m['a'] >= -1) ENFORCED NORELY")
292292
}
293293
}
294294

@@ -316,7 +316,7 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
316316
val constraint = getCheckConstraint(table)
317317
assert(constraint.name() == "valid_array")
318318
assert(constraint.toDDL ==
319-
"CONSTRAINT valid_array CHECK (a[1] >= -2) ENFORCED VALID NORELY")
319+
"CONSTRAINT valid_array CHECK (a[1] >= -2) ENFORCED NORELY")
320320
}
321321
}
322322

@@ -336,7 +336,7 @@ class CheckConstraintSuite extends QueryTest with CommandSuiteBase with DDLComma
336336
condition = "CONSTRAINT_ALREADY_EXISTS",
337337
sqlState = "42710",
338338
parameters = Map("constraintName" -> "abc",
339-
"oldConstraint" -> "CONSTRAINT abc CHECK (id > 0) ENFORCED VALID NORELY")
339+
"oldConstraint" -> "CONSTRAINT abc CHECK (id > 0) ENFORCED NORELY")
340340
)
341341
}
342342
}

sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ForeignKeyConstraintSuite.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class ForeignKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
2323
override protected def command: String = "FOREIGN KEY CONSTRAINT"
2424

2525
private val validConstraintCharacteristics = Seq(
26-
("", "NOT ENFORCED UNVALIDATED NORELY"),
27-
("NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
28-
("NOT ENFORCED NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
29-
("NORELY NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
30-
("NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
31-
("RELY", "NOT ENFORCED UNVALIDATED RELY")
26+
("", "NOT ENFORCED NORELY"),
27+
("NOT ENFORCED", "NOT ENFORCED NORELY"),
28+
("NOT ENFORCED NORELY", "NOT ENFORCED NORELY"),
29+
("NORELY NOT ENFORCED", "NOT ENFORCED NORELY"),
30+
("NORELY", "NOT ENFORCED NORELY"),
31+
("RELY", "NOT ENFORCED RELY")
3232
)
3333

3434
test("Add foreign key constraint") {
@@ -104,7 +104,7 @@ class ForeignKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
104104
parameters = Map("constraintName" -> "fk1",
105105
"oldConstraint" ->
106106
("CONSTRAINT fk1 FOREIGN KEY (fk) " +
107-
"REFERENCES test_catalog.ns.tbl_ref (id) NOT ENFORCED UNVALIDATED NORELY"))
107+
"REFERENCES test_catalog.ns.tbl_ref (id) NOT ENFORCED NORELY"))
108108
)
109109
}
110110
}
@@ -124,7 +124,7 @@ class ForeignKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
124124
assert(constraint.name() == "fk1")
125125
assert(constraint.toDDL ==
126126
s"CONSTRAINT fk1 FOREIGN KEY (fk1, fk2) " +
127-
s"REFERENCES test_catalog.ns.tbl_ref (id1, id2) NOT ENFORCED UNVALIDATED NORELY")
127+
s"REFERENCES test_catalog.ns.tbl_ref (id1, id2) NOT ENFORCED NORELY")
128128
}
129129
}
130130
}

sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/PrimaryKeyConstraintSuite.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class PrimaryKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
2323
override protected def command: String = "PRIMARY KEY CONSTRAINT"
2424

2525
private val validConstraintCharacteristics = Seq(
26-
("", "NOT ENFORCED UNVALIDATED NORELY"),
27-
("NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
28-
("NOT ENFORCED NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
29-
("NORELY NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
30-
("NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
31-
("RELY", "NOT ENFORCED UNVALIDATED RELY")
26+
("", "NOT ENFORCED NORELY"),
27+
("NOT ENFORCED", "NOT ENFORCED NORELY"),
28+
("NOT ENFORCED NORELY", "NOT ENFORCED NORELY"),
29+
("NORELY NOT ENFORCED", "NOT ENFORCED NORELY"),
30+
("NORELY", "NOT ENFORCED NORELY"),
31+
("RELY", "NOT ENFORCED RELY")
3232
)
3333

3434
test("Add primary key constraint") {
@@ -92,7 +92,7 @@ class PrimaryKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
9292
condition = "CONSTRAINT_ALREADY_EXISTS",
9393
sqlState = "42710",
9494
parameters = Map("constraintName" -> "pk1",
95-
"oldConstraint" -> "CONSTRAINT pk1 PRIMARY KEY (id) NOT ENFORCED UNVALIDATED NORELY")
95+
"oldConstraint" -> "CONSTRAINT pk1 PRIMARY KEY (id) NOT ENFORCED NORELY")
9696
)
9797
}
9898
}
@@ -109,7 +109,7 @@ class PrimaryKeyConstraintSuite extends QueryTest with CommandSuiteBase with DDL
109109
val constraint = table.constraints.head
110110
assert(constraint.name() == "pk1")
111111
assert(constraint.toDDL ==
112-
"CONSTRAINT pk1 PRIMARY KEY (id1, id2) NOT ENFORCED UNVALIDATED NORELY")
112+
"CONSTRAINT pk1 PRIMARY KEY (id1, id2) NOT ENFORCED NORELY")
113113
}
114114
}
115115
}

sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/ShowCreateTableSuite.scala

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,60 @@ class ShowCreateTableSuite extends command.ShowCreateTableSuiteBase with Command
181181
)
182182
}
183183
}
184+
185+
test("show table constraints") {
186+
withNamespaceAndTable("ns", "tbl", nonPartitionCatalog) { t =>
187+
withTable("other_table") {
188+
sql(
189+
s"""
190+
|CREATE TABLE other_table (
191+
| id STRING PRIMARY KEY
192+
|)
193+
|USING parquet
194+
""".stripMargin)
195+
sql(
196+
s"""
197+
|CREATE TABLE $t (
198+
| a INT,
199+
| b STRING,
200+
| c STRING,
201+
| PRIMARY KEY (a),
202+
| CONSTRAINT uk_b UNIQUE (b),
203+
| CONSTRAINT fk_c FOREIGN KEY (c) REFERENCES other_table(id) RELY,
204+
| CONSTRAINT c1 CHECK (c IS NOT NULL),
205+
| CONSTRAINT c2 CHECK (a > 0)
206+
|)
207+
|$defaultUsing
208+
""".stripMargin)
209+
var showDDL = getShowCreateDDL(t)
210+
val expectedDDLPrefix = Array(
211+
s"CREATE TABLE $nonPartitionCatalog.ns.tbl (",
212+
"a INT NOT NULL,",
213+
"b STRING,",
214+
"c STRING,",
215+
"CONSTRAINT tbl_pk PRIMARY KEY (a) NOT ENFORCED NORELY,",
216+
"CONSTRAINT uk_b UNIQUE (b) NOT ENFORCED NORELY,",
217+
"CONSTRAINT fk_c FOREIGN KEY (c) REFERENCES other_table (id) NOT ENFORCED RELY,",
218+
"CONSTRAINT c1 CHECK (c IS NOT NULL) ENFORCED NORELY,"
219+
)
220+
assert(showDDL === expectedDDLPrefix ++ Array(
221+
"CONSTRAINT c2 CHECK (a > 0) ENFORCED NORELY)",
222+
defaultUsing))
223+
224+
sql(s"ALTER TABLE $t ADD CONSTRAINT c3 CHECK (b IS NOT NULL) ENFORCED RELY")
225+
showDDL = getShowCreateDDL(t)
226+
val expectedDDLArrayWithNewConstraint = expectedDDLPrefix ++ Array(
227+
"CONSTRAINT c2 CHECK (a > 0) ENFORCED NORELY,",
228+
"CONSTRAINT c3 CHECK (b IS NOT NULL) ENFORCED RELY)",
229+
defaultUsing
230+
)
231+
assert(showDDL === expectedDDLArrayWithNewConstraint)
232+
sql(s"ALTER TABLE $t DROP CONSTRAINT c1")
233+
showDDL = getShowCreateDDL(t)
234+
val expectedDDLArrayAfterDrop = expectedDDLArrayWithNewConstraint.filterNot(
235+
_.contains("c1 CHECK (c IS NOT NULL) ENFORCED NORELY"))
236+
assert(showDDL === expectedDDLArrayAfterDrop)
237+
}
238+
}
239+
}
184240
}

sql/core/src/test/scala/org/apache/spark/sql/execution/command/v2/UniqueConstraintSuite.scala

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class UniqueConstraintSuite extends QueryTest with CommandSuiteBase with DDLComm
2323
override protected def command: String = "UNIQUE CONSTRAINT"
2424

2525
private val validConstraintCharacteristics = Seq(
26-
("", "NOT ENFORCED UNVALIDATED NORELY"),
27-
("NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
28-
("NOT ENFORCED NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
29-
("NORELY NOT ENFORCED", "NOT ENFORCED UNVALIDATED NORELY"),
30-
("NORELY", "NOT ENFORCED UNVALIDATED NORELY"),
31-
("RELY", "NOT ENFORCED UNVALIDATED RELY")
26+
("", "NOT ENFORCED NORELY"),
27+
("NOT ENFORCED", "NOT ENFORCED NORELY"),
28+
("NOT ENFORCED NORELY", "NOT ENFORCED NORELY"),
29+
("NORELY NOT ENFORCED", "NOT ENFORCED NORELY"),
30+
("NORELY", "NOT ENFORCED NORELY"),
31+
("RELY", "NOT ENFORCED RELY")
3232
)
3333

3434
test("Add unique constraint") {
@@ -92,7 +92,7 @@ class UniqueConstraintSuite extends QueryTest with CommandSuiteBase with DDLComm
9292
condition = "CONSTRAINT_ALREADY_EXISTS",
9393
sqlState = "42710",
9494
parameters = Map("constraintName" -> "uk1",
95-
"oldConstraint" -> "CONSTRAINT uk1 UNIQUE (id) NOT ENFORCED UNVALIDATED NORELY")
95+
"oldConstraint" -> "CONSTRAINT uk1 UNIQUE (id) NOT ENFORCED NORELY")
9696
)
9797
}
9898
}
@@ -109,7 +109,7 @@ class UniqueConstraintSuite extends QueryTest with CommandSuiteBase with DDLComm
109109
val constraint = table.constraints.head
110110
assert(constraint.name() == "uk1")
111111
assert(constraint.toDDL ==
112-
"CONSTRAINT uk1 UNIQUE (id1, id2) NOT ENFORCED UNVALIDATED NORELY")
112+
"CONSTRAINT uk1 UNIQUE (id1, id2) NOT ENFORCED NORELY")
113113
}
114114
}
115115
}

0 commit comments

Comments
 (0)