-- ============================================================================ -- Converts standard Zabbix tables to Partitioned tables. -- WARNING: This renames existing tables to *_old. -- ============================================================================ DO $$ DECLARE v_row record; v_table text; v_old_table text; v_pk_sql text; v_schema text; BEGIN FOR v_row IN SELECT * FROM partitions.config LOOP v_table := v_row.table_name; v_old_table := v_table || '_old'; -- Determine schema 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 pg_table_is_visible(c.oid); IF EXISTS (SELECT 1 FROM pg_class WHERE relname = v_table AND relkind = 'r' AND pg_table_is_visible(oid)) THEN RAISE NOTICE 'Converting table % to partitioned table...', v_table; -- 1. Rename existing table EXECUTE format('ALTER TABLE %I.%I RENAME TO %I', v_schema, v_table, v_old_table); -- 2. Create new partitioned table (handling auditlog PK uniquely) IF v_table = 'auditlog' THEN EXECUTE format('CREATE TABLE %I.%I (LIKE %I.%I INCLUDING DEFAULTS INCLUDING COMMENTS) PARTITION BY RANGE (clock)', v_schema, v_table, v_schema, v_old_table); EXECUTE format('ALTER TABLE %I.%I ADD PRIMARY KEY (auditid, clock)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_p_1 ON %I.%I (userid, clock)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_p_2 ON %I.%I (clock)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_p_3 ON %I.%I (resourcetype, resourceid)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_p_4 ON %I.%I (recordsetid)', v_schema, v_table); EXECUTE format('CREATE INDEX IF NOT EXISTS auditlog_p_5 ON %I.%I (ip)', v_schema, v_table); ELSE EXECUTE format('CREATE TABLE %I.%I (LIKE %I.%I INCLUDING ALL) PARTITION BY RANGE (clock)', v_schema, v_table, v_schema, v_old_table); END IF; -- 3. Create initial partitions RAISE NOTICE 'Creating initial partitions for %...', v_table; CALL partitions.maintain_table(v_table, v_row.period, v_row.keep_history, v_row.future_partitions); -- Optional: Migrate existing data -- EXECUTE format('INSERT INTO %I.%I SELECT * FROM %I.%I', v_schema, v_table, v_schema, v_old_table); ELSIF EXISTS (SELECT 1 FROM pg_class WHERE relname = v_table AND relkind = 'p' AND pg_table_is_visible(oid)) THEN RAISE NOTICE 'Table % is already partitioned. Skipping conversion.', v_table; -- Just run maintenance for this specific table to ensure partitions exist CALL partitions.maintain_table(v_table, v_row.period, v_row.keep_history, v_row.future_partitions); ELSE RAISE WARNING 'Table % not found!', v_table; END IF; END LOOP; -- Attach trigger to housekeeper table to silently discard tasks for partitioned tables. -- Dynamically determine the schema of the housekeeper table to support custom schemas. 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); EXECUTE format('CREATE TRIGGER housekeeper_filter BEFORE INSERT ON %I.housekeeper FOR EACH ROW EXECUTE FUNCTION partitions.housekeeper_insert_trigger()', v_schema); RAISE NOTICE 'Housekeeper intercept trigger installed on %.housekeeper', v_schema; ELSE RAISE WARNING 'housekeeper table not found — trigger NOT installed!'; END IF; END $$; -- ========================================================================== -- IMPORTANT: If the Zabbix Server connects with a non-superuser (e.g., 'zabbix'), -- that user MUST have access to the partitions schema for the housekeeper trigger -- to work. Without these GRANTs, every INSERT into housekeeper will FAIL. -- Uncomment and adjust the username below: -- ========================================================================== -- GRANT USAGE ON SCHEMA partitions TO zabbix; -- GRANT SELECT ON partitions.config TO zabbix;