1.22.  altertableforreplication( integer )

Propriétés de la fonction
Langage: PLPGSQL
Type du code retour: integer

Configure une table pour la réplication. Sur l'origine, ceci implique d'ajouter le trigger "logTrigger()" sur la table. Sur un nœud abonné, ceci implique de désactiver les triggers et les règles, et d'ajouter le trigger qui interdit l'accès aux tables répliquées.

declare
        p_tab_id                        alias for $1;
        v_no_id                         int4;
        v_tab_row                       record;
        v_tab_fqname            text;
        v_tab_attkind           text;
        v_n                                     int4;
        v_trec  record;
        v_tgbad boolean;
begin
        -- ----
        -- Grab the central configuration lock
        -- ----
        lock table sl_config_lock;

        -- ----
        -- Get our local node ID
        -- ----
        v_no_id := getLocalNodeId('_schemadoc');

        -- ----
        -- Get the sl_table row and the current origin of the table. 
        -- Verify that the table currently is NOT in altered state.
        -- ----
        select T.tab_reloid, T.tab_set, T.tab_idxname, T.tab_altered,
                        S.set_origin, PGX.indexrelid,
                        slon_quote_brute(PGN.nspname) || '.' ||
                        slon_quote_brute(PGC.relname) as tab_fqname
                        into v_tab_row
                        from sl_table T, sl_set S,
                                "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN,
                                "pg_catalog".pg_index PGX, "pg_catalog".pg_class PGXC
                        where T.tab_id = p_tab_id
                                and T.tab_set = S.set_id
                                and T.tab_reloid = PGC.oid
                                and PGC.relnamespace = PGN.oid
                                and PGX.indrelid = T.tab_reloid
                                and PGX.indexrelid = PGXC.oid
                                and PGXC.relname = T.tab_idxname
                                for update;
        if not found then
                raise exception 'Slony-I: alterTableForReplication(): Table with id % not found', p_tab_id;
        end if;
        v_tab_fqname = v_tab_row.tab_fqname;
        if v_tab_row.tab_altered then
                raise exception 'Slony-I: alterTableForReplication(): Table % is already in altered state',
                                v_tab_fqname;
        end if;

        v_tab_attkind := determineAttKindUnique(v_tab_row.tab_fqname, 
                                                v_tab_row.tab_idxname);

        execute 'lock table ' || v_tab_fqname || ' in access exclusive mode';

        -- ----
        -- Procedures are different on origin and subscriber
        -- ----
        if v_no_id = v_tab_row.set_origin then
                -- ----
                -- On the Origin we add the log trigger to the table and done
                -- ----
                execute 'create trigger "_schemadoc_logtrigger_' || 
                                p_tab_id || '" after insert or update or delete on ' ||
                                v_tab_fqname || ' for each row execute procedure
                                logTrigger (''_schemadoc'', ''' || 
                                        p_tab_id || ''', ''' || 
                                        v_tab_attkind || ''');';
        else
                -- ----
                -- On the subscriber the thing is a bit more difficult. We want
                -- to disable all user- and foreign key triggers and rules.
                -- ----


                -- ----
                -- Check to see if there are any trigger conflicts...
                -- ----
                v_tgbad := 'false';
                for v_trec in 
                        select pc.relname, tg1.tgname from
                        "pg_catalog".pg_trigger tg1, 
                        "pg_catalog".pg_trigger tg2,
                        "pg_catalog".pg_class pc,
                        "pg_catalog".pg_index pi,
                        sl_table tab
                        where 
                         tg1.tgname = tg2.tgname and        -- Trigger names match
                         tg1.tgrelid = tab.tab_reloid and   -- trigger 1 is on the table
                         pi.indexrelid = tg2.tgrelid and    -- trigger 2 is on the index
                         pi.indrelid = tab.tab_reloid and   -- indexes table is this table
                         pc.oid = tab.tab_reloid
                loop
                        raise notice 'Slony-I: alterTableForReplication(): multiple instances of trigger % on table %',
                                v_trec.tgname, v_trec.relname;
                        v_tgbad := 'true';
                end loop;
                if v_tgbad then
                        raise exception 'Slony-I: Unable to disable triggers';
                end if;                 

                -- ----
                -- Disable all existing triggers
                -- ----
                update "pg_catalog".pg_trigger
                                set tgrelid = v_tab_row.indexrelid
                                where tgrelid = v_tab_row.tab_reloid
                                and not exists (
                                                select true from sl_table TAB,
                                                                sl_trigger TRIG
                                                                where TAB.tab_reloid = tgrelid
                                                                and TAB.tab_id = TRIG.trig_tabid
                                                                and TRIG.trig_tgname = tgname
                                        );
                get diagnostics v_n = row_count;
                if v_n > 0 then
                        update "pg_catalog".pg_class
                                        set reltriggers = reltriggers - v_n
                                        where oid = v_tab_row.tab_reloid;
                end if;

                -- ----
                -- Disable all existing rules
                -- ----
                update "pg_catalog".pg_rewrite
                                set ev_class = v_tab_row.indexrelid
                                where ev_class = v_tab_row.tab_reloid;
                get diagnostics v_n = row_count;
                if v_n > 0 then
                        update "pg_catalog".pg_class
                                        set relhasrules = false
                                        where oid = v_tab_row.tab_reloid;
                end if;

                -- ----
                -- Add the trigger that denies write access to replicated tables
                -- ----
                execute 'create trigger "_schemadoc_denyaccess_' || 
                                p_tab_id || '" before insert or update or delete on ' ||
                                v_tab_fqname || ' for each row execute procedure
                                denyAccess (''_schemadoc'');';
        end if;

        -- ----
        -- Mark the table altered in our configuration
        -- ----
        update sl_table
                        set tab_altered = true where tab_id = p_tab_id;

        return p_tab_id;
end;