This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 808338ea5aa GH-50622: [Docs][Format] Align Variant `typed_value` 
primitive type mappings with the Parquet shredding spec (#50810)
808338ea5aa is described below

commit 808338ea5aaf5f4c36a7e7d6af8e67a9f98b2bbc
Author: Kosta Tarasov <[email protected]>
AuthorDate: Mon Sep 21 06:23:20 2026 -0400

    GH-50622: [Docs][Format] Align Variant `typed_value` primitive type 
mappings with the Parquet shredding spec (#50810)
    
    ### Rationale for this change
    
    The existing Arrow spec is misleading and allows certain Arrow types to
    be typed value Variant fields. The Parquet Shredding spec specifically
    rejects them - Unsigned integers, Null.
    
    Decimal mapping needs clarification about precision.
    
    ### What changes are included in this PR?
    
    Change the Primitive Type Mappings table for Parquet Variant extension
    type.
    
    Rendered version -
    
https://github.com/sdf-jkl/arrow/blob/gh50622-variant-typed-value-mappings/docs/source/format/CanonicalExtensions.rst#primitive-type-mappings
    
    ### Are these changes tested?
    
    N/A
    
    ### Are there any user-facing changes?
    
    Changes to the Arrow docs
    
    Closes #50622
    
    * GitHub Issue: #50622
---
 docs/source/format/CanonicalExtensions.rst | 160 ++++++++++++++++++-----------
 1 file changed, 102 insertions(+), 58 deletions(-)

diff --git a/docs/source/format/CanonicalExtensions.rst 
b/docs/source/format/CanonicalExtensions.rst
index f1faa4a9e74..42c591c66cc 100644
--- a/docs/source/format/CanonicalExtensions.rst
+++ b/docs/source/format/CanonicalExtensions.rst
@@ -450,7 +450,7 @@ binary values look like.
     * A field named ``value`` which is of type ``Binary``, ``LargeBinary``, or 
``BinaryView``.
       (unshredded variants consist of just the ``metadata`` and ``value`` 
fields only)
 
-    * A field named ``typed_value`` which can be a 
:ref:`variant_primitive_type_mapping` or a ``List``, ``LargeList``, 
``ListView`` or ``Struct``
+    * A field named ``typed_value`` which can be any Arrow type listed in the 
:ref:`variant_primitive_type_mapping` or a ``List``, ``LargeList``, 
``ListView`` or ``Struct``
 
       * If the ``typed_value`` field is a ``List``, ``LargeList`` or 
``ListView`` its elements **must** be *non-nullable* and **must**
         be a ``Struct`` consisting of at least one (or both) of the following:
@@ -488,63 +488,107 @@ binary values look like.
 Primitive Type Mappings
 -----------------------
 
-+----------------------+------------------------+
-| Arrow Primitive Type | Variant Primitive Type |
-+======================+========================+
-| Null                 | Null                   |
-+----------------------+------------------------+
-| Boolean              | Boolean (true/false)   |
-+----------------------+------------------------+
-| Int8                 | Int8                   |
-+----------------------+------------------------+
-| Uint8                | Int16                  |
-+----------------------+------------------------+
-| Int16                | Int16                  |
-+----------------------+------------------------+
-| Uint16               | Int32                  |
-+----------------------+------------------------+
-| Int32                | Int32                  |
-+----------------------+------------------------+
-| Uint32               | Int64                  |
-+----------------------+------------------------+
-| Int64                | Int64                  |
-+----------------------+------------------------+
-| Float                | Float                  |
-+----------------------+------------------------+
-| Double               | Double                 |
-+----------------------+------------------------+
-| Decimal32            | decimal4               |
-+----------------------+------------------------+
-| Decimal64            | decimal8               |
-+----------------------+------------------------+
-| Decimal128           | decimal16              |
-+----------------------+------------------------+
-| Date32               | Date                   |
-+----------------------+------------------------+
-| Time64               | TimeNTZ                |
-+----------------------+------------------------+
-| Timestamp(us, UTC)   | Timestamp (micro)      |
-+----------------------+------------------------+
-| Timestamp(us)        | TimestampNTZ (micro)   |
-+----------------------+------------------------+
-| Timestamp(ns, UTC)   | Timestamp (nano)       |
-+----------------------+------------------------+
-| Timestamp(ns)        | TimestampNTZ (nano)    |
-+----------------------+------------------------+
-| Binary               | Binary                 |
-+----------------------+------------------------+
-| LargeBinary          | Binary                 |
-+----------------------+------------------------+
-| BinaryView           | Binary                 |
-+----------------------+------------------------+
-| String               | String                 |
-+----------------------+------------------------+
-| LargeString          | String                 |
-+----------------------+------------------------+
-| StringView           | String                 |
-+----------------------+------------------------+
-| UUID extension type  | UUID                   |
-+----------------------+------------------------+
+The following table defines the set of Arrow types that are valid as primitive
+``typed_value`` storage. It follows the `Shredded Value Types
+<https://github.com/apache/parquet-format/blob/master/VariantShredding.md#shredded-value-types>`__
+table of the Parquet Variant Shredding specification. Each row maps a Variant
+primitive type to the Parquet `physical type
+<https://parquet.apache.org/docs/file-format/types/>`__ and `logical type
+<https://parquet.apache.org/docs/file-format/types/logicaltypes/>`__
+annotation of a shredded ``typed_value`` column, and to the Arrow
+:ref:`data types <data_types>` covering that Variant type's full value
+domain. An empty *Parquet Logical Type* cell means the physical type carries
+no explicit annotation. This is intentional for ``int32`` and ``int64``:
+Parquet defines ``INT(32, true)`` and ``INT(64, true)`` as implied by the
+unannotated ``INT32`` and ``INT64`` physical types, respectively.
+
+A ``typed_value`` field of a listed Arrow type holds values of exactly the
+corresponding Variant type, and the listed physical and logical types are its
+only valid Parquet representation.
+
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+| Variant Type                           | Parquet Physical Type             | 
Parquet Logical 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 (1 <= P <= 9, 0 <= S <= P)    | INT32                             | 
DECIMAL(P, S)            | Decimal32(P, S)                             |
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+| decimal8 (10 <= P <= 18, 0 <= S <= P)  | INT64                             | 
DECIMAL(P, S)            | Decimal64(P, S)                             |
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+| decimal16 (19 <= P <= 38, 0 <= S <= P) | BYTE_ARRAY / FIXED_LEN_BYTE_ARRAY | 
DECIMAL(P, S)            | Decimal128(P, S)                            |
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+| 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                   | String / LargeString / StringView           |
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+| uuid                                   | FIXED_LEN_BYTE_ARRAY[len=16]      | 
UUID                     | :ref:`UUID extension type <uuid_extension>` |
++----------------------------------------+-----------------------------------+--------------------------+---------------------------------------------+
+
+The decimal precision bands follow the *Decimal table* of the `Variant
+encoding specification
+<https://github.com/apache/parquet-format/blob/master/VariantEncoding.md#encoding-types>`__
+(just below its *Encoding types* table). The bands are disjoint, so
+precision alone selects the row (the narrowest sufficient decimal type is
+required) and the scale must satisfy ``0 <= S <= P``. Arrow decimal types
+outside these bounds (a negative scale, or a wider decimal type than the
+precision requires) are not valid ``typed_value`` storage.
+
+.. note::
+
+   The bands reflect the underlying physical type: a Variant decimal
+   stores its unscaled value as a 4-, 8-, or 16-byte integer, capping the
+   precision at 9, 18, or 38 significant digits.
+
+   ``(P, S)`` refers to the Arrow data type of the ``typed_value`` field
+   (``Decimal32(7, 2)``, for example) and thus applies to the array as a
+   whole: an encoded decimal value carries only a scale (its precision is
+   implied by the unscaled value), while the field's type fixes one
+   precision and scale for every row. A value that the field's type cannot
+   represent is not shredded and remains Variant-encoded in the ``value``
+   field.
+
+.. note::
+
+   Arrow types without a row in this table (such as ``Null`` or the unsigned
+   integer types) must not be used as ``typed_value`` storage, as they have no
+   valid Parquet shredded representation:
+
+   * A Variant null is a present Variant value. It is distinct from a null slot
+     in the corresponding Arrow extension array, which is represented by the
+     storage ``Struct``'s validity bitmap. A Variant null is always encoded in
+     the ``value`` field (as ``00``), never in ``typed_value``. A null
+     ``typed_value`` signals that the row is not shredded. For shredded object
+     fields, a null ``typed_value`` together with a null ``value`` means the
+     field is missing.
+
+   * Variant has no unsigned integer types, so unsigned Arrow values must be
+     converted to a signed Variant type wide enough to hold them: for example,
+     ``UInt8`` values become Variant ``int16``, stored either Variant-encoded
+     in ``value`` or in an ``Int16`` ``typed_value`` column.
 
 .. _timestamp_with_offset_extension:
 

Reply via email to