nsivabalan commented on code in PR #19205:
URL: https://github.com/apache/hudi/pull/19205#discussion_r3763338417


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieWriteMergeHandle.java:
##########
@@ -413,7 +418,16 @@ protected void writeToFile(HoodieKey key, HoodieRecord<T> 
record, HoodieSchema s
     if (shouldPreserveRecordMetadata) {
       // NOTE: `FILENAME_METADATA_FIELD` has to be rewritten to correctly 
point to the
       //       file holding this record even in cases when overall metadata is 
preserved
-      HoodieRecord populatedRecord = record.updateMetaField(schema, 
HoodieRecord.FILENAME_META_FIELD_ORD, newFilePath.getName());
+      //
+      // The rewrite is gated on the mode: hoodie.meta.fields.mode is the 
single authority on which
+      // meta columns hold values, and this path would otherwise populate 
_hoodie_file_name on a
+      // COMMIT_TIME_ONLY / NONE table. The value written when the mode opts 
out is an explicit null
+      // rather than a skipped update, because the record being preserved here 
came from the previous
+      // base file — under a narrowed mode it can still carry a file name 
written while the table was
+      // on ALL, and leaving that in place would carry a stale value forward.
+      String fileNameToWrite =
+          metaFieldsMode.isFileNamePopulated() ? newFilePath.getName() : null;
+      HoodieRecord populatedRecord = record.updateMetaField(schema, 
HoodieRecord.FILENAME_META_FIELD_ORD, fileNameToWrite);

Review Comment:
   Confirmed and fixed in `128933f5876a` — thank you, this was a real crash and 
my tests could not have caught it.
   
   `HoodieInternalRow#update` accepts only `UTF8String` or `String` and reports 
anything else via `value.getClass()`, which NPEs on a null before the 
`IllegalArgumentException` is built. So clearing the column threw for 
`HoodieSparkRecord`, exactly as described.
   
   Fixed in `HoodieSparkRecord#updateMetaField` rather than at the two call 
sites, since it is the shared entry point both use: a null now routes through 
`setNullAt`, which already handles the meta-field range correctly. Clearing a 
meta column is a legitimate request rather than an error — a selective mode 
leaves it unpopulated, and a record copied forward from a file written under 
`ALL` needs the stale value cleared rather than carried over.
   
   One correction to the diagnosis, which matters for the test: you attributed 
the miss to the E2E tests using `SaveMode.Overwrite`. They do use `UPSERT` + 
`Append`. The actual reason is the record type — those tests take the **Avro** 
path, whose `data.put(ordinal, null)` tolerates a null. Reaching the Spark path 
needs 
`hoodie.write.record.merge.custom.implementation.classes=org.apache.hudi.DefaultSparkRecordMerger`;
 `row.writer.enable` alone does not do it.
   
   That distinction cost me a round: my first version of the regression test 
passed **with the fix reverted**. The committed one is verified both ways — 
`NullPointerException` without the fix, 29/29 with it.
   



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/BaseCreateHandle.java:
##########
@@ -164,8 +167,17 @@ record = record.prependMetaFields(schema, 
writeSchemaWithMetaFields, new Metadat
   }
 
   protected HoodieRecord<T> updateFileName(HoodieRecord<T> record, 
HoodieSchema schema, HoodieSchema targetSchema, String fileName, Properties 
prop) {
-    MetadataValues metadataValues = new MetadataValues().setFileName(fileName);
-    return record.prependMetaFields(schema, targetSchema, metadataValues, 
prop);
+    // hoodie.meta.fields.mode decides whether _hoodie_file_name carries a 
value. On the
+    // preserve-metadata path the record comes from an existing file, so 
leaving the column alone is
+    // not enough — MetadataValues skips null entries, and a record written 
while the table was on
+    // ALL would keep the file name it already had. Overwrite it with an 
explicit null instead.
+    if (metaFieldsMode.isFileNamePopulated()) {
+      MetadataValues metadataValues = new 
MetadataValues().setFileName(fileName);
+      return record.prependMetaFields(schema, targetSchema, metadataValues, 
prop);
+    }
+    HoodieRecord<T> withMetaFields =
+        record.prependMetaFields(schema, targetSchema, new MetadataValues(), 
prop);
+    return withMetaFields.updateMetaField(targetSchema, 
HoodieRecord.FILENAME_META_FIELD_ORD, null);

Review Comment:
   Confirmed and fixed in `128933f5876a` — thank you, this was a real crash and 
my tests could not have caught it.
   
   `HoodieInternalRow#update` accepts only `UTF8String` or `String` and reports 
anything else via `value.getClass()`, which NPEs on a null before the 
`IllegalArgumentException` is built. So clearing the column threw for 
`HoodieSparkRecord`, exactly as described.
   
   Fixed in `HoodieSparkRecord#updateMetaField` rather than at the two call 
sites, since it is the shared entry point both use: a null now routes through 
`setNullAt`, which already handles the meta-field range correctly. Clearing a 
meta column is a legitimate request rather than an error — a selective mode 
leaves it unpopulated, and a record copied forward from a file written under 
`ALL` needs the stale value cleared rather than carried over.
   
   One correction to the diagnosis, which matters for the test: you attributed 
the miss to the E2E tests using `SaveMode.Overwrite`. They do use `UPSERT` + 
`Append`. The actual reason is the record type — those tests take the **Avro** 
path, whose `data.put(ordinal, null)` tolerates a null. Reaching the Spark path 
needs 
`hoodie.write.record.merge.custom.implementation.classes=org.apache.hudi.DefaultSparkRecordMerger`;
 `row.writer.enable` alone does not do it.
   
   That distinction cost me a round: my first version of the regression test 
passed **with the fix reverted**. The committed one is verified both ways — 
`NullPointerException` without the fix, 29/29 with it.
   



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

Reply via email to