Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.hop.core.row.RowDataUtil;
import org.apache.hop.core.row.RowMeta;
import org.apache.hop.core.row.value.ValueMetaFactory;
import org.apache.hop.core.row.value.ValueMetaString;
import org.apache.hop.core.util.StringUtil;
import org.apache.hop.core.util.Utils;
import org.apache.hop.i18n.BaseMessages;
Expand All @@ -57,12 +58,26 @@ public Constant(
public static final RowMetaAndData buildRow(
ConstantMeta meta, ConstantData data, List<ICheckResult> remarks) {
IRowMeta rowMeta = new RowMeta();
Object[] rowData = new Object[meta.getFields().size()];
// Collected in lockstep with rowMeta: a field that gets skipped below must not leave a hole
// in the data, or every constant after it ends up in the previous field's column.
List<Object> rowData = new ArrayList<>();

for (int i = 0; i < meta.getFields().size(); i++) {
ConstantField field = meta.getFields().get(i);
int fieldNr = 0;
for (ConstantField field : meta.getFields()) {
fieldNr++;
int valtype = ValueMetaFactory.getIdForValueMeta(field.getFieldType());
if (field.getFieldName() != null) {
// Skip unnamed fields exactly like ConstantMeta.getFields() does. That method builds the
// transform's output row meta, so keeping a blank-named field here would make the constants
// row one value wider than the meta describing it.
if (StringUtils.isEmpty(field.getFieldName())) {
// A field that was filled in but never named can't become a column. Say so rather than
// dropping it quietly - it is nearly always a forgotten name, not a deliberate blank.
if (hasContent(field)) {
String message =
BaseMessages.getString(PKG, "Constant.CheckResult.NoFieldNameWarning", fieldNr);
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_WARNING, message, null));
}
} else {
IValueMeta value = null;
try {
value = ValueMetaFactory.createValueMeta(field.getFieldName(), valtype);
Expand All @@ -74,24 +89,22 @@ public static final RowMetaAndData buildRow(
value.setLength(field.getFieldLength());
value.setPrecision(field.getFieldPrecision());

Object fieldValue = null;
if (field.isEmptyString()) {
// Just set empty string
rowData[i] = StringUtil.EMPTY_STRING;
fieldValue = StringUtil.EMPTY_STRING;
} else if (value.getType() == IValueMeta.TYPE_NONE) {
// No value type was selected for this field, so there's nothing to convert to.
String message =
BaseMessages.getString(
PKG, "Constant.CheckResult.SpecifyTypeError", value.getName(), field.getValue());
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null));
} else {

String stringValue = field.getValue();

// If the value is empty: consider it to be NULL.
if (Utils.isEmpty(stringValue)) {
rowData[i] = null;

if (value.getType() == IValueMeta.TYPE_NONE) {
String message =
BaseMessages.getString(
PKG, "Constant.CheckResult.SpecifyTypeError", value.getName(), stringValue);
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null));
}
} else {
if (!Utils.isEmpty(stringValue)) {
switch (value.getType()) {
case IValueMeta.TYPE_NUMBER:
try {
Expand All @@ -115,7 +128,7 @@ public static final RowMetaAndData buildRow(
data.df.setDecimalFormatSymbols(data.dfs);
}

rowData[i] = data.nf.parse(stringValue).doubleValue();
fieldValue = data.nf.parse(stringValue).doubleValue();
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -129,7 +142,7 @@ public static final RowMetaAndData buildRow(
break;

case IValueMeta.TYPE_STRING:
rowData[i] = stringValue;
fieldValue = stringValue;
break;

case IValueMeta.TYPE_DATE:
Expand All @@ -139,7 +152,7 @@ public static final RowMetaAndData buildRow(
data.daf.setDateFormatSymbols(data.dafs);
}

rowData[i] = data.daf.parse(stringValue);
fieldValue = data.daf.parse(stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -154,7 +167,7 @@ public static final RowMetaAndData buildRow(

case IValueMeta.TYPE_INTEGER:
try {
rowData[i] = Long.valueOf(stringValue);
fieldValue = Long.valueOf(stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -169,7 +182,7 @@ public static final RowMetaAndData buildRow(

case IValueMeta.TYPE_BIGNUMBER:
try {
rowData[i] = new BigDecimal(stringValue);
fieldValue = new BigDecimal(stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -183,17 +196,17 @@ public static final RowMetaAndData buildRow(
break;

case IValueMeta.TYPE_BOOLEAN:
rowData[i] =
fieldValue =
"Y".equalsIgnoreCase(stringValue) || "TRUE".equalsIgnoreCase(stringValue);
break;

case IValueMeta.TYPE_BINARY:
rowData[i] = stringValue.getBytes();
fieldValue = stringValue.getBytes();
break;

case IValueMeta.TYPE_TIMESTAMP:
try {
rowData[i] = Timestamp.valueOf(stringValue);
fieldValue = Timestamp.valueOf(stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -208,7 +221,7 @@ public static final RowMetaAndData buildRow(

case IValueMeta.TYPE_INET:
try {
rowData[i] = InetAddress.getByName(stringValue);
fieldValue = InetAddress.getByName(stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
Expand All @@ -222,20 +235,51 @@ public static final RowMetaAndData buildRow(
break;

default:
String message =
BaseMessages.getString(
PKG, "Constant.CheckResult.SpecifyTypeError", value.getName(), stringValue);
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null));
// Any other value type: let the value meta plugin itself do the conversion.
// This way types like JSON and UUID work without a dedicated case here, and any
// type that simply can't be built from text reports why instead of claiming that
// no type was selected.
try {
IValueMeta stringMeta = new ValueMetaString(field.getFieldName());
stringMeta.setConversionMask(field.getFieldFormat());

fieldValue = value.convertData(stringMeta, stringValue);
} catch (Exception e) {
String message =
BaseMessages.getString(
PKG,
"Constant.BuildRow.Error.Parsing.Type",
value.getTypeDesc(),
value.getName(),
stringValue,
e.toString());
remarks.add(new CheckResult(ICheckResult.TYPE_RESULT_ERROR, message, null));
}
}
}
}
// Now add value to the row!
// This is in fact a copy from the fields row, but now with data.
rowMeta.addValueMeta(value);
rowData.add(fieldValue);
} // end if
} // end for

return new RowMetaAndData(rowMeta, rowData);
return new RowMetaAndData(rowMeta, rowData.toArray());
}

/**
* Whether anything was filled in for this field. Used to tell a forgotten field name apart from a
* leftover blank row, which carries nothing and is not worth reporting.
*/
private static boolean hasContent(ConstantField field) {
return field.isEmptyString()
|| StringUtils.isNotEmpty(field.getValue())
|| StringUtils.isNotEmpty(field.getFieldType())
|| StringUtils.isNotEmpty(field.getFieldFormat())
|| StringUtils.isNotEmpty(field.getCurrency())
|| StringUtils.isNotEmpty(field.getDecimal())
|| StringUtils.isNotEmpty(field.getGroup());
}

@Override
Expand Down Expand Up @@ -286,15 +330,21 @@ public boolean init() {

if (super.init()) {
// Create a row (constants) with all the values in it...
List<ICheckResult> remarks = new ArrayList<>(); // stores the errors...
List<ICheckResult> remarks = new ArrayList<>(); // stores the errors and warnings...
data.constants = buildRow(meta, data, remarks);
if (remarks.isEmpty()) {
return true;
} else {
for (ICheckResult cr : remarks) {

// Only a genuinely unbuildable constant stops the transform. Warnings - a field that was
// filled in but never named - are logged and the transform runs without that field.
boolean initialized = true;
for (ICheckResult cr : remarks) {
if (cr.getType() == ICheckResult.TYPE_RESULT_ERROR) {
logError(cr.getText());
initialized = false;
} else {
logMinimal(cr.getText());
}
}
return initialized;
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.BaseDialog;
import org.apache.hop.ui.core.dialog.BaseMessageDialog;
import org.apache.hop.ui.core.widget.ColumnInfo;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
Expand Down Expand Up @@ -206,6 +207,25 @@ public void getData() {
wFields.optWidth(true);
}

/**
* Returns a comma separated list of the 1-based row numbers that hold something but no field
* name, or null when every filled-in row is named. Only rows the save would keep are considered:
* completely empty rows are dropped anyway and are not a mistake.
*/
private String findUnnamedRows(int nrFields) {
StringBuilder rowNumbers = new StringBuilder();
for (int i = 0; i < nrFields; i++) {
TableItem item = wFields.getNonEmpty(i);
if (Utils.isEmpty(item.getText(1))) {
if (rowNumbers.length() > 0) {
rowNumbers.append(", ");
}
rowNumbers.append(wFields.table.indexOf(item) + 1);
}
}
return rowNumbers.length() == 0 ? null : rowNumbers.toString();
}

private void cancel() {
transformName = null;
input.setChanged(changed);
Expand All @@ -217,11 +237,24 @@ private void ok() {
return;
}

transformName = wTransformName.getText(); // return value

int i;

int nrFields = wFields.nrNonEmpty();

// A row that was filled in but never named cannot become an output field, so saving it would
// quietly lose what was typed. Point at the row instead of accepting it.
String unnamedRows = findUnnamedRows(nrFields);
if (unnamedRows != null) {
new BaseMessageDialog(
shell,
BaseMessages.getString(PKG, "ConstantDialog.NoFieldName.Title"),
BaseMessages.getString(PKG, "ConstantDialog.NoFieldName.Message", unnamedRows))
.open();
return;
}

transformName = wTransformName.getText(); // return value

List<ConstantField> fields = input.getFields();
fields.clear();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Constant.BuildRow.Error.Parsing.Integer=Couldn''t parse Integer field [{0}] with
Constant.BuildRow.Error.Parsing.InternetAddress=Couldn''t parse Internet Address field [{0}] with value [{1}] --> {2}
Constant.BuildRow.Error.Parsing.Number=Couldn''t parse Number field [{0}] with value [{1}] --> {2}
Constant.BuildRow.Error.Parsing.Timestamp=Couldn''t parse Timestamp field [{0}] with value [{1}] --> {2}
Constant.BuildRow.Error.Parsing.Type=Couldn''t parse {0} field [{1}] with value [{2}] --> {3}
Constant.CheckResult.NoFieldNameWarning=Constant {0} has no field name and is ignored. Give it a name to add it to the output rows.
Constant.CheckResult.SpecifyTypeError=Please specify the value type of field [{0}] with value [{1}]
Constant.Log.LineNr=LineNr : {0}
Constant.Log.Wrote.Row=Wrote row {0} : {1}
Expand All @@ -35,6 +37,8 @@ ConstantDialog.Format.Column=Format
ConstantDialog.Group.Column=Group
ConstantDialog.Length.Column=Length
ConstantDialog.Name.Column=Name
ConstantDialog.NoFieldName.Message=Row(s) {0} have a value but no field name.\n\nA constant without a name can''t be added to the output rows. Please give it a name or clear the row.
ConstantDialog.NoFieldName.Title=Missing field name
ConstantDialog.Precision.Column=Precision
ConstantDialog.Type.Column=Type
ConstantDialog.Value.Column=Value
Expand Down
Loading
Loading