|
| 1 | +/* pgactive--2.1.6--2.1.7.sql */ |
| 2 | + |
| 3 | +-- complain if script is sourced in psql, rather than via ALTER EXTENSION |
| 4 | +\echo Use "ALTER EXTENSION pgactive UPDATE TO '2.1.7'" to load this file. \quit |
| 5 | + |
| 6 | +SET pgactive.skip_ddl_replication = true; |
| 7 | +SET LOCAL search_path = pgactive; |
| 8 | +-- Start Upgrade SQLs/Functions/Procedures |
| 9 | + |
| 10 | +DROP FUNCTION pgactive_create_group (text, text, integer, text[]); |
| 11 | + |
| 12 | +CREATE FUNCTION pgactive_create_group ( |
| 13 | + node_name text, |
| 14 | + node_dsn text, |
| 15 | + apply_delay integer DEFAULT NULL, |
| 16 | + replication_sets text[] DEFAULT ARRAY['default'] |
| 17 | + ) |
| 18 | +RETURNS void LANGUAGE plpgsql VOLATILE |
| 19 | +SET search_path = pgactive, pg_catalog |
| 20 | +-- SET pgactive.permit_unsafe_ddl_commands = on is removed for now |
| 21 | +SET pgactive.skip_ddl_replication = on |
| 22 | +-- SET pgactive.skip_ddl_locking = on is removed for now |
| 23 | +AS $body$ |
| 24 | +DECLARE |
| 25 | + t record; |
| 26 | +BEGIN |
| 27 | + |
| 28 | + -- Prohibit enabling pgactive where exclusion constraints exist |
| 29 | + FOR t IN |
| 30 | + SELECT n.nspname, r.relname, c.conname, c.contype |
| 31 | + FROM pg_constraint c |
| 32 | + INNER JOIN pg_namespace n ON c.connamespace = n.oid |
| 33 | + INNER JOIN pg_class r ON c.conrelid = r.oid |
| 34 | + INNER JOIN LATERAL unnest(pgactive.pgactive_get_table_replication_sets(c.conrelid)) rs(rsname) ON (rs.rsname = ANY(replication_sets)) |
| 35 | + WHERE c.contype = 'x' |
| 36 | + AND r.relpersistence = 'p' |
| 37 | + AND r.relkind = 'r' |
| 38 | + AND n.nspname NOT IN ('pg_catalog', 'pgactive', 'information_schema') |
| 39 | + LOOP |
| 40 | + RAISE USING |
| 41 | + MESSAGE = 'pgactive can''t be enabled because exclusion constraints exist on persistent tables that are not excluded from replication', |
| 42 | + ERRCODE = 'object_not_in_prerequisite_state', |
| 43 | + DETAIL = format('Table %I.%I has exclusion constraint %I.', t.nspname, t.relname, t.conname), |
| 44 | + HINT = 'Drop the exclusion constraint(s), change the table(s) to UNLOGGED if they don''t need to be replicated, or exclude the table(s) from the active replication set(s).'; |
| 45 | + END LOOP; |
| 46 | + |
| 47 | + -- Warn users about missing primary keys and replica identity index |
| 48 | + FOR t IN |
| 49 | + SELECT n.nspname, r.relname, c.conname, c.contype |
| 50 | + FROM pg_constraint c |
| 51 | + INNER JOIN pg_namespace n ON c.connamespace = n.oid |
| 52 | + INNER JOIN pg_class r ON c.conrelid = r.oid |
| 53 | + INNER JOIN LATERAL unnest(pgactive.pgactive_get_table_replication_sets(c.conrelid)) rs(rsname) ON (rs.rsname = ANY(replication_sets)) |
| 54 | + WHERE c.contype = 'u' |
| 55 | + AND r.relpersistence = 'p' |
| 56 | + AND r.relkind = 'r' |
| 57 | + AND n.nspname NOT IN ('pg_catalog', 'pgactive', 'information_schema') |
| 58 | + LOOP |
| 59 | + RAISE WARNING USING |
| 60 | + MESSAGE = 'secondary unique constraint(s) exist on replicated table(s)', |
| 61 | + DETAIL = format('Table %I.%I has secondary unique constraint %I. This may cause unhandled replication conflicts.', t.nspname, t.relname, t.conname), |
| 62 | + HINT = 'Drop the secondary unique constraint(s), change the table(s) to UNLOGGED if they don''t need to be replicated, or exclude the table(s) from the active replication set(s).'; |
| 63 | + END LOOP; |
| 64 | + |
| 65 | + -- Warn users about missing primary keys |
| 66 | + FOR t IN |
| 67 | + SELECT n.nspname, r.relname, c.conname |
| 68 | + FROM pg_class r INNER JOIN pg_namespace n ON r.relnamespace = n.oid |
| 69 | + LEFT OUTER JOIN pg_constraint c ON (c.conrelid = r.oid AND c.contype = 'p') |
| 70 | + WHERE n.nspname NOT IN ('pg_catalog', 'pgactive', 'information_schema') |
| 71 | + AND relkind = 'r' |
| 72 | + AND relpersistence = 'p' |
| 73 | + AND c.oid IS NULL AND r.relreplident != 'i' |
| 74 | + LOOP |
| 75 | + RAISE WARNING USING |
| 76 | + MESSAGE = format('table %I.%I has no PRIMARY KEY', t.nspname, t.relname), |
| 77 | + HINT = 'Tables without a PRIMARY KEY and REPLICA IDENTITY INDEX cannot be UPDATED or DELETED from, only INSERTED into. Add a PRIMARY KEY or a REPLICA IDENTITY INDEX.'; |
| 78 | + END LOOP; |
| 79 | + |
| 80 | + -- Create ON TRUNCATE triggers for pgactive on existing tables |
| 81 | + -- See pgactive_truncate_trigger_add for the matching event trigger for tables |
| 82 | + -- created after join. |
| 83 | + -- |
| 84 | + -- The triggers may be created already because the pgactive event trigger |
| 85 | + -- runs when the pgactive extension is created, even if there's no active |
| 86 | + -- pgactive connections yet, so tables created after the extension is created |
| 87 | + -- will get the trigger already. So skip tables that have a tg named |
| 88 | + -- 'truncate_trigger' calling proc 'pgactive.pgactive_queue_truncate'. |
| 89 | + FOR t IN |
| 90 | + SELECT r.oid AS relid |
| 91 | + FROM pg_class r |
| 92 | + INNER JOIN pg_namespace n ON (r.relnamespace = n.oid) |
| 93 | + LEFT JOIN pg_trigger tg ON (r.oid = tg.tgrelid AND tgname = 'truncate_trigger') |
| 94 | + LEFT JOIN pg_proc p ON (p.oid = tg.tgfoid AND p.proname = 'pgactive_queue_truncate') |
| 95 | + LEFT JOIN pg_namespace pn ON (pn.oid = p.pronamespace AND pn.nspname = 'pgactive') |
| 96 | + WHERE r.relpersistence = 'p' |
| 97 | + AND r.relkind = 'r' |
| 98 | + AND n.nspname NOT IN ('pg_catalog', 'pgactive', 'information_schema') |
| 99 | + AND tg.oid IS NULL AND p.oid IS NULL and pn.oid IS NULL |
| 100 | + LOOP |
| 101 | + -- We use a C function here because in addition to trigger creation |
| 102 | + -- we must also mark it tgisinternal. |
| 103 | + PERFORM pgactive.pgactive_internal_create_truncate_trigger(t.relid); |
| 104 | + END LOOP; |
| 105 | + |
| 106 | + PERFORM pgactive.pgactive_join_group( |
| 107 | + node_name := node_name, |
| 108 | + node_dsn := node_dsn, |
| 109 | + join_using_dsn := null, |
| 110 | + apply_delay := apply_delay, |
| 111 | + replication_sets := replication_sets, |
| 112 | + bypass_user_tables_check := true); |
| 113 | +END; |
| 114 | +$body$; |
| 115 | + |
| 116 | +COMMENT ON FUNCTION pgactive_create_group(text, text, integer, text[]) IS |
| 117 | +'Create a pgactive group, turning a stand-alone database into the first node in a pgactive group'; |
| 118 | + |
| 119 | +REVOKE ALL ON FUNCTION pgactive_create_group(text, text, integer, text[]) FROM public; |
| 120 | + |
| 121 | +-- Finish Upgrade SQLs/Functions/Procedures |
| 122 | +RESET pgactive.skip_ddl_replication; |
| 123 | +RESET search_path; |
0 commit comments