Fix NPE when applying a transform that outputs to __time (#12870)

This commit is contained in:
Jonathan Wei 2022-08-07 08:51:47 -05:00 committed by GitHub
parent 9f8982a9a6
commit 2045a1345c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 2 deletions

View File

@ -24,6 +24,7 @@ import org.apache.druid.data.input.InputRowListPlusRawValues;
import org.apache.druid.data.input.Row;
import org.apache.druid.data.input.Rows;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.parsers.ParseException;
import org.apache.druid.query.filter.ValueMatcher;
import org.apache.druid.segment.RowAdapters;
import org.apache.druid.segment.RowBasedColumnSelectorFactory;
@ -114,7 +115,12 @@ public class Transformer
final List<InputRow> originalRows = row.getInputRows();
final List<InputRow> transformedRows = new ArrayList<>(originalRows.size());
for (InputRow originalRow : originalRows) {
transformedRows.add(new TransformedInputRow(originalRow, transforms));
try {
transformedRows.add(new TransformedInputRow(originalRow, transforms));
}
catch (ParseException pe) {
return InputRowListPlusRawValues.of(row.getRawValues(), pe);
}
}
inputRowListPlusRawValues = InputRowListPlusRawValues.ofList(row.getRawValuesList(), transformedRows);
}
@ -170,7 +176,11 @@ public class Transformer
final long ts;
if (transform != null) {
//noinspection ConstantConditions time column is never null
ts = Rows.objectToNumber(ColumnHolder.TIME_COLUMN_NAME, transform.eval(row), true).longValue();
final Number transformedVal = Rows.objectToNumber(ColumnHolder.TIME_COLUMN_NAME, transform.eval(row), true);
if (transformedVal == null) {
throw new ParseException(row.toString(), "Could not transform value for __time.");
}
ts = transformedVal.longValue();
} else {
ts = row.getTimestampFromEpoch();
}

View File

@ -21,10 +21,12 @@ package org.apache.druid.segment.transform;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.data.input.InputRow;
import org.apache.druid.data.input.InputRowListPlusRawValues;
import org.apache.druid.data.input.MapBasedInputRow;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.parsers.ParseException;
import org.apache.druid.query.expression.TestExprMacroTable;
import org.apache.druid.query.filter.SelectorDimFilter;
import org.apache.druid.testing.InitializedNullHandlingTest;
@ -74,6 +76,68 @@ public class TransformerTest extends InitializedNullHandlingTest
Assert.assertEquals(now.minusDays(2), actual.getTimestamp());
}
@Test
public void testTransformTimeColumnWithInvalidTimeValue()
{
final Transformer transformer = new Transformer(
new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("__time", "timestamp_parse(ts, null, 'UTC')", TestExprMacroTable.INSTANCE)
)
)
);
final DateTime now = DateTimes.nowUtc();
final InputRow row = new MapBasedInputRow(
now,
ImmutableList.of("ts", "dim"),
ImmutableMap.of("ts", "not_a_timestamp", "dim", false)
);
if (NullHandling.replaceWithDefault()) {
final InputRow actual = transformer.transform(row);
Assert.assertNotNull(actual);
Assert.assertEquals(DateTimes.of("1970-01-01T00:00:00.000Z"), actual.getTimestamp());
} else {
expectedException.expectMessage("Could not transform value for __time.");
expectedException.expect(ParseException.class);
transformer.transform(row);
}
}
@Test
public void testTransformTimeColumnWithInvalidTimeValueInputRowListPlusRawValues()
{
final Transformer transformer = new Transformer(
new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("__time", "timestamp_parse(ts, null, 'UTC')", TestExprMacroTable.INSTANCE)
)
)
);
final DateTime now = DateTimes.nowUtc();
final InputRow row = new MapBasedInputRow(
now,
ImmutableList.of("ts", "dim"),
ImmutableMap.of("ts", "not_a_timestamp", "dim", false)
);
final InputRowListPlusRawValues actual = transformer.transform(
InputRowListPlusRawValues.of(
row,
ImmutableMap.of("ts", "not_a_timestamp", "dim", false)
)
);
Assert.assertNotNull(actual);
Assert.assertEquals(1, actual.getRawValuesList().size());
if (NullHandling.replaceWithDefault()) {
Assert.assertEquals(1, actual.getInputRows().size());
Assert.assertEquals(DateTimes.of("1970-01-01T00:00:00.000Z"), actual.getInputRows().get(0).getTimestamp());
} else {
Assert.assertNull(actual.getInputRows());
Assert.assertEquals("Could not transform value for __time.", actual.getParseException().getMessage());
}
}
@Test
public void testTransformWithStringTransformOnBooleanColumnTransformAfterCasting()
{