anew commented on code in PR #56686:
URL: https://github.com/apache/spark/pull/56686#discussion_r3553106516


##########
sql/pipelines/src/main/scala/org/apache/spark/sql/pipelines/graph/DatasetManager.scala:
##########
@@ -342,11 +351,127 @@ object DatasetManager extends Logging {
         )
     }
 
-    table.copy(
-      normalizedPath = Option(
-        
catalog.loadTable(identifier).properties().get(TableCatalog.PROP_LOCATION)
+    val catalogTableEntity = catalog.loadTable(identifier)
+    val tableWithMaterializationMetadata =
+      table.copy(
+        normalizedPath =
+          
Option(catalogTableEntity.properties().get(TableCatalog.PROP_LOCATION))
       )
+
+    (tableWithMaterializationMetadata, catalogTableEntity)
+  }
+
+  /**
+   * Validate that the AutoCDC target table is backed by a connector 
implementing
+   * [[SupportsRowLevelOperations]], the DSv2 contract for the 
MERGE/UPDATE/DELETE-with-rewrite
+   * operations the AutoCDC transformation relies on. Reuses the target handle 
already loaded by
+   * [[materializeTable]], so it performs no additional catalog I/O. Only 
AutoCDC auxiliary specs
+   * carry a MERGE-backed target; other auxiliary tables have no such 
requirement.
+   *
+   * @param targetTable              the target table graph entity, source of 
the identifier and
+   *                                 declared format used in the error message.
+   * @param targetTableCatalogEntity the target table's loaded DSv2 handle.
+   */
+  private def requireAutoCdcTargetSupportsRowLevelOps(
+      targetTable: Table,
+      targetTableCatalogEntity: V2Table): Unit = {
+    if (!targetTableCatalogEntity.isInstanceOf[SupportsRowLevelOperations]) {
+      throw new AnalysisException(
+        errorClass = "AUTOCDC_TARGET_DOES_NOT_SUPPORT_MERGE",
+        messageParameters = Map(
+          "tableName" -> targetTable.identifier.quotedString,
+          // Prefer the flow-declared format, falling back to the connector's 
provider property.
+          "format" -> targetTable.format
+            
.orElse(Option(targetTableCatalogEntity.properties.get(TableCatalog.PROP_PROVIDER)))
+            .getOrElse("<unknown>")
+        )
+      )
+    }
+  }
+
+  /**
+   * Materialize the auxiliary table according to the provided spec.
+   *
+   * @param auxiliaryTableSpec the spec describing the auxiliary table to 
create/evolve.
+   * @param isFullRefresh whether the owning table is being fully refreshed.
+   * @param context the context for the pipeline update.
+   */
+  private def materializeAuxiliaryTable(
+      auxiliaryTableSpec: AuxiliaryTableSpec,
+      isFullRefresh: Boolean,
+      context: PipelineUpdateContext): Unit = {
+    // Get the DSv2 catalog handler and identifier for the aux table.
+    val (catalog, auxiliaryTableIdentifier) =
+      PipelinesCatalogUtils.resolveTableCatalog(context.spark, 
auxiliaryTableSpec.identifier)
+
+    logInfo(
+      log"Materializing auxiliary table " +
+      log"${MDC(LogKeys.TABLE_NAME, auxiliaryTableSpec.identifier)}."
     )
+
+    if (isFullRefresh) {
+      // Intentionally DROP and not TRUNCATE on full refresh. The auxiliary 
table is an internal

Review Comment:
   I learned:
   
   DROP is intentional here (see the comment just above at the full-refresh
   branch). The aux table's identity and its metadata -- SCD type and recorded 
key
   columns in table properties -- must not persist across a full refresh, since 
a
   full refresh is precisely how a user changes them. TRUNCATE would keep the 
stale
   properties and force extra reconciliation. It's an internal state table, so
   history preservation / undo isn't a goal for it; the owning target table 
still
   uses TRUNCATE and retains its history.
    



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to