Welcome to the new DOCS.vastdata.com. We've added new menus and a version selector, plus new persona and resource pages to help customers get started. Looking for a previous article? Use the docs search.

Data types

Prev Next

Applies to VAST Cluster 5.5. Examples use the VAST DataBase Python SDK 2.1.0.

This page shows which column types VAST DataBase supports in VAST Cluster 5.5, what each one is called in Arrow, Trino, Spark and the Python SDK, and where precision can change between them.

Type mapping

VAST DataBase Arrow Trino Spark Python SDK (PyArrow)
UINT8, UINT16, UINT32, UINT64 UINT8, UINT16, UINT32, UINT64 n/a n/a pa.uint8() … pa.uint64()
INT8, INT16, INT32, INT64 INT8, INT16, INT32, INT64 TINYINT, SMALLINT, INTEGER, BIGINT TINYINT, SMALLINT, INTEGER, BIGINT pa.int8() … pa.int64()
BOOL BOOL BOOLEAN BOOLEAN pa.bool_()
FLOAT32, FLOAT64 FLOAT, DOUBLE REAL, DOUBLE REAL, DOUBLE pa.float32(), pa.float64()
STRING STRING VARCHAR STRING pa.string() (or pa.utf8())
BINARY BINARY VARBINARY BINARY pa.binary()
DECIMAL128 DECIMAL128 DECIMAL DECIMAL pa.decimal128(precision, scale)
DATE32 DATE32 DATE DATE pa.date32()
TIMESTAMP TIMESTAMP TIMESTAMP TIMESTAMP pa.timestamp(unit), with unit "s", "ms", "us" or "ns"
TIMESTAMP WITH TZ TIMESTAMP TIMESTAMP WITH TIMEZONE TIMESTAMP pa.timestamp(unit, tz=...)
TIME32 TIME32 TIME n/a pa.time32("s"), pa.time32("ms")
TIME64 TIME64 TIME n/a pa.time64("us"), pa.time64("ns")
MAP MAP MAP MapType pa.map_(key_type, item_type)
ARRAY LIST ARRAY ArrayType pa.list_(value_type)
ROW STRUCT ROW StructType pa.struct([...])
UUID UUID UUID CHAR(16) Not available in SDK 2.1.0 (see below)
VECTOR LIST of INT or FLOAT n/a n/a A fixed-size list

See Supported Data Types.

The SDK also supports float16 (pa.float16(), half precision) since SDK 2.0.6 (SDK changelog). The cluster accepts it.

Engine differences

Engine Difference
VAST Query Engine No time-zone types: a TIMESTAMP WITH TIME ZONE column can be created and written, but selecting it fails with Unsupported column type, and TIME WITH TIME ZONE is refused at CREATE TABLE. Use TIMESTAMP in UTC. See data types in SQL.
VAST Query Engine No map type. struct and array are supported. See 5.5.0 release notes and VAST Query Engine.
VAST Query Engine The vector type is written vector(<element-type>, <dimension>), for example vector(float, 128). See SQL reference and Vector index.
Trino No unsigned integers, and no vector type. Views can't use nested types. See Supported Data Types and Trino connector.
Spark No unsigned integers, TIME or vector type. All nested types (struct, array, map) are supported. See Supported Data Types and Spark managed application.

Nested columns (list, map, struct) can't be partition columns or sort columns. For filtering on nested columns, see pushdowns.

Precision caveats

Timestamps. Check the precision of any type that has one. For example, a timestamp in a Parquet file can show as timestamp(3) in Trino, because of a Trino default, while VAST DataBase processes it as timestamp(6) (see Supported Data Types). From the SDK, the unit you give in pa.timestamp() is the unit the column keeps: a pa.timestamp("ns") column comes back as timestamp[ns]. A timezone is kept too: pa.timestamp("us", tz="Europe/Lisbon") comes back unchanged.

Spark has no unsigned or time types. A UINT or TIME column has no Spark type. If Spark has to read the table, use signed integers and timestamps.

Decimal filters in the Python SDK. SDK 2.1.0 turns a decimal literal in a predicate into a Python float before it scales it to an integer, and drops the remainder. So the value the cluster compares against can be one unit of the scale lower than the one you wrote. For example, on a decimal128(10, 2) column, t["price"] == 0.29 matches the row with 0.28. Don't rely on exact decimal comparisons in a pushed-down predicate. Push down a range that's wider by one unit of the scale on each side, then filter exactly in Arrow. Ibis also rejects a decimal.Decimal literal against a decimal column ("not comparable"), so pass a float.

Float literals are sent with the column's own type, so t["f32"] == 0.1 on a float32 column matches a stored 0.1.

Fixed-size lists and vectors

A vector column is a PyArrow fixed-size list whose element field is not nullable: pa.list_(pa.field("item", pa.float32(), nullable=False), dim). The SDK has supported fixed-size lists of numbers since 1.3.11 (SDK changelog).

Rule
Element types: uint8-uint64, int8-int64, float16, float32, float64, decimal128, date32, timestamp, time32, time64
Not allowed as elements: string, binary, bool, lists, maps and structs
The element field must be non-nullable. Otherwise the cluster rejects the table with NotSupportedSchema, message FIXED_SIZE_LIST nullable sub-type (float) is not supported, only non-nullable is supported
The list size must be at least 1. Size 0 is rejected with TabularInvalidColumnTypeParam.

To build a vector index on the column, see VectorIndexSpec. The size of a single cell is limited; see limits.

Types the SDK can't use

If a column type isn't supported, create_table() and add_column() raise vastdb.errors.NotSupportedSchema (error reference). These were all rejected:

PyArrow type Rejected by Use instead
pa.large_string(), pa.string_view() Cluster: Unsupported column type ... pa.string()
pa.large_list(...) Cluster pa.list_(...)
pa.date64() Cluster pa.date32()
pa.decimal256(...) Cluster pa.decimal128(...), up to precision 38
pa.dictionary(...) Cluster The dictionary's value type. Decode with .cast() or pc.dictionary_decode() before you insert.
pa.duration(...) Cluster An integer column
pa.null() Cluster: The field named '<name>' has an unsupported Arrow type 'null' Give the column a real type
pa.binary(n) (fixed-size binary) SDK: Ibis does not support the schema ... pa.binary()
pa.uuid() SDK: Ibis does not support the schema ... pa.binary() or pa.string()
pa.month_day_nano_interval() SDK: Ibis does not support the schema ... Separate integer columns

"SDK" means the error is raised before any request is sent, because Ibis can't represent the type. The SDK needs Ibis to build predicates.

The cluster has a fixed-size binary type: limits gives its cell size. But SDK 2.1.0 can't create or open a table with one (SDK tests, test_unsupported_types).

Example: a table with several types

This example creates a table with a mix of types, prints the column types the cluster reports, then shows the decimal caveat and its workaround. It uses the connection environment variables from the quickstart.

import decimal
import os

import pyarrow as pa
import pyarrow.compute as pc
import vastdb

session = vastdb.connect()
BUCKET = os.environ["VASTDB_BUCKET"]

columns = pa.schema([
    ("id", pa.int64()),
    ("reading", pa.float16()),
    ("price", pa.decimal128(10, 2)),
    ("day", pa.date32()),
    ("taken_at", pa.timestamp("us", tz="UTC")),
    ("tags", pa.list_(pa.utf8())),
    ("embedding", pa.list_(pa.field("item", pa.float32(), nullable=False), 3)),
    ("location", pa.struct([("lat", pa.float64()), ("lon", pa.float64())])),
    ("attrs", pa.map_(pa.utf8(), pa.utf8())),
])

with session.transaction() as tx:
    schema = tx.bucket(BUCKET).create_schema("ref_data_types", fail_if_exists=False)
    table = schema.create_table("samples", columns, fail_if_exists=False)
    for field in table.columns():
        print(f"{field.name}: {field.type}")
id: int64
reading: halffloat
price: decimal128(10, 2)
day: date32[day]
taken_at: timestamp[us, tz=UTC]
tags: list<item: string>
embedding: fixed_size_list<item: float not null>[3]
location: struct<lat: double, lon: double>
attrs: map<string, string>

Insert two rows, then filter for a price of 0.29:

import datetime as dt

rows = pa.table({
    "id": [1, 2],
    "reading": pa.array([0.5, 1.5], pa.float16()),
    "price": [decimal.Decimal("0.28"), decimal.Decimal("0.29")],
    "day": [dt.date(2026, 1, 1), dt.date(2026, 1, 2)],
    "taken_at": [dt.datetime(2026, 1, 1, 12, tzinfo=dt.timezone.utc),
                 dt.datetime(2026, 1, 2, 12, tzinfo=dt.timezone.utc)],
    "tags": [["a"], []],
    "embedding": [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
    "location": [{"lat": 38.7, "lon": -9.1}, {"lat": 59.9, "lon": 10.7}],
    "attrs": [[("colour", "red")], []],
}, schema=columns)

with session.transaction() as tx:
    table = tx.bucket(BUCKET).schema("ref_data_types").table("samples")
    table.insert(rows)
    result = table.select(columns=["id", "price"], predicate=table["price"] == 0.29).read_all()

print(result.sort_by("id").to_pylist())
[{'id': 1, 'price': Decimal('0.28')}]

The row that comes back has price 0.28, not 0.29. To filter on an exact decimal, push down a range one unit of the scale (here 0.01) wider on each side, then compare exactly in Arrow:

with session.transaction() as tx:
    table = tx.bucket(BUCKET).schema("ref_data_types").table("samples")
    wide = table.select(columns=["id", "price"],
                        predicate=table["price"].between(0.28, 0.30)).read_all()

wanted = pa.scalar(decimal.Decimal("0.29"), pa.decimal128(10, 2))
exact = wide.filter(pc.equal(wide["price"], wanted))
print(exact.to_pylist())
[{'id': 2, 'price': Decimal('0.29')}]

Clean up:

with session.transaction() as tx:
    schema = tx.bucket(BUCKET).schema("ref_data_types")
    schema.table("samples").drop()
    schema.drop()
print("Dropped")
Dropped