@@ -235,3 +235,122 @@ DROP TABLE regular_table_to_attach;
235235DROP TABLE attach_test_ref;
236236DROP TABLE attach_test;
237237DROP TABLE devices CASCADE;
238+ -- Test dropping columns after detach/attach
239+ CREATE TABLE drop_after_attach(time timestamptz NOT NULL, x int);
240+ SELECT create_hypertable('drop_after_attach', 'time', chunk_time_interval => interval '1 day');
241+ create_hypertable
242+ --------------------------------
243+ (3,public,drop_after_attach,t)
244+
245+ INSERT INTO drop_after_attach VALUES ('2026-01-01', 1), ('2026-01-05', 1);
246+ SELECT schema_name || '.' || table_name AS "ROUNDTRIP_CHUNK", slices AS "ROUNDTRIP_SLICES"
247+ FROM _timescaledb_functions.show_chunk((SELECT show_chunks('drop_after_attach', older_than => '2026-01-02') LIMIT 1)); \gset
248+ ROUNDTRIP_CHUNK | ROUNDTRIP_SLICES
249+ -----------------------------------------+------------------------------------------------
250+ _timescaledb_internal._hyper_3_15_chunk | {"time": [1767225600000000, 1767312000000000]}
251+
252+ CALL detach_chunk(:'ROUNDTRIP_CHUNK');
253+ CALL attach_chunk('drop_after_attach', :'ROUNDTRIP_CHUNK', :'ROUNDTRIP_SLICES');
254+ -- The re-attached chunk inherits without any locally-defined columns.
255+ SELECT attname, attislocal, attinhcount
256+ FROM pg_attribute
257+ WHERE attrelid = :'ROUNDTRIP_CHUNK'::regclass AND attnum > 0 AND NOT attisdropped
258+ ORDER BY attnum;
259+ attname | attislocal | attinhcount
260+ ---------+------------+-------------
261+ time | f | 1
262+ x | f | 1
263+
264+ ALTER TABLE drop_after_attach DROP COLUMN x;
265+ -- The column is gone from the round-tripped chunk, not left orphaned.
266+ SELECT attname, attislocal, attinhcount
267+ FROM pg_attribute
268+ WHERE attrelid = :'ROUNDTRIP_CHUNK'::regclass AND attname = 'x' AND NOT attisdropped;
269+ attname | attislocal | attinhcount
270+ ---------+------------+-------------
271+
272+ DROP TABLE drop_after_attach;
273+ -- Test dropping a constraint after detach/attach
274+ CREATE TABLE drop_con_after_attach(time timestamptz NOT NULL, x int CHECK (x > 0));
275+ SELECT create_hypertable('drop_con_after_attach', 'time', chunk_time_interval => interval '1 day');
276+ create_hypertable
277+ ------------------------------------
278+ (4,public,drop_con_after_attach,t)
279+
280+ INSERT INTO drop_con_after_attach VALUES ('2026-01-01', 1);
281+ SELECT schema_name || '.' || table_name AS "CON_CHUNK", slices AS "CON_SLICES"
282+ FROM _timescaledb_functions.show_chunk((SELECT show_chunks('drop_con_after_attach') LIMIT 1)); \gset
283+ CON_CHUNK | CON_SLICES
284+ -----------------------------------------+------------------------------------------------
285+ _timescaledb_internal._hyper_4_18_chunk | {"time": [1767225600000000, 1767312000000000]}
286+
287+ CALL detach_chunk(:'CON_CHUNK');
288+ CALL attach_chunk('drop_con_after_attach', :'CON_CHUNK', :'CON_SLICES');
289+ -- The inherited constraint is not marked local; the dimension constraint stays local.
290+ SELECT conname, contype, conislocal, coninhcount
291+ FROM pg_constraint
292+ WHERE conrelid = :'CON_CHUNK'::regclass
293+ ORDER BY conname;
294+ conname | contype | conislocal | coninhcount
295+ -------------------------------+---------+------------+-------------
296+ constraint_30 | c | t | 0
297+ drop_con_after_attach_x_check | c | f | 1
298+
299+ ALTER TABLE drop_con_after_attach DROP CONSTRAINT drop_con_after_attach_x_check;
300+ -- The dropped constraint is gone from the round-tripped chunk.
301+ SELECT count(*) AS leftover_check
302+ FROM pg_constraint
303+ WHERE conrelid = :'CON_CHUNK'::regclass AND conname = 'drop_con_after_attach_x_check';
304+ leftover_check
305+ ----------------
306+ 0
307+
308+ DROP TABLE drop_con_after_attach;
309+ -- Test attaching a foreign table as an OSM chunk
310+ -- A dummy server is enough; the foreign table is never queried by attach.
311+ \c :TEST_DBNAME :ROLE_SUPERUSER
312+ CREATE EXTENSION postgres_fdw;
313+ CREATE SERVER attach_chunk_fdw FOREIGN DATA WRAPPER postgres_fdw;
314+ CREATE TABLE osm_ht(time timestamptz NOT NULL, x int CHECK (x > 0));
315+ SELECT create_hypertable('osm_ht', 'time', chunk_time_interval => interval '1 day');
316+ create_hypertable
317+ ---------------------
318+ (5,public,osm_ht,t)
319+
320+ CREATE FOREIGN TABLE osm_ft(time timestamptz NOT NULL, x int) SERVER attach_chunk_fdw;
321+ SELECT _timescaledb_functions.attach_osm_table_chunk('osm_ht', 'osm_ft');
322+ attach_osm_table_chunk
323+ ------------------------
324+ t
325+
326+ -- The foreign chunk inherits its columns without any left marked local.
327+ SELECT attname, attislocal, attinhcount
328+ FROM pg_attribute
329+ WHERE attrelid = 'osm_ft'::regclass AND attnum > 0 AND NOT attisdropped
330+ ORDER BY attnum;
331+ attname | attislocal | attinhcount
332+ ---------+------------+-------------
333+ time | f | 1
334+ x | f | 1
335+
336+ -- The CHECK constraint cloned from the hypertable is inherited, not local.
337+ SELECT conname, contype, conislocal, coninhcount
338+ FROM pg_constraint
339+ WHERE conrelid = 'osm_ft'::regclass AND contype = 'c'
340+ ORDER BY conname;
341+ conname | contype | conislocal | coninhcount
342+ ----------------+---------+------------+-------------
343+ osm_ht_x_check | c | f | 1
344+
345+ ALTER TABLE osm_ht DROP COLUMN x;
346+ -- Dropping the column on the hypertable propagates to the foreign chunk.
347+ SELECT attname
348+ FROM pg_attribute
349+ WHERE attrelid = 'osm_ft'::regclass AND attname = 'x' AND NOT attisdropped;
350+ attname
351+ ---------
352+
353+ -- Dropping the hypertable also drops the attached foreign chunk.
354+ DROP TABLE osm_ht;
355+ DROP SERVER attach_chunk_fdw;
356+ DROP EXTENSION postgres_fdw;
0 commit comments