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

voonhous pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/hudi.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 2f77af6096af docs(sql-ddl): partition columns must be declared last in 
CREATE TABLE (#19555)
2f77af6096af is described below

commit 2f77af6096af3c3a918092edf34b620d72f0adbb
Author: deepakpanda93 <[email protected]>
AuthorDate: Sun Aug 9 12:46:51 2026 +0530

    docs(sql-ddl): partition columns must be declared last in CREATE TABLE 
(#19555)
    
    Spark moves partition columns to the end of the table schema. Declaring one
    earlier makes the stored column order differ from what was written, and a
    positional INSERT then assigns values to the wrong columns.
    
    Verified on Spark 3.5.7 with Hudi 1.2.0. Declaring
    (id, name, price, dt, ts) with PARTITIONED BY (dt) stores the table as
    (id, name, price, ts, dt), and `insert into t select 
1,'a1',10.0,'2021-03-21',1L`
    fails with
    
        [INCOMPATIBLE_DATA_FOR_TABLE.CANNOT_SAFELY_CAST]
        Cannot safely cast `ts` "STRING" to "BIGINT"
    
    which is the symptom reported in the issue. Worse, when the shifted columns
    happen to be type-compatible there is no error at all: declaring
    (id, a, dt, b) as strings and inserting 1,'VALUE_A','VALUE_DT','VALUE_B'
    returns exit 0 and stores b='VALUE_DT' with dt='VALUE_B', putting the
    partition value in a data column and vice versa.
    
    The example in this section was an instance of that. With schema
    (id, name, dt, hh) and PARTITIONED BY (dt), hh trails the partition column,
    so Spark stores (id, name, hh, dt) and a reader following the example
    silently gets hh='2024-01-01' and dt='10'. Partitioning by both columns
    fixes it without touching the schema: dt and hh are then the trailing
    columns already, in declaration order, so nothing is reordered and the
    positional insert lands correctly. Measured on all four variants of this
    schema -- PARTITIONED BY (dt) misplaces values, (dt, hh) and (hh) are
    correct, and (hh, dt) is rejected outright by
    HoodieSchemaUtils.checkPartitionSchemaOrder.
    
    The multi-field note is unchanged and remains correct.
    
    Applied to next and to every 1.x versioned copy, which all carried the same
    broken example. This is a correction rather than an addition, so it follows
    the wider backport used in apache/hudi#19459 rather than the
    next-plus-current convention. Re-ran the decisive pair against the 1.0.2
    bundle to confirm the older releases behave identically: PARTITIONED BY (dt)
    stores (id, name, hh, dt) and yields dt='10', hh='2024-01-01', while
    (dt, hh) leaves the order untouched and lands correctly.
    
    The 0.14.x and 0.15.x copies carry the same broken example and are left
    alone as end-of-life.
    
    Closes #17357.
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 website/docs/sql_ddl.md                         | 14 ++++++++++++--
 website/versioned_docs/version-1.0.0/sql_ddl.md | 12 +++++++++++-
 website/versioned_docs/version-1.0.1/sql_ddl.md | 12 +++++++++++-
 website/versioned_docs/version-1.0.2/sql_ddl.md | 12 +++++++++++-
 website/versioned_docs/version-1.1.1/sql_ddl.md | 12 +++++++++++-
 website/versioned_docs/version-1.2.0/sql_ddl.md | 14 ++++++++++++--
 6 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/website/docs/sql_ddl.md b/website/docs/sql_ddl.md
index f18f14812686..150a8197ffc0 100644
--- a/website/docs/sql_ddl.md
+++ b/website/docs/sql_ddl.md
@@ -2,7 +2,7 @@
 title: SQL DDL
 summary: "In this page, we discuss using SQL DDL commands with Hudi"
 toc: true
-last_modified_at: 2026-05-29T00:00:00-00:00
+last_modified_at: 2026-08-07T20:54:32+05:30
 ---
 import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 
diff --git a/website/versioned_docs/version-1.0.0/sql_ddl.md 
b/website/versioned_docs/version-1.0.0/sql_ddl.md
index 565a62f480ef..edb256b96b32 100644
--- a/website/versioned_docs/version-1.0.0/sql_ddl.md
+++ b/website/versioned_docs/version-1.0.0/sql_ddl.md
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 
diff --git a/website/versioned_docs/version-1.0.1/sql_ddl.md 
b/website/versioned_docs/version-1.0.1/sql_ddl.md
index 565a62f480ef..edb256b96b32 100644
--- a/website/versioned_docs/version-1.0.1/sql_ddl.md
+++ b/website/versioned_docs/version-1.0.1/sql_ddl.md
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 
diff --git a/website/versioned_docs/version-1.0.2/sql_ddl.md 
b/website/versioned_docs/version-1.0.2/sql_ddl.md
index 565a62f480ef..edb256b96b32 100644
--- a/website/versioned_docs/version-1.0.2/sql_ddl.md
+++ b/website/versioned_docs/version-1.0.2/sql_ddl.md
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 
diff --git a/website/versioned_docs/version-1.1.1/sql_ddl.md 
b/website/versioned_docs/version-1.1.1/sql_ddl.md
index d1c5ba865bdb..a522fa83515a 100644
--- a/website/versioned_docs/version-1.1.1/sql_ddl.md
+++ b/website/versioned_docs/version-1.1.1/sql_ddl.md
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 
diff --git a/website/versioned_docs/version-1.2.0/sql_ddl.md 
b/website/versioned_docs/version-1.2.0/sql_ddl.md
index f18f14812686..150a8197ffc0 100644
--- a/website/versioned_docs/version-1.2.0/sql_ddl.md
+++ b/website/versioned_docs/version-1.2.0/sql_ddl.md
@@ -2,7 +2,7 @@
 title: SQL DDL
 summary: "In this page, we discuss using SQL DDL commands with Hudi"
 toc: true
-last_modified_at: 2026-05-29T00:00:00-00:00
+last_modified_at: 2026-08-07T20:54:32+05:30
 ---
 import Tabs from '@theme/Tabs';
 import TabItem from '@theme/TabItem';
@@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS hudi_table_partitioned (
 TBLPROPERTIES (
   type = 'cow'
 )
-PARTITIONED BY (dt);
+PARTITIONED BY (dt, hh);
 ```
 
 :::note
@@ -73,6 +73,16 @@ in the same order as they appear in the `CREATE TABLE` 
schema. For example, for
 should be specified as `PARTITIONED BY (dt, hh)`.
 :::
 
+:::caution
+Declare partition columns last in the `CREATE TABLE` column list. Spark moves 
partition columns to the end of the table
+schema, so declaring one earlier makes the stored column order differ from 
what you wrote. Declaring
+`(id, name, price, dt, ts)` with `PARTITIONED BY (dt)`, for example, stores 
the table as `(id, name, price, ts, dt)`.
+A positional `INSERT INTO ... SELECT` then assigns values to the wrong 
columns: it fails with `CANNOT_SAFELY_CAST` when
+the shifted types are incompatible, and writes values to the wrong columns 
without reporting an error when they are
+compatible. Naming the columns explicitly, as in `INSERT INTO tbl (id, name, 
price, dt, ts) SELECT ...`, also avoids the
+mismatch.
+:::
+
 ### Create table with record keys and ordering fields
 
 As discussed [here](quick-start-guide.md#keys), tables track each record in 
the table using a record key. Hudi auto-generated a highly compressed 

Reply via email to