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 7b926265fc clear results when pipeline has copy rows to restult, fixes 
#4581 (#8585)
7b926265fc is described below

commit 7b926265fc3d772f703548896add471b1d3023f3
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Fri Sep 25 11:59:37 2026 +0200

    clear results when pipeline has copy rows to restult, fixes #4581 (#8585)
---
 .../workflow/actions/pipeline/ActionPipeline.java  |  16 ++-
 .../pipeline/ActionPipelineResultRowsTest.java     | 121 +++++++++++++++++++++
 2 files changed, 135 insertions(+), 2 deletions(-)

diff --git 
a/plugins/actions/pipeline/src/main/java/org/apache/hop/workflow/actions/pipeline/ActionPipeline.java
 
b/plugins/actions/pipeline/src/main/java/org/apache/hop/workflow/actions/pipeline/ActionPipeline.java
index 22c7244e56..ab9bf5c2aa 100644
--- 
a/plugins/actions/pipeline/src/main/java/org/apache/hop/workflow/actions/pipeline/ActionPipeline.java
+++ 
b/plugins/actions/pipeline/src/main/java/org/apache/hop/workflow/actions/pipeline/ActionPipeline.java
@@ -77,6 +77,9 @@ import org.apache.hop.workflow.engine.IWorkflowEngine;
 public class ActionPipeline extends ActionBase implements Cloneable, IAction {
   private static final Class<?> PKG = ActionPipeline.class;
 
+  /** Plugin id of the "Copy rows to result" transform. */
+  private static final String ROWS_TO_RESULT_PLUGIN_ID = "RowsToResult";
+
   public static final class ParameterDefinition {
     @HopMetadataProperty(key = "pass_all_parameters")
     private boolean passingAllParameters = true;
@@ -662,11 +665,20 @@ public class ActionPipeline extends ActionBase implements 
Cloneable, IAction {
     result.clear(); // clear only the numbers, NOT the files or rows.
     result.add(newResult);
 
-    if (!Utils.isEmpty(newResult.getRows())) {
-      result.setRows(newResult.getRows());
+    // A pipeline that copies rows to the result replaces the previous rows, 
even when it copied
+    // none. Only a pipeline without such a transform passes the previous rows 
on unchanged.
+    //
+    if (!Utils.isEmpty(newResult.getRows()) || 
producesResultRows(pipeline.getPipelineMeta())) {
+      result.setRows(newResult.getRows() == null ? new ArrayList<>() : 
newResult.getRows());
     }
   }
 
+  static boolean producesResultRows(PipelineMeta pipelineMeta) {
+    return pipelineMeta != null
+        && pipelineMeta.getTransforms().stream()
+            .anyMatch(t -> 
ROWS_TO_RESULT_PLUGIN_ID.equals(t.getTransformPluginId()));
+  }
+
   public PipelineMeta getPipelineMeta(IHopMetadataProvider metadataProvider, 
IVariables variables)
       throws HopException {
     try {
diff --git 
a/plugins/actions/pipeline/src/test/java/org/apache/hop/workflow/actions/pipeline/ActionPipelineResultRowsTest.java
 
b/plugins/actions/pipeline/src/test/java/org/apache/hop/workflow/actions/pipeline/ActionPipelineResultRowsTest.java
new file mode 100644
index 0000000000..58b26d3420
--- /dev/null
+++ 
b/plugins/actions/pipeline/src/test/java/org/apache/hop/workflow/actions/pipeline/ActionPipelineResultRowsTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.hop.workflow.actions.pipeline;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.hop.core.Result;
+import org.apache.hop.core.RowMetaAndData;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.engine.IPipelineEngine;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.junit.jupiter.api.Test;
+
+/** Which rows an action hands to the next action once its pipeline finished 
(#4581, #4559). */
+class ActionPipelineResultRowsTest {
+
+  @Test
+  void copyRowsToResultWithNoRowsReplacesPreviousRows() throws Exception {
+    Result result = resultWithRows(3);
+
+    updateResult(result, pipelineResult(new ArrayList<>()), "RowsToResult", 
"Dummy");
+
+    assertTrue(result.getRows().isEmpty());
+  }
+
+  @Test
+  void copyRowsToResultReplacesPreviousRows() throws Exception {
+    Result result = resultWithRows(3);
+    List<RowMetaAndData> newRows = rows(1);
+
+    updateResult(result, pipelineResult(newRows), "RowsToResult");
+
+    assertSame(newRows, result.getRows());
+  }
+
+  @Test
+  void pipelineWithoutCopyRowsToResultPassesPreviousRowsOn() throws Exception {
+    Result result = resultWithRows(3);
+    List<RowMetaAndData> previousRows = result.getRows();
+
+    updateResult(result, pipelineResult(new ArrayList<>()), "Dummy", 
"WriteToLog");
+
+    assertSame(previousRows, result.getRows());
+    assertEquals(3, result.getRows().size());
+  }
+
+  @Test
+  void missingRowListFromTheEngineBecomesAnEmptyList() throws Exception {
+    Result result = resultWithRows(3);
+
+    updateResult(result, pipelineResult(null), "RowsToResult");
+
+    assertNotNull(result.getRows());
+    assertTrue(result.getRows().isEmpty());
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void updateResult(Result result, Result pipelineResult, 
String... pluginIds)
+      throws Exception {
+    List<TransformMeta> transforms = new ArrayList<>();
+    for (String pluginId : pluginIds) {
+      TransformMeta transformMeta = mock(TransformMeta.class);
+      when(transformMeta.getTransformPluginId()).thenReturn(pluginId);
+      transforms.add(transformMeta);
+    }
+    PipelineMeta pipelineMeta = mock(PipelineMeta.class);
+    when(pipelineMeta.getTransforms()).thenReturn(transforms);
+
+    IPipelineEngine<PipelineMeta> pipeline = mock(IPipelineEngine.class);
+    when(pipeline.getPipelineMeta()).thenReturn(pipelineMeta);
+    when(pipeline.getResult()).thenReturn(pipelineResult);
+
+    ActionPipeline action = new ActionPipeline("run-child");
+    Field field = ActionPipeline.class.getDeclaredField("pipeline");
+    field.setAccessible(true);
+    field.set(action, pipeline);
+
+    action.updateResult(result);
+  }
+
+  private static Result pipelineResult(List<RowMetaAndData> rows) {
+    Result result = new Result();
+    result.setRows(rows);
+    return result;
+  }
+
+  private static Result resultWithRows(int count) {
+    return pipelineResult(rows(count));
+  }
+
+  private static List<RowMetaAndData> rows(int count) {
+    List<RowMetaAndData> rows = new ArrayList<>();
+    for (int i = 0; i < count; i++) {
+      rows.add(new RowMetaAndData());
+    }
+    return rows;
+  }
+}

Reply via email to