-- ============================================================================ -- Reverts Zabbix partitioned tables back to standard non-partitioned tables. -- Existing partitioned tables will be renamed to *_part (data is preserved). -- ============================================================================ DO $$ DECLARE v_row record; v_table text; v_part_table text; v_schema text; BEGIN FOR v_row IN SELECT * FROM partitions.config LOOP v_table := v_row.table_name; v_part_table := v_table || '_part'; -- Determine schema of the partitioned table SELECT n.nspname INTO v_schema FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = v_table AND c.relkind = 'p' AND pg_table_is_visible(c.oid); IF v_schema IS NOT NULL THEN RAISE NOTICE 'Reverting partitioned table %...', v_table; -- 1. Rename existing partitioned table to *_part EXECUTE format('ALTER TABLE %I.%I RENAME TO %I', v_schema, v_table, v_part_table); -- 2. Create standard (unpartitioned) replacement table based on the structure IF v_table = 'auditlog' THEN -- For auditlog, we need to try and restore the original single-column PK (auditid) if possible EXECUTE format('CREATE TABLE %I.%I (LIKE %I.%I INCLUDING DEFAULTS INCLUDING COMMENTS)', v_schema, v_table, v_schema, v_part_table); BEGIN EXECUTE format('ALTER TABLE %I.%I ADD PRIMARY KEY (auditid)', v_schema, v_table); EXCEPTION WHEN others THEN RAISE WARNING 'Failed to create primary key on auditlog, might already exist or duplicates present.'; END; EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_1 ON %I.%I (userid, clock)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_2 ON %I.%I (clock)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_3 ON %I.%I (resourcetype, resourceid)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_4 ON %I.%I (recordsetid)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_5 ON %I.%I (ip)', v_schema, v_table); ELSE -- For others, copy everything including indexes EXECUTE format('CREATE TABLE %I.%I (LIKE %I.%I INCLUDING ALL)', v_schema, v_table, v_schema, v_part_table); END IF; RAISE NOTICE 'SUCCESS: % reverted to default. Partitioned data stored in % (You can DROP TABLE % CASCADE; later).', v_table, v_part_table, v_part_table; ELSIF EXISTS (SELECT 1 FROM pg_class WHERE relname = v_table AND relkind = 'r' AND pg_table_is_visible(oid)) THEN RAISE NOTICE 'Table % is already a regular table. Skipping.', v_table; ELSE RAISE WARNING 'Partitioned table % not found!', v_table; END IF; END LOOP; -- Drop the housekeeper intercept trigger (dynamically determine schema for custom schema support) SELECT n.nspname INTO v_schema FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relname = 'housekeeper' AND pg_table_is_visible(c.oid); IF v_schema IS NOT NULL THEN EXECUTE format('DROP TRIGGER IF EXISTS housekeeper_filter ON %I.housekeeper', v_schema); RAISE NOTICE 'Housekeeper intercept trigger removed from %.housekeeper', v_schema; ELSE RAISE WARNING 'housekeeper table not found — trigger removal skipped.'; END IF; RAISE NOTICE '================================================================================'; RAISE NOTICE 'Undo complete. Partitioned tables have been renamed to *_part.'; RAISE NOTICE 'If you want to migrate your history back, you must do it manually:'; RAISE NOTICE ' INSERT INTO history SELECT * FROM history_part;'; RAISE NOTICE 'Once done, or if you do not need the data, drop the partitioned tables:'; RAISE NOTICE ' DROP TABLE history_part CASCADE;'; RAISE NOTICE 'After that, you can safely remove the partitions infrastructure:'; RAISE NOTICE ' DROP SCHEMA partitions CASCADE;'; RAISE NOTICE '================================================================================'; END $$;