This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 0e4fa8af7b GH-37021 [Java][arrow-jdbc] Pluggable getConsumer (#37085)
0e4fa8af7b is described below
commit 0e4fa8af7b72493ffe05388a7f3fed0d4181e7b2
Author: Diego Fernández Giraldo <[email protected]>
AuthorDate: Thu Aug 10 17:43:45 2023 -0400
GH-37021 [Java][arrow-jdbc] Pluggable getConsumer (#37085)
### Rationale for this change
This was discussed in [this
thread](https://github.com/apache/arrow/issues/37021#issuecomment-1666169351).
The `getConsumer` implementation depends on the implementation for
`getArrowTypeFromJdbcType`, especially for timestamp objects. Since we can
provide a different implementation for `JdbcToArrowTypeConverter` it follows we
should be able to provide a different implementation for `JdbcConsumerGetter`
### What changes are included in this PR?
Adds a way to configure an alternate `JdbcToArrowUtils.getConsumer`
function through `JdbcToArrowConfigBuilder.setJdbcConsumerGetter`.
It also throws a more helpful exception from the default implementations
when a provided type is not mapped.
### Are these changes tested?
No, the default behavior remains unchanged.
* Related: #37021
* Closes: #37021
Authored-by: Diego Fernandez <[email protected]>
Signed-off-by: David Li <[email protected]>
---
.../arrow/adapter/jdbc/ArrowVectorIterator.java | 2 +-
.../arrow/adapter/jdbc/JdbcToArrowConfig.java | 53 ++++++++++++++++++++++
.../adapter/jdbc/JdbcToArrowConfigBuilder.java | 15 ++++++
.../arrow/adapter/jdbc/JdbcToArrowUtils.java | 4 +-
.../arrow/flight/sql/example/FlightSqlExample.java | 9 ++--
5 files changed, 77 insertions(+), 6 deletions(-)
diff --git
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/ArrowVectorIterator.java
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/ArrowVectorIterator.java
index 6c3e9cf43e..6e789009dd 100644
---
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/ArrowVectorIterator.java
+++
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/ArrowVectorIterator.java
@@ -139,7 +139,7 @@ public class ArrowVectorIterator implements
Iterator<VectorSchemaRoot>, AutoClos
for (int i = 1; i <= consumers.length; i++) {
final JdbcFieldInfo columnFieldInfo =
JdbcToArrowUtils.getJdbcFieldInfoForColumn(rsmd, i, config);
ArrowType arrowType =
config.getJdbcToArrowTypeConverter().apply(columnFieldInfo);
- consumers[i - 1] = JdbcToArrowUtils.getConsumer(
+ consumers[i - 1] = config.getJdbcConsumerGetter().apply(
arrowType, i, isColumnNullable(resultSet.getMetaData(), i,
columnFieldInfo), root.getVector(i - 1), config);
}
}
diff --git
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfig.java
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfig.java
index 012cd95c0b..e23bad54af 100644
---
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfig.java
+++
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfig.java
@@ -22,8 +22,10 @@ import java.util.Calendar;
import java.util.Map;
import java.util.function.Function;
+import org.apache.arrow.adapter.jdbc.consumer.JdbcConsumer;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.util.Preconditions;
+import org.apache.arrow.vector.FieldVector;
import org.apache.arrow.vector.types.pojo.ArrowType;
/**
@@ -76,6 +78,7 @@ public final class JdbcToArrowConfig {
private final int targetBatchSize;
private final Function<JdbcFieldInfo, ArrowType> jdbcToArrowTypeConverter;
+ private final JdbcConsumerFactory jdbcConsumerGetter;
/**
* Constructs a new configuration from the provided allocator and calendar.
The <code>allocator</code>
@@ -195,6 +198,38 @@ public final class JdbcToArrowConfig {
Map<String, String> schemaMetadata,
Map<Integer, Map<String, String>> columnMetadataByColumnIndex,
RoundingMode bigDecimalRoundingMode) {
+ this(
+ allocator,
+ calendar,
+ includeMetadata,
+ reuseVectorSchemaRoot,
+ arraySubTypesByColumnIndex,
+ arraySubTypesByColumnName,
+ targetBatchSize,
+ jdbcToArrowTypeConverter,
+ null,
+ explicitTypesByColumnIndex,
+ explicitTypesByColumnName,
+ schemaMetadata,
+ columnMetadataByColumnIndex,
+ bigDecimalRoundingMode);
+ }
+
+ JdbcToArrowConfig(
+ BufferAllocator allocator,
+ Calendar calendar,
+ boolean includeMetadata,
+ boolean reuseVectorSchemaRoot,
+ Map<Integer, JdbcFieldInfo> arraySubTypesByColumnIndex,
+ Map<String, JdbcFieldInfo> arraySubTypesByColumnName,
+ int targetBatchSize,
+ Function<JdbcFieldInfo, ArrowType> jdbcToArrowTypeConverter,
+ JdbcConsumerFactory jdbcConsumerGetter,
+ Map<Integer, JdbcFieldInfo> explicitTypesByColumnIndex,
+ Map<String, JdbcFieldInfo> explicitTypesByColumnName,
+ Map<String, String> schemaMetadata,
+ Map<Integer, Map<String, String>> columnMetadataByColumnIndex,
+ RoundingMode bigDecimalRoundingMode) {
Preconditions.checkNotNull(allocator, "Memory allocator cannot be null");
this.allocator = allocator;
this.calendar = calendar;
@@ -212,6 +247,8 @@ public final class JdbcToArrowConfig {
// set up type converter
this.jdbcToArrowTypeConverter = jdbcToArrowTypeConverter != null ?
jdbcToArrowTypeConverter :
(jdbcFieldInfo) ->
JdbcToArrowUtils.getArrowTypeFromJdbcType(jdbcFieldInfo, calendar);
+
+ this.jdbcConsumerGetter = jdbcConsumerGetter != null ? jdbcConsumerGetter
: JdbcToArrowUtils::getConsumer;
}
/**
@@ -264,6 +301,13 @@ public final class JdbcToArrowConfig {
return jdbcToArrowTypeConverter;
}
+ /**
+ * Gets the JDBC consumer getter.
+ */
+ public JdbcConsumerFactory getJdbcConsumerGetter() {
+ return jdbcConsumerGetter;
+ }
+
/**
* Returns the array sub-type {@link JdbcFieldInfo} defined for the provided
column index.
*
@@ -338,4 +382,13 @@ public final class JdbcToArrowConfig {
public RoundingMode getBigDecimalRoundingMode() {
return bigDecimalRoundingMode;
}
+
+ /**
+ * Interface for a function that gets a JDBC consumer for the given values.
+ */
+ @FunctionalInterface
+ public interface JdbcConsumerFactory {
+ JdbcConsumer apply(ArrowType arrowType, int columnIndex, boolean nullable,
FieldVector vector,
+ JdbcToArrowConfig config);
+ }
}
diff --git
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigBuilder.java
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigBuilder.java
index 2fe0492deb..7d88c23832 100644
---
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigBuilder.java
+++
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigBuilder.java
@@ -26,6 +26,7 @@ import java.util.function.Function;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.util.Preconditions;
+import org.apache.arrow.vector.FieldVector;
import org.apache.arrow.vector.types.pojo.ArrowType;
/**
@@ -44,6 +45,7 @@ public class JdbcToArrowConfigBuilder {
private Map<Integer, Map<String, String>> columnMetadataByColumnIndex;
private int targetBatchSize;
private Function<JdbcFieldInfo, ArrowType> jdbcToArrowTypeConverter;
+ private JdbcToArrowConfig.JdbcConsumerFactory jdbcConsumerGetter;
private RoundingMode bigDecimalRoundingMode;
/**
@@ -221,6 +223,18 @@ public class JdbcToArrowConfigBuilder {
return this;
}
+ /**
+ * Set the function used to get a JDBC consumer for a given type.
+ * <p>
+ * Defaults to wrapping {@link
+ * JdbcToArrowUtils#getConsumer(ArrowType, Integer, Boolean, FieldVector,
JdbcToArrowConfig)}.
+ */
+ public JdbcToArrowConfigBuilder setJdbcConsumerGetter(
+ JdbcToArrowConfig.JdbcConsumerFactory jdbcConsumerGetter) {
+ this.jdbcConsumerGetter = jdbcConsumerGetter;
+ return this;
+ }
+
/**
* Set whether to use the same {@link
org.apache.arrow.vector.VectorSchemaRoot} instance on each iteration,
* or to allocate a new one.
@@ -274,6 +288,7 @@ public class JdbcToArrowConfigBuilder {
arraySubTypesByColumnName,
targetBatchSize,
jdbcToArrowTypeConverter,
+ jdbcConsumerGetter,
explicitTypesByColumnIndex,
explicitTypesByColumnName,
schemaMetadata,
diff --git
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowUtils.java
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowUtils.java
index dc79f6efff..f8a13b93b1 100644
---
a/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowUtils.java
+++
b/java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowUtils.java
@@ -208,7 +208,7 @@ public class JdbcToArrowUtils {
return new ArrowType.Struct();
default:
// no-op, shouldn't get here
- return null;
+ throw new UnsupportedOperationException("Unmapped JDBC type: " +
fieldInfo.getJdbcType());
}
}
@@ -489,7 +489,7 @@ public class JdbcToArrowUtils {
return new NullConsumer((NullVector) vector);
default:
// no-op, shouldn't get here
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("No consumer for Arrow type: "
+ arrowType);
}
}
}
diff --git
a/java/flight/flight-sql/src/test/java/org/apache/arrow/flight/sql/example/FlightSqlExample.java
b/java/flight/flight-sql/src/test/java/org/apache/arrow/flight/sql/example/FlightSqlExample.java
index fe1e1445af..3cc8f4a1c1 100644
---
a/java/flight/flight-sql/src/test/java/org/apache/arrow/flight/sql/example/FlightSqlExample.java
+++
b/java/flight/flight-sql/src/test/java/org/apache/arrow/flight/sql/example/FlightSqlExample.java
@@ -299,9 +299,12 @@ public class FlightSqlExample implements
FlightSqlProducer, AutoCloseable {
}
private static ArrowType getArrowTypeFromJdbcType(final int jdbcDataType,
final int precision, final int scale) {
- final ArrowType type =
- JdbcToArrowUtils.getArrowTypeFromJdbcType(new
JdbcFieldInfo(jdbcDataType, precision, scale), DEFAULT_CALENDAR);
- return isNull(type) ? ArrowType.Utf8.INSTANCE : type;
+ try {
+ return JdbcToArrowUtils.getArrowTypeFromJdbcType(new
JdbcFieldInfo(jdbcDataType, precision, scale),
+ DEFAULT_CALENDAR);
+ } catch (UnsupportedOperationException ignored) {
+ return ArrowType.Utf8.INSTANCE;
+ }
}
private static void saveToVector(final Byte data, final UInt1Vector vector,
final int index) {