You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ba...@apache.org on 2026/10/01 07:10:34 UTC

(hop) branch main updated: Issue #3123 : Add option to exclude the field to split from output (#8678)

This is an automated email from the ASF dual-hosted git repository.

bamaer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 217d3a6816 Issue #3123 : Add option to exclude the field to split from output (#8678)
217d3a6816 is described below

commit 217d3a68167b96a824561ae670d8af51619d14c4
Author: Matt Casters <ma...@gmail.com>
AuthorDate: Thu Oct 1 09:10:29 2026 +0200

    Issue #3123 : Add option to exclude the field to split from output (#8678)
---
 .../pipeline/transforms/splitfieldtorows.adoc      |  5 +-
 .../splitfieldtorows/SplitFieldToRows.java         | 12 ++-
 .../splitfieldtorows/SplitFieldToRowsDialog.java   | 28 ++++++-
 .../splitfieldtorows/SplitFieldToRowsMeta.java     | 30 +++++++
 .../messages/messages_en_US.properties             |  3 +
 .../splitfieldtorows/SplitFieldToRowsMetaTest.java | 91 +++++++++++++++++++++-
 .../splitfieldtorows/SplitFieldToRowsTest.java     | 82 ++++++++++++++++++-
 7 files changed, 238 insertions(+), 13 deletions(-)

diff --git a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/splitfieldtorows.adoc b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/splitfieldtorows.adoc
index 4cff7dd4f1..b5f2bc9625 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/splitfieldtorows.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/pipeline/transforms/splitfieldtorows.adoc
@@ -29,9 +29,7 @@ The Split Fields To Rows transform splits a row containing a delimited field int
 
 The original row is not delivered to following transforms.
 
-The original field is left in each new row to assist in debugging or error handling.
-
-It can be removed via a xref:pipeline/transforms/selectvalues.adoc[Select Values] transform if needed.
+By default the original field is left in each new row to assist in debugging or error handling. Enable *Exclude field to split from output* to drop that field from the output rows. It can also be removed with a xref:pipeline/transforms/selectvalues.adoc[Select Values] transform.
 
 The original field must be a string field.
 
@@ -50,6 +48,7 @@ If the value type/format of the new row is not specified, the new field will use
 |Option|Description
 |Transform name|Name of the transform.
 |Field to split|The field you want to split.
+|Exclude field to split from output|When enabled, the field to split is removed from each output row. The split values are still written to the new field. Disabled by default, so existing pipelines keep the original field.
 |Delimiter|The delimiter or separator used.
 Special characters (e.g. CHAR ASCII HEX01) can be set with the format $[value], e.g. $[01] or $[6F,FF,00,1F].
 |Enclosure|Optional enclosure string. Delimiters inside a pair of enclosure characters are not treated as split points, and the enclosure characters are removed from the output values.
diff --git a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRows.java b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRows.java
index f3346945be..5984cda8f4 100644
--- a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRows.java
+++ b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRows.java
@@ -101,13 +101,17 @@ public class SplitFieldToRows extends BaseTransform<SplitFieldToRowsMeta, SplitF
       data.rownr = 1L;
     }
 
+    Object[] baseRow = rowData;
+    if (meta.isExcludeSplitField()) {
+      baseRow = RowDataUtil.removeItem(rowData, data.fieldnr);
+    }
+    int newFieldIndex = data.outputRowMeta.size() - (meta.isIncludeRowNumber() ? 2 : 1);
     String[] splitStrings = splitSource(originalString);
     for (String string : splitStrings) {
-      Object[] outputRow = RowDataUtil.createResizedCopy(rowData, data.outputRowMeta.size());
-      outputRow[rowMeta.size()] = string;
-      // Include row number in output?
+      Object[] outputRow = RowDataUtil.createResizedCopy(baseRow, data.outputRowMeta.size());
+      outputRow[newFieldIndex] = string;
       if (meta.isIncludeRowNumber()) {
-        outputRow[rowMeta.size() + 1] = data.rownr;
+        outputRow[newFieldIndex + 1] = data.rownr;
       }
       putRow(data.outputRowMeta, outputRow);
       data.rownr++;
diff --git a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsDialog.java b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsDialog.java
index 79d02858bd..5e65515374 100644
--- a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsDialog.java
+++ b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsDialog.java
@@ -67,6 +67,8 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
 
   private Button wDelimiterIsRegex;
 
+  private Button wExcludeSplitField;
+
   public SplitFieldToRowsDialog(
       Shell parent,
       IVariables variables,
@@ -123,6 +125,26 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
           }
         });
 
+    Label wlExcludeSplitField = new Label(shell, SWT.RIGHT);
+    wlExcludeSplitField.setText(
+        BaseMessages.getString(PKG, "SplitFieldToRowsDialog.ExcludeSplitField.Label"));
+    PropsUi.setLook(wlExcludeSplitField);
+    FormData fdlExcludeSplitField = new FormData();
+    fdlExcludeSplitField.left = new FormAttachment(0, 0);
+    fdlExcludeSplitField.top = new FormAttachment(wSplitField, margin);
+    fdlExcludeSplitField.right = new FormAttachment(middle, -margin);
+    wlExcludeSplitField.setLayoutData(fdlExcludeSplitField);
+    wExcludeSplitField = new Button(shell, SWT.CHECK);
+    wExcludeSplitField.setToolTipText(
+        BaseMessages.getString(PKG, "SplitFieldToRowsDialog.ExcludeSplitField.Tooltip"));
+    PropsUi.setLook(wExcludeSplitField);
+    FormData fdExcludeSplitField = new FormData();
+    fdExcludeSplitField.left = new FormAttachment(middle, 0);
+    fdExcludeSplitField.top = new FormAttachment(wlExcludeSplitField, 0, SWT.CENTER);
+    fdExcludeSplitField.right = new FormAttachment(100, 0);
+    wExcludeSplitField.setLayoutData(fdExcludeSplitField);
+    wExcludeSplitField.addSelectionListener(new ComponentSelectionListener(input));
+
     // Delimiter line
     Label wlDelimiter = new Label(shell, SWT.RIGHT);
     wlDelimiter.setText(BaseMessages.getString(PKG, "SplitFieldToRowsDialog.Delimiter.Label"));
@@ -130,7 +152,7 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
     FormData fdlDelimiter = new FormData();
     fdlDelimiter.left = new FormAttachment(0, 0);
     fdlDelimiter.right = new FormAttachment(middle, -margin);
-    fdlDelimiter.top = new FormAttachment(wSplitField, margin);
+    fdlDelimiter.top = new FormAttachment(wExcludeSplitField, margin);
     wlDelimiter.setLayoutData(fdlDelimiter);
     wDelimiter = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
     wDelimiter.setText("");
@@ -138,7 +160,7 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
     wDelimiter.addModifyListener(lsMod);
     FormData fdDelimiter = new FormData();
     fdDelimiter.left = new FormAttachment(middle, 0);
-    fdDelimiter.top = new FormAttachment(wSplitField, margin);
+    fdDelimiter.top = new FormAttachment(wExcludeSplitField, margin);
     fdDelimiter.right = new FormAttachment(100, 0);
     wDelimiter.setLayoutData(fdDelimiter);
 
@@ -320,6 +342,7 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
     wValName.setText(Const.NVL(input.getNewFieldname(), ""));
     wInclRownum.setSelection(input.isIncludeRowNumber());
     wDelimiterIsRegex.setSelection(input.isIsDelimiterRegex());
+    wExcludeSplitField.setSelection(input.isExcludeSplitField());
     if (input.getRowNumberField() != null) {
       wInclRownumField.setText(input.getRowNumberField());
     }
@@ -346,6 +369,7 @@ public class SplitFieldToRowsDialog extends BaseTransformDialog {
     input.setRowNumberField(wInclRownumField.getText());
     input.setResetRowNumber(wResetRownum.getSelection());
     input.setIsDelimiterRegex(wDelimiterIsRegex.getSelection());
+    input.setExcludeSplitField(wExcludeSplitField.getSelection());
     dispose();
   }
 }
diff --git a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMeta.java b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMeta.java
index 232c9c441c..f2af542e69 100644
--- a/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMeta.java
+++ b/plugins/transforms/splitfieldtorows/src/main/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMeta.java
@@ -103,6 +103,13 @@ public class SplitFieldToRowsMeta
       injectionKeyDescription = "SplitFieldsToRow.Injection.DelimiterIsRegexp.Description")
   private boolean isDelimiterRegex;
 
+  /** Remove the field to split from each output row */
+  @HopMetadataProperty(
+      key = "exclude_split_field",
+      injectionKey = "EXCLUDE_SPLIT_FIELD",
+      injectionKeyDescription = "SplitFieldsToRow.Injection.ExcludeSplitField.Description")
+  private boolean excludeSplitField;
+
   public boolean isIsDelimiterRegex() {
     return isDelimiterRegex;
   }
@@ -165,6 +172,7 @@ public class SplitFieldToRowsMeta
     newFieldname = "";
     includeRowNumber = false;
     isDelimiterRegex = false;
+    excludeSplitField = false;
     rowNumberField = "";
     resetRowNumber = true;
   }
@@ -179,6 +187,14 @@ public class SplitFieldToRowsMeta
       IHopMetadataProvider metadataProvider)
       throws HopTransformException {
 
+    if (excludeSplitField && !Utils.isEmpty(splitField)) {
+      String realSplitField = variables.resolve(splitField);
+      int splitIndex = row.indexOfValue(realSplitField);
+      if (splitIndex >= 0) {
+        row.removeValueMeta(splitIndex);
+      }
+    }
+
     IValueMeta v = new ValueMetaString(newFieldname);
     v.setOrigin(name);
     row.addValueMeta(v);
@@ -348,4 +364,18 @@ public class SplitFieldToRowsMeta
   public boolean isIncludeRowNumber() {
     return includeRowNumber;
   }
+
+  /**
+   * @return {@code true} when the field to split is removed from the output
+   */
+  public boolean isExcludeSplitField() {
+    return excludeSplitField;
+  }
+
+  /**
+   * @param excludeSplitField {@code true} to remove the field to split from the output
+   */
+  public void setExcludeSplitField(boolean excludeSplitField) {
+    this.excludeSplitField = excludeSplitField;
+  }
 }
diff --git a/plugins/transforms/splitfieldtorows/src/main/resources/org/apache/hop/pipeline/transforms/splitfieldtorows/messages/messages_en_US.properties b/plugins/transforms/splitfieldtorows/src/main/resources/org/apache/hop/pipeline/transforms/splitfieldtorows/messages/messages_en_US.properties
index 170f97675f..42b8fcdc69 100644
--- a/plugins/transforms/splitfieldtorows/src/main/resources/org/apache/hop/pipeline/transforms/splitfieldtorows/messages/messages_en_US.properties
+++ b/plugins/transforms/splitfieldtorows/src/main/resources/org/apache/hop/pipeline/transforms/splitfieldtorows/messages/messages_en_US.properties
@@ -18,6 +18,7 @@
 SplitFieldsToRow.Injection.Delimiter.Description=Field''s delimiter character
 SplitFieldsToRow.Injection.DelimiterIsRegexp.Description=Delimiter is a Regular Expression
 SplitFieldsToRow.Injection.Enclosure.Description=Enclosure string. Delimiters inside enclosure pairs are not treated as split points.
+SplitFieldsToRow.Injection.ExcludeSplitField.Description=Exclude the field to split from the output? (Y/N)
 SplitFieldsToRow.Injection.FieldToSplit.Description=Field to split
 SplitFieldsToRow.Injection.IncludeRowNum.Description=Include rownum field in output?(Y/N)
 SplitFieldsToRow.Injection.NewFieldname.Description=New field name
@@ -36,6 +37,8 @@ SplitFieldToRowsDialog.DelimiterIsRegex.Label=Delimiter is a Regular Expression
 SplitFieldToRowsDialog.DelimiterIsRegex.Tooltip=Check this if the delimiter is to be interpreted as a regular expression.\nRegex features like lookahead and lookbehind often prove very useful in string split contexts. 
 SplitFieldToRowsDialog.Enclosure.Label=Enclosure
 SplitFieldToRowsDialog.Enclosure.Tooltip=Ignore delimiters within pairs of enclosures (leave blank if none).\nEnclosure characters are removed from the output values.\nThis option is ignored when the delimiter is a regular expression.
+SplitFieldToRowsDialog.ExcludeSplitField.Label=Exclude field to split from output
+SplitFieldToRowsDialog.ExcludeSplitField.Tooltip=Remove the field to split from each output row.\nSplit values are still written to the new field.
 SplitFieldToRowsDialog.InclRownum.Label=Include rownum in output
 SplitFieldToRowsDialog.InclRownum.Tooltip=Check this to add a field (Integer) containing the row number.
 SplitFieldToRowsDialog.InclRownumField.Label=Rownum fieldname
diff --git a/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMetaTest.java b/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMetaTest.java
index 4f14449b1e..5713040be4 100644
--- a/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMetaTest.java
+++ b/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsMetaTest.java
@@ -17,12 +17,19 @@
 
 package org.apache.hop.pipeline.transforms.splitfieldtorows;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.core.variables.Variables;
 import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
 import org.apache.hop.pipeline.transforms.loadsave.LoadSaveTester;
 import org.apache.hop.pipeline.transforms.loadsave.validator.IFieldLoadSaveValidator;
@@ -50,7 +57,8 @@ class SplitFieldToRowsMetaTest {
             "includeRowNumber",
             "rowNumberField",
             "resetRowNumber",
-            "delimiterRegex");
+            "delimiterRegex",
+            "excludeSplitField");
 
     Map<String, String> getterMap = new HashMap<>();
     getterMap.put("includeRowNumber", "isIncludeRowNumber");
@@ -73,4 +81,85 @@ class SplitFieldToRowsMetaTest {
 
     loadSaveTester.testSerialization();
   }
+
+  @Test
+  void getFieldsKeepsSplitFieldByDefault() throws Exception {
+    SplitFieldToRowsMeta meta = meta("licenses_string", "licenses");
+
+    IRowMeta row = inputRow();
+    meta.getFields(row, "split", null, null, new Variables(), null);
+
+    assertEquals(List.of("id", "licenses_string", "name", "licenses"), names(row));
+  }
+
+  @Test
+  void getFieldsRemovesSplitFieldWhenExcluded() throws Exception {
+    SplitFieldToRowsMeta meta = meta("licenses_string", "licenses");
+    meta.setExcludeSplitField(true);
+
+    IRowMeta row = inputRow();
+    meta.getFields(row, "split", null, null, new Variables(), null);
+
+    assertEquals(List.of("id", "name", "licenses"), names(row));
+    assertTrue(row.searchValueMeta("licenses").isString());
+  }
+
+  @Test
+  void getFieldsRemovesSplitFieldResolvedFromVariable() throws Exception {
+    SplitFieldToRowsMeta meta = meta("${FIELD}", "licenses");
+    meta.setExcludeSplitField(true);
+    Variables variables = new Variables();
+    variables.setVariable("FIELD", "licenses_string");
+
+    IRowMeta row = inputRow();
+    meta.getFields(row, "split", null, null, variables, null);
+
+    assertEquals(List.of("id", "name", "licenses"), names(row));
+  }
+
+  @Test
+  void getFieldsLeavesOtherFieldsWhenSplitFieldIsMissing() throws Exception {
+    SplitFieldToRowsMeta meta = meta("missing", "licenses");
+    meta.setExcludeSplitField(true);
+
+    IRowMeta row = inputRow();
+    meta.getFields(row, "split", null, null, new Variables(), null);
+
+    assertEquals(List.of("id", "licenses_string", "name", "licenses"), names(row));
+  }
+
+  @Test
+  void getFieldsAppendsRowNumberAfterRemovingSplitField() throws Exception {
+    SplitFieldToRowsMeta meta = meta("licenses_string", "licenses");
+    meta.setExcludeSplitField(true);
+    meta.setIncludeRowNumber(true);
+    meta.setRowNumberField("${NR}");
+    Variables variables = new Variables();
+    variables.setVariable("NR", "nr");
+
+    IRowMeta row = inputRow();
+    meta.getFields(row, "split", null, null, variables, null);
+
+    assertEquals(List.of("id", "name", "licenses", "nr"), names(row));
+    assertTrue(row.searchValueMeta("nr").isInteger());
+  }
+
+  private static SplitFieldToRowsMeta meta(String splitField, String newFieldname) {
+    SplitFieldToRowsMeta meta = new SplitFieldToRowsMeta();
+    meta.setSplitField(splitField);
+    meta.setNewFieldname(newFieldname);
+    return meta;
+  }
+
+  private static IRowMeta inputRow() {
+    RowMeta row = new RowMeta();
+    row.addValueMeta(new ValueMetaString("id"));
+    row.addValueMeta(new ValueMetaString("licenses_string"));
+    row.addValueMeta(new ValueMetaString("name"));
+    return row;
+  }
+
+  private static List<String> names(IRowMeta row) {
+    return List.of(row.getFieldNames());
+  }
 }
diff --git a/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsTest.java b/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsTest.java
index bfe70166f6..4dc30e9c87 100644
--- a/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsTest.java
+++ b/plugins/transforms/splitfieldtorows/src/test/java/org/apache/hop/pipeline/transforms/splitfieldtorows/SplitFieldToRowsTest.java
@@ -28,12 +28,14 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import org.apache.hop.core.BlockingRowSet;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.logging.ILoggingObject;
+import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.RowMeta;
 import org.apache.hop.core.row.value.ValueMetaString;
 import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
@@ -51,6 +53,8 @@ class SplitFieldToRowsTest {
 
   private TransformMockHelper<SplitFieldToRowsMeta, SplitFieldToRowsData> transformMockHelper;
 
+  private IRowMeta lastOutputRowMeta;
+
   @BeforeAll
   static void initHop() throws Exception {
     HopEnvironment.init();
@@ -199,6 +203,57 @@ class SplitFieldToRowsTest {
     assertEquals(3L, rows.get(2)[2]);
   }
 
+  @Test
+  void keepsSurroundingFieldsAndAppendsSplitValue() throws Exception {
+    SplitFieldToRowsMeta meta = createMeta(",", null, false);
+    List<Object[]> rows =
+        executeSplit(meta, row("id", "csv", "name"), new Object[] {"1", "a,b", "n"}, Map.of());
+
+    assertEquals(List.of("1", "a,b", "n", "a"), prefix(rows.get(0), 4));
+    assertEquals(List.of("1", "a,b", "n", "b"), prefix(rows.get(1), 4));
+    assertEquals(List.of("id", "csv", "name", "value"), fieldNames());
+  }
+
+  @Test
+  void excludesSplitFieldFromOutput() throws Exception {
+    SplitFieldToRowsMeta meta = createMeta(",", null, false);
+    meta.setExcludeSplitField(true);
+    List<Object[]> rows =
+        executeSplit(meta, row("id", "csv", "name"), new Object[] {"1", "a,b", "n"}, Map.of());
+
+    assertEquals(List.of("1", "n", "a"), prefix(rows.get(0), 3));
+    assertEquals(List.of("1", "n", "b"), prefix(rows.get(1), 3));
+    assertEquals(List.of("id", "name", "value"), fieldNames());
+  }
+
+  @Test
+  void excludesSplitFieldAndKeepsRowNumbers() throws Exception {
+    SplitFieldToRowsMeta meta = createMeta(",", null, false);
+    meta.setExcludeSplitField(true);
+    meta.setIncludeRowNumber(true);
+    meta.setRowNumberField("rowNr");
+    meta.setResetRowNumber(true);
+    List<Object[]> rows =
+        executeSplit(meta, row("id", "csv", "name"), new Object[] {"1", "a,b", "n"}, Map.of());
+
+    assertEquals(List.of("1", "n", "a", 1L), prefix(rows.get(0), 4));
+    assertEquals(List.of("1", "n", "b", 2L), prefix(rows.get(1), 4));
+    assertEquals(List.of("id", "name", "value", "rowNr"), fieldNames());
+  }
+
+  @Test
+  void excludesSplitFieldResolvedFromVariable() throws Exception {
+    SplitFieldToRowsMeta meta = createMeta(",", null, false);
+    meta.setSplitField("${COL}");
+    meta.setExcludeSplitField(true);
+    List<Object[]> rows =
+        executeSplit(meta, row("id", "csv"), new Object[] {"1", "a,b"}, Map.of("COL", "csv"));
+
+    assertEquals(List.of("1", "a"), prefix(rows.get(0), 2));
+    assertEquals(List.of("1", "b"), prefix(rows.get(1), 2));
+    assertEquals(List.of("id", "value"), fieldNames());
+  }
+
   private List<Object[]> executeSplit(
       String value, String delimiter, String enclosure, boolean delimiterIsRegex) throws Exception {
     return executeSplit(createMeta(delimiter, enclosure, delimiterIsRegex), value);
@@ -210,6 +265,12 @@ class SplitFieldToRowsTest {
 
   private List<Object[]> executeSplit(
       SplitFieldToRowsMeta meta, String value, Map<String, String> variables) throws Exception {
+    return executeSplit(meta, row("csv"), new Object[] {value}, variables);
+  }
+
+  private List<Object[]> executeSplit(
+      SplitFieldToRowsMeta meta, RowMeta input, Object[] inputRow, Map<String, String> variables)
+      throws Exception {
     SplitFieldToRowsData data = new SplitFieldToRowsData();
     when(transformMockHelper.transformMeta.getTransform()).thenReturn(meta);
 
@@ -224,19 +285,18 @@ class SplitFieldToRowsTest {
     variables.forEach(transform::setVariable);
     transform.init();
 
-    RowMeta input = new RowMeta();
-    input.addValueMeta(new ValueMetaString("csv"));
     transform.setInputRowMeta(input);
 
     BlockingRowSet output = new BlockingRowSet(20);
     transform.setOutputRowSets(Collections.singletonList(output));
 
     SplitFieldToRows spyTransform = spy(transform);
-    doReturn(new Object[] {value}).doReturn(null).when(spyTransform).getRow();
+    doReturn(inputRow).doReturn(null).when(spyTransform).getRow();
 
     assertTrue(spyTransform.processRow());
     assertFalse(spyTransform.processRow());
 
+    lastOutputRowMeta = data.outputRowMeta;
     List<Object[]> result = new ArrayList<>();
     Object[] row;
     while ((row = output.getRowImmediate()) != null) {
@@ -245,6 +305,22 @@ class SplitFieldToRowsTest {
     return result;
   }
 
+  private static RowMeta row(String... names) {
+    RowMeta input = new RowMeta();
+    for (String name : names) {
+      input.addValueMeta(new ValueMetaString(name));
+    }
+    return input;
+  }
+
+  private static List<Object> prefix(Object[] row, int size) {
+    return Arrays.asList(row).subList(0, size);
+  }
+
+  private List<String> fieldNames() {
+    return List.of(lastOutputRowMeta.getFieldNames());
+  }
+
   private static SplitFieldToRowsMeta createMeta(
       String delimiter, String enclosure, boolean delimiterIsRegex) {
     SplitFieldToRowsMeta meta = new SplitFieldToRowsMeta();