diff --git a/.github/workflows/arrow-flight-tests.yml b/.github/workflows/arrow-flight-tests.yml
new file mode 100644
index 000000000000..ee77c122536e
--- /dev/null
+++ b/.github/workflows/arrow-flight-tests.yml
@@ -0,0 +1,82 @@
+name: arrow flight tests
+
+on:
+ pull_request:
+
+env:
+ CONTINUOUS_INTEGRATION: true
+ MAVEN_OPTS: "-Xmx1024M -XX:+ExitOnOutOfMemoryError"
+ MAVEN_INSTALL_OPTS: "-Xmx2G -XX:+ExitOnOutOfMemoryError"
+ MAVEN_FAST_INSTALL: "-B -V --quiet -T 1C -DskipTests -Dair.check.skip-all --no-transfer-progress -Dmaven.javadoc.skip=true"
+ MAVEN_TEST: "-B -Dair.check.skip-all -Dmaven.javadoc.skip=true -DLogTestDurationListener.enabled=true --no-transfer-progress --fail-at-end"
+ RETRY: .github/bin/retry
+
+jobs:
+ changes:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: read
+ outputs:
+ codechange: ${{ steps.filter.outputs.codechange }}
+ steps:
+ - uses: dorny/paths-filter@v2
+ id: filter
+ with:
+ filters: |
+ codechange:
+ - '!presto-docs/**'
+ test:
+ runs-on: ubuntu-latest
+ needs: changes
+ strategy:
+ fail-fast: false
+ matrix:
+ modules:
+ - ":presto-base-arrow-flight" # Only run tests for the `presto-base-arrow-flight` module
+
+ timeout-minutes: 80
+ concurrency:
+ group: ${{ github.workflow }}-test-${{ matrix.modules }}-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
+ steps:
+ # Checkout the code only if there are changes in the relevant files
+ - uses: actions/checkout@v4
+ if: needs.changes.outputs.codechange == 'true'
+ with:
+ show-progress: false
+
+ # Set up Java for the build environment
+ - uses: actions/setup-java@v2
+ if: needs.changes.outputs.codechange == 'true'
+ with:
+ distribution: 'temurin'
+ java-version: 8
+
+ # Cache Maven dependencies to speed up the build
+ - name: Cache local Maven repository
+ if: needs.changes.outputs.codechange == 'true'
+ id: cache-maven
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-2-
+
+ # Resolve Maven dependencies (if cache is not found)
+ - name: Populate Maven cache
+ if: steps.cache-maven.outputs.cache-hit != 'true' && needs.changes.outputs.codechange == 'true'
+ run: ./mvnw de.qaware.maven:go-offline-maven-plugin:resolve-dependencies --no-transfer-progress && .github/bin/download_nodejs
+
+ # Install dependencies for the target module
+ - name: Maven Install
+ if: needs.changes.outputs.codechange == 'true'
+ run: |
+ export MAVEN_OPTS="${MAVEN_INSTALL_OPTS}"
+ ./mvnw install ${MAVEN_FAST_INSTALL} -am -pl ${{ matrix.modules }}
+
+ # Run Maven tests for the target module
+ - name: Maven Tests
+ if: needs.changes.outputs.codechange == 'true'
+ run: ./mvnw test ${MAVEN_TEST} -pl ${{ matrix.modules }}
diff --git a/.github/workflows/test-other-modules.yml b/.github/workflows/test-other-modules.yml
index 3c3f84817a0d..1065fe3d0c6e 100644
--- a/.github/workflows/test-other-modules.yml
+++ b/.github/workflows/test-other-modules.yml
@@ -84,4 +84,5 @@ jobs:
!presto-test-coverage,
!presto-iceberg,
!presto-singlestore,
- !presto-native-sidecar-plugin'
+ !presto-native-sidecar-plugin,
+ !presto-base-arrow-flight'
diff --git a/pom.xml b/pom.xml
index 82099ffb5b04..338af56f350f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -85,6 +85,7 @@
3.25.5
4.1.115.Final
2.0
+ 17.0.0
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+
+
+ org.apache.arrow
+ flight-core
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+
+ com.facebook.airlift
+ bootstrap
+
+
+
+ com.facebook.airlift
+ log
+
+
+
+ com.google.guava
+ guava
+
+
+
+ javax.inject
+ javax.inject
+
+
+
+ com.facebook.presto
+ presto-spi
+
+
+
+ io.airlift
+ slice
+
+
+
+ com.facebook.airlift
+ log-manager
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+
+ com.facebook.presto
+ presto-common
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+ com.google.code.findbugs
+ jsr305
+ true
+
+
+
+ com.google.inject
+ guice
+
+
+
+ com.facebook.airlift
+ configuration
+
+
+
+ joda-time
+ joda-time
+
+
+
+ org.jdbi
+ jdbi3-core
+
+
+
+
+ org.testng
+ testng
+ test
+
+
+
+ io.airlift.tpch
+ tpch
+ test
+
+
+
+ com.facebook.presto
+ presto-tpch
+ test
+
+
+
+ com.facebook.airlift
+ json
+ test
+
+
+
+ com.facebook.presto
+ presto-testng-services
+ test
+
+
+
+ com.facebook.airlift
+ testing
+ test
+
+
+
+ com.facebook.presto
+ presto-main
+ test
+
+
+
+ com.facebook.presto
+ presto-tests
+ test
+
+
+
+ com.h2database
+ h2
+ test
+
+
+
+
+
+
+ com.google.errorprone
+ error_prone_annotations
+ ${error_prone_annotations.version}
+
+
+
+ io.perfmark
+ perfmark-api
+ ${perfmark-api.version}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ -Xss10M
+
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ org.basepom.maven
+ duplicate-finder-maven-plugin
+ 1.2.1
+
+
+ module-info
+ META-INF.versions.9.module-info
+
+
+ arrow-git.properties
+ about.html
+
+
+
+
+
+ check
+
+
+
+
+
+
+
diff --git a/presto-base-arrow-flight/src/main/java/com/facebook/plugin/arrow/ArrowBlockBuilder.java b/presto-base-arrow-flight/src/main/java/com/facebook/plugin/arrow/ArrowBlockBuilder.java
new file mode 100644
index 000000000000..cf3f8f5e6f4f
--- /dev/null
+++ b/presto-base-arrow-flight/src/main/java/com/facebook/plugin/arrow/ArrowBlockBuilder.java
@@ -0,0 +1,941 @@
+/*
+ * 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 com.facebook.plugin.arrow;
+
+import com.facebook.presto.common.block.Block;
+import com.facebook.presto.common.block.BlockBuilder;
+import com.facebook.presto.common.block.DictionaryBlock;
+import com.facebook.presto.common.type.ArrayType;
+import com.facebook.presto.common.type.BigintType;
+import com.facebook.presto.common.type.BooleanType;
+import com.facebook.presto.common.type.CharType;
+import com.facebook.presto.common.type.DateType;
+import com.facebook.presto.common.type.DecimalType;
+import com.facebook.presto.common.type.Decimals;
+import com.facebook.presto.common.type.DoubleType;
+import com.facebook.presto.common.type.IntegerType;
+import com.facebook.presto.common.type.RealType;
+import com.facebook.presto.common.type.RowType;
+import com.facebook.presto.common.type.SmallintType;
+import com.facebook.presto.common.type.TimeType;
+import com.facebook.presto.common.type.TimestampType;
+import com.facebook.presto.common.type.TinyintType;
+import com.facebook.presto.common.type.Type;
+import com.facebook.presto.common.type.VarbinaryType;
+import com.facebook.presto.common.type.VarcharType;
+import com.google.common.base.CharMatcher;
+import io.airlift.slice.Slice;
+import io.airlift.slice.Slices;
+import org.apache.arrow.vector.BigIntVector;
+import org.apache.arrow.vector.BitVector;
+import org.apache.arrow.vector.DateDayVector;
+import org.apache.arrow.vector.DateMilliVector;
+import org.apache.arrow.vector.DecimalVector;
+import org.apache.arrow.vector.FieldVector;
+import org.apache.arrow.vector.Float4Vector;
+import org.apache.arrow.vector.Float8Vector;
+import org.apache.arrow.vector.IntVector;
+import org.apache.arrow.vector.NullVector;
+import org.apache.arrow.vector.SmallIntVector;
+import org.apache.arrow.vector.TimeMicroVector;
+import org.apache.arrow.vector.TimeMilliVector;
+import org.apache.arrow.vector.TimeSecVector;
+import org.apache.arrow.vector.TimeStampMicroVector;
+import org.apache.arrow.vector.TimeStampMilliTZVector;
+import org.apache.arrow.vector.TimeStampMilliVector;
+import org.apache.arrow.vector.TimeStampSecVector;
+import org.apache.arrow.vector.TinyIntVector;
+import org.apache.arrow.vector.ValueVector;
+import org.apache.arrow.vector.VarBinaryVector;
+import org.apache.arrow.vector.VarCharVector;
+import org.apache.arrow.vector.complex.ListVector;
+import org.apache.arrow.vector.dictionary.Dictionary;
+import org.apache.arrow.vector.dictionary.DictionaryProvider;
+import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.types.pojo.Field;
+import org.apache.arrow.vector.util.JsonStringArrayList;
+
+import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static com.facebook.plugin.arrow.ArrowErrorCode.ARROW_FLIGHT_TYPE_ERROR;
+import static java.util.Objects.requireNonNull;
+
+public class ArrowBlockBuilder
+{
+ public Block buildBlockFromFieldVector(FieldVector vector, Type type, DictionaryProvider dictionaryProvider)
+ {
+ if (vector.getField().getDictionary() != null) {
+ Dictionary dictionary = dictionaryProvider.lookup(vector.getField().getDictionary().getId());
+ return buildBlockFromDictionaryVector(vector, dictionary.getVector());
+ }
+ else {
+ return buildBlockFromValueVector(vector, type);
+ }
+ }
+
+ public Block buildBlockFromDictionaryVector(FieldVector fieldVector, FieldVector dictionaryVector)
+ {
+ // Validate inputs
+ requireNonNull(fieldVector, "encoded vector is null");
+ requireNonNull(dictionaryVector, "dictionary vector is null");
+
+ Type prestoType = getPrestoTypeFromArrowField(dictionaryVector.getField());
+
+ Block dictionaryblock = buildBlockFromValueVector(dictionaryVector, prestoType);
+
+ // Return Presto DictionaryBlock
+ return getDictionaryBlock(fieldVector, dictionaryblock);
+ }
+
+ protected Type getPrestoTypeFromArrowField(Field field)
+ {
+ switch (field.getType().getTypeID()) {
+ case Int:
+ ArrowType.Int intType = (ArrowType.Int) field.getType();
+ return getPrestoTypeForArrowIntType(intType);
+ case Binary:
+ case LargeBinary:
+ case FixedSizeBinary:
+ return VarbinaryType.VARBINARY;
+ case Date:
+ return DateType.DATE;
+ case Timestamp:
+ return TimestampType.TIMESTAMP;
+ case Utf8:
+ case LargeUtf8:
+ return VarcharType.VARCHAR;
+ case FloatingPoint:
+ ArrowType.FloatingPoint floatingPoint = (ArrowType.FloatingPoint) field.getType();
+ return getPrestoTypeForArrowFloatingPointType(floatingPoint);
+ case Decimal:
+ ArrowType.Decimal decimalType = (ArrowType.Decimal) field.getType();
+ return DecimalType.createDecimalType(decimalType.getPrecision(), decimalType.getScale());
+ case Bool:
+ return BooleanType.BOOLEAN;
+ case Time:
+ return TimeType.TIME;
+ default:
+ throw new UnsupportedOperationException("The data type " + field.getType().getTypeID() + " is not supported.");
+ }
+ }
+
+ private Type getPrestoTypeForArrowFloatingPointType(ArrowType.FloatingPoint floatingPoint)
+ {
+ switch (floatingPoint.getPrecision()) {
+ case SINGLE:
+ return RealType.REAL;
+ case DOUBLE:
+ return DoubleType.DOUBLE;
+ default:
+ throw new ArrowException(ARROW_FLIGHT_TYPE_ERROR, "Unexpected floating point precision " + floatingPoint.getPrecision());
+ }
+ }
+
+ private Type getPrestoTypeForArrowIntType(ArrowType.Int intType)
+ {
+ switch (intType.getBitWidth()) {
+ case 64:
+ return BigintType.BIGINT;
+ case 32:
+ return IntegerType.INTEGER;
+ case 16:
+ return SmallintType.SMALLINT;
+ case 8:
+ return TinyintType.TINYINT;
+ default:
+ throw new ArrowException(ARROW_FLIGHT_TYPE_ERROR, "Unexpected bit width " + intType.getBitWidth());
+ }
+ }
+
+ private DictionaryBlock getDictionaryBlock(FieldVector fieldVector, Block dictionaryblock)
+ {
+ if (fieldVector instanceof IntVector) {
+ // Get the Arrow indices vector
+ IntVector indicesVector = (IntVector) fieldVector;
+ int[] ids = new int[indicesVector.getValueCount()];
+ for (int i = 0; i < indicesVector.getValueCount(); i++) {
+ ids[i] = indicesVector.get(i);
+ }
+ return new DictionaryBlock(ids.length, dictionaryblock, ids);
+ }
+ else if (fieldVector instanceof SmallIntVector) {
+ // Get the SmallInt indices vector
+ SmallIntVector smallIntIndicesVector = (SmallIntVector) fieldVector;
+ int[] ids = new int[smallIntIndicesVector.getValueCount()];
+ for (int i = 0; i < smallIntIndicesVector.getValueCount(); i++) {
+ ids[i] = smallIntIndicesVector.get(i);
+ }
+ return new DictionaryBlock(ids.length, dictionaryblock, ids);
+ }
+ else if (fieldVector instanceof TinyIntVector) {
+ // Get the TinyInt indices vector
+ TinyIntVector tinyIntIndicesVector = (TinyIntVector) fieldVector;
+ int[] ids = new int[tinyIntIndicesVector.getValueCount()];
+ for (int i = 0; i < tinyIntIndicesVector.getValueCount(); i++) {
+ ids[i] = tinyIntIndicesVector.get(i);
+ }
+ return new DictionaryBlock(ids.length, dictionaryblock, ids);
+ }
+ else {
+ // Handle the case where the FieldVector is of an unsupported type
+ throw new IllegalArgumentException("Unsupported FieldVector type: " + fieldVector.getClass());
+ }
+ }
+
+ private Block buildBlockFromValueVector(ValueVector vector, Type type)
+ {
+ if (vector instanceof BitVector) {
+ return buildBlockFromBitVector((BitVector) vector, type);
+ }
+ else if (vector instanceof TinyIntVector) {
+ return buildBlockFromTinyIntVector((TinyIntVector) vector, type);
+ }
+ else if (vector instanceof IntVector) {
+ return buildBlockFromIntVector((IntVector) vector, type);
+ }
+ else if (vector instanceof SmallIntVector) {
+ return buildBlockFromSmallIntVector((SmallIntVector) vector, type);
+ }
+ else if (vector instanceof BigIntVector) {
+ return buildBlockFromBigIntVector((BigIntVector) vector, type);
+ }
+ else if (vector instanceof DecimalVector) {
+ return buildBlockFromDecimalVector((DecimalVector) vector, type);
+ }
+ else if (vector instanceof NullVector) {
+ return buildBlockFromNullVector((NullVector) vector, type);
+ }
+ else if (vector instanceof TimeStampMicroVector) {
+ return buildBlockFromTimeStampMicroVector((TimeStampMicroVector) vector, type);
+ }
+ else if (vector instanceof TimeStampMilliVector) {
+ return buildBlockFromTimeStampMilliVector((TimeStampMilliVector) vector, type);
+ }
+ else if (vector instanceof Float4Vector) {
+ return buildBlockFromFloat4Vector((Float4Vector) vector, type);
+ }
+ else if (vector instanceof Float8Vector) {
+ return buildBlockFromFloat8Vector((Float8Vector) vector, type);
+ }
+ else if (vector instanceof VarCharVector) {
+ if (type instanceof CharType) {
+ return buildCharTypeBlockFromVarcharVector((VarCharVector) vector, type);
+ }
+ else if (type instanceof TimeType) {
+ return buildTimeTypeBlockFromVarcharVector((VarCharVector) vector, type);
+ }
+ else {
+ return buildBlockFromVarCharVector((VarCharVector) vector, type);
+ }
+ }
+ else if (vector instanceof VarBinaryVector) {
+ return buildBlockFromVarBinaryVector((VarBinaryVector) vector, type);
+ }
+ else if (vector instanceof DateDayVector) {
+ return buildBlockFromDateDayVector((DateDayVector) vector, type);
+ }
+ else if (vector instanceof DateMilliVector) {
+ return buildBlockFromDateMilliVector((DateMilliVector) vector, type);
+ }
+ else if (vector instanceof TimeMilliVector) {
+ return buildBlockFromTimeMilliVector((TimeMilliVector) vector, type);
+ }
+ else if (vector instanceof TimeSecVector) {
+ return buildBlockFromTimeSecVector((TimeSecVector) vector, type);
+ }
+ else if (vector instanceof TimeStampSecVector) {
+ return buildBlockFromTimeStampSecVector((TimeStampSecVector) vector, type);
+ }
+ else if (vector instanceof TimeMicroVector) {
+ return buildBlockFromTimeMicroVector((TimeMicroVector) vector, type);
+ }
+ else if (vector instanceof TimeStampMilliTZVector) {
+ return buildBlockFromTimeMilliTZVector((TimeStampMilliTZVector) vector, type);
+ }
+ else if (vector instanceof ListVector) {
+ return buildBlockFromListVector((ListVector) vector, type);
+ }
+ else {
+ throw new UnsupportedOperationException("Unsupported vector type: " + vector.getClass());
+ }
+ }
+
+ public Block buildBlockFromTimeMilliTZVector(TimeStampMilliTZVector vector, Type type)
+ {
+ if (!(type instanceof TimestampType)) {
+ throw new IllegalArgumentException("Type must be a TimestampType for TimeStampMilliTZVector");
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long millis = vector.get(i);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromBitVector(BitVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeBoolean(builder, vector.get(i) == 1);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromIntVector(IntVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeLong(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromSmallIntVector(SmallIntVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeLong(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTinyIntVector(TinyIntVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeLong(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromBigIntVector(BigIntVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeLong(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromDecimalVector(DecimalVector vector, Type type)
+ {
+ if (!(type instanceof DecimalType)) {
+ throw new IllegalArgumentException("Type must be a DecimalType for DecimalVector");
+ }
+
+ DecimalType decimalType = (DecimalType) type;
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ BigDecimal decimal = vector.getObject(i); // Get the BigDecimal value
+ if (decimalType.isShort()) {
+ builder.writeLong(decimal.unscaledValue().longValue());
+ }
+ else {
+ Slice slice = Decimals.encodeScaledValue(decimal);
+ decimalType.writeSlice(builder, slice, 0, slice.length());
+ }
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromNullVector(NullVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ builder.appendNull();
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeStampMicroVector(TimeStampMicroVector vector, Type type)
+ {
+ if (!(type instanceof TimestampType)) {
+ throw new IllegalArgumentException("Expected TimestampType but got " + type.getClass().getName());
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long micros = vector.get(i);
+ long millis = TimeUnit.MICROSECONDS.toMillis(micros);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeStampMilliVector(TimeStampMilliVector vector, Type type)
+ {
+ if (!(type instanceof TimestampType)) {
+ throw new IllegalArgumentException("Expected TimestampType but got " + type.getClass().getName());
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long millis = vector.get(i);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromFloat8Vector(Float8Vector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeDouble(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromFloat4Vector(Float4Vector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ int intBits = Float.floatToIntBits(vector.get(i));
+ type.writeLong(builder, intBits);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromVarBinaryVector(VarBinaryVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ byte[] value = vector.get(i);
+ type.writeSlice(builder, Slices.wrappedBuffer(value));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromVarCharVector(VarCharVector vector, Type type)
+ {
+ if (!(type instanceof VarcharType)) {
+ throw new IllegalArgumentException("Expected VarcharType but got " + type.getClass().getName());
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ // Directly create a Slice from the raw byte array
+ byte[] rawBytes = vector.get(i);
+ Slice slice = Slices.wrappedBuffer(rawBytes);
+ // Write the Slice directly to the builder
+ type.writeSlice(builder, slice);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromDateDayVector(DateDayVector vector, Type type)
+ {
+ if (!(type instanceof DateType)) {
+ throw new IllegalArgumentException("Expected DateType but got " + type.getClass().getName());
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ type.writeLong(builder, vector.get(i));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromDateMilliVector(DateMilliVector vector, Type type)
+ {
+ if (!(type instanceof DateType)) {
+ throw new IllegalArgumentException("Expected DateType but got " + type.getClass().getName());
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ DateType dateType = (DateType) type;
+ long days = TimeUnit.MILLISECONDS.toDays(vector.get(i));
+ dateType.writeLong(builder, days);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeSecVector(TimeSecVector vector, Type type)
+ {
+ if (!(type instanceof TimeType)) {
+ throw new IllegalArgumentException("Type must be a TimeType for TimeSecVector");
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ int value = vector.get(i);
+ long millis = TimeUnit.SECONDS.toMillis(value);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeMilliVector(TimeMilliVector vector, Type type)
+ {
+ if (!(type instanceof TimeType)) {
+ throw new IllegalArgumentException("Type must be a TimeType for TimeSecVector");
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long millis = vector.get(i);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeMicroVector(TimeMicroVector vector, Type type)
+ {
+ if (!(type instanceof TimeType)) {
+ throw new IllegalArgumentException("Type must be a TimeType for TimemicroVector");
+ }
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long value = vector.get(i);
+ long micro = TimeUnit.MICROSECONDS.toMillis(value);
+ type.writeLong(builder, micro);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromTimeStampSecVector(TimeStampSecVector vector, Type type)
+ {
+ if (!(type instanceof TimestampType)) {
+ throw new IllegalArgumentException("Type must be a TimestampType for TimeStampSecVector");
+ }
+
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ long value = vector.get(i);
+ long millis = TimeUnit.SECONDS.toMillis(value);
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildCharTypeBlockFromVarcharVector(VarCharVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ String value = new String(vector.get(i), StandardCharsets.UTF_8);
+ type.writeSlice(builder, Slices.utf8Slice(CharMatcher.is(' ').trimTrailingFrom(value)));
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildTimeTypeBlockFromVarcharVector(VarCharVector vector, Type type)
+ {
+ BlockBuilder builder = type.createBlockBuilder(null, vector.getValueCount());
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ builder.appendNull();
+ }
+ else {
+ String timeString = new String(vector.get(i), StandardCharsets.UTF_8);
+ LocalTime time = LocalTime.parse(timeString);
+ long millis = Duration.between(LocalTime.MIN, time).toMillis();
+ type.writeLong(builder, millis);
+ }
+ }
+ return builder.build();
+ }
+
+ public Block buildBlockFromListVector(ListVector vector, Type type)
+ {
+ if (!(type instanceof ArrayType)) {
+ throw new IllegalArgumentException("Type must be an ArrayType for ListVector");
+ }
+
+ ArrayType arrayType = (ArrayType) type;
+ Type elementType = arrayType.getElementType();
+ BlockBuilder arrayBuilder = type.createBlockBuilder(null, vector.getValueCount());
+
+ for (int i = 0; i < vector.getValueCount(); i++) {
+ if (vector.isNull(i)) {
+ arrayBuilder.appendNull();
+ }
+ else {
+ BlockBuilder elementBuilder = arrayBuilder.beginBlockEntry();
+ FieldVector dataVector = vector.getDataVector();
+ int startIndex = vector.getElementStartIndex(i);
+ int endIndex = vector.getElementEndIndex(i);
+ for (int j = startIndex; j < endIndex; j++) {
+ appendValueToBuilder(elementType, elementBuilder, dataVector.getObject(j));
+ }
+ arrayBuilder.closeEntry();
+ }
+ }
+ return arrayBuilder.build();
+ }
+
+ public void appendValueToBuilder(Type type, BlockBuilder builder, Object value)
+ {
+ if (value == null) {
+ builder.appendNull();
+ return;
+ }
+
+ if (type instanceof VarcharType) {
+ writeVarcharType(type, builder, value);
+ }
+ else if (type instanceof SmallintType) {
+ writeSmallintType(type, builder, value);
+ }
+ else if (type instanceof TinyintType) {
+ writeTinyintType(type, builder, value);
+ }
+ else if (type instanceof BigintType) {
+ writeBigintType(type, builder, value);
+ }
+ else if (type instanceof IntegerType) {
+ writeIntegerType(type, builder, value);
+ }
+ else if (type instanceof DoubleType) {
+ writeDoubleType(type, builder, value);
+ }
+ else if (type instanceof BooleanType) {
+ writeBooleanType(type, builder, value);
+ }
+ else if (type instanceof DecimalType) {
+ writeDecimalType((DecimalType) type, builder, value);
+ }
+ else if (type instanceof ArrayType) {
+ writeArrayType((ArrayType) type, builder, value);
+ }
+ else if (type instanceof RowType) {
+ writeRowType((RowType) type, builder, value);
+ }
+ else if (type instanceof DateType) {
+ writeDateType(type, builder, value);
+ }
+ else if (type instanceof TimestampType) {
+ writeTimestampType(type, builder, value);
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type: " + type);
+ }
+ }
+
+ public void writeVarcharType(Type type, BlockBuilder builder, Object value)
+ {
+ Slice slice = Slices.utf8Slice(value.toString());
+ type.writeSlice(builder, slice);
+ }
+
+ public void writeSmallintType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Number) {
+ type.writeLong(builder, ((Number) value).shortValue());
+ }
+ else if (value instanceof JsonStringArrayList) {
+ for (Object obj : (JsonStringArrayList) value) {
+ try {
+ short shortValue = Short.parseShort(obj.toString());
+ type.writeLong(builder, shortValue);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid number format in JsonStringArrayList for SmallintType: " + obj, e);
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for SmallintType: " + value.getClass());
+ }
+ }
+
+ public void writeTinyintType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Number) {
+ type.writeLong(builder, ((Number) value).byteValue());
+ }
+ else if (value instanceof JsonStringArrayList) {
+ for (Object obj : (JsonStringArrayList) value) {
+ try {
+ byte byteValue = Byte.parseByte(obj.toString());
+ type.writeLong(builder, byteValue);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid number format in JsonStringArrayList for TinyintType: " + obj, e);
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for TinyintType: " + value.getClass());
+ }
+ }
+
+ public void writeBigintType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Long) {
+ type.writeLong(builder, (Long) value);
+ }
+ else if (value instanceof Integer) {
+ type.writeLong(builder, ((Integer) value).longValue());
+ }
+ else if (value instanceof JsonStringArrayList) {
+ for (Object obj : (JsonStringArrayList) value) {
+ try {
+ long longValue = Long.parseLong(obj.toString());
+ type.writeLong(builder, longValue);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid number format in JsonStringArrayList: " + obj, e);
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for BigintType: " + value.getClass());
+ }
+ }
+
+ public void writeIntegerType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Integer) {
+ type.writeLong(builder, (Integer) value);
+ }
+ else if (value instanceof JsonStringArrayList) {
+ for (Object obj : (JsonStringArrayList) value) {
+ try {
+ int intValue = Integer.parseInt(obj.toString());
+ type.writeLong(builder, intValue);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid number format in JsonStringArrayList: " + obj, e);
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for IntegerType: " + value.getClass());
+ }
+ }
+
+ public void writeDoubleType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Double) {
+ type.writeDouble(builder, (Double) value);
+ }
+ else if (value instanceof Float) {
+ type.writeDouble(builder, ((Float) value).doubleValue());
+ }
+ else if (value instanceof JsonStringArrayList) {
+ for (Object obj : (JsonStringArrayList) value) {
+ try {
+ double doubleValue = Double.parseDouble(obj.toString());
+ type.writeDouble(builder, doubleValue);
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid number format in JsonStringArrayList: " + obj, e);
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for DoubleType: " + value.getClass());
+ }
+ }
+
+ public void writeBooleanType(Type type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof Boolean) {
+ type.writeBoolean(builder, (Boolean) value);
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for BooleanType: " + value.getClass());
+ }
+ }
+
+ public void writeDecimalType(DecimalType type, BlockBuilder builder, Object value)
+ {
+ if (value instanceof BigDecimal) {
+ BigDecimal decimalValue = (BigDecimal) value;
+ if (type.isShort()) {
+ // write ShortDecimalType
+ long unscaledValue = decimalValue.unscaledValue().longValue();
+ type.writeLong(builder, unscaledValue);
+ }
+ else {
+ // write LongDecimalType
+ Slice slice = Decimals.encodeScaledValue(decimalValue);
+ type.writeSlice(builder, slice);
+ }
+ }
+ else if (value instanceof Long) {
+ // Direct handling for ShortDecimalType using long
+ if (type.isShort()) {
+ type.writeLong(builder, (Long) value);
+ }
+ else {
+ throw new IllegalArgumentException("Long value is not supported for LongDecimalType.");
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported type for DecimalType: " + value.getClass());
+ }
+ }
+
+ public void writeArrayType(ArrayType type, BlockBuilder builder, Object value)
+ {
+ Type elementType = type.getElementType();
+ BlockBuilder arrayBuilder = builder.beginBlockEntry();
+ for (Object element : (Iterable>) value) {
+ appendValueToBuilder(elementType, arrayBuilder, element);
+ }
+ builder.closeEntry();
+ }
+
+ public void writeRowType(RowType type, BlockBuilder builder, Object value)
+ {
+ List