Arrow JDBC 轉接器#

Arrow JDBC 轉接器協助處理 JDBC 和 Arrow 資料。目前,它支援將 JDBC ResultSets 讀取到 Arrow VectorSchemaRoots。

ResultSet 到 VectorSchemaRoot 的轉換#

這可以透過 JdbcToArrow 類別存取。產生的 ArrowVectorIterator 將以批次方式將 ResultSet 轉換為 Arrow 資料。

try (ArrowVectorIterator it = JdbcToArrow.sqlToArrowVectorIterator(resultSet, allocator)) {
  while (it.hasNext()) {
    VectorSchemaRoot root = it.next();
    // Consume the root…
  }
}

批次大小和類型映射都可以自訂

JdbcToArrowConfig config = new JdbcToArrowConfigBuilder(allocator, /*calendar=*/null)
    .setReuseVectorSchemaRoot(reuseVectorSchemaRoot)
    .setJdbcToArrowTypeConverter((jdbcFieldInfo -> {
      switch (jdbcFieldInfo.getJdbcType()) {
        case Types.BIGINT:
          // Assume actual value range is SMALLINT
          return new ArrowType.Int(16, true);
        default:
          return null;
      }
    }))
    .build();
try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config)) {
  while (iter.hasNext()) {
    VectorSchemaRoot root = iter.next();
    // Consume the root…
  }
}

可以明確指定 JDBC 類型,這很有用,因為 JDBC 驅動程式可能會提供錯誤的類型資訊。例如,已觀察到 Postgres 驅動程式使用小數位數和精度為 0 的 Decimal 類型;在這些情況下,可以在讀取之前明確指定類型來處理。此外,某些 JDBC 驅動程式可能會傳回具有不一致小數位數的 BigDecimal 值。可以設定 RoundingMode 來處理這些情況

Map<Integer, JdbcFieldInfo> mapping = new HashMap<>();
mapping.put(1, new JdbcFieldInfo(Types.DECIMAL, 20, 7));
JdbcToArrowConfig config = new JdbcToArrowConfigBuilder(allocator, /*calendar=*/null)
    .setBigDecimalRoundingMode(RoundingMode.UNNECESSARY)
    .setExplicitTypesByColumnIndex(mapping)
    .build();
try (ArrowVectorIterator iter = JdbcToArrow.sqlToArrowVectorIterator(rs, config)) {
  while (iter.hasNext()) {
    VectorSchemaRoot root = iter.next();
    // Consume the root…
  }
}

從 JDBC 類型到 Arrow 類型的映射可以透過 JdbcToArrowConfig 覆寫,但無法自訂從 JDBC 值到 Arrow 值的轉換本身,也無法為不支援的類型定義轉換。

類型映射#

JDBC 到 Arrow 類型的映射可以在執行時從 JdbcToArrowUtils.getArrowTypeFromJdbcType 取得。

JDBC 類型

Arrow 類型

注意事項

ARRAY

List

(1)

BIGINT

Int64

BINARY

Binary

BIT

Bool

BLOB

Binary

BOOLEAN

Bool

CHAR

Utf8

CLOB

Utf8

DATE

Date32

DECIMAL

Decimal128

(2)

DOUBLE

Double

FLOAT

Float32

INTEGER

Int32

LONGVARBINARY

Binary

LONGNVARCHAR

Utf8

LONGVARCHAR

Utf8

NCHAR

Utf8

NULL

Null

NUMERIC

Decimal128

NVARCHAR

Utf8

REAL

Float32

SMALLINT

Int16

STRUCT

Struct

(3)

TIME

Time32[ms]

TIMESTAMP

Timestamp[ms]

(4)

TINYINT

Int8

VARBINARY

Binary

VARCHAR

Utf8

  • (1) 列表值類型必須明確配置,且無法推斷。使用 setArraySubTypeByColumnIndexMapsetArraySubTypeByColumnNameMap

  • (2) 預設情況下,小數值的 scale 必須與類型中的 scale 完全匹配;精度允許為大於或等於類型精度的任何值。如果存在不匹配,預設情況下將拋出例外。這可以透過使用 setBigDecimalRoundingMode 設定不同的 RoundingMode 來配置。

  • (3) 未完全支援:雖然定義了類型轉換,但未定義值轉換。請參閱 ARROW-17006

  • (4) 如果提供 Calendar,則時間戳記將具有 Calendar 的時區,否則它將是沒有時區的時間戳記。

VectorSchemaRoot 到 PreparedStatement 參數轉換#

轉接器可以將 VectorSchemaRoot 中的 Arrow 資料列繫結到 JDBC PreparedStatement 的參數。這可以透過 JdbcParameterBinder 類別存取。每次呼叫 next() 都會繫結來自下一列資料的參數,然後應用程式可以根據需要執行語句、呼叫 addBatch() 等。Null 值將導致使用適當的 JDBC 類型代碼(如下所列)呼叫 setNull。

final JdbcParameterBinder binder =
    JdbcParameterBinder.builder(statement, root).bindAll().build();
while (binder.next()) {
    statement.executeUpdate();
}
// Use a VectorLoader to update the root
binder.reset();
while (binder.next()) {
    statement.executeUpdate();
}

向量到參數的映射、轉換器使用的 JDBC 類型代碼以及類型轉換本身都可以自訂

final JdbcParameterBinder binder =
    JdbcParameterBinder.builder(statement, root)
        .bind(/*parameterIndex*/2, /*columnIndex*/0)
        .bind(/*parameterIndex*/1, customColumnBinderInstance)
        .build();

類型映射#

Arrow 到 JDBC 類型的映射可以在執行時透過 ColumnBinder 上的方法取得。

Arrow 類型

JDBC 類型

注意事項

Binary

VARBINARY (setBytes)

Bool

BOOLEAN (setBoolean)

Date32

DATE (setDate)

Date64

DATE (setDate)

Decimal128

DECIMAL (setBigDecimal)

Decimal256

DECIMAL (setBigDecimal)

FixedSizeBinary

BINARY (setBytes)

Float32

REAL (setFloat)

Int8

TINYINT (setByte)

Int16

SMALLINT (setShort)

Int32

INTEGER (setInt)

Int64

BIGINT (setLong)

LargeBinary

LONGVARBINARY (setBytes)

LargeUtf8

LONGVARCHAR (setString)

(1)

Time[s]

TIME (setTime)

Time[ms]

TIME (setTime)

Time[us]

TIME (setTime)

Time[ns]

TIME (setTime)

Timestamp[s]

TIMESTAMP (setTimestamp)

(2)

Timestamp[ms]

TIMESTAMP (setTimestamp)

(2)

Timestamp[us]

TIMESTAMP (setTimestamp)

(2)

Timestamp[ns]

TIMESTAMP (setTimestamp)

(2)

Utf8

VARCHAR (setString)

  • (1) 長度超過 Integer.MAX_VALUE 位元組(Java byte[] 的最大長度)的字串將導致執行階段例外。

  • (2) 如果時間戳記具有時區,則 JDBC 類型預設為 TIMESTAMP_WITH_TIMEZONE。如果時間戳記沒有時區,從 Arrow 值到 JDBC 值在技術上沒有正確的轉換,因為 JDBC Timestamp 是 UTC 時間,而我們沒有時區資訊。在這種情況下,預設繫結器將呼叫 setTimestamp(int, Timestamp),這將導致驅動程式使用「預設時區」(Java VM 的時區)。