From 64c312db55340dec4d57f3c1fb4ad2db90aeb3f2 Mon Sep 17 00:00:00 2001
From: David Li
Date: Sat, 27 Jan 2024 14:52:41 -0500
Subject: [PATCH] test(java): add Checker Framework
Fixes #624.
---
.pre-commit-config.yaml | 2 +-
....arrow.adapter.jdbc.JdbcToArrowUtils.astub | 28 ++++++
...he.arrow.vector.types.pojo.ArrowType.astub | 31 ++++++
.../org.junit.jupiter.api.Assumptions.astub | 29 ++++++
java/core/pom.xml | 6 ++
.../arrow/adbc/core/AdbcConnection.java | 3 +-
.../apache/arrow/adbc/core/AdbcDriver.java | 1 +
.../apache/arrow/adbc/core/AdbcException.java | 17 ++--
.../apache/arrow/adbc/core/ErrorDetail.java | 3 +-
.../arrow/adbc/core/PartitionDescriptor.java | 3 +-
.../arrow/adbc/core/StandardSchemas.java | 96 ++++++++++++++-----
.../org/apache/arrow/adbc/core/TypedKey.java | 10 +-
java/driver-manager/pom.xml | 6 ++
.../adbc/drivermanager/AdbcDriverManager.java | 14 ++-
.../driver/flightsql/FlightSqlQuirks.java | 4 +-
java/driver/flight-sql/pom.xml | 6 ++
.../driver/flightsql/FlightInfoReader.java | 12 ++-
.../driver/flightsql/FlightSqlConnection.java | 5 +-
.../driver/flightsql/FlightSqlDriverUtil.java | 7 +-
.../driver/flightsql/FlightSqlStatement.java | 59 +++++++-----
.../driver/flightsql/InfoMetadataBuilder.java | 8 +-
java/driver/jdbc/pom.xml | 6 ++
.../arrow/adbc/driver/jdbc/JdbcDriver.java | 2 +
.../adbc/driver/jdbc/JdbcDriverUtil.java | 3 +-
.../arrow/adbc/driver/jdbc/JdbcStatement.java | 2 +-
.../adbc/driver/jdbc/StandardJdbcQuirks.java | 46 +--------
.../arrow/adbc/driver/jdbc/UrlDataSource.java | 7 +-
.../adapter/JdbcToArrowTypeConverters.java | 5 +-
.../AbstractConnectionMetadataTest.java | 3 +-
.../testsuite/AbstractTransactionTest.java | 12 +--
.../adbc/driver/testsuite/SqlTestUtil.java | 6 +-
java/pom.xml | 32 ++++++-
java/sql/pom.xml | 6 ++
.../org/apache/arrow/adbc/sql/SqlQuirks.java | 79 +++++++--------
34 files changed, 380 insertions(+), 179 deletions(-)
create mode 100644 java/.checker-framework/org.apache.arrow.adapter.jdbc.JdbcToArrowUtils.astub
create mode 100644 java/.checker-framework/org.apache.arrow.vector.types.pojo.ArrowType.astub
create mode 100644 java/.checker-framework/org.junit.jupiter.api.Assumptions.astub
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 480ca074f5..fb3a19cdae 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -65,7 +65,7 @@ repos:
entry: bash -c 'cd go/adbc && golangci-lint run --fix --timeout 5m'
types_or: [go]
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
- rev: v2.3.0
+ rev: v2.12.0
hooks:
- id: pretty-format-golang
- id: pretty-format-java
diff --git a/java/.checker-framework/org.apache.arrow.adapter.jdbc.JdbcToArrowUtils.astub b/java/.checker-framework/org.apache.arrow.adapter.jdbc.JdbcToArrowUtils.astub
new file mode 100644
index 0000000000..0ee9d0ebf7
--- /dev/null
+++ b/java/.checker-framework/org.apache.arrow.adapter.jdbc.JdbcToArrowUtils.astub
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.arrow.adapter.jdbc;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.Calendar;
+
+import org.apache.arrow.vector.types.pojo.ArrowType;
+
+public class JdbcToArrowUtils {
+ public static ArrowType getArrowTypeFromJdbcType(JdbcFieldInfo fieldInfo, @Nullable Calendar calendar);
+}
diff --git a/java/.checker-framework/org.apache.arrow.vector.types.pojo.ArrowType.astub b/java/.checker-framework/org.apache.arrow.vector.types.pojo.ArrowType.astub
new file mode 100644
index 0000000000..8827b847af
--- /dev/null
+++ b/java/.checker-framework/org.apache.arrow.vector.types.pojo.ArrowType.astub
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.arrow.vector.types.pojo;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import org.apache.arrow.vector.types.TimeUnit;
+
+public abstract class ArrowType {
+ public abstract static class PrimitiveType extends ArrowType {
+ }
+
+ public static class Timestamp extends PrimitiveType {
+ public Timestamp(TimeUnit unit, @Nullable String timezone);
+ }
+}
diff --git a/java/.checker-framework/org.junit.jupiter.api.Assumptions.astub b/java/.checker-framework/org.junit.jupiter.api.Assumptions.astub
new file mode 100644
index 0000000000..46ee85fb35
--- /dev/null
+++ b/java/.checker-framework/org.junit.jupiter.api.Assumptions.astub
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.junit.jupiter.api;
+
+import org.checkerframework.dataflow.qual.AssertMethod;
+import org.opentest4j.TestAbortedException;
+
+public class Assumptions {
+ @AssertMethod(value = TestAbortedException.class)
+ public static void assumeTrue(boolean assumption, String message) throws TestAbortedException;
+
+ @AssertMethod(isAssertFalse = true, value = TestAbortedException.class)
+ public static void assumeFalse(boolean assumption, String message) throws TestAbortedException;
+}
diff --git a/java/core/pom.xml b/java/core/pom.xml
index ac499b9a25..f61c686896 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -33,6 +33,12 @@
arrow-vector
+
+
+ org.checkerframework
+ checker-qual
+
+
org.assertj
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
index c8e897eeee..060c65e816 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
@@ -20,6 +20,7 @@
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.ipc.ArrowReader;
import org.apache.arrow.vector.types.pojo.Schema;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A connection to a {@link AdbcDatabase}.
@@ -79,7 +80,7 @@ default ArrowReader readPartition(ByteBuffer descriptor) throws AdbcException {
*
* @param infoCodes The metadata items to fetch.
*/
- ArrowReader getInfo(int[] infoCodes) throws AdbcException;
+ ArrowReader getInfo(int @Nullable [] infoCodes) throws AdbcException;
/**
* Get metadata about the driver/database.
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java
index 5e32fd1ed7..797b863586 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java
@@ -54,6 +54,7 @@ public interface AdbcDriver {
/** ADBC API revision 1.0.0. */
long ADBC_VERSION_1_0_0 = 1_000_000;
+
/** ADBC API revision 1.1.0. */
long ADBC_VERSION_1_1_0 = 1_001_000;
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java
index dce7570e3d..193bbaa96c 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcException.java
@@ -18,6 +18,7 @@
import java.util.Collection;
import java.util.Collections;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* An error in the database or ADBC driver.
@@ -34,20 +35,24 @@
*/
public class AdbcException extends Exception {
private final AdbcStatusCode status;
- private final String sqlState;
+ private final @Nullable String sqlState;
private final int vendorCode;
private Collection details;
public AdbcException(
- String message, Throwable cause, AdbcStatusCode status, String sqlState, int vendorCode) {
+ @Nullable String message,
+ @Nullable Throwable cause,
+ AdbcStatusCode status,
+ @Nullable String sqlState,
+ int vendorCode) {
this(message, cause, status, sqlState, vendorCode, Collections.emptyList());
}
public AdbcException(
- String message,
- Throwable cause,
+ @Nullable String message,
+ @Nullable Throwable cause,
AdbcStatusCode status,
- String sqlState,
+ @Nullable String sqlState,
int vendorCode,
Collection details) {
super(message, cause);
@@ -83,7 +88,7 @@ public AdbcStatusCode getStatus() {
}
/** A SQLSTATE error code, if provided, as defined by the SQL:2003 standard. */
- public String getSqlState() {
+ public @Nullable String getSqlState() {
return sqlState;
}
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/ErrorDetail.java b/java/core/src/main/java/org/apache/arrow/adbc/core/ErrorDetail.java
index 13521fb82e..5149b9de77 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/ErrorDetail.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/ErrorDetail.java
@@ -17,6 +17,7 @@
package org.apache.arrow.adbc.core;
import java.util.Objects;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Additional details (not necessarily human-readable) contained in an {@link AdbcException}. */
public class ErrorDetail {
@@ -37,7 +38,7 @@ public Object getValue() {
}
@Override
- public boolean equals(Object o) {
+ public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/PartitionDescriptor.java b/java/core/src/main/java/org/apache/arrow/adbc/core/PartitionDescriptor.java
index 3f2047801c..5890db9047 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/PartitionDescriptor.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/PartitionDescriptor.java
@@ -18,6 +18,7 @@
import java.nio.ByteBuffer;
import java.util.Objects;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** An opaque descriptor for a part of a potentially distributed or partitioned result set. */
public final class PartitionDescriptor {
@@ -32,7 +33,7 @@ public ByteBuffer getDescriptor() {
}
@Override
- public boolean equals(Object o) {
+ public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/StandardSchemas.java b/java/core/src/main/java/org/apache/arrow/adbc/core/StandardSchemas.java
index c059bb1b57..31f8ddb97b 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/StandardSchemas.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/StandardSchemas.java
@@ -98,30 +98,64 @@ private StandardSchemas() {
public static final List COLUMN_SCHEMA =
Arrays.asList(
- new Field("column_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
- new Field("ordinal_position", FieldType.nullable(INT32), null),
- new Field("remarks", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_data_type", FieldType.nullable(INT16), null),
- new Field("xdbc_type_name", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_column_size", FieldType.nullable(INT32), null),
- new Field("xdbc_decimal_digits", FieldType.nullable(INT16), null),
- new Field("xdbc_num_prec_radix", FieldType.nullable(INT16), null),
- new Field("xdbc_nullable", FieldType.nullable(INT16), null),
- new Field("xdbc_column_def", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_sql_data_type", FieldType.nullable(INT16), null),
- new Field("xdbc_datetime_sub", FieldType.nullable(INT16), null),
- new Field("xdbc_char_octet_length", FieldType.nullable(INT32), null),
- new Field("xdbc_is_nullable", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_scope_catalog", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_scope_schema", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_scope_table", FieldType.nullable(ArrowType.Utf8.INSTANCE), null),
- new Field("xdbc_is_autoincrement", FieldType.nullable(ArrowType.Bool.INSTANCE), null),
- new Field("xdbc_is_generatedcolumn", FieldType.nullable(ArrowType.Bool.INSTANCE), null));
+ new Field(
+ "column_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field("ordinal_position", FieldType.nullable(INT32), Collections.emptyList()),
+ new Field(
+ "remarks", FieldType.nullable(ArrowType.Utf8.INSTANCE), Collections.emptyList()),
+ new Field("xdbc_data_type", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field(
+ "xdbc_type_name",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field("xdbc_column_size", FieldType.nullable(INT32), Collections.emptyList()),
+ new Field("xdbc_decimal_digits", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field("xdbc_num_prec_radix", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field("xdbc_nullable", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field(
+ "xdbc_column_def",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field("xdbc_sql_data_type", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field("xdbc_datetime_sub", FieldType.nullable(INT16), Collections.emptyList()),
+ new Field("xdbc_char_octet_length", FieldType.nullable(INT32), Collections.emptyList()),
+ new Field(
+ "xdbc_is_nullable",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "xdbc_scope_catalog",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "xdbc_scope_schema",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "xdbc_scope_table",
+ FieldType.nullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "xdbc_is_autoincrement",
+ FieldType.nullable(ArrowType.Bool.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "xdbc_is_generatedcolumn",
+ FieldType.nullable(ArrowType.Bool.INSTANCE),
+ Collections.emptyList()));
public static final List TABLE_SCHEMA =
Arrays.asList(
- new Field("table_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
- new Field("table_type", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
+ new Field(
+ "table_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
+ new Field(
+ "table_type",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
new Field(
"table_columns",
FieldType.nullable(ArrowType.List.INSTANCE),
@@ -136,7 +170,10 @@ private StandardSchemas() {
public static final List DB_SCHEMA_SCHEMA =
Arrays.asList(
- new Field("db_schema_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
+ new Field(
+ "db_schema_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
new Field(
"db_schema_tables",
FieldType.nullable(ArrowType.List.INSTANCE),
@@ -150,7 +187,10 @@ private StandardSchemas() {
public static final Schema GET_OBJECTS_SCHEMA =
new Schema(
Arrays.asList(
- new Field("catalog_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
+ new Field(
+ "catalog_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
new Field(
"catalog_db_schemas",
FieldType.nullable(ArrowType.List.INSTANCE),
@@ -180,7 +220,10 @@ private StandardSchemas() {
public static final List STATISTICS_DB_SCHEMA_SCHEMA =
Arrays.asList(
- new Field("db_schema_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
+ new Field(
+ "db_schema_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
new Field(
"db_schema_statistics",
FieldType.notNullable(ArrowType.List.INSTANCE),
@@ -195,7 +238,10 @@ private StandardSchemas() {
public static final Schema GET_STATISTICS_SCHEMA =
new Schema(
Arrays.asList(
- new Field("catalog_name", FieldType.notNullable(ArrowType.Utf8.INSTANCE), null),
+ new Field(
+ "catalog_name",
+ FieldType.notNullable(ArrowType.Utf8.INSTANCE),
+ Collections.emptyList()),
new Field(
"catalog_db_schemas",
FieldType.notNullable(ArrowType.List.INSTANCE),
diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java b/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
index 21523bb429..1f1dda2f4b 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/TypedKey.java
@@ -19,6 +19,8 @@
import java.util.Map;
import java.util.Objects;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A typesafe option key.
@@ -45,8 +47,8 @@ public String getKey() {
*
* @throws ClassCastException if the value is of the wrong type.
*/
- public T get(Map options) {
- Object value = options.get(key);
+ public @Nullable T get(Map options) {
+ @Nullable Object value = options.get(key);
if (value == null) {
return null;
}
@@ -59,12 +61,12 @@ public T get(Map options) {
* @param options The options.
* @param value The option value.
*/
- public void set(Map options, T value) {
+ public void set(Map options, @NonNull T value) {
options.put(key, value);
}
@Override
- public boolean equals(Object o) {
+ public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
diff --git a/java/driver-manager/pom.xml b/java/driver-manager/pom.xml
index 79ad55b992..ce9464a087 100644
--- a/java/driver-manager/pom.xml
+++ b/java/driver-manager/pom.xml
@@ -28,6 +28,12 @@
adbc-core
+
+
+ org.checkerframework
+ checker-qual
+
+
org.assertj
diff --git a/java/driver-manager/src/main/java/org/apache/arrow/adbc/drivermanager/AdbcDriverManager.java b/java/driver-manager/src/main/java/org/apache/arrow/adbc/drivermanager/AdbcDriverManager.java
index c2e20efd02..5068fb9a1f 100644
--- a/java/driver-manager/src/main/java/org/apache/arrow/adbc/drivermanager/AdbcDriverManager.java
+++ b/java/driver-manager/src/main/java/org/apache/arrow/adbc/drivermanager/AdbcDriverManager.java
@@ -27,6 +27,7 @@
import org.apache.arrow.adbc.core.AdbcException;
import org.apache.arrow.adbc.core.AdbcStatusCode;
import org.apache.arrow.memory.BufferAllocator;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Instantiate connections to ABDC databases generically based on driver name. */
public final class AdbcDriverManager {
@@ -38,10 +39,13 @@ private AdbcDriverManager() {
driverFactoryFunctions = new ConcurrentHashMap<>();
final ServiceLoader serviceLoader =
ServiceLoader.load(AdbcDriverFactory.class);
- serviceLoader.forEach(
- driverFactory ->
- driverFactoryFunctions.putIfAbsent(
- driverFactory.getClass().getCanonicalName(), driverFactory::getDriver));
+ for (AdbcDriverFactory driverFactory : serviceLoader) {
+ final @Nullable String className = driverFactory.getClass().getCanonicalName();
+ if (className == null) {
+ throw new RuntimeException("Class has no canonical name");
+ }
+ driverFactoryFunctions.putIfAbsent(className, driverFactory::getDriver);
+ }
}
/**
@@ -77,7 +81,7 @@ public AdbcDatabase connect(
* fully-qualified class name of an AdbcDriverFactory class.
* @return A function to construct an AdbcDriver from a BufferAllocator, or null if not found.
*/
- Function lookupDriver(String driverFactoryName) {
+ @Nullable Function lookupDriver(String driverFactoryName) {
return driverFactoryFunctions.get(driverFactoryName);
}
diff --git a/java/driver/flight-sql-validation/src/test/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlQuirks.java b/java/driver/flight-sql-validation/src/test/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlQuirks.java
index d3f79889ec..fe01a18cd6 100644
--- a/java/driver/flight-sql-validation/src/test/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlQuirks.java
+++ b/java/driver/flight-sql-validation/src/test/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlQuirks.java
@@ -36,8 +36,8 @@ public class FlightSqlQuirks extends SqlValidationQuirks {
static String getFlightLocation() {
final String location = System.getenv(FLIGHT_SQL_LOCATION_ENV_VAR);
- Assumptions.assumeFalse(
- location == null || location.isEmpty(),
+ Assumptions.assumeTrue(
+ location != null && !location.isEmpty(),
"Flight SQL server not found, set " + FLIGHT_SQL_LOCATION_ENV_VAR);
return location;
}
diff --git a/java/driver/flight-sql/pom.xml b/java/driver/flight-sql/pom.xml
index 26dd8a7262..040a9a3ba7 100644
--- a/java/driver/flight-sql/pom.xml
+++ b/java/driver/flight-sql/pom.xml
@@ -67,6 +67,12 @@
adbc-sql
+
+
+ org.checkerframework
+ checker-qual
+
+
org.assertj
diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightInfoReader.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightInfoReader.java
index 9b0cda91dc..5b73c80dd0 100644
--- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightInfoReader.java
+++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightInfoReader.java
@@ -36,6 +36,7 @@
import org.apache.arrow.vector.ipc.ArrowReader;
import org.apache.arrow.vector.ipc.message.ArrowRecordBatch;
import org.apache.arrow.vector.types.pojo.Schema;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** An ArrowReader that wraps a FlightInfo. */
public class FlightInfoReader extends ArrowReader {
@@ -47,6 +48,8 @@ public class FlightInfoReader extends ArrowReader {
private FlightStream currentStream;
private long bytesRead;
+ @SuppressWarnings(
+ "method.invocation") // Checker Framework does not like the ensureInitialized call
FlightInfoReader(
BufferAllocator allocator,
FlightSqlClient client,
@@ -120,8 +123,12 @@ private FlightStream tryLoadNextStream(FlightEndpoint endpoint) throws IOExcepti
Collections.shuffle(locations);
IOException failure = null;
for (final Location location : locations) {
+ final @Nullable FlightClient client = clientCache.get(location);
+ if (client == null) {
+ throw new IllegalStateException("Could not connect to " + location);
+ }
try {
- return Objects.requireNonNull(clientCache.get(location)).getStream(endpoint.getTicket());
+ return client.getStream(endpoint.getTicket());
} catch (RuntimeException e) {
// Also handles CompletionException (from clientCache#get), FlightRuntimeException
if (failure == null) {
@@ -133,6 +140,9 @@ private FlightStream tryLoadNextStream(FlightEndpoint endpoint) throws IOExcepti
}
}
}
+ if (failure == null) {
+ throw new IllegalStateException("FlightEndpoint had no locations");
+ }
throw Objects.requireNonNull(failure);
}
}
diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java
index f583f2b866..b9dd29be0e 100644
--- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java
+++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlConnection.java
@@ -39,6 +39,7 @@
import org.apache.arrow.util.AutoCloseables;
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.ipc.ArrowReader;
+import org.checkerframework.checker.nullness.qual.Nullable;
public class FlightSqlConnection implements AdbcConnection {
private final BufferAllocator allocator;
@@ -54,7 +55,7 @@ public class FlightSqlConnection implements AdbcConnection {
Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.removalListener(
- (Location key, FlightClient value, RemovalCause cause) -> {
+ (@Nullable Location key, @Nullable FlightClient value, RemovalCause cause) -> {
if (value == null) return;
try {
value.close();
@@ -108,7 +109,7 @@ public AdbcStatement bulkIngest(String targetTableName, BulkIngestMode mode)
}
@Override
- public ArrowReader getInfo(int[] infoCodes) throws AdbcException {
+ public ArrowReader getInfo(int @Nullable [] infoCodes) throws AdbcException {
try (InfoMetadataBuilder builder = new InfoMetadataBuilder(allocator, client, infoCodes)) {
try (final VectorSchemaRoot root = builder.build()) {
return RootArrowReader.fromRoot(allocator, root);
diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDriverUtil.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDriverUtil.java
index 45b42df2ee..0e9291ae34 100644
--- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDriverUtil.java
+++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlDriverUtil.java
@@ -24,13 +24,18 @@
import org.apache.arrow.adbc.core.ErrorDetail;
import org.apache.arrow.flight.FlightRuntimeException;
import org.apache.arrow.flight.FlightStatusCode;
+import org.checkerframework.checker.nullness.qual.Nullable;
final class FlightSqlDriverUtil {
private FlightSqlDriverUtil() {
throw new AssertionError("Do not instantiate this class");
}
- static String prefixExceptionMessage(final String s) {
+ static String prefixExceptionMessage(final @Nullable String s) {
+ // Allow null since Throwable#getMessage may be null
+ if (s == null) {
+ return "[Flight SQL] (No or unknown error)";
+ }
return "[Flight SQL] " + s;
}
diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java
index e64508b4bf..30ef03c09a 100644
--- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java
+++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/FlightSqlStatement.java
@@ -41,6 +41,7 @@
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.types.pojo.Field;
import org.apache.arrow.vector.types.pojo.Schema;
+import org.checkerframework.checker.nullness.qual.Nullable;
public class FlightSqlStatement implements AdbcStatement {
private final BufferAllocator allocator;
@@ -49,11 +50,11 @@ public class FlightSqlStatement implements AdbcStatement {
private final SqlQuirks quirks;
// State for SQL queries
- private String sqlQuery;
- private FlightSqlClient.PreparedStatement preparedStatement;
+ private @Nullable String sqlQuery;
+ private FlightSqlClient.@Nullable PreparedStatement preparedStatement;
// State for bulk ingest
- private BulkState bulkOperation;
- private VectorSchemaRoot bindRoot;
+ private @Nullable BulkState bulkOperation;
+ private @Nullable VectorSchemaRoot bindRoot;
FlightSqlStatement(
BufferAllocator allocator,
@@ -65,6 +66,9 @@ public class FlightSqlStatement implements AdbcStatement {
this.clientCache = clientCache;
this.quirks = quirks;
this.sqlQuery = null;
+ this.preparedStatement = null;
+ this.bulkOperation = null;
+ this.bindRoot = null;
}
static FlightSqlStatement ingestRoot(
@@ -77,9 +81,7 @@ static FlightSqlStatement ingestRoot(
Objects.requireNonNull(targetTableName);
final FlightSqlStatement statement =
new FlightSqlStatement(allocator, client, clientCache, quirks);
- statement.bulkOperation = new BulkState();
- statement.bulkOperation.mode = mode;
- statement.bulkOperation.targetTable = targetTableName;
+ statement.bulkOperation = new BulkState(mode, targetTableName);
return statement;
}
@@ -97,7 +99,8 @@ public void bind(VectorSchemaRoot root) {
bindRoot = root;
}
- private void createBulkTable() throws AdbcException {
+ private void createBulkTable(BulkState bulkOperation, VectorSchemaRoot bindRoot)
+ throws AdbcException {
final StringBuilder create = new StringBuilder("CREATE TABLE ");
create.append(bulkOperation.targetTable);
create.append(" (");
@@ -129,20 +132,21 @@ private void createBulkTable() throws AdbcException {
}
}
- private UpdateResult executeBulk() throws AdbcException {
+ private UpdateResult executeBulk(BulkState bulkOperation) throws AdbcException {
if (bindRoot == null) {
throw AdbcException.invalidState("[Flight SQL] Must call bind() before bulk insert");
}
+ final VectorSchemaRoot bindParams = bindRoot;
if (bulkOperation.mode == BulkIngestMode.CREATE) {
- createBulkTable();
+ createBulkTable(bulkOperation, bindParams);
}
// XXX: potential injection
final StringBuilder insert = new StringBuilder("INSERT INTO ");
insert.append(bulkOperation.targetTable);
insert.append(" VALUES (");
- for (int col = 0; col < bindRoot.getFieldVectors().size(); col++) {
+ for (int col = 0; col < bindParams.getFieldVectors().size(); col++) {
if (col > 0) {
insert.append(", ");
}
@@ -164,7 +168,7 @@ private UpdateResult executeBulk() throws AdbcException {
}
try {
try {
- statement.setParameters(new NonOwningRoot(bindRoot));
+ statement.setParameters(new NonOwningRoot(bindParams));
statement.executeUpdate();
} finally {
statement.close();
@@ -178,7 +182,7 @@ private UpdateResult executeBulk() throws AdbcException {
}
throw FlightSqlDriverUtil.fromFlightException(e);
}
- return new UpdateResult(bindRoot.getRowCount());
+ return new UpdateResult(bindParams.getRowCount());
}
@FunctionalInterface
@@ -192,13 +196,14 @@ private R execute(
throws AdbcException {
try {
if (preparedStatement != null) {
+ FlightSqlClient.PreparedStatement prepared = preparedStatement;
// TODO: This binds only the LAST row
// See https://lists.apache.org/thread/47zfk3xooojckvfjq2h6ldlqkjrqnsjt
// "[DISC] Flight SQL: clarifying prepared statements with parameters and result sets"
if (bindRoot != null) {
- preparedStatement.setParameters(new NonOwningRoot(bindRoot));
+ prepared.setParameters(new NonOwningRoot(bindRoot));
}
- return doPrepared.execute(preparedStatement);
+ return doPrepared.execute(prepared);
} else {
return doRegular.execute(client);
}
@@ -213,8 +218,8 @@ private FlightInfo executeFlightInfo() throws AdbcException {
} else if (sqlQuery == null) {
throw AdbcException.invalidState("[Flight SQL] Must setSqlQuery() before execute");
}
- return execute(
- FlightSqlClient.PreparedStatement::execute, (client) -> client.execute(sqlQuery));
+ final String query = sqlQuery;
+ return execute(FlightSqlClient.PreparedStatement::execute, (client) -> client.execute(query));
}
@Override
@@ -254,18 +259,20 @@ public Schema executeSchema() throws AdbcException {
} else if (sqlQuery == null) {
throw AdbcException.invalidState("[Flight SQL] Must setSqlQuery() before execute");
}
+ final String query = sqlQuery;
return execute(
FlightSqlClient.PreparedStatement::getResultSetSchema,
- (client) -> client.getExecuteSchema(sqlQuery).getSchema());
+ (client) -> client.getExecuteSchema(query).getSchema());
}
@Override
public UpdateResult executeUpdate() throws AdbcException {
if (bulkOperation != null) {
- return executeBulk();
+ return executeBulk(bulkOperation);
} else if (sqlQuery == null) {
throw AdbcException.invalidState("[Flight SQL] Must setSqlQuery() before executeUpdate");
}
+ final String query = sqlQuery;
long updatedRows =
execute(
(preparedStatement) -> {
@@ -276,7 +283,7 @@ public UpdateResult executeUpdate() throws AdbcException {
throw FlightSqlDriverUtil.fromFlightException(e);
}
},
- (client) -> client.executeUpdate(sqlQuery));
+ (client) -> client.executeUpdate(query));
return new UpdateResult(updatedRows);
}
@@ -304,12 +311,20 @@ public void prepare() throws AdbcException {
@Override
public void close() throws Exception {
- AutoCloseables.close(preparedStatement);
+ // TODO(https://github.com/apache/arrow/issues/39814): this is annotated wrongly upstream
+ if (preparedStatement != null) {
+ AutoCloseables.close(preparedStatement);
+ }
}
private static final class BulkState {
- public BulkIngestMode mode;
+ BulkIngestMode mode;
String targetTable;
+
+ public BulkState(BulkIngestMode mode, String targetTableName) {
+ this.mode = mode;
+ this.targetTable = targetTableName;
+ }
}
/** A VectorSchemaRoot which does not own its data. */
diff --git a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/InfoMetadataBuilder.java b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/InfoMetadataBuilder.java
index 318405d6ce..20d1e0f2c4 100644
--- a/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/InfoMetadataBuilder.java
+++ b/java/driver/flight-sql/src/main/java/org/apache/arrow/adbc/driver/flightsql/InfoMetadataBuilder.java
@@ -39,6 +39,7 @@
import org.apache.arrow.vector.VarCharVector;
import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.complex.DenseUnionVector;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Helper class to track state needed to build up the info structure. */
final class InfoMetadataBuilder implements AutoCloseable {
@@ -80,7 +81,8 @@ interface AddInfo {
});
}
- InfoMetadataBuilder(BufferAllocator allocator, FlightSqlClient client, int[] infoCodes) {
+ InfoMetadataBuilder(
+ BufferAllocator allocator, FlightSqlClient client, int @Nullable [] infoCodes) {
if (infoCodes == null) {
this.requestedCodes = new ArrayList<>(SUPPORTED_CODES.keySet());
this.requestedCodes.add(AdbcInfoCode.DRIVER_NAME.getValue());
@@ -144,9 +146,7 @@ VectorSchemaRoot build() throws AdbcException {
}
root.setRowCount(dstIndex);
- VectorSchemaRoot result = root;
- root = null;
- return result;
+ return root;
}
@Override
diff --git a/java/driver/jdbc/pom.xml b/java/driver/jdbc/pom.xml
index 6b9eda4afe..5a415c38f1 100644
--- a/java/driver/jdbc/pom.xml
+++ b/java/driver/jdbc/pom.xml
@@ -51,6 +51,12 @@
adbc-sql
+
+
+ org.checkerframework
+ checker-qual
+
+
org.assertj
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriver.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriver.java
index 14d4f0bee3..e197d225bc 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriver.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriver.java
@@ -30,8 +30,10 @@
public class JdbcDriver implements AdbcDriver {
/** A parameter for creating an {@link AdbcDatabase} from a {@link DataSource}. */
public static final String PARAM_DATASOURCE = "adbc.jdbc.datasource";
+
/** A parameter for specifying backend-specific configuration (type: {@link JdbcQuirks}). */
public static final String PARAM_JDBC_QUIRKS = "adbc.jdbc.quirks";
+
/**
* A parameter for specifying a URI to connect to.
*
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriverUtil.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriverUtil.java
index b2b65d7744..ed38bd1b2a 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriverUtil.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcDriverUtil.java
@@ -23,6 +23,7 @@
import java.util.Set;
import org.apache.arrow.adbc.core.AdbcException;
import org.apache.arrow.adbc.core.AdbcStatusCode;
+import org.checkerframework.checker.nullness.qual.Nullable;
final class JdbcDriverUtil {
// Do our best to properly map database-specific errors to NOT_FOUND status.
@@ -45,7 +46,7 @@ static String prefixExceptionMessage(final String s) {
return "[JDBC] " + s;
}
- static AdbcStatusCode guessStatusCode(String sqlState) {
+ static AdbcStatusCode guessStatusCode(@Nullable String sqlState) {
if (sqlState == null) {
return AdbcStatusCode.UNKNOWN;
} else if (SQLSTATE_TABLE_NOT_FOUND.contains(sqlState)) {
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
index fd39e6d08b..b642be0d0b 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
@@ -261,7 +261,7 @@ public QueryResult executeQuery() throws AdbcException {
} catch (SQLException e) {
throw JdbcDriverUtil.fromSqlException(e);
}
- return new QueryResult(/*affectedRows=*/ -1, reader);
+ return new QueryResult(/* affectedRows */ -1, reader);
}
@Override
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/StandardJdbcQuirks.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/StandardJdbcQuirks.java
index e87283cb4e..e345259ae4 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/StandardJdbcQuirks.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/StandardJdbcQuirks.java
@@ -16,17 +16,15 @@
*/
package org.apache.arrow.adbc.driver.jdbc;
-import java.sql.Types;
-import org.apache.arrow.adapter.jdbc.JdbcToArrowUtils;
-import org.apache.arrow.adbc.driver.jdbc.adapter.JdbcFieldInfoExtra;
+import org.apache.arrow.adbc.driver.jdbc.adapter.JdbcToArrowTypeConverters;
import org.apache.arrow.adbc.sql.SqlQuirks;
-import org.apache.arrow.vector.types.TimeUnit;
-import org.apache.arrow.vector.types.Types.MinorType;
import org.apache.arrow.vector.types.pojo.ArrowType;
public final class StandardJdbcQuirks {
public static final JdbcQuirks MS_SQL_SERVER =
- JdbcQuirks.builder("Microsoft SQL Server").typeConverter(StandardJdbcQuirks::mssql).build();
+ JdbcQuirks.builder("Microsoft SQL Server")
+ .typeConverter(JdbcToArrowTypeConverters.MICROSOFT_SQL_SERVER)
+ .build();
public static final JdbcQuirks POSTGRESQL =
JdbcQuirks.builder("PostgreSQL")
.sqlQuirks(
@@ -40,41 +38,7 @@ public final class StandardJdbcQuirks {
arrowType);
}))
.build())
- .typeConverter(StandardJdbcQuirks::postgresql)
+ .typeConverter(JdbcToArrowTypeConverters.POSTGRESQL)
.build();
private static final int MS_SQL_TYPE_DATETIMEOFFSET = -155;
-
- private static ArrowType mssql(JdbcFieldInfoExtra field) {
- switch (field.getJdbcType()) {
- case Types.TIME:
- return MinorType.TIMENANO.getType();
- case Types.TIMESTAMP:
- // DATETIME2
- // Precision is "100 nanoseconds" -> TimeUnit is NANOSECOND
- return MinorType.TIMESTAMPNANO.getType();
- case MS_SQL_TYPE_DATETIMEOFFSET:
- // DATETIMEOFFSET
- // Precision is "100 nanoseconds" -> TimeUnit is NANOSECOND
- return new ArrowType.Timestamp(TimeUnit.NANOSECOND, "UTC");
- default:
- return JdbcToArrowUtils.getArrowTypeFromJdbcType(field.getFieldInfo(), /*calendar*/ null);
- }
- }
-
- private static ArrowType postgresql(JdbcFieldInfoExtra field) {
- switch (field.getJdbcType()) {
- case Types.TIME:
- return MinorType.TIMEMICRO.getType();
- case Types.TIMESTAMP:
- if ("timestamptz".equals(field.getTypeName())) {
- return new ArrowType.Timestamp(TimeUnit.MICROSECOND, "UTC");
- } else if ("timestamp".equals(field.getTypeName())) {
- return MinorType.TIMESTAMPMICRO.getType();
- }
- // Unknown type
- return null;
- default:
- return JdbcToArrowUtils.getArrowTypeFromJdbcType(field.getFieldInfo(), /*calendar*/ null);
- }
- }
}
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/UrlDataSource.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/UrlDataSource.java
index f74b97f448..51266ca006 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/UrlDataSource.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/UrlDataSource.java
@@ -25,15 +25,17 @@
import java.util.Objects;
import java.util.logging.Logger;
import javax.sql.DataSource;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Adapt a JDBC URL to the DataSource interface. */
class UrlDataSource implements DataSource {
final String target;
- PrintWriter logWriter;
+ @Nullable PrintWriter logWriter;
int loginTimeout;
UrlDataSource(String target) {
this.target = Objects.requireNonNull(target);
+ this.logWriter = null;
}
@Override
@@ -47,7 +49,8 @@ public Connection getConnection(String username, String password) throws SQLExce
}
@Override
- public PrintWriter getLogWriter() throws SQLException {
+ @SuppressWarnings("override.return")
+ public @Nullable PrintWriter getLogWriter() throws SQLException {
return logWriter;
}
diff --git a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/adapter/JdbcToArrowTypeConverters.java b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/adapter/JdbcToArrowTypeConverters.java
index 928bfdf8ee..5640a3d459 100644
--- a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/adapter/JdbcToArrowTypeConverters.java
+++ b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/adapter/JdbcToArrowTypeConverters.java
@@ -58,7 +58,8 @@ private static ArrowType postgresql(JdbcFieldInfoExtra field) {
unit = TimeUnit.NANOSECOND;
} else {
// Negative precision?
- return null;
+ throw new UnsupportedOperationException(
+ "Cannot convert type to Arrow Timestamp (precision is negative)");
}
if ("timestamptz".equals(field.getTypeName())) {
return new ArrowType.Timestamp(unit, "UTC");
@@ -66,7 +67,7 @@ private static ArrowType postgresql(JdbcFieldInfoExtra field) {
return new ArrowType.Timestamp(unit, /*timezone*/ null);
}
// Unknown type
- return null;
+ throw new UnsupportedOperationException("Cannot convert type to Arrow Timestamp");
}
default:
return JdbcToArrowUtils.getArrowTypeFromJdbcType(field.getFieldInfo(), /*calendar*/ null);
diff --git a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionMetadataTest.java b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionMetadataTest.java
index 6a5fc9053d..f31588e68c 100644
--- a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionMetadataTest.java
+++ b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionMetadataTest.java
@@ -323,8 +323,7 @@ public void getTableSchema() throws Exception {
final Schema schema =
new Schema(
Arrays.asList(
- Field.nullable(
- quirks.caseFoldColumnName("INTS"), new ArrowType.Int(32, /*signed=*/ true)),
+ Field.nullable(quirks.caseFoldColumnName("INTS"), new ArrowType.Int(32, true)),
Field.nullable(quirks.caseFoldColumnName("STRS"), new ArrowType.Utf8())));
try (final VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator);
final AdbcStatement stmt = connection.bulkIngest(tableName, BulkIngestMode.CREATE)) {
diff --git a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
index 29265ba7e3..e6aaa6e6c4 100644
--- a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
+++ b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
@@ -85,9 +85,7 @@ void toggleAutoCommit() throws Exception {
@Test
void rollback() throws Exception {
final Schema schema =
- new Schema(
- Collections.singletonList(
- Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ true))));
+ new Schema(Collections.singletonList(Field.nullable("ints", new ArrowType.Int(32, true))));
connection.setAutoCommit(false);
try (VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) {
@@ -116,9 +114,7 @@ void rollback() throws Exception {
@Test
void commit() throws Exception {
final Schema schema =
- new Schema(
- Collections.singletonList(
- Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ true))));
+ new Schema(Collections.singletonList(Field.nullable("ints", new ArrowType.Int(32, true))));
final String tableName = quirks.caseFoldTableName("temptable");
connection.setAutoCommit(false);
@@ -149,9 +145,7 @@ void commit() throws Exception {
@Test
void enableAutoCommitAlsoCommits() throws Exception {
final Schema schema =
- new Schema(
- Collections.singletonList(
- Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ true))));
+ new Schema(Collections.singletonList(Field.nullable("ints", new ArrowType.Int(32, true))));
final String tableName = quirks.caseFoldTableName("temptable");
connection.setAutoCommit(false);
diff --git a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/SqlTestUtil.java b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/SqlTestUtil.java
index 814d0a81c4..c0536e5cf5 100644
--- a/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/SqlTestUtil.java
+++ b/java/driver/validation/src/main/java/org/apache/arrow/adbc/driver/testsuite/SqlTestUtil.java
@@ -79,8 +79,7 @@ public Schema ingestTableWithConstraints(
final Schema schema =
new Schema(
Arrays.asList(
- Field.notNullable(
- quirks.caseFoldColumnName("INTS"), new ArrowType.Int(32, /*signed=*/ true)),
+ Field.notNullable(quirks.caseFoldColumnName("INTS"), new ArrowType.Int(32, true)),
Field.nullable(quirks.caseFoldColumnName("INTS2"), new ArrowType.Int(32, true))));
try (final VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) {
final IntVector ints = (IntVector) root.getVector(0);
@@ -133,8 +132,7 @@ public void ingestTablesWithReferentialConstraint(
new Schema(
Collections.singletonList(
Field.notNullable(
- quirks.caseFoldColumnName("PRODUCT_ID"),
- new ArrowType.Int(32, /*signed=*/ true))));
+ quirks.caseFoldColumnName("PRODUCT_ID"), new ArrowType.Int(32, true))));
final Schema dependentSchema =
new Schema(
diff --git a/java/pom.xml b/java/pom.xml
index a632959f51..6ad153c1d1 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -153,6 +153,13 @@
${adbc.version}
+
+
+ org.checkerframework
+ checker-qual
+ 3.42.0
+
+
org.assertj
@@ -297,15 +304,26 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.10.1
+ 3.11.0
1.8
1.8
-
+ UTF-8
+
-XDcompilePolicy=simple
-Xplugin:ErrorProne -Xep:NullAway:ERROR -XepOpt:NullAway:AnnotatedPackages=com.uber
+
+ -Xmaxerrs
+ 10000
+ -Xmaxwarns
+ 10000
+ -AskipDefs=.*Test
+ -AatfDoNotCache
+ -AprintVerboseGenerics
+ -AprintAllQualifiers
+ -Astubs=.checker-framework/:stubs
-
+
com.google.errorprone
error_prone_core
@@ -316,7 +334,15 @@
nullaway
0.10.10
+
+ org.checkerframework
+ checker
+ 3.42.0
+
+
+ org.checkerframework.checker.nullness.NullnessChecker
+
diff --git a/java/sql/pom.xml b/java/sql/pom.xml
index 9894210994..37904359b7 100644
--- a/java/sql/pom.xml
+++ b/java/sql/pom.xml
@@ -28,6 +28,12 @@
arrow-vector
+
+
+ org.checkerframework
+ checker-qual
+
+
org.assertj
diff --git a/java/sql/src/main/java/org/apache/arrow/adbc/sql/SqlQuirks.java b/java/sql/src/main/java/org/apache/arrow/adbc/sql/SqlQuirks.java
index 007f699c0f..fc86435474 100644
--- a/java/sql/src/main/java/org/apache/arrow/adbc/sql/SqlQuirks.java
+++ b/java/sql/src/main/java/org/apache/arrow/adbc/sql/SqlQuirks.java
@@ -19,51 +19,53 @@
import java.util.function.Function;
import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.checkerframework.checker.nullness.qual.Nullable;
/** Parameters to pass to SQL-based drivers to account for driver/vendor-specific SQL quirks. */
public final class SqlQuirks {
- public static final Function DEFAULT_ARROW_TYPE_TO_SQL_TYPE_NAME_MAPPING =
- (arrowType) -> {
- switch (arrowType.getTypeID()) {
- case Null:
- case Struct:
- case List:
- case LargeList:
- case FixedSizeList:
- case Union:
- case Map:
- return null;
- case Int:
- // TODO:
- return "INT";
- case FloatingPoint:
- return null;
- case Utf8:
- return "CLOB";
- case LargeUtf8:
- case Binary:
- case LargeBinary:
- case FixedSizeBinary:
- case Bool:
- case Decimal:
- case Date:
- case Time:
- case Timestamp:
- case Interval:
- case Duration:
- case NONE:
- default:
- return null;
- }
- };
- Function arrowToSqlTypeNameMapping;
+ public static final Function
+ DEFAULT_ARROW_TYPE_TO_SQL_TYPE_NAME_MAPPING =
+ (arrowType) -> {
+ switch (arrowType.getTypeID()) {
+ case Null:
+ case Struct:
+ case List:
+ case LargeList:
+ case FixedSizeList:
+ case Union:
+ case Map:
+ return null;
+ case Int:
+ // TODO:
+ return "INT";
+ case FloatingPoint:
+ return null;
+ case Utf8:
+ return "CLOB";
+ case LargeUtf8:
+ case Binary:
+ case LargeBinary:
+ case FixedSizeBinary:
+ case Bool:
+ case Decimal:
+ case Date:
+ case Time:
+ case Timestamp:
+ case Interval:
+ case Duration:
+ case NONE:
+ default:
+ return null;
+ }
+ };
+ Function arrowToSqlTypeNameMapping;
public SqlQuirks() {
this.arrowToSqlTypeNameMapping = DEFAULT_ARROW_TYPE_TO_SQL_TYPE_NAME_MAPPING;
}
/** The mapping from Arrow type to SQL type name, used to build queries. */
- public Function getArrowToSqlTypeNameMapping() {
+ public Function getArrowToSqlTypeNameMapping() {
return arrowToSqlTypeNameMapping;
}
@@ -73,9 +75,10 @@ public static Builder builder() {
}
public static final class Builder {
- Function arrowToSqlTypeNameMapping;
+ @Nullable Function arrowToSqlTypeNameMapping;
- public Builder arrowToSqlTypeNameMapping(Function mapper) {
+ public Builder arrowToSqlTypeNameMapping(
+ @Nullable Function mapper) {
this.arrowToSqlTypeNameMapping = mapper;
return this;
}