diff --git a/CHANGELOG.md b/CHANGELOG.md index e81c3db..680ac9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), version ## [Unreleased] +## [0.1.3] - 2026-06-09 + +### Fixed + +- **Timezone-stable chunk names.** `_ensure_partitions` rendered `chunk_name` with `to_char(range_start, …)` in the **session timezone**, while `range_start` is an absolute `timestamptz`. Running the partition manager under different session timezones (e.g. a job in UTC vs a client in UTC+2) produced names that no longer matched `range_start`, so the partition manager hit `duplicate key value violates unique constraint "idx_chunk_metadata_chunk_name"` (the `ON CONFLICT (chronotable_id, range_start)` couldn't absorb a `chunk_name` collision). Names are now rendered from the instant in UTC (`v_start AT TIME ZONE 'UTC'`), keeping `chunk_name` 1:1 with `range_start` regardless of session timezone. + +Upgrade by reinstalling `dist/lakets.sql`. Any chunk rows created before this fix under a non-UTC session keep their old names; if the partition manager still collides, drop the stale rows for already-dropped chunks (their partitions are gone) and let it recreate them. + ## [0.1.2] - 2026-06-08 ### Fixed diff --git a/VERSION b/VERSION index d917d3e..b1e80bb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.2 +0.1.3 diff --git a/sql/00_version.sql b/sql/00_version.sql index dc749d4..8822610 100644 --- a/sql/00_version.sql +++ b/sql/00_version.sql @@ -22,7 +22,7 @@ SET client_min_messages TO NOTICE; DO $$ DECLARE v_installed TEXT; - v_incoming TEXT := coalesce(nullif('__LAKETS_VERSION__', '__LAKE' || 'TS_VERSION__'), '0.1.2'); + v_incoming TEXT := coalesce(nullif('__LAKETS_VERSION__', '__LAKE' || 'TS_VERSION__'), '0.1.3'); v_installed_parts INT[]; v_incoming_parts INT[]; BEGIN diff --git a/sql/02_chronotable.sql b/sql/02_chronotable.sql index a5adba7..7860e26 100644 --- a/sql/02_chronotable.sql +++ b/sql/02_chronotable.sql @@ -64,16 +64,21 @@ BEGIN AND status != 'dropped' ) THEN BEGIN + -- Render the chunk name from the absolute instant in UTC. range_start + -- is a timestamptz, so to_char in the session timezone would name the + -- same chunk differently across sessions (e.g. a job in UTC vs a client + -- in UTC+2), desyncing chunk_name from range_start and colliding on the + -- chunk_name unique index. UTC keeps the name 1:1 with range_start. EXECUTE format( 'CREATE TABLE IF NOT EXISTS %I.%I PARTITION OF %I.%I FOR VALUES FROM (%L) TO (%L)', v_schema, - v_table || '_' || to_char(v_start, 'YYYYMMDD_HH24MISS'), + v_table || '_' || to_char(v_start AT TIME ZONE 'UTC', 'YYYYMMDD_HH24MISS'), v_schema, v_table, v_start, v_end ); INSERT INTO lakets._chunk_metadata (chronotable_id, chunk_name, range_start, range_end, status) VALUES (p_chronotable_id, - v_schema || '.' || v_table || '_' || to_char(v_start, 'YYYYMMDD_HH24MISS'), + v_schema || '.' || v_table || '_' || to_char(v_start AT TIME ZONE 'UTC', 'YYYYMMDD_HH24MISS'), v_start, v_end, 'active') ON CONFLICT (chronotable_id, range_start) DO NOTHING; v_partitions_created := v_partitions_created + 1;