Skip to content

Commit 776be7a

Browse files
authored
Merge pull request #301 from benfleis/fix-partition-null-value-handling
update partition empty/null handling to match protocol
2 parents df4a08d + f6f9344 commit 776be7a

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

src/storage/delta_insert.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ static void AddWrittenFiles(DeltaInsertGlobalState &global_state, DataChunk &chu
219219
auto &partition_children = MapValue::GetChildren(partition_info);
220220
for (idx_t col_idx = 0; col_idx < partition_children.size(); col_idx++) {
221221
auto &struct_children = StructValue::GetChildren(partition_children[col_idx]);
222-
auto &part_value = StringValue::Get(struct_children[1]);
222+
// from PROTOCOL doc, Partition Value Serialization: null values are serialized as "".
223+
auto part_value = struct_children[1].IsNull() ? string() : StringValue::Get(struct_children[1]);
223224

224225
DeltaPartition file_partition_info;
225226
file_partition_info.partition_column_idx = col_idx;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# name: test/sql/generated/writing/append/write_null_partition.test
2+
# description: null partition values must round-trip: written as "" in the log, read back as NULL
3+
# group: [append]
4+
5+
require parquet
6+
7+
require delta
8+
9+
require json
10+
11+
require-env GENERATED_DATA_AVAILABLE
12+
13+
statement ok
14+
from copy_dir('data/generated/simple_partitioned', '__TEST_DIR__/write_null_partition/simple_partitioned');
15+
16+
statement ok
17+
ATTACH '__TEST_DIR__/write_null_partition/simple_partitioned/delta_lake' AS t (TYPE delta);
18+
19+
# Baseline
20+
query II
21+
SELECT count(*), sum(i) FROM t;
22+
----
23+
10 45
24+
25+
# Insert a row with NULL for the partition column.
26+
statement ok
27+
INSERT INTO t VALUES (99, NULL);
28+
29+
# from protocol's Partition Value Serialization: "An empty string for any
30+
# type translates to a null partition value" — the written log entry must
31+
# have "" for the null value.
32+
query I
33+
SELECT json_extract_string(add.partitionValues, '$.part')
34+
FROM read_json('__TEST_DIR__/write_null_partition/simple_partitioned/delta_lake/_delta_log/00000000000000000001.json')
35+
WHERE add IS NOT NULL;
36+
----
37+
(empty)
38+
39+
# Verify round-trip: 11 rows total, only 10 have a non-null part
40+
query II
41+
SELECT count(*), count(part) FROM t;
42+
----
43+
11 10
44+
45+
# The inserted row is retrievable via IS NULL
46+
query I
47+
SELECT i FROM t WHERE part IS NULL;
48+
----
49+
99
50+
51+
# Confirm that part=NULL directory is encoded as part=__HIVE_DEFAULT_PARTITION__
52+
statement ok
53+
FROM read_parquet('__TEST_DIR__/write_null_partition/simple_partitioned/delta_lake/part=__HIVE_DEFAULT_PARTITION__/*.parquet');

0 commit comments

Comments
 (0)