Skip to content

Commit 460a82d

Browse files
committed
Consolidate chunk_constraint migrations
Drop two redundant DELETEs from latest-dev.sql; the table is dropped later in the same script so clearing rows first is pointless. Reorder reverse-dev.sql so dimension_slice is rebuilt before chunk_constraint is recreated.
1 parent f3d27a8 commit 460a82d

2 files changed

Lines changed: 95 additions & 122 deletions

File tree

sql/updates/latest-dev.sql

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@ BEGIN
1111
END;
1212
$$;
1313

14-
-- Drop obsolete chunk_constraint rows for inherited CHECK constraints on
15-
-- OSM chunks; PG inheritance handles propagation now.
16-
DELETE FROM _timescaledb_catalog.chunk_constraint cc
17-
USING _timescaledb_catalog.chunk c
18-
WHERE cc.chunk_id = c.id
19-
AND c.osm_chunk
20-
AND cc.dimension_slice_id IS NULL
21-
AND cc.hypertable_constraint_name IS NOT NULL
22-
AND cc.constraint_name = cc.hypertable_constraint_name;
23-
2414
-- Rename legacy chunk-side constraints to the names the new code recomputes:
2515
-- FKs use the parent's name; unique/PK/exclusion/trigger use the deterministic
2616
-- "<chunk_id>_<parent>" form
@@ -52,14 +42,6 @@ BEGIN
5242
END
5343
$$;
5444

55-
-- Remove the chunk_constraint rows that mirrored non-dimensional constraints.
56-
-- FK chunk-side constraints are now located by name through the event-trigger
57-
-- hooks; unique/PK/exclusion/trigger constraints through the deterministic
58-
-- "<chunk_id>_<parent>" name pattern.
59-
DELETE FROM _timescaledb_catalog.chunk_constraint
60-
WHERE dimension_slice_id IS NULL
61-
AND hypertable_constraint_name IS NOT NULL;
62-
6345
ALTER TABLE _timescaledb_catalog.hypertable SET (user_catalog_table = true);
6446
ALTER TABLE _timescaledb_catalog.chunk SET (user_catalog_table = true);
6547

sql/updates/reverse-dev.sql

Lines changed: 95 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,87 @@
22
DROP VIEW IF EXISTS _timescaledb_catalog.chunk_constraint;
33
DROP FUNCTION IF EXISTS _timescaledb_functions.chunk_constraint_add_table_constraint( integer, name, name);
44

5+
ALTER TABLE _timescaledb_catalog.hypertable RESET (user_catalog_table);
6+
ALTER TABLE _timescaledb_catalog.chunk RESET (user_catalog_table);
7+
8+
--
9+
-- Rebuild the catalog table `_timescaledb_catalog.dimension_slice` back to
10+
-- the pre-chunk_id schema. Per-chunk slice duplicates are collapsed back
11+
-- into one shared row per (dimension_id, range_start, range_end), and the
12+
-- old UNIQUE on that triple is restored.
13+
--
14+
CREATE TABLE _timescaledb_internal.tmp_dimension_slice AS
15+
SELECT * FROM _timescaledb_catalog.dimension_slice;
16+
CREATE TABLE _timescaledb_internal.tmp_dimension_slice_seq_value AS
17+
SELECT last_value, is_called FROM _timescaledb_catalog.dimension_slice_id_seq;
18+
19+
ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.dimension_slice;
20+
ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.dimension_slice_id_seq;
21+
22+
DROP TABLE _timescaledb_catalog.dimension_slice;
23+
24+
CREATE TABLE _timescaledb_catalog.dimension_slice (
25+
id serial NOT NULL,
26+
dimension_id integer NOT NULL,
27+
range_start bigint NOT NULL,
28+
range_end bigint NOT NULL,
29+
CONSTRAINT dimension_slice_pkey PRIMARY KEY (id),
30+
CONSTRAINT dimension_slice_dimension_id_range_start_range_end_key UNIQUE (dimension_id, range_start, range_end),
31+
CONSTRAINT dimension_slice_check CHECK (range_start <= range_end),
32+
CONSTRAINT dimension_slice_dimension_id_fkey FOREIGN KEY (dimension_id) REFERENCES _timescaledb_catalog.dimension (id) ON DELETE CASCADE
33+
);
34+
35+
-- One row per unique (dimension_id, range_start, range_end), reusing the
36+
-- lowest old id so the chunk-side CHECK named constraint_<min_id> keeps the
37+
-- correct name without renaming.
38+
INSERT INTO _timescaledb_catalog.dimension_slice (id, dimension_id, range_start, range_end)
39+
SELECT min(id), dimension_id, range_start, range_end
40+
FROM _timescaledb_internal.tmp_dimension_slice
41+
GROUP BY dimension_id, range_start, range_end;
42+
43+
-- Rename chunk-side CHECK constraints from constraint_<old_id> to
44+
-- constraint_<kept_id> for chunks whose per-chunk slice was collapsed onto
45+
-- a shared row. Keeps the legacy invariant
46+
-- constraint_name == 'constraint_<dimension_slice_id>'.
47+
DO $$
48+
DECLARE
49+
r RECORD;
50+
BEGIN
51+
FOR r IN
52+
SELECT pg_catalog.format('%I.%I', c.schema_name, c.table_name) AS chunk_table,
53+
format('constraint_%s', tmp.id)::name AS old_name,
54+
format('constraint_%s', ds.id)::name AS new_name
55+
FROM _timescaledb_internal.tmp_dimension_slice tmp
56+
JOIN _timescaledb_catalog.chunk c ON c.id = tmp.chunk_id
57+
JOIN _timescaledb_catalog.dimension_slice ds
58+
ON ds.dimension_id = tmp.dimension_id
59+
AND ds.range_start = tmp.range_start
60+
AND ds.range_end = tmp.range_end
61+
WHERE tmp.id <> ds.id
62+
AND EXISTS (
63+
SELECT 1 FROM pg_constraint pc
64+
WHERE pc.conrelid = pg_catalog.format('%I.%I', c.schema_name, c.table_name)::regclass
65+
AND pc.conname = format('constraint_%s', tmp.id)::name
66+
AND pc.contype = 'c'
67+
)
68+
LOOP
69+
EXECUTE pg_catalog.format('ALTER TABLE %s RENAME CONSTRAINT %I TO %I',
70+
r.chunk_table, r.old_name, r.new_name);
71+
END LOOP;
72+
END
73+
$$;
74+
75+
ALTER SEQUENCE _timescaledb_catalog.dimension_slice_id_seq OWNED BY _timescaledb_catalog.dimension_slice.id;
76+
SELECT setval('_timescaledb_catalog.dimension_slice_id_seq', last_value, is_called)
77+
FROM _timescaledb_internal.tmp_dimension_slice_seq_value;
78+
79+
SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.dimension_slice', '');
80+
SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.dimension_slice', 'id'), '');
81+
82+
GRANT SELECT ON _timescaledb_catalog.dimension_slice TO PUBLIC;
83+
GRANT SELECT ON _timescaledb_catalog.dimension_slice_id_seq TO PUBLIC;
84+
-- end rebuild _timescaledb_catalog.dimension_slice table --
85+
586
-- Recreate the chunk_constraint catalog table.
687
CREATE TABLE _timescaledb_catalog.chunk_constraint (
788
chunk_id integer NOT NULL,
@@ -23,11 +104,17 @@ SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.chunk_constrain
23104
GRANT SELECT ON _timescaledb_catalog.chunk_constraint TO PUBLIC;
24105
GRANT SELECT ON _timescaledb_catalog.chunk_constraint_name TO PUBLIC;
25106

26-
-- Restore the dimensional rows from the per-chunk slice rows.
107+
-- Restore dimensional rows. Join the per-chunk snapshot to the rebuilt
108+
-- (deduplicated) dimension_slice so each chunk_constraint row points
109+
-- directly at the kept slice id.
27110
INSERT INTO _timescaledb_catalog.chunk_constraint
28111
(chunk_id, dimension_slice_id, constraint_name, hypertable_constraint_name)
29-
SELECT chunk_id, id, format('constraint_%s', id)::name, ''::name
30-
FROM _timescaledb_catalog.dimension_slice;
112+
SELECT tmp.chunk_id, ds.id, format('constraint_%s', ds.id)::name, ''::name
113+
FROM _timescaledb_internal.tmp_dimension_slice tmp
114+
JOIN _timescaledb_catalog.dimension_slice ds
115+
ON ds.dimension_id = tmp.dimension_id
116+
AND ds.range_start = tmp.range_start
117+
AND ds.range_end = tmp.range_end;
31118

32119
-- Restore chunk_constraint rows for CHECK constraints on OSM chunks.
33120
INSERT INTO _timescaledb_catalog.chunk_constraint
@@ -41,11 +128,6 @@ JOIN pg_constraint con
41128
WHERE c.osm_chunk
42129
ON CONFLICT DO NOTHING;
43130

44-
-- Drop chunk stats related objects
45-
DROP VIEW IF EXISTS timescaledb_information.stat_chunk_activity;
46-
DROP FUNCTION IF EXISTS _timescaledb_functions.chunk_statistics(regclass, regclass, timestamptz);
47-
DROP FUNCTION IF EXISTS _timescaledb_functions.chunk_statistics_reset();
48-
49131
-- Restore chunk_constraint rows for outbound FKs by matching chunk-side
50132
-- FKs to their hypertable-side counterpart by name.
51133
INSERT INTO _timescaledb_catalog.chunk_constraint
@@ -77,115 +159,24 @@ JOIN pg_constraint child
77159
AND child.conname = format('%s_%s', c.id, parent.conname)
78160
ON CONFLICT DO NOTHING;
79161

80-
ALTER TABLE _timescaledb_catalog.hypertable RESET (user_catalog_table);
81-
ALTER TABLE _timescaledb_catalog.chunk RESET (user_catalog_table);
82-
83-
--
84-
-- Rebuild the catalog table `_timescaledb_catalog.dimension_slice` back to
85-
-- the pre-chunk_id schema. Per-chunk slice duplicates are collapsed back
86-
-- into one shared row per (dimension_id, range_start, range_end), and the
87-
-- old UNIQUE on that triple is restored.
88-
--
89-
CREATE TABLE _timescaledb_internal.tmp_dimension_slice AS
90-
SELECT * FROM _timescaledb_catalog.dimension_slice;
91-
CREATE TABLE _timescaledb_internal.tmp_dimension_slice_seq_value AS
92-
SELECT last_value, is_called FROM _timescaledb_catalog.dimension_slice_id_seq;
93-
94-
ALTER EXTENSION timescaledb DROP TABLE _timescaledb_catalog.dimension_slice;
95-
ALTER EXTENSION timescaledb DROP SEQUENCE _timescaledb_catalog.dimension_slice_id_seq;
96-
97-
DROP TABLE _timescaledb_catalog.dimension_slice;
98-
99-
CREATE TABLE _timescaledb_catalog.dimension_slice (
100-
id serial NOT NULL,
101-
dimension_id integer NOT NULL,
102-
range_start bigint NOT NULL,
103-
range_end bigint NOT NULL,
104-
CONSTRAINT dimension_slice_pkey PRIMARY KEY (id),
105-
CONSTRAINT dimension_slice_dimension_id_range_start_range_end_key UNIQUE (dimension_id, range_start, range_end),
106-
CONSTRAINT dimension_slice_check CHECK (range_start <= range_end),
107-
CONSTRAINT dimension_slice_dimension_id_fkey FOREIGN KEY (dimension_id) REFERENCES _timescaledb_catalog.dimension (id) ON DELETE CASCADE
108-
);
109-
110-
-- One row per unique (dimension_id, range_start, range_end), reusing the
111-
-- lowest old id so existing chunk_constraint rows that already point at
112-
-- it don't need repointing.
113-
INSERT INTO _timescaledb_catalog.dimension_slice (id, dimension_id, range_start, range_end)
114-
SELECT min(id), dimension_id, range_start, range_end
115-
FROM _timescaledb_internal.tmp_dimension_slice
116-
GROUP BY dimension_id, range_start, range_end;
117-
118-
-- Repoint chunk_constraint rows that referenced one of the deduplicated
119-
-- (now deleted) slice ids at the kept slice with the same range.
120-
UPDATE _timescaledb_catalog.chunk_constraint cc
121-
SET dimension_slice_id = ds.id
122-
FROM _timescaledb_internal.tmp_dimension_slice tmp,
123-
_timescaledb_catalog.dimension_slice ds
124-
WHERE cc.dimension_slice_id IS NOT NULL
125-
AND tmp.id = cc.dimension_slice_id
126-
AND tmp.id <> ds.id
127-
AND ds.dimension_id = tmp.dimension_id
128-
AND ds.range_start = tmp.range_start
129-
AND ds.range_end = tmp.range_end;
130-
131-
-- Restore the legacy invariant constraint_name == 'constraint_<dimension_slice_id>'
132-
-- for rows whose dimension_slice_id was just repointed at a deduplicated slice.
133-
-- Rename the chunk-side CHECK on disk and update the catalog row in lockstep.
134-
DO $$
135-
DECLARE
136-
r RECORD;
137-
BEGIN
138-
FOR r IN
139-
SELECT pg_catalog.format('%I.%I', c.schema_name, c.table_name) AS chunk_table,
140-
cc.constraint_name AS old_name,
141-
format('constraint_%s', cc.dimension_slice_id)::name AS new_name,
142-
cc.chunk_id,
143-
cc.dimension_slice_id
144-
FROM _timescaledb_catalog.chunk_constraint cc
145-
JOIN _timescaledb_catalog.chunk c ON c.id = cc.chunk_id
146-
WHERE cc.dimension_slice_id IS NOT NULL
147-
AND cc.constraint_name <> format('constraint_%s', cc.dimension_slice_id)::name
148-
AND EXISTS (
149-
SELECT 1 FROM pg_constraint pc
150-
WHERE pc.conrelid = pg_catalog.format('%I.%I', c.schema_name, c.table_name)::regclass
151-
AND pc.conname = cc.constraint_name
152-
AND pc.contype = 'c'
153-
)
154-
LOOP
155-
EXECUTE pg_catalog.format('ALTER TABLE %s RENAME CONSTRAINT %I TO %I',
156-
r.chunk_table, r.old_name, r.new_name);
157-
UPDATE _timescaledb_catalog.chunk_constraint
158-
SET constraint_name = r.new_name
159-
WHERE chunk_id = r.chunk_id
160-
AND dimension_slice_id = r.dimension_slice_id;
161-
END LOOP;
162-
END
163-
$$;
164-
165-
ALTER SEQUENCE _timescaledb_catalog.dimension_slice_id_seq OWNED BY _timescaledb_catalog.dimension_slice.id;
166-
SELECT setval('_timescaledb_catalog.dimension_slice_id_seq', last_value, is_called)
167-
FROM _timescaledb_internal.tmp_dimension_slice_seq_value;
168-
169162
ALTER TABLE _timescaledb_catalog.chunk_constraint
170163
ADD CONSTRAINT chunk_constraint_dimension_slice_id_fkey
171164
FOREIGN KEY (dimension_slice_id) REFERENCES _timescaledb_catalog.dimension_slice (id);
172165

173166
DROP TABLE _timescaledb_internal.tmp_dimension_slice;
174167
DROP TABLE _timescaledb_internal.tmp_dimension_slice_seq_value;
175168

176-
SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.dimension_slice', '');
177-
SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.dimension_slice', 'id'), '');
178-
179-
GRANT SELECT ON _timescaledb_catalog.dimension_slice TO PUBLIC;
180-
GRANT SELECT ON _timescaledb_catalog.dimension_slice_id_seq TO PUBLIC;
181-
-- end rebuild _timescaledb_catalog.dimension_slice table --
169+
-- Drop chunk stats related objects
170+
DROP VIEW IF EXISTS timescaledb_information.stat_chunk_activity;
171+
DROP FUNCTION IF EXISTS _timescaledb_functions.chunk_statistics(regclass, regclass, timestamptz);
172+
DROP FUNCTION IF EXISTS _timescaledb_functions.chunk_statistics_reset();
182173

183174
DROP FUNCTION IF EXISTS @extschema@.create_hypertable(relation REGCLASS, time_column_name NAME, partitioning_column NAME, number_partitions INTEGER, associated_schema_name NAME, associated_table_prefix NAME, chunk_time_interval ANYELEMENT, create_default_indexes BOOLEAN, if_not_exists BOOLEAN, partitioning_func REGPROC, migrate_data BOOLEAN, time_partitioning_func REGPROC);
184175

185-
186176
-- Restore the chunk_target_size check constraint dropped in the forward path.
187177
ALTER TABLE _timescaledb_catalog.hypertable
188178
ADD CONSTRAINT hypertable_chunk_target_size_check CHECK (chunk_target_size >= 0);
179+
189180
DROP FUNCTION IF EXISTS _timescaledb_functions.rebuild_sparse_index(REGCLASS, BOOLEAN);
190181

191182
-- Rebuild the catalog table `_timescaledb_catalog.continuous_agg` to drop the

0 commit comments

Comments
 (0)