github-actions[bot] commented on code in PR #66685:
URL: https://github.com/apache/doris/pull/66685#discussion_r3791982938


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPaimonTableSink.java:
##########
@@ -168,6 +192,106 @@ static boolean requiresSingleWriter(FileStoreTable 
paimonTable) {
                                 == 
CoreOptions.ChangelogProducer.FULL_COMPACTION);
     }
 
+    private DistributionSpecPaimonTableSinkHashPartitioned 
buildFixedBucketDistributionSpec(
+            FileStoreTable paimonTable) {
+        if (Config.be_exec_version
+                < 
DistributionSpecExternalTableSinkHashPartitioned.MIN_BE_EXEC_VERSION) {
+            return null;
+        }
+        return buildFixedBucketDistributionSpec(paimonTable, cols, 
child().getOutput());
+    }
+
+    static DistributionSpecPaimonTableSinkHashPartitioned 
buildFixedBucketDistributionSpec(
+            FileStoreTable paimonTable, List<Column> sinkColumns, List<Slot> 
sinkOutput) {
+        if (paimonTable.bucketMode() != BucketMode.HASH_FIXED) {
+            return null;
+        }
+
+        TableSchema schema = paimonTable.schema();
+        CoreOptions coreOptions = CoreOptions.fromMap(schema.options());
+        if (coreOptions.bucketFunctionType() != 
CoreOptions.BucketFunctionType.DEFAULT) {
+            return null;
+        }
+
+        if (schema.numBuckets() <= 0 || schema.bucketKeys().isEmpty()
+                || sinkColumns.size() != sinkOutput.size()) {
+            return null;
+        }
+
+        Map<String, Slot> outputByName = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        for (int i = 0; i < sinkColumns.size(); i++) {
+            if (outputByName.put(sinkColumns.get(i).getName(), 
sinkOutput.get(i)) != null) {
+                return null;
+            }
+        }
+        Map<String, DataField> fieldsByName = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        for (DataField field : schema.fields()) {
+            fieldsByName.put(field.name(), field);
+        }
+
+        List<ExprId> routeExprIds = new ArrayList<>();
+        Map<String, Integer> routeIndexes = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        List<Integer> partitionFieldIndexes = appendRouteFields(
+                schema.partitionKeys(), outputByName, fieldsByName, 
routeExprIds, routeIndexes);
+        List<Integer> bucketFieldIndexes = appendRouteFields(
+                schema.bucketKeys(), outputByName, fieldsByName, routeExprIds, 
routeIndexes);
+        if (partitionFieldIndexes == null || bucketFieldIndexes == null
+                || bucketFieldIndexes.isEmpty()) {
+            return null;
+        }
+        return new DistributionSpecPaimonTableSinkHashPartitioned(
+                routeExprIds, schema.numBuckets(), partitionFieldIndexes, 
bucketFieldIndexes);
+    }
+
+    private static List<Integer> appendRouteFields(List<String> fieldNames,
+            Map<String, Slot> outputByName, Map<String, DataField> 
fieldsByName,
+            List<ExprId> routeExprIds, Map<String, Integer> routeIndexes) {

Review Comment:
   [P1] Fall back when a Paimon route field has a default
   
   This admits nullable partition/bucket fields based only on their type, but 
the two sides do not hash the same logical value for an explicit `NULL`. The BE 
exchange hashes the null as-is; [Paimon 1.4.2's 
`TableWriteImpl`](https://github.com/apache/paimon/blob/release-1.4.2/paimon-core/src/main/java/org/apache/paimon/table/sink/TableWriteImpl.java#L183-L190)
 then applies `DefaultValueRow` before extracting the partition and bucket, 
replacing that null with the schema default. For example, with a nullable `INT 
DEFAULT 1` bucket key and four writers, the checked-in hashes route NULL 
(bucket 0) and literal 1 (bucket 2) to different writers even though both are 
ultimately written to bucket 2. In the normal `write-only=false` append mode, 
both sessions may then restore and compact the same prior bucket files. Please 
reject route fields with non-null defaults (using the existing safe fallback) 
until the exchange applies Paimon's converted defaults, and cover explicit NULL 
for defaulted bu
 cket and partition keys.



-- 
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