Skip to content

Commit 2836f5a

Browse files
szehon-hodongjoon-hyun
authored andcommitted
[SPARK-54289][SQL][FOLLOW-UP] Make Merge Into update assignment by field default for UPDATE SET * and align configs
### What changes were proposed in this pull request? Follow up of: #53149 1. Make the update assignment by field the Spark 4.1 behavior. For context, the case to allow assignment key and value to be different struct for MERGE INTO is new in Spark 4.1 so we have a chance to define the behavior. In Spark, nested fields are usually treated as top level column so it should follow the behavior: see #53149 (comment) 2. Rename existing config to control the struct type compatibility check in assignment. We do not need to mention 'source' as actually the assignment can be to anything, not necessarily to source table. ### Why are the changes needed? See above ### Does this PR introduce _any_ user-facing change? No, this feature is unreleased (allowing assignment source to be of different struct type as target) ### How was this patch tested? Existing unit test ### Was this patch authored or co-authored using generative AI tooling? No Closes #53199 from szehon-ho/merge_schema_evolution_update_nested_follow. Authored-by: Szehon Ho <szehon.apache@gmail.com> Signed-off-by: Dongjoon Hyun <dongjoon@apache.org> (cherry picked from commit 9846dd8) Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
1 parent 9813870 commit 2836f5a

File tree

4 files changed

+428
-511
lines changed

4 files changed

+428
-511
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AssignmentUtils.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import org.apache.spark.sql.catalyst.util.CharVarcharUtils
2929
import org.apache.spark.sql.catalyst.util.ResolveDefaultColumns.getDefaultValueExprOrNullLit
3030
import org.apache.spark.sql.connector.catalog.CatalogV2Implicits._
3131
import org.apache.spark.sql.errors.QueryCompilationErrors
32-
import org.apache.spark.sql.internal.SQLConf
3332
import org.apache.spark.sql.types.{DataType, StructType}
3433
import org.apache.spark.util.ArrayImplicits._
3534

@@ -183,7 +182,7 @@ object AssignmentUtils extends SQLConfHelper with CastSupport {
183182
} else if (exactAssignments.isEmpty && fieldAssignments.isEmpty) {
184183
TableOutputResolver.checkNullability(colExpr, col, conf, colPath)
185184
} else if (exactAssignments.nonEmpty) {
186-
if (SQLConf.get.mergeUpdateStructsByField && updateStar) {
185+
if (updateStar) {
187186
val value = exactAssignments.head.value
188187
col.dataType match {
189188
case structType: StructType =>

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/ResolveRowLevelCommandAssignments.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object ResolveRowLevelCommandAssignments extends Rule[LogicalPlan] {
5353
case m: MergeIntoTable if !m.skipSchemaResolution && m.resolved && m.rewritable && !m.aligned &&
5454
!m.needSchemaEvolution =>
5555
validateStoreAssignmentPolicy()
56-
val coerceNestedTypes = SQLConf.get.mergeCoerceNestedTypes
56+
val coerceNestedTypes = SQLConf.get.coerceMergeNestedTypes
5757
m.copy(
5858
targetTable = cleanAttrMetadata(m.targetTable),
5959
matchedActions = alignActions(m.targetTable.output, m.matchedActions,

sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6620,18 +6620,6 @@ object SQLConf {
66206620
.booleanConf
66216621
.createWithDefault(true)
66226622

6623-
val MERGE_INTO_NESTED_TYPE_UPDATE_BY_FIELD =
6624-
buildConf("spark.sql.merge.nested.type.assign.by.field")
6625-
.internal()
6626-
.doc("If enabled and spark.sql.merge.source.nested.type.coercion.enabled is true," +
6627-
"allow MERGE INTO with UPDATE SET * action to set nested structs field by field. " +
6628-
"In updated rows, target structs will preserve the original value for fields missing " +
6629-
"in the the source struct. If disabled, the entire target struct will be replaced, " +
6630-
"and fields missing in the source struct will be null.")
6631-
.version("4.1.0")
6632-
.booleanConf
6633-
.createWithDefault(true)
6634-
66356623
/**
66366624
* Holds information about keys that have been deprecated.
66376625
*
@@ -7789,12 +7777,9 @@ class SQLConf extends Serializable with Logging with SqlApiConf {
77897777
def legacyXMLParserEnabled: Boolean =
77907778
getConf(SQLConf.LEGACY_XML_PARSER_ENABLED)
77917779

7792-
def mergeCoerceNestedTypes: Boolean =
7780+
def coerceMergeNestedTypes: Boolean =
77937781
getConf(SQLConf.MERGE_INTO_NESTED_TYPE_COERCION_ENABLED)
77947782

7795-
def mergeUpdateStructsByField: Boolean =
7796-
getConf(SQLConf.MERGE_INTO_NESTED_TYPE_UPDATE_BY_FIELD)
7797-
77987783
/** ********************** SQLConf functionality methods ************ */
77997784

78007785
/** Set Spark SQL configuration properties. */

0 commit comments

Comments
 (0)