Skip to content

Commit 9846dd8

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>
1 parent d14209c commit 9846dd8

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
@@ -6704,18 +6704,6 @@ object SQLConf {
67046704
.booleanConf
67056705
.createWithDefault(true)
67066706

6707-
val MERGE_INTO_NESTED_TYPE_UPDATE_BY_FIELD =
6708-
buildConf("spark.sql.merge.nested.type.assign.by.field")
6709-
.internal()
6710-
.doc("If enabled and spark.sql.merge.source.nested.type.coercion.enabled is true," +
6711-
"allow MERGE INTO with UPDATE SET * action to set nested structs field by field. " +
6712-
"In updated rows, target structs will preserve the original value for fields missing " +
6713-
"in the the source struct. If disabled, the entire target struct will be replaced, " +
6714-
"and fields missing in the source struct will be null.")
6715-
.version("4.1.0")
6716-
.booleanConf
6717-
.createWithDefault(true)
6718-
67196707
/**
67206708
* Holds information about keys that have been deprecated.
67216709
*
@@ -7915,12 +7903,9 @@ class SQLConf extends Serializable with Logging with SqlApiConf {
79157903
def legacyXMLParserEnabled: Boolean =
79167904
getConf(SQLConf.LEGACY_XML_PARSER_ENABLED)
79177905

7918-
def mergeCoerceNestedTypes: Boolean =
7906+
def coerceMergeNestedTypes: Boolean =
79197907
getConf(SQLConf.MERGE_INTO_NESTED_TYPE_COERCION_ENABLED)
79207908

7921-
def mergeUpdateStructsByField: Boolean =
7922-
getConf(SQLConf.MERGE_INTO_NESTED_TYPE_UPDATE_BY_FIELD)
7923-
79247909
/** ********************** SQLConf functionality methods ************ */
79257910

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

0 commit comments

Comments
 (0)