DuckDB Type Support
Foundations JDBC provides comprehensive support for DuckDB's rich type system, including nested types (LIST, STRUCT, MAP, UNION) and extended integer types.
Integer Types (Signed)
| DuckDB Type | Java Type | Range |
|---|---|---|
TINYINT | Byte | -128 to 127 |
SMALLINT | Short | -32,768 to 32,767 |
INTEGER / INT | Integer | -2^31 to 2^31-1 |
BIGINT | Long | -2^63 to 2^63-1 |
HUGEINT | BigInteger | -2^127 to 2^127-1 |
- Kotlin
- Java
- Scala
val tinyType: DuckDbType<Byte> = DuckDbTypes.tinyint
val intType: DuckDbType<Int> = DuckDbTypes.integer
val hugeType: DuckDbType<BigInteger> = DuckDbTypes.hugeint
DuckDbType<Byte> tinyType = DuckDbTypes.tinyint;
DuckDbType<Integer> intType = DuckDbTypes.integer;
DuckDbType<BigInteger> hugeType = DuckDbTypes.hugeint;
val tinyType: DuckDbType[Byte] = DuckDbTypes.tinyint
val intType: DuckDbType[Int] = DuckDbTypes.integer
val hugeType: DuckDbType[java.math.BigInteger] = DuckDbTypes.hugeint
Integer Types (Unsigned)
| DuckDB Type | Java Type | Range |
|---|---|---|
UTINYINT | Uint1 | 0 to 255 |
USMALLINT | Uint2 | 0 to 65,535 |
UINTEGER | Uint4 | 0 to 2^32-1 |
UBIGINT | Uint8 | 0 to 2^64-1 |
UHUGEINT | BigInteger | 0 to 2^128-1 |
- Kotlin
- Java
- Scala
val utinyType: DuckDbType<Uint1> = DuckDbTypes.utinyint
val uintType: DuckDbType<Uint4> = DuckDbTypes.uinteger
val uhugeType: DuckDbType<BigInteger> = DuckDbTypes.uhugeint
DuckDbType<Uint1> utinyType = DuckDbTypes.utinyint;
DuckDbType<Uint4> uintType = DuckDbTypes.uinteger;
DuckDbType<BigInteger> uhugeType = DuckDbTypes.uhugeint;
val utinyType: DuckDbType[Uint1] = DuckDbTypes.utinyint
val uintType: DuckDbType[Uint4] = DuckDbTypes.uinteger
val uhugeType: DuckDbType[BigInteger] = DuckDbTypes.uhugeint
Floating-Point Types
| DuckDB Type | Java Type | Notes |
|---|---|---|
FLOAT / FLOAT4 / REAL | Float | 32-bit IEEE 754 |
DOUBLE / FLOAT8 | Double | 64-bit IEEE 754 |
- Kotlin
- Java
- Scala
val floatType: DuckDbType<Float> = DuckDbTypes.float_
val doubleType: DuckDbType<Double> = DuckDbTypes.double_
DuckDbType<Float> floatType = DuckDbTypes.float_;
DuckDbType<Double> doubleType = DuckDbTypes.double_;
val floatType: DuckDbType[Float] = DuckDbTypes.float_
val doubleType: DuckDbType[Double] = DuckDbTypes.double_
Fixed-Point Types
| DuckDB Type | Java Type | Notes |
|---|---|---|
DECIMAL(p,s) | BigDecimal | Arbitrary precision |
NUMERIC(p,s) | BigDecimal | Alias for DECIMAL |
- Kotlin
- Java
- Scala
val decimalType: DuckDbType<BigDecimal> = DuckDbTypes.decimal
val precise: DuckDbType<BigDecimal> = DuckDbTypes.decimal(18, 6) // DECIMAL(18,6)
DuckDbType<BigDecimal> decimalType = DuckDbTypes.decimal;
DuckDbType<BigDecimal> precise = DuckDbTypes.decimal(18, 6); // DECIMAL(18,6)
val decimalType: DuckDbType[BigDecimal] = DuckDbTypes.decimal
val precise: DuckDbType[BigDecimal] = DuckDbTypes.decimal(18, 6) // DECIMAL(18,6)
Boolean Type
| DuckDB Type | Java Type |
|---|---|
BOOLEAN / BOOL | Boolean |
- Kotlin
- Java
- Scala
val boolType: DuckDbType<Boolean> = DuckDbTypes.boolean_
DuckDbType<Boolean> boolType = DuckDbTypes.boolean_;
val boolType: DuckDbType[Boolean] = DuckDbTypes.boolean_
String Types
| DuckDB Type | Java Type | Notes |
|---|---|---|
VARCHAR / STRING / TEXT | String | Variable length |
CHAR(n) | String | Fixed length |
- Kotlin
- Java
- Scala
val varcharType: DuckDbType<String> = DuckDbTypes.varchar
val charType: DuckDbType<String> = DuckDbTypes.char_(10)
DuckDbType<String> varcharType = DuckDbTypes.varchar;
DuckDbType<String> charType = DuckDbTypes.char_(10);
val varcharType: DuckDbType[String] = DuckDbTypes.varchar
val charType: DuckDbType[String] = DuckDbTypes.char_(10)
Binary Types
| DuckDB Type | Java Type |
|---|---|
BLOB / BYTEA / BINARY / VARBINARY | byte[] |
- Kotlin
- Java
- Scala
val blobType: DuckDbType<ByteArray> = DuckDbTypes.blob
DuckDbType<byte[]> blobType = DuckDbTypes.blob;
val blobType: DuckDbType[Array[Byte]] = DuckDbTypes.blob
Bit String Type
| DuckDB Type | Java Type | Notes |
|---|---|---|
BIT / BITSTRING | String | String of 0s and 1s |
- Kotlin
- Java
- Scala
val bitType: DuckDbType<String> = DuckDbTypes.bit
val bit8: DuckDbType<String> = DuckDbTypes.bit(8) // BIT(8)
DuckDbType<String> bitType = DuckDbTypes.bit;
DuckDbType<String> bit8 = DuckDbTypes.bit(8); // BIT(8)
val bitType: DuckDbType[String] = DuckDbTypes.bit
val bit8: DuckDbType[String] = DuckDbTypes.bit(8) // BIT(8)
Date/Time Types
| DuckDB Type | Java Type | Notes |
|---|---|---|
DATE | LocalDate | Date only |
TIME | LocalTime | Time only |
TIMESTAMP / DATETIME | LocalDateTime | Date and time |
TIMESTAMP WITH TIME ZONE | OffsetDateTime | With timezone |
TIME WITH TIME ZONE | OffsetDateTime | Time with timezone |
INTERVAL | Duration | Time duration |
- Kotlin
- Java
- Scala
val dateType: DuckDbType<LocalDate> = DuckDbTypes.date
val tsType: DuckDbType<LocalDateTime> = DuckDbTypes.timestamp
val tstzType: DuckDbType<OffsetDateTime> = DuckDbTypes.timestamptz
val intervalType: DuckDbType<Duration> = DuckDbTypes.interval
DuckDbType<LocalDate> dateType = DuckDbTypes.date;
DuckDbType<LocalDateTime> tsType = DuckDbTypes.timestamp;
DuckDbType<OffsetDateTime> tstzType = DuckDbTypes.timestamptz;
DuckDbType<Duration> intervalType = DuckDbTypes.interval;
val dateType: DuckDbType[LocalDate] = DuckDbTypes.date
val tsType: DuckDbType[LocalDateTime] = DuckDbTypes.timestamp
val tstzType: DuckDbType[OffsetDateTime] = DuckDbTypes.timestamptz
val intervalType: DuckDbType[Duration] = DuckDbTypes.interval
Timestamp Precision Variants
| DuckDB Type | Java Type | Precision |
|---|---|---|
TIMESTAMP_S | LocalDateTime | Seconds |
TIMESTAMP_MS | LocalDateTime | Milliseconds |
TIMESTAMP | LocalDateTime | Microseconds (default) |
TIMESTAMP_NS | LocalDateTime | Nanoseconds |
- Kotlin
- Java
- Scala
val tsSeconds: DuckDbType<LocalDateTime> = DuckDbTypes.timestamp_s
val tsMillis: DuckDbType<LocalDateTime> = DuckDbTypes.timestamp_ms
val tsNanos: DuckDbType<LocalDateTime> = DuckDbTypes.timestamp_ns
DuckDbType<LocalDateTime> tsSeconds = DuckDbTypes.timestamp_s;
DuckDbType<LocalDateTime> tsMillis = DuckDbTypes.timestamp_ms;
DuckDbType<LocalDateTime> tsNanos = DuckDbTypes.timestamp_ns;
val tsSeconds: DuckDbType[LocalDateTime] = DuckDbTypes.timestamp_s
val tsMillis: DuckDbType[LocalDateTime] = DuckDbTypes.timestamp_ms
val tsNanos: DuckDbType[LocalDateTime] = DuckDbTypes.timestamp_ns
UUID Type
| DuckDB Type | Java Type |
|---|---|
UUID | java.util.UUID |
- Kotlin
- Java
- Scala
val uuidType: DuckDbType<UUID> = DuckDbTypes.uuid
DuckDbType<UUID> uuidType = DuckDbTypes.uuid;
val uuidType: DuckDbType[UUID] = DuckDbTypes.uuid
JSON Type
| DuckDB Type | Java Type |
|---|---|
JSON | Json |
- Kotlin
- Java
- Scala
val jsonType: DuckDbType<Json> = DuckDbTypes.json
val data: Json = Json("{\"name\": \"DuckDB\"}")
DuckDbType<Json> jsonType = DuckDbTypes.json;
Json data = new Json("{\"name\": \"DuckDB\"}");
val jsonType: DuckDbType[Json] = DuckDbTypes.json
val data: Json = new Json("{\"name\": \"DuckDB\"}")
Enum Type
- Kotlin
- Java
- Scala
// Define your Kotlin enum
enum class Status { PENDING, ACTIVE, COMPLETED }
// Create DuckDbType for it
val statusType: DuckDbType<Status> = DuckDbTypes.ofEnum("status", Status::valueOf)
// Define your Java enum
public enum Status { PENDING, ACTIVE, COMPLETED }
// Create DuckDbType for it
DuckDbType<Status> statusType = DuckDbTypes.ofEnum("status", Status::valueOf);
// Define your Scala 3 enum
enum Status:
case PENDING, ACTIVE, COMPLETED
// Create a DuckDbType using transform (Scala 3 enums don't extend java.lang.Enum)
val statusType: DuckDbType[Status] = DuckDbTypes.varchar.transform(
Status.valueOf,
_.toString
)
Array Types
Any type can be converted to an array type using .array():
| DuckDB Type | Java Type |
|---|---|
INTEGER[] | Integer[] |
VARCHAR[] | String[] |
BOOLEAN[] | Boolean[] |
| ... | ... |
- Kotlin
- Java
- Scala
val intArray: DuckDbType<Array<Int>> = DuckDbTypes.integerArray
val strArray: DuckDbType<Array<String>> = DuckDbTypes.varcharArray
val uuidArray: DuckDbType<Array<UUID>> = DuckDbTypes.uuidArray
// Create array for any type
// val customArray: DuckDbType<Array<MyType>> = myType.array()
DuckDbType<Integer[]> intArray = DuckDbTypes.integerArray;
DuckDbType<String[]> strArray = DuckDbTypes.varcharArray;
DuckDbType<UUID[]> uuidArray = DuckDbTypes.uuidArray;
// Create array for any type
// DuckDbType<MyType[]> customArray = myType.array();
val intArray: DuckDbType[Array[Int]] = DuckDbTypes.integerArray
val strArray: DuckDbType[Array[String]] = DuckDbTypes.varcharArray
val uuidArray: DuckDbType[Array[UUID]] = DuckDbTypes.uuidArray
// Create array for any type
// val customArray: DuckDbType[Array[MyType]] = myType.array()
LIST Types
DuckDB's LIST type is similar to arrays but with different semantics:
| DuckDB Type | Java Type |
|---|---|
LIST<INTEGER> | List<Integer> |
LIST<VARCHAR> | List<String> |
LIST<DATE> | List<LocalDate> |
| ... | ... |
- Kotlin
- Java
- Scala
// Pre-defined list types with optimized native JNI support
val listInt: DuckDbType<List<Int>> = DuckDbTypes.listInteger
val listStr: DuckDbType<List<String>> = DuckDbTypes.listVarchar
val listDouble: DuckDbType<List<Double>> = DuckDbTypes.listDouble
// Types that use SQL literal conversion (slightly slower but correct)
val listUuid: DuckDbType<List<UUID>> = DuckDbTypes.listUuid
val listDate: DuckDbType<List<LocalDate>> = DuckDbTypes.listDate
val listDecimal: DuckDbType<List<BigDecimal>> = DuckDbTypes.listDecimal
// Pre-defined list types with optimized native JNI support
DuckDbType<List<Integer>> listInt = DuckDbTypes.listInteger;
DuckDbType<List<String>> listStr = DuckDbTypes.listVarchar;
DuckDbType<List<Double>> listDouble = DuckDbTypes.listDouble;
// Types that use SQL literal conversion (slightly slower but correct)
DuckDbType<List<UUID>> listUuid = DuckDbTypes.listUuid;
DuckDbType<List<LocalDate>> listDate = DuckDbTypes.listDate;
DuckDbType<List<BigDecimal>> listDecimal = DuckDbTypes.listDecimal;
// Pre-defined list types with optimized native JNI support
val listInt: DuckDbType[List[Integer]] = DuckDbTypes.listInteger
val listStr: DuckDbType[List[String]] = DuckDbTypes.listVarchar
val listDouble: DuckDbType[List[java.lang.Double]] = DuckDbTypes.listDouble
// Types that use SQL literal conversion (slightly slower but correct)
val listUuid: DuckDbType[List[UUID]] = DuckDbTypes.listUuid
val listDate: DuckDbType[List[LocalDate]] = DuckDbTypes.listDate
val listDecimal: DuckDbType[List[BigDecimal]] = DuckDbTypes.listDecimal
MAP Types
DuckDB's MAP type for key-value pairs:
| DuckDB Type | Java Type |
|---|---|
MAP(VARCHAR, INTEGER) | Map<String, Integer> |
MAP(VARCHAR, VARCHAR) | Map<String, String> |
- Kotlin
- Java
- Scala
// Create map types using the mapTo() combinator
val mapStrInt: DuckDbType<Map<String, Int>> = DuckDbTypes.varchar.mapTo(DuckDbTypes.integer)
val mapStrStr: DuckDbType<Map<String, String>> = DuckDbTypes.varchar.mapTo(DuckDbTypes.varchar)
val mapUuidTime: DuckDbType<Map<UUID, LocalTime>> = DuckDbTypes.uuid.mapTo(DuckDbTypes.time)
// Works with any combination of types
val mapStrDate: DuckDbType<Map<String, LocalDate>> = DuckDbTypes.varchar.mapTo(DuckDbTypes.date)
// Create map types using the mapTo() combinator
DuckDbType<Map<String, Integer>> mapStrInt = DuckDbTypes.varchar.mapTo(DuckDbTypes.integer);
DuckDbType<Map<String, String>> mapStrStr = DuckDbTypes.varchar.mapTo(DuckDbTypes.varchar);
DuckDbType<Map<UUID, LocalTime>> mapUuidTime = DuckDbTypes.uuid.mapTo(DuckDbTypes.time);
// Works with any combination of types
DuckDbType<Map<String, LocalDate>> mapStrDate = DuckDbTypes.varchar.mapTo(DuckDbTypes.date);
// Create map types using the mapTo() combinator
val mapStrInt: DuckDbType[Map[String, Int]] = DuckDbTypes.varchar.mapTo(DuckDbTypes.integer)
val mapStrStr: DuckDbType[Map[String, String]] = DuckDbTypes.varchar.mapTo(DuckDbTypes.varchar)
val mapUuidTime: DuckDbType[Map[UUID, LocalTime]] = DuckDbTypes.uuid.mapTo(DuckDbTypes.time)
// Works with any combination of types
val mapStrDate: DuckDbType[Map[String, LocalDate]] = DuckDbTypes.varchar.mapTo(DuckDbTypes.date)
STRUCT Types
DuckDB's STRUCT type for composite values:
// Structs are typically handled via generated code
// The structure is defined by the table schema
UNION Types
DuckDB's UNION type for tagged unions:
// Unions are typically handled via generated code
// The variants are defined by the table schema
Nullable Types
Any type can be made nullable using .opt():
- Kotlin
- Java
- Scala
val notNull: DuckDbType<Int> = DuckDbTypes.integer
val nullable: DuckDbType<Int?> = DuckDbTypes.integer.opt()
DuckDbType<Integer> notNull = DuckDbTypes.integer;
DuckDbType<Optional<Integer>> nullable = DuckDbTypes.integer.opt();
val notNull: DuckDbType[Int] = DuckDbTypes.integer
val nullable: DuckDbType[Option[Int]] = DuckDbTypes.integer.opt
Custom Domain Types
Wrap base types with custom Java types using transform:
- Kotlin
- Java
- Scala
// Wrapper type
data class ProductId(val value: Long)
// Create DuckDbType from bigint
val productIdType: DuckDbType<ProductId> = DuckDbTypes.bigint.transform(::ProductId, ProductId::value)
// Wrapper type
public record ProductId(Long value) {}
// Create DuckDbType from bigint
DuckDbType<ProductId> productIdType = DuckDbTypes.bigint.transform(ProductId::new, ProductId::value);
// Wrapper type
case class ProductId(value: Long)
// Create DuckDbType from bigint
val productIdType: DuckDbType[ProductId] = DuckDbTypes.bigint.transform(ProductId.apply, _.value)