|
17 | 17 | package org.apache.spark.sql.delta
|
18 | 18 |
|
19 | 19 | // scalastyle:off import.ordering.noEmptyLine
|
20 |
| -import org.apache.spark.sql.delta.DeltaTestUtils.BOOLEAN_DOMAIN |
21 |
| -import org.apache.spark.sql.delta.commands.cdc.CDCReader |
22 | 20 | import org.apache.spark.sql.delta.sources.DeltaSQLConf
|
23 | 21 |
|
24 | 22 | import org.apache.spark.sql.Row
|
25 | 23 |
|
26 | 24 | trait MergeIntoNotMatchedBySourceSuite extends MergeIntoSuiteBase {
|
27 | 25 | import testImplicits._
|
28 | 26 |
|
29 |
| - // All CDC suites run using MergeIntoSQLSuite only. The SQL API for NOT MATCHED BY SOURCE will |
30 |
| - // only be available with Spark 3.4. In the meantime, we explicitly run NOT MATCHED BY SOURCE |
31 |
| - // tests with CDF enabled and disabled against the Scala API. Use [[testExtendedMerge] |
32 |
| - // instead once we can run tests against the SQL API. |
| 27 | + /** |
| 28 | + * Variant of `testExtendedMerge` that runs a MERGE INTO command, checks the expected result and |
| 29 | + * additionally validate that the CDC produced is correct. |
| 30 | + */ |
33 | 31 | protected def testExtendedMergeWithCDC(
|
34 | 32 | name: String,
|
35 | 33 | namePrefix: String = "not matched by source")(
|
@@ -65,74 +63,87 @@ trait MergeIntoNotMatchedBySourceSuite extends MergeIntoSuiteBase {
|
65 | 63 | }
|
66 | 64 |
|
67 | 65 | // Test analysis errors with NOT MATCHED BY SOURCE clauses.
|
68 |
| - testErrorsInUnlimitedClauses( |
| 66 | + testMergeAnalysisException( |
69 | 67 | "error on multiple not matched by source update clauses without condition")(
|
70 | 68 | mergeOn = "s.key = t.key",
|
71 | 69 | updateNotMatched(condition = "t.key == 3", set = "value = 2 * value"),
|
72 | 70 | updateNotMatched(set = "value = 3 * value"),
|
73 | 71 | updateNotMatched(set = "value = 4 * value"))(
|
74 |
| - errorStrs = "when there are more than one not matched by source clauses in a merge " + |
75 |
| - "statement, only the last not matched by source clause can omit the condition" :: Nil) |
| 72 | + expectedErrorClass = "NON_LAST_NOT_MATCHED_BY_SOURCE_CLAUSE_OMIT_CONDITION", |
| 73 | + expectedMessageParameters = Map.empty) |
76 | 74 |
|
77 |
| - testErrorsInUnlimitedClauses( |
| 75 | + testMergeAnalysisException( |
78 | 76 | "error on multiple not matched by source update/delete clauses without condition")(
|
79 | 77 | mergeOn = "s.key = t.key",
|
80 | 78 | updateNotMatched(condition = "t.key == 3", set = "value = 2 * value"),
|
81 | 79 | deleteNotMatched(),
|
82 | 80 | updateNotMatched(set = "value = 4 * value"))(
|
83 |
| - errorStrs = "when there are more than one not matched by source clauses in a merge " + |
84 |
| - "statement, only the last not matched by source clause can omit the condition" :: Nil) |
| 81 | + expectedErrorClass = "NON_LAST_NOT_MATCHED_BY_SOURCE_CLAUSE_OMIT_CONDITION", |
| 82 | + expectedMessageParameters = Map.empty) |
85 | 83 |
|
86 |
| - testErrorsInUnlimitedClauses( |
| 84 | + testMergeAnalysisException( |
87 | 85 | "error on non-empty condition following empty condition in not matched by source " +
|
88 | 86 | "update clauses")(
|
89 | 87 | mergeOn = "s.key = t.key",
|
90 | 88 | updateNotMatched(set = "value = 2 * value"),
|
91 | 89 | updateNotMatched(condition = "t.key < 3", set = "value = value"))(
|
92 |
| - errorStrs = "when there are more than one not matched by source clauses in a merge " + |
93 |
| - "statement, only the last not matched by source clause can omit the condition" :: Nil) |
| 90 | + expectedErrorClass = "NON_LAST_NOT_MATCHED_BY_SOURCE_CLAUSE_OMIT_CONDITION", |
| 91 | + expectedMessageParameters = Map.empty) |
94 | 92 |
|
95 |
| - testErrorsInUnlimitedClauses( |
| 93 | + testMergeAnalysisException( |
96 | 94 | "error on non-empty condition following empty condition in not matched by source " +
|
97 | 95 | "delete clauses")(
|
98 | 96 | mergeOn = "s.key = t.key",
|
99 | 97 | deleteNotMatched(),
|
100 | 98 | deleteNotMatched(condition = "t.key < 3"))(
|
101 |
| - errorStrs = "when there are more than one not matched by source clauses in a merge " + |
102 |
| - "statement, only the last not matched by source clause can omit the condition" :: Nil) |
| 99 | + expectedErrorClass = "NON_LAST_NOT_MATCHED_BY_SOURCE_CLAUSE_OMIT_CONDITION", |
| 100 | + expectedMessageParameters = Map.empty) |
103 | 101 |
|
104 |
| - testAnalysisErrorsInExtendedMerge("update not matched condition - unknown reference")( |
| 102 | + testMergeAnalysisException("update not matched condition - unknown reference")( |
105 | 103 | mergeOn = "s.key = t.key",
|
106 | 104 | updateNotMatched(condition = "unknownAttrib > 1", set = "tgtValue = tgtValue + 1"))(
|
107 |
| - // Should show unknownAttrib as invalid ref and (key, tgtValue, srcValue) as valid column names. |
108 |
| - errorStrs = "UPDATE condition" :: "unknownAttrib" :: "key" :: "tgtValue" :: Nil) |
| 105 | + expectedErrorClass = "DELTA_MERGE_UNRESOLVED_EXPRESSION", |
| 106 | + expectedMessageParameters = Map( |
| 107 | + "sqlExpr" -> "unknownAttrib", |
| 108 | + "clause" -> "UPDATE condition", |
| 109 | + "cols" -> "t.key, t.tgtValue")) |
109 | 110 |
|
110 |
| - testAnalysisErrorsInExtendedMerge("update not matched condition - aggregation function")( |
| 111 | + testMergeAnalysisException("update not matched condition - aggregation function")( |
111 | 112 | mergeOn = "s.key = t.key",
|
112 | 113 | updateNotMatched(condition = "max(0) > 0", set = "tgtValue = tgtValue + 1"))(
|
113 |
| - errorStrs = "UPDATE condition" :: "aggregate functions are not supported" :: Nil) |
| 114 | + expectedErrorClass = "DELTA_AGGREGATION_NOT_SUPPORTED", |
| 115 | + expectedMessageParameters = Map( |
| 116 | + "operation" -> "UPDATE condition of MERGE operation", |
| 117 | + "predicate" -> "(condition = (max(0) > 0)).")) |
114 | 118 |
|
115 |
| - testAnalysisErrorsInExtendedMerge("update not matched condition - subquery")( |
| 119 | + testMergeAnalysisException("update not matched condition - subquery")( |
116 | 120 | mergeOn = "s.key = t.key",
|
117 |
| - updateNotMatched(condition = "s.value in (select value from t)", set = "tgtValue = 1"))( |
118 |
| - errorStrs = Nil |
119 |
| - ) // subqueries fail for unresolved reference to `t` |
| 121 | + updateNotMatched(condition = "tgtValue in (select value from t)", set = "tgtValue = 1"))( |
| 122 | + expectedErrorClass = "TABLE_OR_VIEW_NOT_FOUND", |
| 123 | + expectedMessageParameters = Map("relationName" -> "`t`")) |
120 | 124 |
|
121 |
| - testAnalysisErrorsInExtendedMerge("delete not matched condition - unknown reference")( |
| 125 | + testMergeAnalysisException("delete not matched condition - unknown reference")( |
122 | 126 | mergeOn = "s.key = t.key",
|
123 | 127 | deleteNotMatched(condition = "unknownAttrib > 1"))(
|
124 |
| - // Should show unknownAttrib as invalid ref and (key, tgtValue, srcValue) as valid column names. |
125 |
| - errorStrs = "DELETE condition" :: "unknownAttrib" :: "key" :: "tgtValue" :: Nil) |
| 128 | + expectedErrorClass = "DELTA_MERGE_UNRESOLVED_EXPRESSION", |
| 129 | + expectedMessageParameters = Map( |
| 130 | + "sqlExpr" -> "unknownAttrib", |
| 131 | + "clause" -> "DELETE condition", |
| 132 | + "cols" -> "t.key, t.tgtValue")) |
126 | 133 |
|
127 |
| - testAnalysisErrorsInExtendedMerge("delete not matched condition - aggregation function")( |
| 134 | + testMergeAnalysisException("delete not matched condition - aggregation function")( |
128 | 135 | mergeOn = "s.key = t.key",
|
129 | 136 | deleteNotMatched(condition = "max(0) > 0"))(
|
130 |
| - errorStrs = "DELETE condition" :: "aggregate functions are not supported" :: Nil) |
| 137 | + expectedErrorClass = "DELTA_AGGREGATION_NOT_SUPPORTED", |
| 138 | + expectedMessageParameters = Map( |
| 139 | + "operation" -> "DELETE condition of MERGE operation", |
| 140 | + "predicate" -> "(condition = (max(0) > 0)).")) |
131 | 141 |
|
132 |
| - testAnalysisErrorsInExtendedMerge("delete not matched condition - subquery")( |
| 142 | + testMergeAnalysisException("delete not matched condition - subquery")( |
133 | 143 | mergeOn = "s.key = t.key",
|
134 |
| - deleteNotMatched(condition = "s.srcValue in (select tgtValue from t)"))( |
135 |
| - errorStrs = Nil) // subqueries fail for unresolved reference to `t` |
| 144 | + deleteNotMatched(condition = "tgtValue in (select tgtValue from t)"))( |
| 145 | + expectedErrorClass = "TABLE_OR_VIEW_NOT_FOUND", |
| 146 | + expectedMessageParameters = Map("relationName" -> "`t`")) |
136 | 147 |
|
137 | 148 | // Test correctness with NOT MATCHED BY SOURCE clauses.
|
138 | 149 | testExtendedMergeWithCDC("all 3 types of match clauses without conditions")(
|
|
0 commit comments