This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch IOTDB-3319 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 3e56d5831613907ef4d3e8e5c1ba7c2216654435 Author: JackieTien97 <[email protected]> AuthorDate: Mon May 30 16:27:04 2022 +0800 [IOTDB-3319] fix IndexOutOfBoundsException when executing linear fill in group by query --- .../operator/process/LinearFillOperator.java | 3 +- .../execution/operator/LinearFillOperatorTest.java | 113 ++++++++++++++++++++- 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/LinearFillOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/LinearFillOperator.java index 35277da1ae..dbbe1b638a 100644 --- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/LinearFillOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/LinearFillOperator.java @@ -125,7 +125,8 @@ public class LinearFillOperator implements ProcessOperator { TsBlock result = new TsBlock(originTsBlock.getPositionCount(), originTsBlock.getTimeColumn(), columns); for (int i = 0; i < outputColumnCount; i++) { - nextTsBlockIndex[i]--; + // make sure nextTsBlockIndex for each column >= 1 + nextTsBlockIndex[i] = Math.max(1, nextTsBlockIndex[i] - 1); } return result; } diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/LinearFillOperatorTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/LinearFillOperatorTest.java index 6c17c09d4f..2fb9898418 100644 --- a/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/LinearFillOperatorTest.java +++ b/server/src/test/java/org/apache/iotdb/db/mpp/execution/operator/LinearFillOperatorTest.java @@ -233,8 +233,8 @@ public class LinearFillOperatorTest { } assertTrue(fillOperator.isFinished()); - assertEquals(3, count); - assertEquals(4, nullBlockIndex); + assertEquals(res.length, count); + assertEquals(nullBlock.length, nullBlockIndex); } finally { instanceNotificationExecutor.shutdown(); @@ -431,8 +431,113 @@ public class LinearFillOperatorTest { } assertTrue(fillOperator.isFinished()); - assertEquals(3, count); - assertEquals(5, nullBlockIndex); + assertEquals(res.length, count); + assertEquals(nullBlock.length, nullBlockIndex); + + } finally { + instanceNotificationExecutor.shutdown(); + } + } + + @Test + public void batchLinearFillTest3() { + ExecutorService instanceNotificationExecutor = + IoTDBThreadPoolFactory.newFixedThreadPool(1, "test-instance-notification"); + try { + QueryId queryId = new QueryId("stub_query"); + FragmentInstanceId instanceId = + new FragmentInstanceId(new PlanFragmentId(queryId, 0), "stub-instance"); + FragmentInstanceStateMachine stateMachine = + new FragmentInstanceStateMachine(instanceId, instanceNotificationExecutor); + FragmentInstanceContext fragmentInstanceContext = + createFragmentInstanceContext(instanceId, stateMachine); + PlanNodeId planNodeId1 = new PlanNodeId("1"); + fragmentInstanceContext.addOperatorContext( + 1, planNodeId1, LinearFillOperator.class.getSimpleName()); + + LinearFill[] fillArray = new LinearFill[] {new FloatLinearFill()}; + LinearFillOperator fillOperator = + new LinearFillOperator( + fragmentInstanceContext.getOperatorContexts().get(0), + fillArray, + new Operator() { + private int index = 0; + private final float[][][] value = + new float[][][] { + {{0.0f}}, {{2.0f}}, {{3.0f}}, {{4.0f}}, {{0.0f}}, {{0.0f}}, {{0.0f}} + }; + final boolean[][][] isNull = + new boolean[][][] { + {{true}}, {{false}}, {{false}}, {{false}}, {{true}}, {{true}}, {{true}} + }; + + @Override + public OperatorContext getOperatorContext() { + return null; + } + + @Override + public TsBlock next() { + TsBlockBuilder builder = new TsBlockBuilder(ImmutableList.of(TSDataType.FLOAT)); + for (int i = 0; i < 1; i++) { + builder.getTimeColumnBuilder().writeLong(i + index); + for (int j = 0; j < 1; j++) { + if (isNull[index][i][j]) { + builder.getColumnBuilder(j).appendNull(); + } else { + builder.getColumnBuilder(j).writeFloat(value[index][i][j]); + } + } + builder.declarePosition(); + } + index++; + return builder.build(); + } + + @Override + public boolean hasNext() { + return index < 7; + } + + @Override + public boolean isFinished() { + return index >= 7; + } + }); + + int count = 0; + float[][][] res = + new float[][][] {{{0.0f}}, {{2.0f}}, {{3.0f}}, {{4.0f}}, {{0.0f}}, {{0.0f}}, {{0.0f}}}; + boolean[][][] isNull = + new boolean[][][] { + {{true}}, {{false}}, {{false}}, {{false}}, {{true}}, {{true}}, {{true}} + }; + + boolean[] nullBlock = + new boolean[] {true, false, false, false, false, true, true, true, false, false, false}; + int nullBlockIndex = 0; + while (fillOperator.hasNext()) { + TsBlock block = fillOperator.next(); + assertEquals(nullBlock[nullBlockIndex++], block == null); + if (block == null) { + continue; + } + for (int i = 0; i < block.getPositionCount(); i++) { + long expectedTime = i + count; + assertEquals(expectedTime, block.getTimeByIndex(i)); + for (int j = 0; j < 1; j++) { + assertEquals(isNull[count][i][j], block.getColumn(j).isNull(i)); + if (!isNull[count][i][j]) { + assertEquals(res[count][i][j], block.getColumn(j).getFloat(i), 0.00001f); + } + } + } + count++; + } + + assertTrue(fillOperator.isFinished()); + assertEquals(res.length, count); + assertEquals(nullBlock.length, nullBlockIndex); } finally { instanceNotificationExecutor.shutdown();
