diff --git a/omnioperator/omniop-openlookeng-extension/pom.xml b/omnioperator/omniop-openlookeng-extension/pom.xml
index d10d2e43e2ed3c74589b1e2a9bc8ccf9b1923ba4..590586a18cf51d3f2f4276e43874e53c07681626 100644
--- a/omnioperator/omniop-openlookeng-extension/pom.xml
+++ b/omnioperator/omniop-openlookeng-extension/pom.xml
@@ -22,6 +22,7 @@
3.1.2-1
2.10.0
1.0.0
+ src/test/java
@@ -194,6 +195,7 @@
boostkit-omniop-openlookeng-${openLooKeng.version}-${omniruntime.version}-aarch64
+ ${test.source.dir}
org.jacoco
@@ -288,5 +290,13 @@
+
+
+ omni-test
+
+ src/test/omni
+
+
+
\ No newline at end of file
diff --git a/omnioperator/omniop-openlookeng-extension/src/main/java/nova/hetu/olk/tool/OperatorUtils.java b/omnioperator/omniop-openlookeng-extension/src/main/java/nova/hetu/olk/tool/OperatorUtils.java
index 07d16bb753b8865be3ba6fb2f9c17b8479c0ddf1..60c60e9b6e2a93b071e2bd24e0426e82d683049b 100644
--- a/omnioperator/omniop-openlookeng-extension/src/main/java/nova/hetu/olk/tool/OperatorUtils.java
+++ b/omnioperator/omniop-openlookeng-extension/src/main/java/nova/hetu/olk/tool/OperatorUtils.java
@@ -80,9 +80,9 @@ import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static io.prestosql.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR;
import static io.prestosql.spi.type.Decimals.MAX_SHORT_PRECISION;
+import static io.prestosql.spi.type.DoubleType.DOUBLE;
import static java.lang.Double.doubleToLongBits;
import static java.lang.Double.longBitsToDouble;
-import static javassist.bytecode.StackMap.DOUBLE;
/**
* The type Operator utils.
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/BlockUtil.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/BlockUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cdb96b96886bfc4e81607b55dc24b3413a7dc94
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/BlockUtil.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk;
+
+import io.airlift.slice.Slice;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.DictionaryBlock;
+import io.prestosql.spi.type.CharType;
+import io.prestosql.spi.type.DecimalType;
+import io.prestosql.spi.type.VarcharType;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static io.prestosql.spi.type.BigintType.BIGINT;
+import static io.prestosql.spi.type.BooleanType.BOOLEAN;
+import static io.prestosql.spi.type.DateType.DATE;
+import static io.prestosql.spi.type.Decimals.encodeUnscaledValue;
+import static io.prestosql.spi.type.DoubleType.DOUBLE;
+import static io.prestosql.spi.type.IntegerType.INTEGER;
+import static io.prestosql.spi.type.RealType.REAL;
+import static io.prestosql.spi.type.TimestampType.TIMESTAMP;
+import static io.prestosql.spi.type.VarcharType.VARCHAR;
+import static java.lang.Float.floatToRawIntBits;
+
+public final class BlockUtil
+{
+ private BlockUtil()
+ {
+ }
+
+ public static Block createStringSequenceBlock(int start, int end, VarcharType type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, 100);
+
+ for (int i = start; i < end; i++) {
+ type.writeString(builder, String.valueOf(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createStringSequenceBlock(int start, int end, CharType type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, 100);
+
+ for (int i = start; i < end; i++) {
+ type.writeString(builder, String.valueOf(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createIntegerSequenceBlock(int start, int end)
+ {
+ BlockBuilder builder = INTEGER.createFixedSizeBlockBuilder(end - start);
+
+ for (int i = start; i < end; i++) {
+ INTEGER.writeLong(builder, i);
+ }
+
+ return builder.build();
+ }
+
+ public static Block createStringDictionaryBlock(int start, int length, VarcharType type)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = type.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ type.writeString(builder, String.valueOf(i));
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createStringDictionaryBlock(int start, int length, CharType type)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = type.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ type.writeString(builder, String.valueOf(i));
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createLongDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = BIGINT.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ BIGINT.writeLong(builder, i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createIntegerDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = INTEGER.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ INTEGER.writeLong(builder, i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createRealDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = REAL.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ REAL.writeLong(builder, floatToRawIntBits((float) i));
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createDoubleDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = DOUBLE.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ DOUBLE.writeDouble(builder, i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createBooleanDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = BOOLEAN.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ BOOLEAN.writeBoolean(builder, i % 2 == 0);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createDateDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = DATE.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ DATE.writeLong(builder, i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createTimestampDictionaryBlock(int start, int length)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BlockBuilder builder = TIMESTAMP.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ TIMESTAMP.writeLong(builder, i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createShortDecimalDictionaryBlock(int start, int length, DecimalType type)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ long base = BigInteger.TEN.pow(type.getScale()).longValue();
+
+ BlockBuilder builder = type.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ type.writeLong(builder, base * i);
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createLongDecimalDictionaryBlock(int start, int length, DecimalType type)
+ {
+ checkArgument(length > 5, "block must have more than 5 entries");
+
+ int dictionarySize = length / 5;
+ BigInteger base = BigInteger.TEN.pow(type.getScale());
+
+ BlockBuilder builder = type.createBlockBuilder(null, dictionarySize);
+ for (int i = start; i < start + dictionarySize; i++) {
+ type.writeSlice(builder, encodeUnscaledValue(BigInteger.valueOf(i).multiply(base)));
+ }
+ int[] ids = new int[length];
+ for (int i = 0; i < length; i++) {
+ ids[i] = i % dictionarySize;
+ }
+ return new DictionaryBlock(builder.build(), ids);
+ }
+
+ public static Block createIntegerBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = INTEGER.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ INTEGER.writeLong(builder, values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createLongBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = BIGINT.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ BIGINT.writeLong(builder, values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createRealBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = REAL.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ REAL.writeLong(builder, floatToRawIntBits((float) values.get(i)));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createDoubleBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = DOUBLE.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ DOUBLE.writeDouble(builder, (double) values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createStringBlock(String prefix, List values, VarcharType type)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = type.createBlockBuilder(null, positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ type.writeString(builder, prefix + values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createBooleanBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = BOOLEAN.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ BOOLEAN.writeBoolean(builder, values.get(i) == 0);
+ }
+
+ return builder.build();
+ }
+
+ public static Block createDateBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = DATE.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ DATE.writeLong(builder, values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createTimestampBlock(List values)
+ {
+ int positionCount = values.size();
+ BlockBuilder builder = TIMESTAMP.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ TIMESTAMP.writeLong(builder, values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createShortDecimalBlock(List values, DecimalType type)
+ {
+ int positionCount = values.size();
+ long base = BigInteger.TEN.pow(type.getScale()).longValue();
+ BlockBuilder builder = type.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ type.writeLong(builder, base * values.get(i));
+ }
+
+ return builder.build();
+ }
+
+ public static Block createLongDecimalBlock(List values, DecimalType type)
+ {
+ int positionCount = values.size();
+ BigInteger base = BigInteger.TEN.pow(type.getScale());
+ BlockBuilder builder = type.createFixedSizeBlockBuilder(positionCount);
+ for (int i = 0; i < positionCount; i++) {
+ type.writeSlice(builder, encodeUnscaledValue(BigInteger.valueOf(values.get(i)).multiply(base)));
+ }
+
+ return builder.build();
+ }
+
+ private static Block createDictionaryBlock(Block block)
+ {
+ int dictionarySize = block.getPositionCount();
+ int[] ids = new int[dictionarySize];
+ for (int i = 0; i < dictionarySize; i++) {
+ ids[i] = i;
+ }
+ return new DictionaryBlock(block, ids);
+ }
+
+ public static Block createIntegerDictionaryBlock(List values)
+ {
+ Block block = createIntegerBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createLongDictionaryBlock(List values)
+ {
+ Block block = createLongBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createRealDictionaryBlock(List values)
+ {
+ Block block = createRealBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createDoubleDictionaryBlock(List values)
+ {
+ Block block = createDoubleBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createStringDictionaryBlock(String prefix, List values, VarcharType type)
+ {
+ Block block = createStringBlock(prefix, values, type);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createBooleanDictionaryBlock(List values)
+ {
+ Block block = createBooleanBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createDateDictionaryBlock(List values)
+ {
+ Block block = createDateBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createTimestampDictionaryBlock(List values)
+ {
+ Block block = createTimestampBlock(values);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createShortDecimalDictionaryBlock(List values, DecimalType type)
+ {
+ Block block = createShortDecimalBlock(values, type);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block createLongDecimalDictionaryBlock(List values, DecimalType type)
+ {
+ Block block = createLongDecimalBlock(values, type);
+ return createDictionaryBlock(block);
+ }
+
+ public static Block buildVarcharBlock(int rowSize, int width, int offset)
+ {
+ BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, rowSize);
+ for (int i = 0; i < rowSize; i++) {
+ VARCHAR.writeString(blockBuilder, createFixedWidthString(i, offset, width));
+ }
+ return blockBuilder.build();
+ }
+
+ public static Slice[] getBlockSlices(Block block, int rowSize, int width)
+ {
+ Slice[] slice = new Slice[rowSize];
+ for (int i = 0; i < rowSize; i++) {
+ slice[i] = block.getSlice(i, 0, width);
+ }
+ return slice;
+ }
+
+ private static String createFixedWidthString(int index, int offset, int width)
+ {
+ String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int j = 0; j < width; j++) {
+ stringBuilder.append(str.charAt((index + offset + j) % str.length()));
+ }
+ return stringBuilder.toString();
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/PageBuilderUtil.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/PageBuilderUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef799b5ab26b4b2929ca97fcbf2fbdf550a795fb
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/PageBuilderUtil.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk;
+
+import io.prestosql.block.BlockAssertions;
+import io.prestosql.spi.Page;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.type.CharType;
+import io.prestosql.spi.type.DecimalType;
+import io.prestosql.spi.type.Type;
+import io.prestosql.spi.type.VarcharType;
+
+import java.util.List;
+
+import static io.prestosql.spi.type.BigintType.BIGINT;
+import static io.prestosql.spi.type.BooleanType.BOOLEAN;
+import static io.prestosql.spi.type.DateType.DATE;
+import static io.prestosql.spi.type.Decimals.isLongDecimal;
+import static io.prestosql.spi.type.Decimals.isShortDecimal;
+import static io.prestosql.spi.type.DoubleType.DOUBLE;
+import static io.prestosql.spi.type.IntegerType.INTEGER;
+import static io.prestosql.spi.type.RealType.REAL;
+import static io.prestosql.spi.type.TimestampType.TIMESTAMP;
+
+public final class PageBuilderUtil
+{
+ private PageBuilderUtil()
+ {
+ }
+
+ public static Page createSequencePage(List extends Type> types, int length)
+ {
+ return createSequencePage(types, length, new int[types.size()]);
+ }
+
+ public static Page createSequencePage(List extends Type> types, int length, int... initialValues)
+ {
+ Block[] blocks = new Block[initialValues.length];
+ for (int i = 0; i < blocks.length; i++) {
+ Type type = types.get(i);
+ int initialValue = initialValues[i];
+
+ if (type.equals(INTEGER)) {
+ blocks[i] = BlockUtil.createIntegerSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(BIGINT)) {
+ blocks[i] = BlockAssertions.createLongSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(REAL)) {
+ blocks[i] = BlockAssertions.createSequenceBlockOfReal(initialValue, initialValue + length);
+ }
+ else if (type.equals(DOUBLE)) {
+ blocks[i] = BlockAssertions.createDoubleSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (type instanceof VarcharType) {
+ blocks[i] = BlockUtil.createStringSequenceBlock(initialValue, initialValue + length,
+ (VarcharType) type);
+ }
+ else if (type instanceof CharType) {
+ blocks[i] = BlockUtil.createStringSequenceBlock(initialValue, initialValue + length,
+ (CharType) type);
+ }
+ else if (type.equals(BOOLEAN)) {
+ blocks[i] = BlockAssertions.createBooleanSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(DATE)) {
+ blocks[i] = BlockAssertions.createDateSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(TIMESTAMP)) {
+ blocks[i] = BlockAssertions.createTimestampSequenceBlock(initialValue, initialValue + length);
+ }
+ else if (isShortDecimal(type)) {
+ blocks[i] = BlockAssertions.createShortDecimalSequenceBlock(initialValue, initialValue + length,
+ (DecimalType) type);
+ }
+ else if (isLongDecimal(type)) {
+ blocks[i] = BlockAssertions.createLongDecimalSequenceBlock(initialValue, initialValue + length,
+ (DecimalType) type);
+ }
+ else {
+ throw new IllegalStateException("Unsupported type " + type);
+ }
+ }
+
+ return new Page(blocks);
+ }
+
+ public static Page createSequencePageWithDictionaryBlocks(List extends Type> types, int length)
+ {
+ return createSequencePageWithDictionaryBlocks(types, length, new int[types.size()]);
+ }
+
+ public static Page createSequencePageWithDictionaryBlocks(List extends Type> types, int length, int... initialValues)
+ {
+ Block[] blocks = new Block[initialValues.length];
+ for (int i = 0; i < blocks.length; i++) {
+ Type type = types.get(i);
+ int initialValue = initialValues[i];
+ if (type.equals(INTEGER)) {
+ blocks[i] = BlockUtil.createIntegerDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(BIGINT)) {
+ blocks[i] = BlockUtil.createLongDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(REAL)) {
+ blocks[i] = BlockUtil.createRealDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(DOUBLE)) {
+ blocks[i] = BlockUtil.createDoubleDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type instanceof VarcharType) {
+ blocks[i] = BlockUtil.createStringDictionaryBlock(initialValue, initialValue + length,
+ (VarcharType) type);
+ }
+ else if (type instanceof CharType) {
+ blocks[i] = BlockUtil.createStringDictionaryBlock(initialValue, initialValue + length,
+ (CharType) type);
+ }
+ else if (type.equals(BOOLEAN)) {
+ blocks[i] = BlockUtil.createBooleanDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(DATE)) {
+ blocks[i] = BlockUtil.createDateDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (type.equals(TIMESTAMP)) {
+ blocks[i] = BlockUtil.createTimestampDictionaryBlock(initialValue, initialValue + length);
+ }
+ else if (isShortDecimal(type)) {
+ blocks[i] = BlockUtil.createShortDecimalDictionaryBlock(initialValue, initialValue + length,
+ (DecimalType) type);
+ }
+ else if (isLongDecimal(type)) {
+ blocks[i] = BlockUtil.createLongDecimalDictionaryBlock(initialValue, initialValue + length,
+ (DecimalType) type);
+ }
+ else {
+ throw new IllegalStateException("Unsupported type " + type);
+ }
+ }
+
+ return new Page(blocks);
+ }
+
+ public static Page createPage(List extends Type> types, String prefix, List> columnValues)
+ {
+ Block[] blocks = new Block[types.size()];
+ for (int i = 0; i < blocks.length; i++) {
+ Type type = types.get(i);
+ if (type.equals(INTEGER)) {
+ blocks[i] = BlockUtil.createIntegerBlock(columnValues.get(i));
+ }
+ else if (type.equals(BIGINT)) {
+ blocks[i] = BlockUtil.createLongBlock(columnValues.get(i));
+ }
+ else if (type.equals(REAL)) {
+ blocks[i] = BlockUtil.createRealBlock(columnValues.get(i));
+ }
+ else if (type.equals(DOUBLE)) {
+ blocks[i] = BlockUtil.createDoubleBlock(columnValues.get(i));
+ }
+ else if (type instanceof VarcharType) {
+ blocks[i] = BlockUtil.createStringBlock(prefix, columnValues.get(i), (VarcharType) type);
+ }
+ else if (type.equals(BOOLEAN)) {
+ blocks[i] = BlockUtil.createBooleanBlock(columnValues.get(i));
+ }
+ else if (type.equals(DATE)) {
+ blocks[i] = BlockUtil.createDateBlock(columnValues.get(i));
+ }
+ else if (type.equals(TIMESTAMP)) {
+ blocks[i] = BlockUtil.createTimestampBlock(columnValues.get(i));
+ }
+ else if (isShortDecimal(type)) {
+ blocks[i] = BlockUtil.createShortDecimalBlock(columnValues.get(i), (DecimalType) type);
+ }
+ else if (isLongDecimal(type)) {
+ blocks[i] = BlockUtil.createLongDecimalBlock(columnValues.get(i), (DecimalType) type);
+ }
+ else {
+ throw new IllegalStateException("Unsupported type " + type);
+ }
+ }
+
+ return new Page(blocks);
+ }
+
+ public static Page createPageWithDictionaryBlocks(List extends Type> types, String prefix, List> columnValues)
+ {
+ Block[] blocks = new Block[types.size()];
+ for (int i = 0; i < blocks.length; i++) {
+ Type type = types.get(i);
+ if (type.equals(INTEGER)) {
+ blocks[i] = BlockUtil.createIntegerDictionaryBlock(columnValues.get(i));
+ }
+ else if (type.equals(BIGINT)) {
+ blocks[i] = BlockUtil.createLongDictionaryBlock(columnValues.get(i));
+ }
+ else if (type.equals(REAL)) {
+ blocks[i] = BlockUtil.createRealDictionaryBlock(columnValues.get(i));
+ }
+ else if (type.equals(DOUBLE)) {
+ blocks[i] = BlockUtil.createDoubleDictionaryBlock(columnValues.get(i));
+ }
+ else if (type instanceof VarcharType) {
+ blocks[i] = BlockUtil.createStringDictionaryBlock(prefix, columnValues.get(i), (VarcharType) type);
+ }
+ else if (type.equals(BOOLEAN)) {
+ blocks[i] = BlockUtil.createBooleanDictionaryBlock(columnValues.get(i));
+ }
+ else if (type.equals(DATE)) {
+ blocks[i] = BlockUtil.createDateDictionaryBlock(columnValues.get(i));
+ }
+ else if (type.equals(TIMESTAMP)) {
+ blocks[i] = BlockUtil.createTimestampDictionaryBlock(columnValues.get(i));
+ }
+ else if (isShortDecimal(type)) {
+ blocks[i] = BlockUtil.createShortDecimalDictionaryBlock(columnValues.get(i), (DecimalType) type);
+ }
+ else if (isLongDecimal(type)) {
+ blocks[i] = BlockUtil.createLongDecimalDictionaryBlock(columnValues.get(i), (DecimalType) type);
+ }
+ else {
+ throw new IllegalStateException("Unsupported type " + type);
+ }
+ }
+
+ return new Page(blocks);
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestByteArrayOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestByteArrayOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..4366a2cd8492a462bc91beb6eac3f8143a41ac0c
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestByteArrayOmniBlock.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.type.Type;
+import io.prestosql.spi.util.BloomFilter;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.vector.BooleanVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.BooleanType.BOOLEAN;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestByteArrayOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlockByBuilder();
+ BooleanVec booleanVec = new BooleanVec(4);
+ booleanVec.set(0, false);
+ booleanVec.set(1, true);
+ booleanVec.set(2, false);
+ booleanVec.set(3, true);
+ ByteArrayOmniBlock byteArrayOmniBlock = new ByteArrayOmniBlock(4, booleanVec);
+ assertBlockEquals(BOOLEAN, byteArrayOmniBlock, baseBlock);
+ assertEquals(baseBlock.toString(), byteArrayOmniBlock.toString());
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ byteArrayOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (size == booleanVec.getCapacityInBytes()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ Block byteArrayOmniBlockRegion = byteArrayOmniBlock.getRegion(2, 2);
+ assertEquals(byteArrayOmniBlockRegion.getPositionCount(), 2);
+
+ for (int i = 0; i < byteArrayOmniBlockRegion.getPositionCount(); i++) {
+ assertEquals(byteArrayOmniBlockRegion.get(i), byteArrayOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, (BooleanVec) baseBlock.getValues());
+
+ baseBlock.close();
+ byteArrayOmniBlock.close();
+ byteArrayOmniBlockRegion.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ byte[] bytes = {};
+ byte[] values = {};
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, 1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, -1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+ byte[] values2len = new byte[6];
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 0, 4, bytes, values2len))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ Block baseBlock = buildBlockByBuilder();
+ BooleanVec booleanVec = (BooleanVec) baseBlock.getValues();
+ byte[] bytes2array = {};
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(-1, 4, bytes2array, booleanVec))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(1, -1, bytes2array, booleanVec))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(1, 6, bytes2array, booleanVec))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+ assertThatThrownBy(() -> new ByteArrayOmniBlock(1, 4, bytes2array, booleanVec))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ BooleanVec booleanVec = new BooleanVec(4);
+ booleanVec.set(0, false);
+ booleanVec.set(1, true);
+ booleanVec.set(2, false);
+ booleanVec.set(3, true);
+ Block byteArrayOmniBlock = new ByteArrayOmniBlock(4, booleanVec);
+ long expect = 2L;
+ long expectSizeBytes = 8L;
+ long expectStates = 1L;
+ boolean[] position = {true, true, true, true};
+ assertEquals(byteArrayOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(byteArrayOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(byteArrayOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(byteArrayOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+ byteArrayOmniBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ BooleanVec booleanVec = new BooleanVec(4);
+ booleanVec.set(0, false);
+ booleanVec.set(1, true);
+ booleanVec.set(2, false);
+ booleanVec.set(3, true);
+ Block byteArrayOmniBlock = new ByteArrayOmniBlock(4, booleanVec);
+ Block copyRegionBlock = byteArrayOmniBlock.copyRegion(0, byteArrayOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, (BooleanVec) byteArrayOmniBlock.getValues());
+
+ Block copyNotEqualRegionBlock = byteArrayOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, (BooleanVec) byteArrayOmniBlock.getValues());
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ BooleanVec booleanVec = new BooleanVec(4);
+ booleanVec.set(0, false);
+ booleanVec.set(1, true);
+ booleanVec.set(2, false);
+ booleanVec.set(3, true);
+ Block byteArrayOmniBlock = new ByteArrayOmniBlock(4, booleanVec);
+
+ int[] positions = {0, 2, 3};
+ Block copyPositionsBlock = byteArrayOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyPositionsBlock.getByte(i, 0), byteArrayOmniBlock.getByte(positions[i], 0));
+ }
+ byteArrayOmniBlock.close();
+ copyPositionsBlock.close();
+ }
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = BOOLEAN.createBlockBuilder(null, 4);
+ blockBuilder.appendNull();
+ BOOLEAN.writeBoolean(blockBuilder, false);
+ blockBuilder.appendNull();
+ BOOLEAN.writeBoolean(blockBuilder, false);
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+
+ ByteArrayOmniBlock nullByteArrayOmniBlock = new ByteArrayOmniBlock(4, (BooleanVec) block.getValues());
+ // build block from vec
+ AssertJUnit.assertTrue(nullByteArrayOmniBlock.isNull(0));
+ AssertJUnit.assertTrue(nullByteArrayOmniBlock.isNull(2));
+
+ nullByteArrayOmniBlock.close();
+ }
+
+ @Test
+ public void testFilter()
+ {
+ int count = 4;
+ int size = 4;
+ boolean[] valid = new boolean[count];
+ Arrays.fill(valid, Boolean.TRUE);
+ ByteArrayOmniBlock block = getBlock(count);
+ Byte[] values = new Byte[block.getPositionCount()];
+
+ BloomFilter bf = getBf(size);
+ for (int i = 0; i < block.getPositionCount(); i++) {
+ values[i] = (block.getByte(i, 0));
+ }
+ boolean[] actualValidPositions = block.filter(bf, valid);
+ assertEquals(actualValidPositions, valid);
+
+ int[] positions = {0, 1, 2, 3};
+ int positionCount = 4;
+ int[] matchedPosition = new int[4];
+ int actualFilterPositions = block.filter(positions, positionCount, matchedPosition, (x) -> {
+ return true;
+ });
+ assertEquals(actualFilterPositions, positionCount);
+
+ block.close();
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder blockBuilder = BOOLEAN.createBlockBuilder(null, 4);
+ BOOLEAN.writeBoolean(blockBuilder, false);
+ BOOLEAN.writeBoolean(blockBuilder, true);
+ BOOLEAN.writeBoolean(blockBuilder, false);
+ BOOLEAN.writeBoolean(blockBuilder, true);
+ return OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+ }
+
+ private ByteArrayOmniBlock getBlock(int count)
+ {
+ BooleanVec booleanVec = new BooleanVec(count);
+ for (int i = 0; i < count; i++) {
+ if ((i & 1) == 1) {
+ booleanVec.set(i, true);
+ }
+ else {
+ booleanVec.set(i, false);
+ }
+ }
+ return new ByteArrayOmniBlock(count, booleanVec);
+ }
+
+ private BloomFilter getBf(int size)
+ {
+ Random rnd = new Random();
+ BloomFilter bf = new BloomFilter(size, 0.01);
+ for (int i = 0; i < 100; i++) {
+ bf.test(("value" + rnd.nextLong()).getBytes());
+ }
+ return bf;
+ }
+
+ private static void assertBlockEquals(Block actual, BooleanVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(actual.get(position), (expected.get(position)) ? (byte) 1 : (byte) 0);
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDictionaryOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDictionaryOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..13ce260949e723ea189617fa278ba813462f4b80
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDictionaryOmniBlock.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.block.DictionaryId;
+import io.prestosql.spi.type.Type;
+import io.prestosql.spi.util.BloomFilter;
+import nova.hetu.omniruntime.vector.DictionaryVec;
+import nova.hetu.omniruntime.vector.VarcharVec;
+import nova.hetu.omniruntime.vector.Vec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.VarcharType.VARCHAR;
+import static nova.hetu.olk.tool.OperatorUtils.buildOffHeapBlock;
+import static nova.hetu.olk.tool.OperatorUtils.buildOnHeapBlock;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestDictionaryOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ int[] ids = {0, 1, 2, 3};
+ Block baseBlock = buildBlockByBuilder();
+ DictionaryOmniBlock dictionaryOmniBlock = new DictionaryOmniBlock((Vec) baseBlock.getValues(), ids);
+ assertBlockEquals(VARCHAR, dictionaryOmniBlock, baseBlock);
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ dictionaryOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (part == ids) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ DictionaryId dictionaryId = dictionaryOmniBlock.getDictionarySourceId();
+ int[] positions = new int[11];
+ DictionaryOmniBlock interceptBlock = (DictionaryOmniBlock) dictionaryOmniBlock.getPositions(positions, 0, 4);
+ assertEquals(interceptBlock.getDictionarySourceId(), dictionaryId);
+
+ Block regionDicOmniBlock = dictionaryOmniBlock.getRegion(2, 2);
+ assertEquals(regionDicOmniBlock.getPositionCount(), 2);
+ for (int i = 0; i < regionDicOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionDicOmniBlock.get(i), dictionaryOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, buildOnHeapBlock(dictionaryOmniBlock));
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, (VarcharVec) baseBlock.getValues());
+
+ baseBlock.close();
+ dictionaryOmniBlock.close();
+ regionDicOmniBlock.close();
+ interceptBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] ids = {0, 1, 2, 3};
+ Block dictionaryOmniBlock = new DictionaryOmniBlock((Vec) baseBlock.getValues(), ids);
+ Block copyRegionBlock = dictionaryOmniBlock.copyRegion(0, dictionaryOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock,
+ (VarcharVec) ((DictionaryOmniBlock) dictionaryOmniBlock).getDictionary().getValues());
+
+ Block compactDicBlock = buildBlock2Compact();
+ int[] ids1 = {0, 1, 2, 3};
+ Block newBlock2Compact = new DictionaryOmniBlock((Vec) compactDicBlock.getValues(), ids1);
+ Block copyRegionBlock2Compact = newBlock2Compact.copyRegion(0, newBlock2Compact.getPositionCount());
+ assertBlockEquals(copyRegionBlock2Compact,
+ (VarcharVec) ((DictionaryOmniBlock) newBlock2Compact).getDictionary().getValues());
+
+ baseBlock.close();
+ dictionaryOmniBlock.close();
+ copyRegionBlock.close();
+ compactDicBlock.close();
+ newBlock2Compact.close();
+ copyRegionBlock2Compact.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] ids = {0, 1, 2, 3};
+ Block dictionaryOmniBlock = new DictionaryOmniBlock((Vec) baseBlock.getValues(), ids);
+ int[] positions = {0, 2, 3};
+ Block copyRegionBlock = dictionaryOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyRegionBlock.getString(i, 0, 0), dictionaryOmniBlock.getString(positions[i], 0, 0));
+ }
+
+ baseBlock.close();
+ dictionaryOmniBlock.close();
+ copyRegionBlock.close();
+ }
+
+ @Test
+ public void testFilter()
+ {
+ int count = 4;
+ int size = 1000;
+ boolean[] valid = new boolean[count];
+ Arrays.fill(valid, Boolean.TRUE);
+ DictionaryOmniBlock block = getBlock(count);
+ String[] values = new String[block.getPositionCount()];
+
+ BloomFilter bf = getBf(size);
+ for (int i = 0; i < block.getPositionCount(); i++) {
+ values[i] = block.getString(i, 0, 0);
+ }
+
+ boolean[] actualValidPositions = block.filter(bf, valid);
+ assertEquals(actualValidPositions, valid);
+
+ int[] positions = {0, 1, 2, 3};
+ int positionCount = 4;
+ int[] matchedPosition = new int[4];
+ int actualFilterPositions = block.filter(positions, positionCount, matchedPosition, (x) -> {
+ return true;
+ });
+ assertEquals(actualFilterPositions, positionCount);
+ block.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] ids = {0, 1, 2, 3};
+ DictionaryOmniBlock dictionaryOmniBlock = new DictionaryOmniBlock((Vec) baseBlock.getValues(), ids);
+ long expect = 14L;
+ long expectSizeBytes = 55L;
+ long expectStates = 5L;
+ boolean[] position = {true, true, true, true};
+ long expect2LogicalSizeInBytes = 39L;
+ String expectStr = "DictionaryOmniBlock{positionCount=4}";
+ assertEquals(dictionaryOmniBlock.toString(), expectStr);
+ assertEquals(dictionaryOmniBlock.getLogicalSizeInBytes(), expect2LogicalSizeInBytes);
+ assertEquals(dictionaryOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(dictionaryOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(dictionaryOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(dictionaryOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ Block loadedOmniBlock = dictionaryOmniBlock.getLoadedBlock();
+ assertBlockEquals(VARCHAR, dictionaryOmniBlock, loadedOmniBlock);
+
+ baseBlock.close();
+ loadedOmniBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] ids = {0, 1, 2, 3};
+ DictionaryOmniBlock throwDicOmniBlock = new DictionaryOmniBlock((Vec) baseBlock.getValues(), ids);
+ assertThatThrownBy(() -> new DictionaryOmniBlock(1, -1, (Vec) baseBlock.getValues(), ids, false,
+ throwDicOmniBlock.getDictionarySourceId())).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("positionCount is negative");
+ assertThatThrownBy(() -> new DictionaryOmniBlock(1, 4, (Vec) baseBlock.getValues(), ids, false,
+ throwDicOmniBlock.getDictionarySourceId())).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("ids length is less than positionCount");
+ assertThatThrownBy(() -> new DictionaryOmniBlock(1, -1, (DictionaryVec) throwDicOmniBlock.getValues(), ids,
+ baseBlock, false, throwDicOmniBlock.getDictionarySourceId()))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("positionCount is negative");
+ assertThatThrownBy(() -> new DictionaryOmniBlock(1, 4, (DictionaryVec) throwDicOmniBlock.getValues(), ids,
+ baseBlock, false, throwDicOmniBlock.getDictionarySourceId()))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("ids length is less than positionCount");
+
+ baseBlock.close();
+ throwDicOmniBlock.close();
+ }
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "alice");
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "bob");
+ Block block = buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+
+ int[] ids = {0, 1, 2, 3};
+ DictionaryOmniBlock nullDicOmniBlock = new DictionaryOmniBlock((Vec) block.getValues(), ids);
+ // build block from vec
+ assertTrue(nullDicOmniBlock.isNull(0));
+ assertTrue(nullDicOmniBlock.isNull(2));
+
+ nullDicOmniBlock.close();
+ block.close();
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder dictionaryOmniBuilder = VARCHAR.createBlockBuilder(null, 4);
+ VARCHAR.writeString(dictionaryOmniBuilder, "alice");
+ VARCHAR.writeString(dictionaryOmniBuilder, "bob");
+ VARCHAR.writeString(dictionaryOmniBuilder, "charlie");
+ VARCHAR.writeString(dictionaryOmniBuilder, "dave");
+ return buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, dictionaryOmniBuilder.build());
+ }
+
+ private Block buildBlock2Compact()
+ {
+ BlockBuilder dictionaryOmniBuilder = VARCHAR.createBlockBuilder(null, 5);
+ VARCHAR.writeString(dictionaryOmniBuilder, "alice");
+ VARCHAR.writeString(dictionaryOmniBuilder, "bob");
+ VARCHAR.writeString(dictionaryOmniBuilder, "charlie");
+ VARCHAR.writeString(dictionaryOmniBuilder, "dave");
+ VARCHAR.writeString(dictionaryOmniBuilder, "dave");
+ return buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, dictionaryOmniBuilder.build());
+ }
+
+ private DictionaryOmniBlock getBlock(int count)
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] ids = {0, 1, 2, 3};
+ Vec dictionary = (Vec) baseBlock.getValues();
+ DictionaryOmniBlock dictionaryOmniBlock = new DictionaryOmniBlock(count, dictionary, ids);
+ baseBlock.close();
+ return dictionaryOmniBlock;
+ }
+
+ private BloomFilter getBf(int size)
+ {
+ Random rnd = new Random();
+ BloomFilter bf = new BloomFilter(size, 0.01);
+ for (int i = 0; i < 100; i++) {
+ bf.test(("value" + rnd.nextLong()).getBytes());
+ }
+ return bf;
+ }
+
+ private static void assertBlockEquals(Block actual, VarcharVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(new String((byte[]) actual.get(position)), new String(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDoubleArrayOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDoubleArrayOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4048940a7fc25cf5f09057541feddd56efce987
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestDoubleArrayOmniBlock.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.type.Type;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.vector.DoubleVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.DoubleType.DOUBLE;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestDoubleArrayOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test(enabled = false)
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = DOUBLE.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ DOUBLE.writeDouble(blockBuilder, 42.33);
+ blockBuilder.appendNull();
+ DOUBLE.writeDouble(blockBuilder, Double.MAX_VALUE);
+ Block onHeapBlock = blockBuilder.build();
+
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, onHeapBlock);
+
+ assertTrue(block.isNull(0));
+ assertEquals(DOUBLE.getDouble(block, 1), 42.33);
+ assertTrue(block.isNull(2));
+ assertEquals(DOUBLE.getDouble(block, 3), Double.MAX_VALUE);
+
+ // build block from vec
+ Block block1 = new DoubleArrayOmniBlock(4, (DoubleVec) block.getValues());
+ assertTrue(block1.isNull(0));
+ assertEquals(DOUBLE.getDouble(block1, 1), 42.33);
+ assertTrue(block1.isNull(2));
+ assertEquals(DOUBLE.getDouble(block1, 3), Double.MAX_VALUE);
+ block.close();
+ }
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlockByVec();
+ DoubleArrayOmniBlock doubleArrayOmniBlock = new DoubleArrayOmniBlock(baseBlock.getPositionCount(),
+ (DoubleVec) baseBlock.getValues());
+ assertBlockEquals(DOUBLE, baseBlock, doubleArrayOmniBlock);
+ assertEquals(baseBlock.toString(), doubleArrayOmniBlock.toString());
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ doubleArrayOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (size == ((DoubleVec) baseBlock.getValues()).getCapacityInBytes()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ Block regionOmniBlock = doubleArrayOmniBlock.getRegion(2, 2);
+ assertEquals(regionOmniBlock.getPositionCount(), 2);
+ for (int i = 0; i < regionOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionOmniBlock.get(i), doubleArrayOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ Block serBlock = OperatorUtils.buildOnHeapBlock(baseBlock);
+ blockEncodingSerde.writeBlock(sliceOutput, serBlock);
+ Block deSerBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ Block actualBlock = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, deSerBlock,
+ deSerBlock.getClass().getSimpleName(), deSerBlock.getPositionCount(), DOUBLE);
+ assertBlockEquals(actualBlock, (DoubleVec) baseBlock.getValues());
+
+ doubleArrayOmniBlock.close();
+ regionOmniBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlockByVec();
+ Block doubleArrayOmniBlock = new DoubleArrayOmniBlock(baseBlock.getPositionCount(),
+ (DoubleVec) baseBlock.getValues());
+ Block copyRegionBlock = doubleArrayOmniBlock.copyRegion(0, doubleArrayOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, (DoubleVec) doubleArrayOmniBlock.getValues());
+
+ Block copyNotEqualRegionBlock = doubleArrayOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, (DoubleVec) doubleArrayOmniBlock.getValues());
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlockByVec();
+ Block doubleArrayOmniBlock = new DoubleArrayOmniBlock(baseBlock.getPositionCount(),
+ (DoubleVec) baseBlock.getValues());
+
+ int[] positions = {0, 2, 3};
+ Block copyRegionBlock = doubleArrayOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyRegionBlock.getDouble(i, 0), doubleArrayOmniBlock.getDouble(positions[i], 0));
+ }
+
+ doubleArrayOmniBlock.close();
+ copyRegionBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ byte[] bytes = {};
+ double[] values = {};
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, 1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, -1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ double[] values2len = new double[6];
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values2len))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ Block baseBlock = buildBlockByVec();
+ DoubleVec expected = (DoubleVec) baseBlock.getValues();
+ byte[] bytes2array = {};
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(-1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(1, -1, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(1, 6, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ assertThatThrownBy(() -> new DoubleArrayOmniBlock(1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlockByVec();
+ Block doubleArrayOmniBlock = new DoubleArrayOmniBlock(baseBlock.getPositionCount(),
+ (DoubleVec) baseBlock.getValues());
+ long expect = 9;
+ long expectSizeBytes = 36;
+ long expectStates = 8;
+ boolean[] position = {true, true, true, true};
+ assertEquals(doubleArrayOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(doubleArrayOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(doubleArrayOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(doubleArrayOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ doubleArrayOmniBlock.close();
+ }
+
+ private Block buildBlockByVec()
+ {
+ DoubleVec doubleVec = new DoubleVec(4);
+ doubleVec.set(0, 42.33);
+ doubleVec.set(0, 43.34);
+ doubleVec.set(0, 44.35);
+ doubleVec.set(0, 45.36);
+
+ return new DoubleArrayOmniBlock(4, doubleVec);
+ }
+
+ private static void assertBlockEquals(Block actual, DoubleVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(actual.get(position), new Double(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestInt128ArrayOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestInt128ArrayOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..79a1739774920ccf03661feb7efe3cae7b6a5e3d
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestInt128ArrayOmniBlock.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import nova.hetu.omniruntime.vector.Decimal128Vec;
+import nova.hetu.omniruntime.vector.Vec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestInt128ArrayOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ int positionCount = 4;
+ long[] values = {0L, 0L, 0L, 42L, 0L, 0L, Long.MAX_VALUE, Long.MAX_VALUE};
+ byte[] valueIsNull = {Vec.NULL, Vec.NOT_NULL, Vec.NULL, Vec.NOT_NULL};
+ Int128ArrayOmniBlock block = new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, positionCount,
+ Optional.of(valueIsNull), values);
+
+ assertTrue(block.isNull(0));
+ assertEquals(block.get(1), new long[]{0L, 42L});
+ assertTrue(block.isNull(2));
+ assertEquals(block.get(3), new long[]{Long.MAX_VALUE, Long.MAX_VALUE});
+
+ // build block from vec
+ Block block1 = new Int128ArrayOmniBlock(4, (Decimal128Vec) block.getValues());
+ assertTrue(block1.isNull(0));
+ assertEquals(block1.get(1), new long[]{0L, 42L});
+ assertTrue(block1.isNull(2));
+ assertEquals(block.get(3), new long[]{Long.MAX_VALUE, Long.MAX_VALUE});
+ block.close();
+ }
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlock();
+ Int128ArrayOmniBlock int128ArrayOmniBlock = new Int128ArrayOmniBlock(baseBlock.getPositionCount(),
+ (Decimal128Vec) baseBlock.getValues());
+ assertBlockEquals(int128ArrayOmniBlock, baseBlock);
+ String expect = "Int128ArrayOmniBlock{positionCount=4}";
+ assertEquals(int128ArrayOmniBlock.toString(), expect);
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ int128ArrayOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (part == baseBlock.getValues()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ Block regionInt128ArrayOmniBlock = int128ArrayOmniBlock.getRegion(2, 2);
+ assertEquals(regionInt128ArrayOmniBlock.getPositionCount(), 2);
+ for (int i = 0; i < regionInt128ArrayOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionInt128ArrayOmniBlock.get(i), int128ArrayOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, baseBlock);
+
+ int128ArrayOmniBlock.close();
+ regionInt128ArrayOmniBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlock();
+ Block int128ArrayOmniBlock = new Int128ArrayOmniBlock(baseBlock.getPositionCount(),
+ (Decimal128Vec) baseBlock.getValues());
+ Block copyRegionBlock = int128ArrayOmniBlock.copyRegion(0, int128ArrayOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, int128ArrayOmniBlock);
+
+ Block copyNotEqualRegionBlock = int128ArrayOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, int128ArrayOmniBlock);
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlock();
+ Block int128ArrayOmniBlock = new Int128ArrayOmniBlock(baseBlock.getPositionCount(),
+ (Decimal128Vec) baseBlock.getValues());
+
+ int[] positions = {0, 1, 2, 3};
+ Block copyRegionBlock = int128ArrayOmniBlock.copyPositions(positions, 0, 4);
+ assertBlockEquals(copyRegionBlock, int128ArrayOmniBlock);
+
+ int128ArrayOmniBlock.close();
+ copyRegionBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ byte[] bytes = {};
+ long[] values = {};
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, 1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionOffset is negative");
+
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, -1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ long[] values2len = new long[6];
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 1, bytes, values2len))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ Block baseBlock = buildBlock();
+ Decimal128Vec expected = (Decimal128Vec) baseBlock.getValues();
+ byte[] bytes2array = {};
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(-1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionOffset is negative");
+
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(1, -1, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(1, 6, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ assertThatThrownBy(() -> new Int128ArrayOmniBlock(1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlock();
+ Block int128ArrayOmniBlock = new Int128ArrayOmniBlock(baseBlock.getPositionCount(),
+ (Decimal128Vec) baseBlock.getValues());
+ long expect = 17;
+ long expectSizeBytes = 68;
+ long expectStates = 0;
+ boolean[] position = {true, true, true, true};
+ assertEquals(int128ArrayOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(int128ArrayOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(int128ArrayOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(int128ArrayOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ int128ArrayOmniBlock.close();
+ }
+
+ private Block buildBlock()
+ {
+ int positionCount = 4;
+ long[] values = {0L, 0L, 0L, 42L, 0L, 0L, Long.MAX_VALUE, Long.MAX_VALUE};
+ byte[] valueIsNull = {Vec.NULL, Vec.NOT_NULL, Vec.NULL, Vec.NOT_NULL};
+ Int128ArrayOmniBlock block = new Int128ArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, positionCount,
+ Optional.of(valueIsNull), values);
+ return block;
+ }
+
+ private static void assertBlockEquals(Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(actual.get(position), expected.get(position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestIntArrayOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestIntArrayOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ef9377ae81f6c7811d9a0ae2a75466ff64a3f7f
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestIntArrayOmniBlock.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.type.Type;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.vector.IntVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.IntegerType.INTEGER;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestIntArrayOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = INTEGER.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ INTEGER.writeLong(blockBuilder, 42);
+ blockBuilder.appendNull();
+ INTEGER.writeLong(blockBuilder, Integer.MAX_VALUE);
+ Block onHeapBlock = blockBuilder.build();
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, onHeapBlock);
+
+ assertTrue(block.isNull(0));
+ assertEquals(INTEGER.getLong(block, 1), 42);
+ assertTrue(block.isNull(2));
+ assertEquals(INTEGER.getLong(block, 3), Integer.MAX_VALUE);
+
+ // build block from vec
+ Block nullOmniBlock = new IntArrayOmniBlock(4, (IntVec) block.getValues());
+ assertTrue(nullOmniBlock.isNull(0));
+ assertEquals(INTEGER.getLong(nullOmniBlock, 1), 42);
+ assertTrue(nullOmniBlock.isNull(2));
+ assertEquals(INTEGER.getLong(nullOmniBlock, 3), Integer.MAX_VALUE);
+
+ block.close();
+ }
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlockByBuilder();
+ IntArrayOmniBlock intArrayOmniBlock = new IntArrayOmniBlock(baseBlock.getPositionCount(),
+ (IntVec) baseBlock.getValues());
+ assertBlockEquals(INTEGER, intArrayOmniBlock, baseBlock);
+ assertEquals(baseBlock.toString(), intArrayOmniBlock.toString());
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ intArrayOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (size == ((IntVec) baseBlock.getValues()).getCapacityInBytes()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+ Block regionOmniBlock = intArrayOmniBlock.getRegion(2, 2);
+ assertEquals(regionOmniBlock.getPositionCount(), 2);
+ for (int i = 0; i < regionOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionOmniBlock.get(i), intArrayOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, (IntVec) baseBlock.getValues());
+
+ intArrayOmniBlock.close();
+ regionOmniBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block intArrayOmniBlock = new IntArrayOmniBlock(baseBlock.getPositionCount(), (IntVec) baseBlock.getValues());
+
+ int[] positions = {0, 2, 3};
+ Block copyPositionsBlock = intArrayOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyPositionsBlock.getInt(i, 0), intArrayOmniBlock.getInt(positions[i], 0));
+ }
+ intArrayOmniBlock.close();
+ copyPositionsBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block intArrayOmniBlock = new IntArrayOmniBlock(baseBlock.getPositionCount(), (IntVec) baseBlock.getValues());
+ Block copyRegionBlock = intArrayOmniBlock.copyRegion(0, intArrayOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, (IntVec) intArrayOmniBlock.getValues());
+
+ Block copyNotEqualRegionBlock = intArrayOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, (IntVec) intArrayOmniBlock.getValues());
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ byte[] bytes = {};
+ int[] values = {};
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, 1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, -1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ int[] values2len = new int[6];
+ assertThatThrownBy(() -> new IntArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values2len))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ Block baseBlock = buildBlockByBuilder();
+ IntVec expected = (IntVec) baseBlock.getValues();
+ byte[] bytes2array = {};
+ assertThatThrownBy(() -> new IntArrayOmniBlock(-1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(1, -1, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(1, 6, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ assertThatThrownBy(() -> new IntArrayOmniBlock(1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block intArrayOmniBlock = new IntArrayOmniBlock(baseBlock.getPositionCount(), (IntVec) baseBlock.getValues());
+ long expect = 5;
+ long expectSizeBytes = 20;
+ long expectStates = 4;
+ boolean[] position = {true, true, true, true};
+ assertEquals(intArrayOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(intArrayOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(intArrayOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(intArrayOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ intArrayOmniBlock.close();
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder blockBuilder = INTEGER.createBlockBuilder(null, 4);
+ INTEGER.writeLong(blockBuilder, 42);
+ INTEGER.writeLong(blockBuilder, 43);
+ INTEGER.writeLong(blockBuilder, 44);
+ INTEGER.writeLong(blockBuilder, 45);
+ return OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+ }
+
+ private static void assertBlockEquals(Block actual, IntVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals((Integer) actual.get(position), new Integer(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestLongArrayOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestLongArrayOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..518332fc610a8be17677a8073b6cc906399a6e39
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestLongArrayOmniBlock.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.type.Type;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.vector.LongVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.BigintType.BIGINT;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestLongArrayOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = BIGINT.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ BIGINT.writeLong(blockBuilder, 42);
+ blockBuilder.appendNull();
+ BIGINT.writeLong(blockBuilder, Long.MAX_VALUE);
+ Block onHeapBlock = blockBuilder.build();
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, onHeapBlock);
+
+ assertTrue(block.isNull(0));
+ assertEquals(BIGINT.getLong(block, 1), 42L);
+ assertTrue(block.isNull(2));
+ assertEquals(BIGINT.getLong(block, 3), Long.MAX_VALUE);
+
+ // build block from vec
+ Block longArrayOmniBlock = new LongArrayOmniBlock(4, (LongVec) block.getValues());
+ assertTrue(longArrayOmniBlock.isNull(0));
+ assertEquals(BIGINT.getLong(longArrayOmniBlock, 1), 42L);
+ assertTrue(longArrayOmniBlock.isNull(2));
+ assertEquals(BIGINT.getLong(longArrayOmniBlock, 3), Long.MAX_VALUE);
+
+ block.close();
+ }
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlockByBuilder();
+ LongArrayOmniBlock longArrayOmniBlock = new LongArrayOmniBlock(baseBlock.getPositionCount(),
+ (LongVec) baseBlock.getValues());
+ assertBlockEquals(BIGINT, longArrayOmniBlock, baseBlock);
+ assertEquals(baseBlock.toString(), longArrayOmniBlock.toString());
+
+ Block regionOmniBlock = longArrayOmniBlock.getRegion(2, 2);
+ assertEquals(regionOmniBlock.getPositionCount(), 2);
+ for (int i = 0; i < regionOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionOmniBlock.get(i), longArrayOmniBlock.get(i + 2));
+ }
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ longArrayOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (size == ((LongVec) baseBlock.getValues()).getCapacityInBytes()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, (LongVec) baseBlock.getValues());
+
+ longArrayOmniBlock.close();
+ regionOmniBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block longArrayOmniBlock = new LongArrayOmniBlock(baseBlock.getPositionCount(),
+ (LongVec) baseBlock.getValues());
+ Block copyRegionBlock = longArrayOmniBlock.copyRegion(0, longArrayOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, (LongVec) longArrayOmniBlock.getValues());
+
+ Block copyNotEqualRegionBlock = longArrayOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, (LongVec) longArrayOmniBlock.getValues());
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block longArrayOmniBlock = new LongArrayOmniBlock(baseBlock.getPositionCount(), (LongVec) baseBlock.getValues());
+
+ int[] positions = {0, 2, 3};
+ Block copyRegionBlock = longArrayOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyRegionBlock.getLong(i, 0), longArrayOmniBlock.getLong(positions[i], 0));
+ }
+ longArrayOmniBlock.close();
+ copyRegionBlock.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ byte[] bytes = {};
+ long[] values = {};
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, 1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, -1, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ long[] values2len = new long[6];
+ assertThatThrownBy(() -> new LongArrayOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, bytes, values2len))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ LongVec expected = (LongVec) baseBlock.getValues();
+ byte[] bytes2array = {};
+ assertThatThrownBy(() -> new LongArrayOmniBlock(-1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(1, -1, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(1, 6, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("values length is less than positionCount");
+
+ assertThatThrownBy(() -> new LongArrayOmniBlock(1, 4, bytes2array, expected))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("isNull length is less than positionCount");
+
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block longArrayOmniBlock = new LongArrayOmniBlock(baseBlock.getPositionCount(),
+ (LongVec) baseBlock.getValues());
+ long expect = 9;
+ long expectSizeBytes = 36;
+ long expectStates = 8;
+ boolean[] position = {true, true, true, true};
+ assertEquals(longArrayOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(longArrayOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(longArrayOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(longArrayOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ longArrayOmniBlock.close();
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder blockBuilder = BIGINT.createBlockBuilder(null, 4);
+ BIGINT.writeLong(blockBuilder, 42);
+ BIGINT.writeLong(blockBuilder, 43);
+ BIGINT.writeLong(blockBuilder, 44);
+ BIGINT.writeLong(blockBuilder, 45);
+ return OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+ }
+
+ private static void assertBlockEquals(Block actual, LongVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals((Long) actual.get(position), new Long(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestRowOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestRowOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa3798c4e9b7357da9c1b4c8ade89b00f2fd4e9a
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestRowOmniBlock.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.block.RowBlock;
+import io.prestosql.spi.type.Type;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.type.DataType;
+import nova.hetu.omniruntime.type.VarcharDataType;
+import nova.hetu.omniruntime.vector.VarcharVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.airlift.slice.SizeOf.sizeOf;
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.VarcharType.VARCHAR;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestRowOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ RowOmniBlock baseBlock = (RowOmniBlock) buildBlockByBuilder();
+ RowOmniBlock loadedBlock = (RowOmniBlock) baseBlock.getLoadedBlock();
+ Block varcharBlock = baseBlock.getRawFieldBlocks()[0];
+ Block varcharBlock2 = loadedBlock.getRawFieldBlocks()[0];
+ assertBlockEquals(VARCHAR, varcharBlock, varcharBlock2);
+
+ int[] fieldBlockOffsets = {0, 1};
+ long sizes = sizeOf(fieldBlockOffsets);
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ loadedBlock.retainedBytesForEachPart((part, size) -> {
+ if (size.equals(sizes)) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ Block rawFieldBlock = loadedBlock.getRawFieldBlocks()[0].getRegion(2, 2);
+ assertEquals(rawFieldBlock.getPositionCount(), 2);
+ for (int i = 0; i < rawFieldBlock.getPositionCount(); i++) {
+ assertEquals(rawFieldBlock.get(i), varcharBlock2.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ RowBlock actualBlock = (RowBlock) blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock.getRawFieldBlocks()[0],
+ (VarcharVec) baseBlock.getRawFieldBlocks()[0].getValues());
+
+ loadedBlock.close();
+ rawFieldBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "alice");
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "bob");
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+
+ assertTrue(block.isNull(0));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block, 1), "alice");
+ assertTrue(block.isNull(2));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block, 3), "bob");
+
+ // build block from vec
+ Block block1 = new VariableWidthOmniBlock(4, (VarcharVec) block.getValues());
+ assertTrue(block1.isNull(0));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block1, 1), "alice");
+ assertTrue(block1.isNull(2));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block1, 3), "bob");
+ block.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ byte[] rowIsNull = {};
+ int[] fieldBlockOffsets = {};
+ Block[] fieldBlocks = {};
+ assertThatThrownBy(() -> new RowOmniBlock(-1, 4, rowIsNull, fieldBlockOffsets, fieldBlocks, DataType.INVALID))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("Number of fields in RowBlock must be positive");
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder rowBlockBuilder = VARCHAR.createBlockBuilder(null, 4);
+ VARCHAR.writeString(rowBlockBuilder, "alice");
+ VARCHAR.writeString(rowBlockBuilder, "bob");
+ VARCHAR.writeString(rowBlockBuilder, "charlie");
+ VARCHAR.writeString(rowBlockBuilder, "dave");
+ Block varCharBlock = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR,
+ rowBlockBuilder.build());
+
+ byte[] rowIsNull = new byte[1];
+ int[] fieldBlockOffsets = {0, 1};
+ Block[] blocks = new Block[1];
+ blocks[0] = varCharBlock;
+
+ return new RowOmniBlock(0, 1, rowIsNull, fieldBlockOffsets, blocks, VarcharDataType.VARCHAR);
+ }
+
+ private static void assertBlockEquals(Block actual, VarcharVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(new String((byte[]) actual.get(position)), new String(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestVariableWidthOmniBlock.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestVariableWidthOmniBlock.java
new file mode 100644
index 0000000000000000000000000000000000000000..4296a8c8e52404c40f9f6dba78d339d375b353e3
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/block/TestVariableWidthOmniBlock.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.block;
+
+import io.airlift.slice.DynamicSliceOutput;
+import io.airlift.slice.Slice;
+import io.airlift.slice.Slices;
+import io.prestosql.metadata.InternalBlockEncodingSerde;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.BlockEncodingSerde;
+import io.prestosql.spi.type.Type;
+import io.prestosql.spi.util.BloomFilter;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.vector.VarcharVec;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.prestosql.metadata.MetadataManager.createTestMetadataManager;
+import static io.prestosql.spi.block.TestingSession.SESSION;
+import static io.prestosql.spi.type.VarcharType.VARCHAR;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class TestVariableWidthOmniBlock
+{
+ private final BlockEncodingSerde blockEncodingSerde = new InternalBlockEncodingSerde(
+ createTestMetadataManager().getFunctionAndTypeManager());
+
+ @Test
+ public void testBasicFunc()
+ {
+ // build vec through vec
+ Block baseBlock = buildBlockByBuilder();
+ VariableWidthOmniBlock variableWidthOmniBlock = new VariableWidthOmniBlock(baseBlock.getPositionCount(),
+ (VarcharVec) baseBlock.getValues());
+ assertBlockEquals(VARCHAR, variableWidthOmniBlock, baseBlock);
+ assertEquals(baseBlock.toString(), variableWidthOmniBlock.toString());
+
+ AtomicBoolean isIdentical = new AtomicBoolean(false);
+ variableWidthOmniBlock.retainedBytesForEachPart((part, size) -> {
+ if (size == ((VarcharVec) baseBlock.getValues()).getCapacityInBytes()) {
+ isIdentical.set(true);
+ }
+ });
+ assertTrue(isIdentical.get());
+
+ variableWidthOmniBlock.setClosable(true);
+
+ Block regionOmniBlock = variableWidthOmniBlock.getRegion(2, 2);
+ assertEquals(regionOmniBlock.getPositionCount(), 2);
+
+ for (int i = 0; i < regionOmniBlock.getPositionCount(); i++) {
+ assertEquals(regionOmniBlock.get(i), variableWidthOmniBlock.get(i + 2));
+ }
+
+ DynamicSliceOutput sliceOutput = new DynamicSliceOutput(1024);
+ blockEncodingSerde.writeBlock(sliceOutput, baseBlock);
+ Block actualBlock = blockEncodingSerde.readBlock(sliceOutput.slice().getInput());
+ assertBlockEquals(actualBlock, (VarcharVec) baseBlock.getValues());
+
+ variableWidthOmniBlock.close();
+ regionOmniBlock.close();
+ actualBlock.close();
+ }
+
+ @Test
+ public void testCopyRegion()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block variableWidthOmniBlock = new VariableWidthOmniBlock(baseBlock.getPositionCount(),
+ (VarcharVec) baseBlock.getValues());
+ Block copyRegionBlock = variableWidthOmniBlock.copyRegion(0, variableWidthOmniBlock.getPositionCount());
+ assertBlockEquals(copyRegionBlock, (VarcharVec) variableWidthOmniBlock.getValues());
+
+ Block copyNotEqualRegionBlock = variableWidthOmniBlock.copyRegion(0, 3);
+ assertBlockEquals(copyNotEqualRegionBlock, (VarcharVec) variableWidthOmniBlock.getValues());
+
+ copyNotEqualRegionBlock.close();
+ }
+
+ @Test
+ public void testCopyPosition()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block variableWidthOmniBlock = new VariableWidthOmniBlock(baseBlock.getPositionCount(),
+ (VarcharVec) baseBlock.getValues());
+
+ int[] positions = {0, 2, 3};
+ Block copyPositionsBlock = variableWidthOmniBlock.copyPositions(positions, 0, 3);
+ for (int i = 0; i < 3; i++) {
+ assertEquals(copyPositionsBlock.getString(i, 0, 0), variableWidthOmniBlock.getString(positions[i], 0, 0));
+ }
+ variableWidthOmniBlock.close();
+ copyPositionsBlock.close();
+ }
+
+ @Test
+ public void testVarcharVecWithLastValueIsNull()
+ {
+ int position = 5;
+ String[] strs = new String[]{"alice", "bob", "charlie"};
+ StringBuilder builder = new StringBuilder();
+ for (String data : strs) {
+ builder.append(data);
+ }
+ int[] offset = new int[]{0, 5, 8, 15};
+ VarcharVec values = new VarcharVec(1024, position);
+ values.put(0, builder.toString().getBytes(StandardCharsets.UTF_8), 0, offset, 0, 3);
+ values.setNull(3);
+ values.setNull(4);
+ VariableWidthOmniBlock block = new VariableWidthOmniBlock(position, values);
+ int totalLen = 0;
+ for (int i = 0; i < position; i++) {
+ totalLen += block.getSliceLength(i);
+ }
+ assertEquals(totalLen, 15);
+ totalLen = 0;
+ VariableWidthOmniBlock variableWidthOmniBlock = new VariableWidthOmniBlock(3, values.slice(2, 5));
+ for (int i = 0; i < 3; i++) {
+ totalLen += variableWidthOmniBlock.getSliceLength(i);
+ }
+ assertEquals(totalLen, 7);
+
+ block.close();
+ variableWidthOmniBlock.close();
+ }
+
+ @Test
+ public void testFilter()
+ {
+ int count = 1024;
+ int size = 1000;
+ boolean[] valid = new boolean[count];
+ Arrays.fill(valid, Boolean.TRUE);
+ VariableWidthOmniBlock block = getBlock(count);
+ String[] values = new String[block.getPositionCount()];
+
+ BloomFilter bf = getBf(size);
+ for (int i = 0; i < block.getPositionCount(); i++) {
+ values[i] = block.getString(i, 0, 0);
+ }
+
+ boolean[] actualValidPositions = block.filter(bf, valid);
+ assertEquals(actualValidPositions, valid);
+
+ int[] positions = {0, 1, 2, 3};
+ int positionCount = 4;
+ int[] matchedPosition = new int[4];
+ int actualFilterPositions = block.filter(positions, positionCount, matchedPosition, (x) -> {
+ return true;
+ });
+ assertEquals(actualFilterPositions, positionCount);
+ block.close();
+ }
+
+ @Test
+ public void testMultipleValuesWithNull()
+ {
+ BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, 10);
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "alice");
+ blockBuilder.appendNull();
+ VARCHAR.writeString(blockBuilder, "bob");
+ Block block = OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+
+ assertTrue(block.isNull(0));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block, 1), "alice");
+ assertTrue(block.isNull(2));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block, 3), "bob");
+
+ // build block from vec
+ Block block1 = new VariableWidthOmniBlock(4, (VarcharVec) block.getValues());
+ assertTrue(block1.isNull(0));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block1, 1), "alice");
+ assertTrue(block1.isNull(2));
+ assertEquals(VARCHAR.getObjectValue(SESSION, block1, 3), "bob");
+ block.close();
+ }
+
+ @Test
+ public void testInvalidInput()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ int[] offsets = {};
+ byte[] bytes = {};
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(-1, baseBlock.getPositionCount(),
+ (VarcharVec) baseBlock.getValues(), offsets, bytes)).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("arrayOffset is negative");
+
+ int[] offsets2 = {};
+ byte[] bytes2 = {};
+ assertThatThrownBy(
+ () -> new VariableWidthOmniBlock(1, -1, (VarcharVec) baseBlock.getValues(), offsets2, bytes2))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("positionCount is negative");
+
+ int[] offsets2values = {};
+ byte[] bytes2values = {};
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(1, 2, null, offsets2values, bytes2values))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("values is null");
+
+ int[] offsets2offsetsLen = {0};
+ byte[] bytes2offsetsLen = {};
+ assertThatThrownBy(
+ () -> new VariableWidthOmniBlock(1, 2, (VarcharVec) baseBlock.getValues(),
+ offsets2offsetsLen, bytes2offsetsLen)).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("offsets length is less than positionCount");
+
+ byte[] bytes4 = {0};
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(1, 4, (VarcharVec) baseBlock.getValues(), null, bytes4))
+ .isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("offsets is null");
+
+ int[] offsets5 = new int[6];
+ byte[] bytes5 = {0};
+ assertThatThrownBy(
+ () -> new VariableWidthOmniBlock(1, 4, (VarcharVec) baseBlock.getValues(), offsets5, bytes5))
+ .isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("valueIsNull length is less than positionCount");
+
+ StringBuilder builder = new StringBuilder();
+ Slice slice = Slices.wrappedBuffer(builder.toString().getBytes());
+ byte[] bytes2Array = {0};
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, -1, -1, slice,
+ offsets, bytes2Array)).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("arrayOffset is negative");
+
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 0, -1, slice, offsets,
+ bytes2Array)).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("positionCount is negative");
+
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 0, 0, null, offsets,
+ bytes2Array)).isInstanceOfAny(IllegalArgumentException.class).hasMessageMatching("slice is null");
+
+ int[] offsets2valueIsNullLen = new int[6];
+ assertThatThrownBy(() -> new VariableWidthOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, 1, 4, slice,
+ offsets2valueIsNullLen, bytes2Array)).isInstanceOfAny(IllegalArgumentException.class)
+ .hasMessageMatching("valueIsNull length is less than positionCount");
+ baseBlock.close();
+ }
+
+ @Test
+ public void testGet()
+ {
+ Block baseBlock = buildBlockByBuilder();
+ Block variableWidthOmniBlock = new VariableWidthOmniBlock(4, (VarcharVec) baseBlock.getValues());
+ long expect = 10;
+ long expectSizeBytes = 39;
+ long expectStates = 5;
+ boolean[] position = {true, true, true, true};
+ assertEquals(variableWidthOmniBlock.getRegionSizeInBytes(0, 1), expect);
+ assertEquals(variableWidthOmniBlock.getRegionSizeInBytes(0, 4), expectSizeBytes);
+ assertEquals(variableWidthOmniBlock.getEstimatedDataSizeForStats(0), expectStates);
+ assertEquals(variableWidthOmniBlock.getPositionsSizeInBytes(position), expectSizeBytes);
+
+ variableWidthOmniBlock.close();
+ }
+
+ private Block buildBlockByBuilder()
+ {
+ BlockBuilder blockBuilder = VARCHAR.createBlockBuilder(null, 4);
+ VARCHAR.writeString(blockBuilder, "alice");
+ VARCHAR.writeString(blockBuilder, "bob");
+ VARCHAR.writeString(blockBuilder, "charlie");
+ VARCHAR.writeString(blockBuilder, "dave");
+ return OperatorUtils.buildOffHeapBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, blockBuilder.build());
+ }
+
+ private VariableWidthOmniBlock getBlock(int count)
+ {
+ // returns test data
+ int[] offsets = new int[count + 1];
+ int offset = 0;
+ StringBuilder buffer = new StringBuilder();
+
+ for (int i = 0; i < count; i++) {
+ offsets[i + 1] = offset;
+ String value = "value" + i;
+ buffer.append(value);
+ offset += value.getBytes().length;
+ }
+ Slice slice = Slices.wrappedBuffer(buffer.toString().getBytes());
+ return new VariableWidthOmniBlock(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, count, slice, offsets,
+ Optional.empty());
+ }
+
+ private BloomFilter getBf(int size)
+ {
+ Random rnd = new Random();
+
+ BloomFilter bf = new BloomFilter(size, 0.01);
+ for (int i = 0; i < 100; i++) {
+ bf.test(("value" + rnd.nextLong()).getBytes());
+ }
+ return bf;
+ }
+
+ private static void assertBlockEquals(Block actual, VarcharVec expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(new String((byte[]) actual.get(position)), new String(expected.get(position)));
+ }
+ }
+
+ private static void assertBlockEquals(Type type, Block actual, Block expected)
+ {
+ for (int position = 0; position < actual.getPositionCount(); position++) {
+ assertEquals(type.getObjectValue(SESSION, actual, position),
+ type.getObjectValue(SESSION, expected, position));
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/e2e/TestExtensionExecutionPlan.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/e2e/TestExtensionExecutionPlan.java
new file mode 100644
index 0000000000000000000000000000000000000000..3871d0a895ee44ee6f0fbf3a3db788f31252a164
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/e2e/TestExtensionExecutionPlan.java
@@ -0,0 +1,5 @@
+package nova.hetu.olk.e2e;
+
+public class TestExtensionExecutionPlan
+{
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/LocalStateStoreProviderTest.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/LocalStateStoreProviderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fe01ca40e7ea38da2655a3789dd0cb10377e23a
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/LocalStateStoreProviderTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.operator;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
+import io.airlift.log.Logger;
+import io.prestosql.metastore.MetaStoreConstants;
+import io.prestosql.seedstore.SeedStoreManager;
+import io.prestosql.spi.PrestoException;
+import io.prestosql.spi.classloader.ThreadContextClassLoader;
+import io.prestosql.spi.seedstore.SeedStoreSubType;
+import io.prestosql.spi.statestore.StateCollection;
+import io.prestosql.spi.statestore.StateStore;
+import io.prestosql.spi.statestore.StateStoreFactory;
+import io.prestosql.statestore.LocalStateStoreProvider;
+import io.prestosql.statestore.StateStoreConstants;
+import io.prestosql.statestore.StateStoreProvider;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.google.common.base.Preconditions.checkState;
+import static io.airlift.configuration.ConfigurationLoader.loadPropertiesFrom;
+import static io.prestosql.spi.StandardErrorCode.STATE_STORE_FAILURE;
+import static io.prestosql.statestore.StateStoreConstants.STATE_STORE_CONFIGURATION_PATH;
+import static io.prestosql.statestore.StateStoreConstants.STATE_STORE_NAME_PROPERTY_NAME;
+import static io.prestosql.statestore.StateStoreConstants.STATE_STORE_TYPE_PROPERTY_NAME;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+public class LocalStateStoreProviderTest
+ implements StateStoreProvider
+{
+ private static final Logger log = Logger.get(LocalStateStoreProvider.class);
+ private static final File STATE_STORE_CONFIGURATION = new File(STATE_STORE_CONFIGURATION_PATH);
+ private static final String DEFAULT_STATE_STORE_NAME = "default-state-store";
+ private static final long SLEEP_INTERVAL = 2000L;
+
+ private final Map stateStoreFactories = new ConcurrentHashMap<>();
+ private StateStore stateStore;
+ private final SeedStoreManager seedStoreManager;
+
+ @Inject
+ public LocalStateStoreProviderTest(SeedStoreManager seedStoreManager)
+ {
+ this.seedStoreManager = requireNonNull(seedStoreManager, "seedStoreManager is null");
+ }
+
+ @Override
+ public void addStateStoreFactory(StateStoreFactory factory)
+ {
+ if (stateStoreFactories.putIfAbsent(factory.getName(), factory) != null) {
+ throw new IllegalArgumentException(format("State Store '%s' is already registered", factory.getName()));
+ }
+ }
+
+ @Override
+ public void loadStateStore()
+ throws Exception
+ {
+ if (STATE_STORE_CONFIGURATION.exists()) {
+ Map properties = new HashMap<>(loadPropertiesFrom(STATE_STORE_CONFIGURATION.getPath()));
+ String stateStoreType = properties.remove(STATE_STORE_TYPE_PROPERTY_NAME);
+ setStateStore(stateStoreType, properties);
+ createStateCollections();
+ }
+ else {
+ log.info("No configuration file found, skip loading state store client");
+ }
+ }
+
+ public void setStateStore(String stateStoreType, Map properties)
+ {
+ requireNonNull(stateStoreType, "stateStoreType is null");
+ requireNonNull(properties, "properties is null");
+
+ log.info("-- Loading state store --");
+ StateStoreFactory stateStoreFactory = stateStoreFactories.get(stateStoreType);
+ checkState(stateStoreFactory != null, "State store %s is not registered", stateStoreType);
+ try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(stateStoreFactory.getClass().getClassLoader())) {
+ String stateStoreName = properties.remove(STATE_STORE_NAME_PROPERTY_NAME);
+ if (stateStoreName == null) {
+ log.info("State store name not provided, using default state store name: %s", DEFAULT_STATE_STORE_NAME);
+ stateStoreName = DEFAULT_STATE_STORE_NAME;
+ }
+ // Create state stores defined in config
+ stateStore = stateStoreFactory.create(stateStoreName, seedStoreManager.getSeedStore(SeedStoreSubType.HAZELCAST), ImmutableMap.copyOf(properties));
+ stateStore.registerClusterFailureHandler(this::handleClusterDisconnection);
+ stateStore.init();
+ }
+ catch (Exception e) {
+ throw new PrestoException(STATE_STORE_FAILURE, "Unable to create state store: " + e.getMessage());
+ }
+ log.info("-- Loaded state store %s --", stateStoreType);
+ }
+
+ @Override
+ public StateStore getStateStore()
+ {
+ return stateStore;
+ }
+
+ public void createStateCollections()
+ {
+ // Create essential state collections
+ stateStore.createStateCollection(StateStoreConstants.DISCOVERY_SERVICE_COLLECTION_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(StateStoreConstants.QUERY_STATE_COLLECTION_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(StateStoreConstants.FINISHED_QUERY_STATE_COLLECTION_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(StateStoreConstants.OOM_QUERY_STATE_COLLECTION_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(StateStoreConstants.CPU_USAGE_STATE_COLLECTION_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(StateStoreConstants.TRANSACTION_STATE_COLLECTION_NAME, StateCollection.Type.MAP);
+
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_CATALOGCACHE_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_CATALOGSCACHE_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_TABLECACHE_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_TABLESCACHE_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_DATABASECACHE_NAME, StateCollection.Type.MAP);
+ stateStore.createStateCollection(MetaStoreConstants.HETU_META_STORE_DATABASESCACHE_NAME, StateCollection.Type.MAP);
+ }
+
+ void handleClusterDisconnection(Object obj)
+ {
+ log.info("Connection to Hazelcast state store has SHUTDOWN.");
+ while (true) {
+ try {
+ Thread.sleep(SLEEP_INTERVAL);
+ seedStoreManager.loadSeedStore();
+ loadStateStore();
+ break;
+ }
+ catch (Exception ex) {
+ log.info("Failed to reload state store: %s", ex.getMessage());
+ }
+ }
+ }
+}
diff --git a/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/TestAggregationOmniOperator.java b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/TestAggregationOmniOperator.java
new file mode 100644
index 0000000000000000000000000000000000000000..92859119d8be190433e4beeca40e6c6278a853d5
--- /dev/null
+++ b/omnioperator/omniop-openlookeng-extension/src/test/omni/nova/hetu/olk/operator/TestAggregationOmniOperator.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2020-2022. Huawei Technologies Co., Ltd. All rights reserved.
+ * Licensed 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 nova.hetu.olk.operator;
+
+import com.google.common.collect.ImmutableList;
+import io.prestosql.operator.DriverContext;
+import io.prestosql.spi.Page;
+import io.prestosql.spi.block.Block;
+import io.prestosql.spi.block.BlockBuilder;
+import io.prestosql.spi.block.RowBlockBuilder;
+import io.prestosql.spi.plan.AggregationNode;
+import io.prestosql.spi.plan.PlanNodeId;
+import io.prestosql.spi.type.RowType;
+import io.prestosql.spi.type.Type;
+import io.prestosql.testing.MaterializedResult;
+import nova.hetu.olk.operator.AggregationOmniOperator.AggregationOmniOperatorFactory;
+import nova.hetu.olk.tool.OperatorUtils;
+import nova.hetu.omniruntime.constants.FunctionType;
+import nova.hetu.omniruntime.type.BooleanDataType;
+import nova.hetu.omniruntime.type.DataType;
+import nova.hetu.omniruntime.type.DoubleDataType;
+import nova.hetu.omniruntime.type.IntDataType;
+import nova.hetu.omniruntime.type.LongDataType;
+import nova.hetu.omniruntime.type.VarcharDataType;
+import nova.hetu.omniruntime.vector.VecAllocator;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.stream.Collectors;
+
+import static io.airlift.concurrent.Threads.daemonThreadsNamed;
+import static io.airlift.slice.Slices.utf8Slice;
+import static io.prestosql.RowPagesBuilder.rowPagesBuilder;
+import static io.prestosql.SessionTestUtils.TEST_SESSION;
+import static io.prestosql.operator.OperatorAssertion.assertOperatorEquals;
+import static io.prestosql.spi.type.BigintType.BIGINT;
+import static io.prestosql.spi.type.BooleanType.BOOLEAN;
+import static io.prestosql.spi.type.DoubleType.DOUBLE;
+import static io.prestosql.spi.type.IntegerType.INTEGER;
+import static io.prestosql.spi.type.VarcharType.VARCHAR;
+import static io.prestosql.testing.MaterializedResult.resultBuilder;
+import static io.prestosql.testing.TestingTaskContext.createTaskContext;
+import static java.lang.String.format;
+import static java.util.concurrent.Executors.newCachedThreadPool;
+import static java.util.concurrent.Executors.newScheduledThreadPool;
+import static nova.hetu.olk.tool.OperatorUtils.transferToOffHeapPages;
+import static nova.hetu.omniruntime.constants.FunctionType.OMNI_AGGREGATION_TYPE_AVG;
+import static nova.hetu.omniruntime.constants.FunctionType.OMNI_AGGREGATION_TYPE_COUNT_ALL;
+import static nova.hetu.omniruntime.constants.FunctionType.OMNI_AGGREGATION_TYPE_COUNT_COLUMN;
+import static nova.hetu.omniruntime.constants.FunctionType.OMNI_AGGREGATION_TYPE_MAX;
+import static nova.hetu.omniruntime.constants.FunctionType.OMNI_AGGREGATION_TYPE_SUM;
+import static org.testng.Assert.assertEquals;
+
+@Test(singleThreaded = true)
+public class TestAggregationOmniOperator
+{
+ private ExecutorService executor;
+
+ private ScheduledExecutorService scheduledExecutor;
+
+ @BeforeMethod
+ public void setUp()
+ {
+ executor = newCachedThreadPool(daemonThreadsNamed("test-executor-%s"));
+ scheduledExecutor = newScheduledThreadPool(2, daemonThreadsNamed("test-scheduledExecutor-%s"));
+ }
+
+ @DataProvider(name = "hashEnabled")
+ public static Object[][] hashEnabled()
+ {
+ return new Object[][]{{true}, {false}};
+ }
+
+ @AfterMethod(alwaysRun = true)
+ public void tearDown()
+ {
+ executor.shutdownNow();
+ scheduledExecutor.shutdownNow();
+ }
+
+ @Test(invocationCount = 1)
+ public void testAggregation()
+ {
+ List input = rowPagesBuilder(BIGINT, BIGINT, BIGINT, VARCHAR).addSequencePage(100, 0, 0, 0, 300).build();
+
+ int id = 0;
+ List inputTypes = ImmutableList.of(BIGINT, BIGINT, BIGINT, VARCHAR);
+ DataType[] sourceTypes = {LongDataType.LONG, LongDataType.LONG, LongDataType.LONG, new VarcharDataType(10)};
+ FunctionType[] aggregatorTypes = {OMNI_AGGREGATION_TYPE_COUNT_COLUMN, OMNI_AGGREGATION_TYPE_AVG,
+ OMNI_AGGREGATION_TYPE_SUM, OMNI_AGGREGATION_TYPE_MAX};
+ int[] aggregationInputChannels = {0, 1, 2, 3};
+ DataType[] aggregationOutputTypes = {LongDataType.LONG, DoubleDataType.DOUBLE, LongDataType.LONG, new VarcharDataType(10)};
+ AggregationNode.Step step = AggregationNode.Step.SINGLE;
+ ImmutableList.Builder> maskChannels = new ImmutableList.Builder<>();
+ for (int i = 0; i < aggregatorTypes.length; i++) {
+ maskChannels.add(Optional.empty());
+ }
+ AggregationOmniOperatorFactory aggregationOmniOperatorFactory = new AggregationOmniOperatorFactory(id,
+ new PlanNodeId(String.valueOf(id)), inputTypes, aggregatorTypes, aggregationInputChannels,
+ maskChannels.build(), aggregationOutputTypes, step);
+ DriverContext driverContext = createTaskContext(executor, scheduledExecutor, TEST_SESSION)
+ .addPipelineContext(0, true, true, false).addDriverContext();
+
+ MaterializedResult expected = resultBuilder(driverContext.getSession(), BIGINT, DOUBLE, BIGINT, VARCHAR)
+ .row(100L, 49.5, 4950L, "399").build();
+ assertOperatorEquals(aggregationOmniOperatorFactory, driverContext, input, expected);
+ assertEquals(driverContext.getSystemMemoryUsage(), 0);
+ assertEquals(driverContext.getMemoryUsage(), 0);
+ }
+
+ @Test(invocationCount = 1)
+ public void testCountAggregationCompare()
+ {
+ List types = ImmutableList.of(BIGINT, BIGINT, INTEGER);
+ List input = rowPagesBuilder(types).row(1, 1, null).row(null, 2, 2).row(null, 3, 3).row(4, 4, 4)
+ .row(5, null, 5).row(null, 6, 6).build();
+
+ int id = 0;
+ List inputTypes = ImmutableList.of(BIGINT, INTEGER);
+ DataType[] sourceTypes = {LongDataType.LONG, IntDataType.INTEGER};
+ FunctionType[] aggregatorTypes = {OMNI_AGGREGATION_TYPE_COUNT_COLUMN, OMNI_AGGREGATION_TYPE_COUNT_ALL,
+ OMNI_AGGREGATION_TYPE_COUNT_COLUMN};
+ int[] aggregationInputChannels = {0, 2};
+ DataType[] aggregationOutputTypes = {LongDataType.LONG, LongDataType.LONG, LongDataType.LONG};
+ AggregationNode.Step step = AggregationNode.Step.SINGLE;
+ ImmutableList.Builder> maskChannels = new ImmutableList.Builder<>();
+ for (int i = 0; i < aggregatorTypes.length; i++) {
+ maskChannels.add(Optional.empty());
+ }
+ AggregationOmniOperatorFactory aggregationOmniOperatorFactory = new AggregationOmniOperatorFactory(id,
+ new PlanNodeId(String.valueOf(id)), inputTypes, aggregatorTypes, aggregationInputChannels,
+ maskChannels.build(), aggregationOutputTypes, step);
+ DriverContext driverContext = createTaskContext(executor, scheduledExecutor, TEST_SESSION)
+ .addPipelineContext(0, true, true, false).addDriverContext();
+
+ MaterializedResult expected = resultBuilder(driverContext.getSession(), BIGINT, BIGINT, BIGINT).row(3L, 6L, 5L)
+ .build();
+ assertOperatorEquals(aggregationOmniOperatorFactory, driverContext, input, expected);
+ assertEquals(driverContext.getSystemMemoryUsage(), 0);
+ assertEquals(driverContext.getMemoryUsage(), 0);
+ }
+
+ @Test(invocationCount = 1)
+ public void testCountAggregation()
+ {
+ List input = rowPagesBuilder(BIGINT, BIGINT, BOOLEAN, BOOLEAN).row(10L, 20L, true, true)
+ .row(20L, 10L, true, true).pageBreak().row(10L, 30L, false, true).row(30L, 10L, true, false).build();
+
+ // transfer on-heap page to off-heap
+ List offHeapInput = transferToOffHeapPages(VecAllocator.GLOBAL_VECTOR_ALLOCATOR, input);
+
+ int id = 0;
+ List inputTypes = ImmutableList.of(BIGINT, BIGINT, BOOLEAN, BOOLEAN);
+ DataType[] sourceTypes = {LongDataType.LONG, LongDataType.LONG, BooleanDataType.BOOLEAN, BooleanDataType.BOOLEAN};
+ FunctionType[] aggregatorTypes = {OMNI_AGGREGATION_TYPE_COUNT_COLUMN, OMNI_AGGREGATION_TYPE_SUM};
+ int[] aggregationInputChannels = {0, 1};
+ DataType[] aggregationOutputTypes = {LongDataType.LONG, LongDataType.LONG};
+ AggregationNode.Step step = AggregationNode.Step.SINGLE;
+ ImmutableList.Builder> maskChannels = new ImmutableList.Builder<>();
+ maskChannels.add(Optional.of(2));
+ maskChannels.add(Optional.of(3));
+
+ AggregationOmniOperatorFactory aggregationOmniOperatorFactory = new AggregationOmniOperatorFactory(id,
+ new PlanNodeId(String.valueOf(id)), inputTypes, aggregatorTypes, aggregationInputChannels,
+ maskChannels.build(), aggregationOutputTypes, step);
+ DriverContext driverContext = createTaskContext(executor, scheduledExecutor, TEST_SESSION)
+ .addPipelineContext(0, true, true, false).addDriverContext();
+
+ MaterializedResult expected = resultBuilder(driverContext.getSession(), BIGINT, BIGINT).row(3L, 60L).build();
+ assertOperatorEquals(aggregationOmniOperatorFactory, driverContext, offHeapInput, expected);
+ assertEquals(driverContext.getSystemMemoryUsage(), 0);
+ assertEquals(driverContext.getMemoryUsage(), 0);
+ }
+
+ @Test(invocationCount = 1)
+ public void testAggregationWithRowBlock()
+ {
+ List fieldTypes = ImmutableList.of(VARCHAR, BIGINT);
+ List