Skip to content

[Docs][Format] Variant extension: align typed_value primitive type mappings with the Parquet shredding spec #50622

Description

@sdf-jkl

Describe the enhancement requested

The Primitive Type Mappings table in the Variant canonical extension is the normative list of Arrow types allowed for typed_value. The only place the table is referenced from is the typed_value storage rule, so its whole role is defining legal typed_value types:

* A field named ``typed_value`` which can be a :ref:`variant_primitive_type_mapping` or a ``List``, ``LargeList``, ``ListView`` or ``Struct``

The table appears to be derived from the Variant encoding types table (https://github.com/apache/parquet-format/blob/master/VariantEncoding.md#encoding-types), but its role corresponds to the shredding spec's Shredded Value Types table (https://github.com/apache/parquet-format/blob/master/VariantShredding.md#shredded-value-types), which defines what a typed_value column may be. The two tables differ, so the Arrow table currently allows storage with no valid Parquet shredded representation:

In practice the unsigned path already produces non-conformant files: Arrow Go writes unsigned typed_value columns to Parquet with INT(8/16/32, false) annotations, which the shredding spec does not allow.

Proposal: re-derive the table from the shredding spec's Shredded Value Types table. Each row maps one variant type to its Parquet shredded type and the Arrow storage type(s) able to represent its full value domain. The table then defines reconstruction (a typed_value column of the listed Arrow type holds values of exactly the listed variant type) and the write-side lowering (the Parquet column is the only valid Parquet representation).

Variant type Parquet type Arrow typed_value type
boolean BOOLEAN Boolean
int8 INT32, INT(8, true) Int8
int16 INT32, INT(16, true) Int16
int32 INT32 Int32
int64 INT64 Int64
float FLOAT Float32
double DOUBLE Float64
decimal4 INT32, DECIMAL(P, S) Decimal32(P, S), 1 <= P <= 9
decimal8 INT64, DECIMAL(P, S) Decimal64(P, S), 10 <= P <= 18
decimal16 BYTE_ARRAY / FIXED_LEN_BYTE_ARRAY, DECIMAL(P, S) Decimal128(P, S), 19 <= P <= 38
date INT32, DATE Date32
time INT64, TIME(false, MICROS) Time64(us)
timestamptz(6) INT64, TIMESTAMP(true, MICROS) Timestamp(us, UTC)
timestamptz(9) INT64, TIMESTAMP(true, NANOS) Timestamp(ns, UTC)
timestampntz(6) INT64, TIMESTAMP(false, MICROS) Timestamp(us)
timestampntz(9) INT64, TIMESTAMP(false, NANOS) Timestamp(ns)
binary BYTE_ARRAY Binary / LargeBinary / BinaryView
string BYTE_ARRAY, STRING Utf8 / LargeUtf8 / Utf8View
uuid FIXED_LEN_BYTE_ARRAY[len=16], UUID UUID extension type

The decimal precision bands follow the decimal table in VariantEncoding.md: precision alone selects the physical type (the bands are disjoint, so the narrowest type is required), and scale must satisfy 0 <= S <= P.

This also resolves three existing ambiguities: the current Time64 row gains its required unit (variant time is micros only), the timestamp rows gain explicit units, and the decimal rows gain their precision bounds.

Related: #50620, apache/parquet-format#591

Component(s)

Format

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions