This is an automated email from the ASF dual-hosted git repository.
hansva 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 4719ab085f Fix Combination Lookup SQL button NPE when parent pipeline
is null (#8431)
4719ab085f is described below
commit 4719ab085f0352e8f5870a922f0b935caf96aa49
Author: Lance <[email protected]>
AuthorDate: Fri Sep 18 16:17:49 2026 +0800
Fix Combination Lookup SQL button NPE when parent pipeline is null (#8431)
Signed-off-by: leehaut <[email protected]>
---
.../combinationlookup/CombinationLookupMeta.java | 9 +-
.../transforms/combinationlookup/KeyField.java | 44 +----
.../transforms/combinationlookup/ReturnFields.java | 82 +--------
.../CombinationLookupMetaTest.java | 201 +++++++++++++++++++++
4 files changed, 219 insertions(+), 117 deletions(-)
diff --git
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMeta.java
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMeta.java
index 146e4ea688..4f9b7f2fee 100644
---
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMeta.java
+++
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMeta.java
@@ -421,8 +421,7 @@ public class CombinationLookupMeta
IRowMeta prev,
IHopMetadataProvider metadataProvider) {
- DatabaseMeta databaseMeta =
-
getParentTransformMeta().getParentPipelineMeta().findDatabase(connectionName,
variables);
+ DatabaseMeta databaseMeta = pipelineMeta.findDatabase(connectionName,
variables);
SqlStatement retval =
new SqlStatement(transformMeta.getName(), databaseMeta, null); //
default: nothing to do!
@@ -673,8 +672,10 @@ public class CombinationLookupMeta
IRowMeta info,
IHopMetadataProvider metadataProvider) {
- DatabaseMeta databaseMeta =
-
getParentTransformMeta().getParentPipelineMeta().findDatabase(connectionName,
variables);
+ DatabaseMeta databaseMeta = pipelineMeta.findDatabase(connectionName,
variables);
+ if (databaseMeta == null || prev == null) {
+ return;
+ }
// The keys are read-only...
for (int i = 0; i < fields.getKeyFields().size(); i++) {
diff --git
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/KeyField.java
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/KeyField.java
index b9058d2917..bb60297e71 100644
---
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/KeyField.java
+++
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/KeyField.java
@@ -18,21 +18,25 @@
package org.apache.hop.pipeline.transforms.combinationlookup;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.hop.metadata.api.HopMetadataProperty;
import org.apache.hop.metadata.api.HopMetadataPropertyType;
+@Getter
+@Setter
public class KeyField {
@HopMetadataProperty(
injectionKey = "KEY_FIELD",
injectionKeyDescription = "CombinationLookup.Injection.KEY_FIELD",
hopMetadataPropertyType = HopMetadataPropertyType.STREAM_FIELD)
- String name;
+ private String name;
@HopMetadataProperty(
injectionKey = "KEY_LOOKUP",
injectionKeyDescription = "CombinationLookup.Injection.KEY_LOOKUP",
hopMetadataPropertyType = HopMetadataPropertyType.RDBMS_COLUMN)
- String lookup;
+ private String lookup;
public KeyField() {}
@@ -45,40 +49,4 @@ public class KeyField {
this.name = f.name;
this.lookup = f.lookup;
}
-
- /**
- * Gets name
- *
- * @return value of name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets name
- *
- * @param name value of name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Gets lookup
- *
- * @return value of lookup
- */
- public String getLookup() {
- return lookup;
- }
-
- /**
- * Sets lookup
- *
- * @param lookup value of lookup
- */
- public void setLookup(String lookup) {
- this.lookup = lookup;
- }
}
diff --git
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/ReturnFields.java
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/ReturnFields.java
index 0359d8aff5..1bfc9c4d53 100644
---
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/ReturnFields.java
+++
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/ReturnFields.java
@@ -18,8 +18,14 @@
package org.apache.hop.pipeline.transforms.combinationlookup;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
import org.apache.hop.metadata.api.HopMetadataProperty;
+@Getter
+@Setter
+@NoArgsConstructor
public class ReturnFields {
/** Technical Key field to return */
@HopMetadataProperty(
@@ -46,9 +52,7 @@ public class ReturnFields {
key = "creation_method",
injectionKey = "TECHNICAL_KEY_CREATION",
injectionKeyDescription =
"CombinationLookup.Injection.TECHNICAL_KEY_CREATION")
- private String techKeyCreation = null;
-
- public ReturnFields() {}
+ private String techKeyCreation;
public ReturnFields(ReturnFields f) {
this.technicalKeyField = f.technicalKeyField;
@@ -56,76 +60,4 @@ public class ReturnFields {
this.lastUpdateField = f.lastUpdateField;
this.techKeyCreation = f.techKeyCreation;
}
-
- /**
- * Gets technicalKeyField
- *
- * @return value of technicalKeyField
- */
- public String getTechnicalKeyField() {
- return technicalKeyField;
- }
-
- /**
- * Sets technicalKeyField
- *
- * @param technicalKeyField value of technicalKeyField
- */
- public void setTechnicalKeyField(String technicalKeyField) {
- this.technicalKeyField = technicalKeyField;
- }
-
- /**
- * Gets useAutoinc
- *
- * @return value of useAutoinc
- */
- public boolean isUseAutoIncrement() {
- return useAutoIncrement;
- }
-
- /**
- * Sets useAutoinc
- *
- * @param useAutoIncrement value of useAutoinc
- */
- public void setUseAutoIncrement(boolean useAutoIncrement) {
- this.useAutoIncrement = useAutoIncrement;
- }
-
- /**
- * Gets lastUpdateField
- *
- * @return value of lastUpdateField
- */
- public String getLastUpdateField() {
- return lastUpdateField;
- }
-
- /**
- * Sets lastUpdateField
- *
- * @param lastUpdateField value of lastUpdateField
- */
- public void setLastUpdateField(String lastUpdateField) {
- this.lastUpdateField = lastUpdateField;
- }
-
- /**
- * Gets techKeyCreation
- *
- * @return value of techKeyCreation
- */
- public String getTechKeyCreation() {
- return techKeyCreation;
- }
-
- /**
- * Sets techKeyCreation
- *
- * @param techKeyCreation value of techKeyCreation
- */
- public void setTechKeyCreation(String techKeyCreation) {
- this.techKeyCreation = techKeyCreation;
- }
}
diff --git
a/plugins/transforms/combinationlookup/src/test/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMetaTest.java
b/plugins/transforms/combinationlookup/src/test/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMetaTest.java
index c40e23a604..6cf97afd9f 100644
---
a/plugins/transforms/combinationlookup/src/test/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMetaTest.java
+++
b/plugins/transforms/combinationlookup/src/test/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupMetaTest.java
@@ -17,13 +17,34 @@
package org.apache.hop.pipeline.transforms.combinationlookup;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.SqlStatement;
+import org.apache.hop.core.database.DatabaseMeta;
import org.apache.hop.core.plugins.PluginRegistry;
+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.i18n.BaseMessages;
+import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
+import org.apache.hop.pipeline.DatabaseImpact;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transform.TransformMeta;
import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CombinationLookupMetaTest {
+ private static final Class<?> PKG = CombinationLookupMeta.class;
+ private static final String CONNECTION_NAME = "h2";
+ private static final String TRANSFORM_NAME = "Combination lookup/update";
+
@BeforeEach
void setUpLoadSave() throws Exception {
HopEnvironment.init();
@@ -35,4 +56,184 @@ class CombinationLookupMetaTest {
TransformSerializationTestUtil.testSerialization(
"/combination-lookup-transform.xml", CombinationLookupMeta.class);
}
+
+ /**
+ * CombinationLookupDialog.create() wraps dialog contents in a new
TransformMeta that never gets a
+ * parent pipeline. getSqlStatements must use the PipelineMeta argument, not
the parent chain.
+ */
+ @Test
+ void getSqlStatementsDoesNotNpeWhenParentPipelineIsNull() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ assertNull(transformMeta.getParentPipelineMeta());
+
+ PipelineMeta pipelineMeta = pipelineWithoutConnection();
+ RowMeta prev = incomingRow();
+
+ SqlStatement sql =
+ info.getSqlStatements(
+ new Variables(), pipelineMeta, transformMeta, prev,
pipelineMeta.getMetadataProvider());
+
+ assertNotNull(sql);
+ assertTrue(sql.hasError());
+ assertEquals(
+ BaseMessages.getString(PKG,
"CombinationLookupMeta.ReturnValue.NotConnectionDefined"),
+ sql.getError());
+ }
+
+ @Test
+ void getSqlStatementsUsesPipelineMetaToResolveConnection() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ info.setTableName("");
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ assertNull(transformMeta.getParentPipelineMeta());
+
+ PipelineMeta pipelineMeta = pipelineWithConnection();
+
+ SqlStatement sql =
+ info.getSqlStatements(
+ new Variables(),
+ pipelineMeta,
+ transformMeta,
+ incomingRow(),
+ pipelineMeta.getMetadataProvider());
+
+ assertNotNull(sql);
+ assertNotNull(sql.getDatabase());
+ assertEquals(CONNECTION_NAME, sql.getDatabase().getName());
+ assertTrue(sql.hasError());
+ assertEquals(
+ BaseMessages.getString(PKG,
"CombinationLookupMeta.ReturnValue.NotTableDefined"),
+ sql.getError());
+ }
+
+ @Test
+ void getSqlStatementsReportsMissingInputFieldsWithoutNpe() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ PipelineMeta pipelineMeta = pipelineWithConnection();
+
+ SqlStatement sql =
+ info.getSqlStatements(
+ new Variables(),
+ pipelineMeta,
+ transformMeta,
+ new RowMeta(),
+ pipelineMeta.getMetadataProvider());
+
+ assertTrue(sql.hasError());
+ assertEquals(
+ BaseMessages.getString(PKG,
"CombinationLookupMeta.ReturnValue.NotReceivingField"),
+ sql.getError());
+ }
+
+ @Test
+ void analyseImpactDoesNotNpeWhenParentPipelineIsNull() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ assertNull(transformMeta.getParentPipelineMeta());
+
+ PipelineMeta pipelineMeta = pipelineWithConnection();
+ pipelineMeta.setName("issue-8283");
+ List<DatabaseImpact> impact = new ArrayList<>();
+
+ info.analyseImpact(
+ new Variables(),
+ impact,
+ pipelineMeta,
+ transformMeta,
+ incomingRow(),
+ new String[] {"Data grid"},
+ new String[0],
+ null,
+ pipelineMeta.getMetadataProvider());
+
+ assertEquals(1, impact.size());
+ DatabaseImpact first = impact.get(0);
+ assertEquals(DatabaseImpact.TYPE_IMPACT_READ_WRITE, first.getType());
+ assertEquals("issue-8283", first.getPipelineName());
+ assertEquals(TRANSFORM_NAME, first.getTransformName());
+ assertEquals("junk_customer", first.getTable());
+ assertEquals("customer_code", first.getField());
+ }
+
+ @Test
+ void analyseImpactSkipsWorkWhenConnectionIsMissing() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ PipelineMeta pipelineMeta = pipelineWithoutConnection();
+ List<DatabaseImpact> impact = new ArrayList<>();
+
+ info.analyseImpact(
+ new Variables(),
+ impact,
+ pipelineMeta,
+ transformMeta,
+ incomingRow(),
+ new String[0],
+ new String[0],
+ null,
+ pipelineMeta.getMetadataProvider());
+
+ assertTrue(impact.isEmpty());
+ }
+
+ @Test
+ void analyseImpactIncludesHashFieldWhenEnabled() throws Exception {
+ CombinationLookupMeta info = dialogStyleMeta();
+ info.setUseHash(true);
+ info.setHashField("hashcode");
+ TransformMeta transformMeta = new TransformMeta(TRANSFORM_NAME, info);
+ PipelineMeta pipelineMeta = pipelineWithConnection();
+ List<DatabaseImpact> impact = new ArrayList<>();
+
+ info.analyseImpact(
+ new Variables(),
+ impact,
+ pipelineMeta,
+ transformMeta,
+ incomingRow(),
+ new String[0],
+ new String[0],
+ null,
+ pipelineMeta.getMetadataProvider());
+
+ assertEquals(2, impact.size());
+ assertEquals("hashcode", impact.get(1).getField());
+ }
+
+ private static CombinationLookupMeta dialogStyleMeta() {
+ CombinationLookupMeta info = new CombinationLookupMeta();
+ info.setConnectionName(CONNECTION_NAME);
+ info.setTableName("junk_customer");
+ info.getFields().getKeyFields().add(new KeyField("customer_code",
"customer_code"));
+ info.getFields().getReturnFields().setTechnicalKeyField("customer_tk");
+ info.getFields()
+ .getReturnFields()
+ .setTechKeyCreation(CombinationLookupMeta.CREATION_METHOD_TABLEMAX);
+ return info;
+ }
+
+ private static PipelineMeta pipelineWithoutConnection() {
+ MemoryMetadataProvider metadataProvider = new MemoryMetadataProvider();
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setMetadataProvider(metadataProvider);
+ return pipelineMeta;
+ }
+
+ private static PipelineMeta pipelineWithConnection() throws Exception {
+ MemoryMetadataProvider metadataProvider = new MemoryMetadataProvider();
+ metadataProvider
+ .getSerializer(DatabaseMeta.class)
+ .save(new DatabaseMeta(CONNECTION_NAME, "NONE", "Native", "", "", "",
"", ""));
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setMetadataProvider(metadataProvider);
+ return pipelineMeta;
+ }
+
+ private static RowMeta incomingRow() {
+ RowMeta prev = new RowMeta();
+ prev.addValueMeta(new ValueMetaString("customer_code"));
+ return prev;
+ }
}