Hi @jonatasdp ,
Feel free to add or correct if any correction required.
I have developed a SQL script to perform chunk-wise decompression and recompression. I thought it might be helpful for others who face similar situations that require changing the primary constraint on a table
DO $$
DECLARE
originally_uncompressed TEXT[ ] := ARRAY[]::TEXT[]; -- chunks that were uncompressed at start
originally_compressed TEXT[] := ARRAY[]::TEXT[]; -- chunks that were compressed at start
decompressed_chunks TEXT[] := ARRAY[]::TEXT[]; -- chunks we successfully decompressed
recompressed_chunks TEXT[] := ARRAY[]::TEXT[]; -- chunks we successfully recompressed
rec RECORD;
BEGIN
-- Step 1: Record original state
FOR rec IN
SELECT chunk_name, is_compressed
FROM timescaledb_information.chunks
WHERE hypertable_name = 'mytable'
LOOP
IF rec.is_compressed THEN
originally_compressed := array_append(originally_compressed, rec.chunk_name);
ELSE
originally_uncompressed := array_append(originally_uncompressed, rec.chunk_name);
END IF;
END LOOP;
-- Step 2: Try decompressing only originally compressed chunks
FOR rec IN SELECT unnest(originally_compressed) AS chunk_name
LOOP
BEGIN
RAISE NOTICE 'Decompressing: _timescaledb_internal.%', rec.chunk_name;
EXECUTE format('SELECT decompress_chunk(%L);', '_timescaledb_internal.' || rec.chunk_name);
decompressed_chunks := array_append(decompressed_chunks, rec.chunk_name);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Decompression failed on chunk: _timescaledb_internal.%', rec.chunk_name;
-- ROLLBACK: Re-compress already decompressed chunks
FOREACH rec.chunk_name IN ARRAY decompressed_chunks
LOOP
BEGIN
RAISE NOTICE 'Rollback: recompressing chunk: %', rec.chunk_name;
EXECUTE format('SELECT compress_chunk(%L);', '_timescaledb_internal.' || rec.chunk_name);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Failed to rollback chunk: %', rec.chunk_name;
END;
END LOOP;
RAISE EXCEPTION 'Aborting due to decompression failure.';
END;
END LOOP;
-- You can do your processing here
RAISE NOTICE 'Performing custom logic here...';
-- Change on primary key constraint or other operation where decompression required;
-- Step 3: Try recompressing only originally compressed chunks
FOR rec IN SELECT unnest(originally_compressed) AS chunk_name
LOOP
BEGIN
RAISE NOTICE 'Compressing: %', rec.chunk_name;
EXECUTE format('SELECT compress_chunk(%I.%I);', '_timescaledb_internal', rec.chunk_name);
recompressed_chunks := array_append(recompressed_chunks, rec.chunk_name);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Compression failed on chunk: %', rec.chunk_name;
-- ROLLBACK: Decompress the chunks we re-compressed
FOREACH rec.chunk_name IN ARRAY recompressed_chunks
LOOP
BEGIN
RAISE NOTICE 'Rollback: decompressing chunk: %', rec.chunk_name;
EXECUTE format('SELECT decompress_chunk(%L);', '_timescaledb_internal.' || rec.chunk_name);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Failed to rollback chunk: %', rec.chunk_name;
END;
END LOOP;
-- Also re-compress chunks that were decompressed earlier but not yet recompressed
FOREACH rec.chunk_name IN ARRAY decompressed_chunks
LOOP
IF NOT rec.chunk_name = ANY(recompressed_chunks) THEN
BEGIN
RAISE NOTICE 'Rollback: compressing chunk: %', rec.chunk_name;
EXECUTE format('SELECT compress_chunk(%L);', '_timescaledb_internal.' || rec.chunk_name);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Failed to rollback chunk: %', rec.chunk_name;
END;
END IF;
END LOOP;
RAISE EXCEPTION 'Aborting due to compression failure.';
END;
END LOOP;
RAISE NOTICE 'Operations completed successfully.';
END $$;