rangareddy commented on code in PR #19463:
URL: https://github.com/apache/hudi/pull/19463#discussion_r3710050149


##########
hudi-hadoop-mr/src/test/java/org/apache/hudi/hadoop/realtime/TestHoodieRealtimeRecordReader.java:
##########
@@ -310,6 +312,65 @@ private File getLogTempFile(long startTime, long endTime, 
String diskType) {
         .orElseGet(() -> new File(""));
   }
 
+  /**
+   * HUDI-1286: a MOR _rt query fails with "Error ordering fields for storage 
read" when Hive's
+   * read-column names and ids have different lengths. CombineHiveInputFormat 
shares one JobConf across
+   * splits, so the two projection lists can accumulate independently and 
diverge; this reproduces that
+   * shape directly on the reader and pins the diagnostics the failure has to 
carry.

Review Comment:
   You are right on all three points, and I checked each before changing 
anything.
   
   - The reported frame is 
`HiveInputFormat.getRecordReader(HiveInputFormat.java:376)` and `:379` — the 
base class, so `CombineHiveInputFormat` was not on that stack.
   - `HoodieRealtimeInputFormatUtils#addProjectionField` sets 
`READ_COLUMN_NAMES_CONF_STR` and `READ_COLUMN_IDS_CONF_STR` in the same `if` 
body (lines 76-77), so Hudi cannot make them diverge that way.
   - HIVE-22438 is already documented in this repo, at 
`HoodieRealtimeInputFormatUtils.java:134`, for exactly this query.
   
   The claim is gone from the code and from the commit message — I rewrote the 
commit rather than leaving it in history, since as you say it would outlive the 
PR. The message now says the mechanism is **unconfirmed**, names HIVE-22438 / 
HUDI-313 as what the repo documents for this query, and states explicitly that 
an earlier draft asserted CombineHiveInputFormat and why that was wrong.
   
   Thank you for this one in particular — it was the difference between a 
plausible story and the actual evidence.



##########
hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HoodieRealtimeRecordReaderUtils.java:
##########
@@ -279,9 +279,13 @@ public static List<String> orderFields(String 
fieldNameCsv, String fieldOrderCsv
     List<String> fieldNames = fieldNameCsv.isEmpty() ? new ArrayList<>() : 
Arrays.stream(fieldNameCsv.split(",")).collect(Collectors.toList());
     Set<String> fieldNamesSet = new LinkedHashSet<>(fieldNames);
     if (fieldNamesSet.size() != fieldOrders.length) {
+      // Report the de-duplicated counts, since those are what were compared: 
quoting the raw name count
+      // can produce a message whose two numbers are equal even though the 
mismatch is real. The inputs are
+      // included because the projection lists come from Hive and are the only 
way to diagnose the mismatch.
       throw new HoodieException(String

Review Comment:
   Confirmed and fixed. Probed all three of your inputs on master first:
   
   ```
   ("a,b,c",    ",2,0")     -> NumberFormatException: For input string: ""
   ("a,b,c,ts", ",2,0,3,5") -> #fieldNames: 4, #fieldPositions: 5, ...
   ("a,b,c",    ",,2,0")    -> NumberFormatException: For input string: ""
   ```
   
   The middle line reproduces #14673 exactly, which I take as good evidence 
that HIVE-22438 is the real mechanism.
   
   Blank tokens are now filtered where the ids are split, with the HIVE-22438 
reference in the comment.
   
   One thing that came out better than your comment predicted: the `(a,b,c,ts | 
,2,0,3,5)` case does not just reach the diagnostic, it **resolves**. Dropping 
the blank leaves four real ids against four names, so the counts only ever 
disagreed because the blank was counted — this is a functional fix for that 
shape, not only a message improvement. I found that when my first version of 
the test asserted an exception and failed.
   
   Both of your inputs are now cases in `TestHoodieRealtimeRecordReaderUtils`: 
`testOrderFieldsIgnoresBlankIdTokens` (including the `,,2,0` form, since 
`cleanProjectionColumnIds` strips only one comma) and 
`testOrderFieldsResolvesTheShapeReportedInTheIssue`. Both fail on master.



##########
hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HoodieRealtimeRecordReaderUtils.java:
##########
@@ -279,9 +279,13 @@ public static List<String> orderFields(String 
fieldNameCsv, String fieldOrderCsv
     List<String> fieldNames = fieldNameCsv.isEmpty() ? new ArrayList<>() : 
Arrays.stream(fieldNameCsv.split(",")).collect(Collectors.toList());
     Set<String> fieldNamesSet = new LinkedHashSet<>(fieldNames);
     if (fieldNamesSet.size() != fieldOrders.length) {
+      // Report the de-duplicated counts, since those are what were compared: 
quoting the raw name count
+      // can produce a message whose two numbers are equal even though the 
mismatch is real. The inputs are
+      // included because the projection lists come from Hive and are the only 
way to diagnose the mismatch.
       throw new HoodieException(String
-          .format("Error ordering fields for storage read. #fieldNames: %d, 
#fieldPositions: %d",
-              fieldNames.size(), fieldOrders.length));
+          .format("Error ordering fields for storage read. #fieldNames: %d, 
#fieldPositions: %d, "
+                  + "read column names: [%s], read column ids: [%s]",
+              fieldNamesSet.size(), fieldOrders.length, fieldNameCsv, 
fieldOrderCsv));
     }
     TreeMap<Integer, String> orderedFieldMap = new TreeMap<>();
     String[] fieldNamesArray = fieldNamesSet.toArray(new String[0]);

Review Comment:
   Verified and filed: **#19506**, referenced from the PR description.
   
   Your reading holds — `appendReadColumns` prepends ids while 
`appendReadColumnNames` appends names, so duplicate positions can differ 
between the two lists, the counts still match, and the mapping is silently 
wrong. I included your worked example and the `getReadColumnIDs` citation, and 
credited you.
   
   I have deliberately not touched the pairing in this PR, and the issue says 
so explicitly, so the message improvement here is not later mistaken for a fix 
for that. Agreed it is not a regression from this change.



##########
hudi-hadoop-mr/src/test/java/org/apache/hudi/hadoop/realtime/TestHoodieRealtimeRecordReader.java:
##########
@@ -310,6 +312,65 @@ private File getLogTempFile(long startTime, long endTime, 
String diskType) {
         .orElseGet(() -> new File(""));
   }
 
+  /**
+   * HUDI-1286: a MOR _rt query fails with "Error ordering fields for storage 
read" when Hive's
+   * read-column names and ids have different lengths. CombineHiveInputFormat 
shares one JobConf across
+   * splits, so the two projection lists can accumulate independently and 
diverge; this reproduces that
+   * shape directly on the reader and pins the diagnostics the failure has to 
carry.
+   */
+  @Test
+  public void testReaderFailsClearlyWhenHiveProjectionListsDiverge() throws 
Exception {
+    HoodieSchema schema = 
HoodieSchemaUtils.addMetadataFields(SchemaTestUtil.getEvolvedSchema());
+    HoodieTestUtils.init(storageConf, basePath.toString(), 
HoodieTableType.MERGE_ON_READ);
+    String instantTime = "100";
+    final int numRecords = 10;
+    File partitionDir = InputFormatTestUtil.prepareParquetTable(basePath, 
schema, 1, numRecords, instantTime,
+        HoodieTableType.MERGE_ON_READ);
+    HoodieCommitMetadata commitMetadata = 
CommitUtils.buildMetadata(Collections.emptyList(), Collections.emptyMap(),
+        Option.empty(), WriteOperationType.UPSERT, schema.toString(), 
HoodieTimeline.DELTA_COMMIT_ACTION);
+    FileCreateUtilsLegacy.createDeltaCommit(COMMIT_METADATA_SER_DE, 
basePath.toString(), instantTime, commitMetadata);
+    FileInputFormat.setInputPaths(baseJobConf, partitionDir.getPath());
+
+    String newCommitTime = "101";
+    HoodieLogFormat.Writer writer =
+        InputFormatTestUtil.writeDataBlockToLogFile(partitionDir, storage, 
schema, "fileid0", instantTime,
+            newCommitTime, numRecords, numRecords, 0);
+    writer.close();
+    FileCreateUtilsLegacy.createDeltaCommit(COMMIT_METADATA_SER_DE, 
basePath.toString(), newCommitTime, commitMetadata);
+
+    HoodieRealtimeFileSplit split = new HoodieRealtimeFileSplit(
+        new FileSplit(new Path(partitionDir + "/fileid0_1-0-1_" + instantTime 
+ ".parquet"), 0, 1, baseJobConf),
+        basePath.toUri().toString(), 
Collections.singletonList(writer.getLogFile()), newCommitTime, false,
+        Option.empty());
+    RecordReader<NullWritable, ArrayWritable> reader = new 
MapredParquetInputFormat().getRecordReader(
+        new FileSplit(split.getPath(), 0, fs.getLength(split.getPath()), 
(String[]) null), baseJobConf, null);
+
+    JobConf jobConf = new JobConf(baseJobConf);
+    List<HoodieSchemaField> fields = schema.getFields();
+    setHiveColumnNameProps(fields, jobConf, true);
+    // One more position than there are names, the shape reported on HUDI-1286.
+    String positions = 
jobConf.get(ColumnProjectionUtils.READ_COLUMN_IDS_CONF_STR);
+    jobConf.set(ColumnProjectionUtils.READ_COLUMN_IDS_CONF_STR, positions + 
"," + fields.size());
+
+    HoodieException thrown = assertThrows(HoodieException.class,
+        () -> new HoodieRealtimeRecordReader(split, jobConf, reader));
+    // The failure is wrapped twice on the way out ("Exception when 
constructing record reader" then
+    // "Could not create HoodieRealtimeRecordReader on path ..."), so the 
actionable detail sits a couple of
+    // causes down. That nesting is why the original report only shows it 
under "Caused by".
+    assertNotNull(thrown.getCause(), "The construction failure should keep its 
cause");
+    StringBuilder chain = new StringBuilder();
+    for (Throwable t = thrown; t != null; t = t.getCause()) {
+      chain.append(t.getMessage()).append(" | ");
+    }
+    String message = chain.toString();
+    assertTrue(message.contains("Error ordering fields for storage read"), () 
-> "Got: " + message);
+    assertTrue(message.contains("#fieldNames: " + fields.size())
+            && message.contains("#fieldPositions: " + (fields.size() + 1)),
+        () -> "The failure must report the counts that were compared. Got: " + 
message);

Review Comment:
   You are right, and I have deleted the test.
   
   The names come from `schema.getFields()` and Avro forbids duplicate field 
names, so `fieldNames.size() == fieldNamesSet.size()` always holds for that 
input and the count assertion cannot discriminate. Only the projection-list 
assertion could, and `TestHoodieRealtimeRecordReaderUtils` covers that without 
building a MOR table, a parquet base file and a log block.
   
   I chose deletion over making it discriminate because your other two comments 
apply to the same test — it was a third copy of the `testUnMergedReader` 
fixture, and the log block it wrote was not needed to reach `orderFields`. 
Removing it resolves all three and keeps the PR proportionate to what it 
changes, which is an error message.
   
   Happy to add it back as a discriminating test routed through a shared 
`prepareMorSplitAndBaseReader` helper if you would rather have end-to-end 
coverage of the cause chain; I did not want to land the helper refactor as a 
side effect of a diagnostics fix.



##########
hudi-hadoop-mr/src/test/java/org/apache/hudi/hadoop/utils/TestHoodieRealtimeRecordReaderUtils.java:
##########
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.hadoop.utils;
+
+import org.apache.hudi.exception.HoodieException;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests {@link HoodieRealtimeRecordReaderUtils#orderFields}, which maps Hive's
+ * {@code hive.io.file.readcolumn.names} and {@code 
hive.io.file.readcolumn.ids} onto an ordered
+ * projection list.
+ */
+class TestHoodieRealtimeRecordReaderUtils {
+
+  @Test
+  void orderFieldsSortsNamesByTheirHivePosition() {
+    assertEquals(Arrays.asList("rider", "driver", "fare"),
+        HoodieRealtimeRecordReaderUtils.orderFields("driver,fare,rider", 
"1,2,0", Collections.emptyList()));
+  }
+
+  @Test
+  void orderFieldsReturnsEmptyForEmptyInput() {
+    assertEquals(Collections.emptyList(),
+        HoodieRealtimeRecordReaderUtils.orderFields("", "", 
Collections.emptyList()));
+  }
+
+  /**
+   * Hive can repeat a name in the read-column list while keeping ids unique, 
which the method
+   * deliberately tolerates by de-duplicating both sides before pairing them.
+   */
+  @Test
+  void orderFieldsDeduplicatesRepeatedNames() {
+    assertEquals(Arrays.asList("rider", "driver"),
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver,rider", 
"0,1", Collections.emptyList()));
+  }
+
+  /**
+   * The counts compared are the de-duplicated ones, so the failure has to 
report those. Reporting the
+   * raw name count instead can produce a message whose two numbers are equal 
even though the mismatch
+   * is real, which is unusable when diagnosing something like HUDI-1286.
+   */
+  @Test
+  void orderFieldsMismatchReportsTheComparedCountsAndTheInputs() {
+    HoodieException withDuplicates = assertThrows(HoodieException.class, () ->
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver,fare,fare", 
"0,1,2,3", Collections.emptyList()));
+    assertTrue(withDuplicates.getMessage().contains("#fieldNames: 3"),
+        () -> "Expected the de-duplicated name count, got: " + 
withDuplicates.getMessage());
+    assertTrue(withDuplicates.getMessage().contains("#fieldPositions: 4"),
+        () -> "Expected the position count, got: " + 
withDuplicates.getMessage());
+    assertTrue(withDuplicates.getMessage().contains("rider,driver,fare,fare")
+            && withDuplicates.getMessage().contains("0,1,2,3"),
+        () -> "Expected the offending inputs to be included, got: " + 
withDuplicates.getMessage());
+
+    HoodieException fewerNames = assertThrows(HoodieException.class, () ->
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver", "0,1,2", 
Collections.emptyList()));
+    assertTrue(fewerNames.getMessage().contains("#fieldNames: 2")
+            && fewerNames.getMessage().contains("#fieldPositions: 3"),
+        () -> "Got: " + fewerNames.getMessage());
+  }
+
+  @Test
+  void orderFieldsIgnoresPartitioningFieldsArgument() {
+    List<String> ordered =
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver", "0,1", 
Arrays.asList("partition_path"));
+    assertEquals(Arrays.asList("rider", "driver"), ordered);
+  }

Review Comment:
   Corrected, and thank you — I had this backwards in the PR description too.
   
   `30d497a19844` ([HUDI-5308], #7355) did remove the `.filter(fn -> 
!partitioningFields.contains(fn))` and its comment, so the parameter was 
implemented and then deliberately dropped. My "intent that was never 
implemented" line was wrong and would have misled whoever picks up HUDI-1286; 
the description now says what actually happened and names the commit.
   
   The test is now your version, as a HUDI-5308 guard with the partition column 
inside the name list:
   
   ```java
   @Test
   public void testOrderFieldsNoLongerFiltersPartitionFields() {
     assertThrows(HoodieException.class, () -> 
HoodieRealtimeRecordReaderUtils.orderFields(
         "rider,driver,partition_path", "0,1", 
Collections.singletonList("partition_path")));
   }
   ```
   
   `java.util.List` is gone from the imports.



##########
hudi-hadoop-mr/src/test/java/org/apache/hudi/hadoop/realtime/TestHoodieRealtimeRecordReader.java:
##########
@@ -310,6 +312,65 @@ private File getLogTempFile(long startTime, long endTime, 
String diskType) {
         .orElseGet(() -> new File(""));
   }
 
+  /**
+   * HUDI-1286: a MOR _rt query fails with "Error ordering fields for storage 
read" when Hive's
+   * read-column names and ids have different lengths. CombineHiveInputFormat 
shares one JobConf across
+   * splits, so the two projection lists can accumulate independently and 
diverge; this reproduces that
+   * shape directly on the reader and pins the diagnostics the failure has to 
carry.
+   */
+  @Test
+  public void testReaderFailsClearlyWhenHiveProjectionListsDiverge() throws 
Exception {
+    HoodieSchema schema = 
HoodieSchemaUtils.addMetadataFields(SchemaTestUtil.getEvolvedSchema());
+    HoodieTestUtils.init(storageConf, basePath.toString(), 
HoodieTableType.MERGE_ON_READ);
+    String instantTime = "100";
+    final int numRecords = 10;
+    File partitionDir = InputFormatTestUtil.prepareParquetTable(basePath, 
schema, 1, numRecords, instantTime,
+        HoodieTableType.MERGE_ON_READ);
+    HoodieCommitMetadata commitMetadata = 
CommitUtils.buildMetadata(Collections.emptyList(), Collections.emptyMap(),
+        Option.empty(), WriteOperationType.UPSERT, schema.toString(), 
HoodieTimeline.DELTA_COMMIT_ACTION);
+    FileCreateUtilsLegacy.createDeltaCommit(COMMIT_METADATA_SER_DE, 
basePath.toString(), instantTime, commitMetadata);
+    FileInputFormat.setInputPaths(baseJobConf, partitionDir.getPath());
+
+    String newCommitTime = "101";
+    HoodieLogFormat.Writer writer =
+        InputFormatTestUtil.writeDataBlockToLogFile(partitionDir, storage, 
schema, "fileid0", instantTime,
+            newCommitTime, numRecords, numRecords, 0);
+    writer.close();
+    FileCreateUtilsLegacy.createDeltaCommit(COMMIT_METADATA_SER_DE, 
basePath.toString(), newCommitTime, commitMetadata);

Review Comment:
   Resolved by deleting the test — see my reply on the assertions. I agreed 
with that comment, so there is no third copy of the fixture to extract a helper 
from.
   
   For the record I think the helper is worth doing on its own: 
`testReaderInternal` and `testUnMergedReader` still open-code the same setup 
twice. I would rather not land that refactor inside a diagnostics PR, but say 
the word and I will raise it separately.



##########
hudi-hadoop-mr/src/test/java/org/apache/hudi/hadoop/utils/TestHoodieRealtimeRecordReaderUtils.java:
##########
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.hadoop.utils;
+
+import org.apache.hudi.exception.HoodieException;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests {@link HoodieRealtimeRecordReaderUtils#orderFields}, which maps Hive's
+ * {@code hive.io.file.readcolumn.names} and {@code 
hive.io.file.readcolumn.ids} onto an ordered
+ * projection list.
+ */
+class TestHoodieRealtimeRecordReaderUtils {
+
+  @Test
+  void orderFieldsSortsNamesByTheirHivePosition() {
+    assertEquals(Arrays.asList("rider", "driver", "fare"),
+        HoodieRealtimeRecordReaderUtils.orderFields("driver,fare,rider", 
"1,2,0", Collections.emptyList()));
+  }
+
+  @Test
+  void orderFieldsReturnsEmptyForEmptyInput() {
+    assertEquals(Collections.emptyList(),
+        HoodieRealtimeRecordReaderUtils.orderFields("", "", 
Collections.emptyList()));
+  }
+
+  /**
+   * Hive can repeat a name in the read-column list while keeping ids unique, 
which the method
+   * deliberately tolerates by de-duplicating both sides before pairing them.
+   */
+  @Test
+  void orderFieldsDeduplicatesRepeatedNames() {
+    assertEquals(Arrays.asList("rider", "driver"),
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver,rider", 
"0,1", Collections.emptyList()));
+  }
+
+  /**
+   * The counts compared are the de-duplicated ones, so the failure has to 
report those. Reporting the
+   * raw name count instead can produce a message whose two numbers are equal 
even though the mismatch
+   * is real, which is unusable when diagnosing something like HUDI-1286.
+   */
+  @Test
+  void orderFieldsMismatchReportsTheComparedCountsAndTheInputs() {
+    HoodieException withDuplicates = assertThrows(HoodieException.class, () ->
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver,fare,fare", 
"0,1,2,3", Collections.emptyList()));
+    assertTrue(withDuplicates.getMessage().contains("#fieldNames: 3"),
+        () -> "Expected the de-duplicated name count, got: " + 
withDuplicates.getMessage());
+    assertTrue(withDuplicates.getMessage().contains("#fieldPositions: 4"),
+        () -> "Expected the position count, got: " + 
withDuplicates.getMessage());
+    assertTrue(withDuplicates.getMessage().contains("rider,driver,fare,fare")
+            && withDuplicates.getMessage().contains("0,1,2,3"),
+        () -> "Expected the offending inputs to be included, got: " + 
withDuplicates.getMessage());
+
+    HoodieException fewerNames = assertThrows(HoodieException.class, () ->
+        HoodieRealtimeRecordReaderUtils.orderFields("rider,driver", "0,1,2", 
Collections.emptyList()));
+    assertTrue(fewerNames.getMessage().contains("#fieldNames: 2")
+            && fewerNames.getMessage().contains("#fieldPositions: 3"),
+        () -> "Got: " + fewerNames.getMessage());

Review Comment:
   Right — that block asserted only counts, which master already printed for an 
input with no duplicates, so it added nothing.
   
   Split into two separately named tests as you suggested, so which one guards 
the change is obvious:
   
   - `testOrderFieldsMismatchReportsDistinctCountsWhenNamesRepeat` — the 
duplicate-name case, asserting `#distinctFieldNames: 3` / 
`#distinctFieldPositions: 4`.
   - `testOrderFieldsMismatchReportsBothProjectionLists` — your 
`("rider,driver", "0,1,2")` input, now asserting `read column names: 
[rider,driver]` and `read column ids: [0,1,2]`.
   
   Both fail on master. In total four of the eight tests fail against master's 
`orderFields`:
   
   ```
   testOrderFieldsMismatchReportsBothProjectionLists          Error ... 
#fieldNames: 2, #fieldPositions: 3
   testOrderFieldsMismatchReportsDistinctCountsWhenNamesRepeat Error ... 
#fieldNames: 4, #fieldPositions: 4
   testOrderFieldsIgnoresBlankIdTokens                        » Hoodie Error 
... #fieldNames: 2, #fieldPositions: 3
   testOrderFieldsResolvesTheShapeReportedInTheIssue          » Hoodie Error 
... #fieldNames: 4, #fieldPositions: 5
   ```
   
   The second line is the equal-numbers pathology and the fourth is the #14673 
shape. The remaining four characterise existing behaviour, which I have said so 
in the commit message rather than implying they guard this change.



##########
hudi-hadoop-mr/src/main/java/org/apache/hudi/hadoop/utils/HoodieRealtimeRecordReaderUtils.java:
##########
@@ -279,9 +279,13 @@ public static List<String> orderFields(String 
fieldNameCsv, String fieldOrderCsv
     List<String> fieldNames = fieldNameCsv.isEmpty() ? new ArrayList<>() : 
Arrays.stream(fieldNameCsv.split(",")).collect(Collectors.toList());
     Set<String> fieldNamesSet = new LinkedHashSet<>(fieldNames);
     if (fieldNamesSet.size() != fieldOrders.length) {
+      // Report the de-duplicated counts, since those are what were compared: 
quoting the raw name count
+      // can produce a message whose two numbers are equal even though the 
mismatch is real. The inputs are
+      // included because the projection lists come from Hive and are the only 
way to diagnose the mismatch.
       throw new HoodieException(String
-          .format("Error ordering fields for storage read. #fieldNames: %d, 
#fieldPositions: %d",
-              fieldNames.size(), fieldOrders.length));
+          .format("Error ordering fields for storage read. #fieldNames: %d, 
#fieldPositions: %d, "
+                  + "read column names: [%s], read column ids: [%s]",

Review Comment:
   Applied — `#distinctFieldNames` / `#distinctFieldPositions`. You are right 
that a de-duplicated count printed beside a raw list reads as a contradiction, 
and naming them removes the need to explain it:
   
   ```
   Error ordering fields for storage read. #distinctFieldNames: 3, 
#distinctFieldPositions: 4,
   read column names: [rider,driver,fare,fare], read column ids: [0,1,2,3]
   ```
   
   The three-line comment is down to the two points that are still not obvious 
from the code. Substring assertions updated in both tests.



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