Fri Dec 17 23:30:09 PST 2004
- Previous message: [Slony1-commit] By darcyb: Add schemadoc building support
- Next message: [Slony1-commit] By darcyb: collateindex is handled by ./configure no need to attempt to
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Log Message:
-----------
Add Internals section, this section has a references of all the tables/views and functions used internaly by slony-I. localxxid is a copy of that found in the how-to directory.
Modified Files:
--------------
slony1-engine/doc/adminguide:
filelist.sgml (r1.4 -> r1.5)
slony.sgml (r1.3 -> r1.4)
Added Files:
-----------
slony1-engine/doc/adminguide:
localxid.sql (r1.1)
schemadoc.xml (r1.1)
-------------- next part --------------
--- /dev/null
+++ doc/adminguide/schemadoc.xml
@@ -0,0 +1,9154 @@
+<!-- $Header: /usr/local/cvsroot/slony1/slony1-engine/doc/adminguide/schemadoc.xml,v 1.1 2004/12/17 23:30:03 darcyb Exp $ -->
+
+<book id="database.schemadoc" xreflabel="schemadoc database schema"><title>schemadoc Model</title>
+
+
+
+
+ <chapter id="schemadoc.schema"
+ xreflabel="schemadoc">
+ <title>Schema schemadoc</title>
+ <para></para>
+
+
+ <section id="schemadoc.table.sl-config-lock"
+ xreflabel="schemadoc.sl_config_lock">
+ <title id="schemadoc.table.sl-config-lock-title">
+ Table:
+
+ <structname>sl_config_lock</structname>
+ </title>
+
+
+ <para>
+ This table exists solely to prevent overlapping execution of configuration change procedures and the resulting possible deadlocks.
+
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_config_lock</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>dummy</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-confirm"
+ xreflabel="schemadoc.sl_confirm">
+ <title id="schemadoc.table.sl-confirm-title">
+ Table:
+
+ <structname>sl_confirm</structname>
+ </title>
+
+
+ <para>
+ Holds confirmation of replication events. After a period of time, Slony removes old confirmed events from both this table and the sl_event table.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_confirm</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>con_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The ID # (from sl_node.no_id) of the source node for this event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>con_received</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>con_seqno</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The ID # for the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>con_timestamp</structfield></term>
+ <listitem><para>
+ <type>timestamp without time zone</type>
+
+
+
+
+
+ <literal>DEFAULT (timeofday())::timestamp without time zone</literal>
+
+
+
+ </para>
+
+ <para>
+ When this event was confirmed
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+ <variablelist>
+ <title>Indexes on sl_confirm</title>
+
+ <varlistentry>
+ <term>sl_confirm_idx1</term>
+ <listitem><para>con_origin, con_received, con_seqno</para></listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term>sl_confirm_idx2</term>
+ <listitem><para>con_received, con_seqno</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-event"
+ xreflabel="schemadoc.sl_event">
+ <title id="schemadoc.table.sl-event-title">
+ Table:
+
+ <structname>sl_event</structname>
+ </title>
+
+
+ <para>
+ Holds information about replication events. After a period of time, Slony removes old confirmed events from both this table and the sl_confirm table.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_event</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>ev_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The ID # (from sl_node.no_id) of the source node for this event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_seqno</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The ID # for the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_timestamp</structfield></term>
+ <listitem><para>
+ <type>timestamp without time zone</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ When this event record was created
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_minxid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Earliest XID on provider node for this event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_maxxid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Latest XID on provider node for this event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_xip</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ List of XIDs, in order, that are part of this event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_type</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The type of event this record is for.
+ SYNC = Synchronise
+ STORE_NODE =
+ ENABLE_NODE =
+ DROP_NODE =
+ STORE_PATH =
+ DROP_PATH =
+ STORE_LISTEN =
+ DROP_LISTEN =
+ STORE_SET =
+ DROP_SET =
+ MERGE_SET =
+ SET_ADD_TABLE =
+ SET_ADD_SEQUENCE =
+ STORE_TRIGGER =
+ DROP_TRIGGER =
+ MOVE_SET =
+ SET_DROP_TABLE =
+ SET_DROP_SEQUENCE =
+ SET_MOVE_TABLE =
+ SET_MOVE_SEQUENCE =
+ FAILOVER_SET =
+ SUBSCRIBE_SET =
+ ENABLE_SUBSCRIPTION =
+ UNSUBSCRIBE_SET =
+ DDL_SCRIPT =
+ ADJUST_SEQ =
+ RESET_CONFIG =
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data1</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data2</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data3</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data4</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data5</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data6</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data7</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ev_data8</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Data field containing an argument needed to process the event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-listen"
+ xreflabel="schemadoc.sl_listen">
+ <title id="schemadoc.table.sl-listen-title">
+ Table:
+
+ <structname>sl_listen</structname>
+ </title>
+
+
+ <para>
+ Indicates how nodes listen to events from other nodes in the Slony-I network.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_listen</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>li_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-node"/>
+
+
+
+
+ </para>
+
+ <para>
+ The ID # (from sl_node.no_id) of the node this listener is operating on
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>li_provider</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-path"/>
+
+
+ </para>
+
+ <para>
+ The ID # (from sl_node.no_id) of the source node for this listening event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>li_receiver</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-path"/>
+
+
+ </para>
+
+ <para>
+ The ID # (from sl_node.no_id) of the target node for this listening event
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-log-1"
+ xreflabel="schemadoc.sl_log_1">
+ <title id="schemadoc.table.sl-log-1-title">
+ Table:
+
+ <structname>sl_log_1</structname>
+ </title>
+
+
+ <para>
+ Stores each change to be propagated to subscriber nodes
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_log_1</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>log_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Origin node from which the change came
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_xid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Transaction ID on the origin node
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_tableid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The table ID (from sl_table.tab_id) that this log entry is to affect
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_actionseq</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_cmdtype</structfield></term>
+ <listitem><para>
+ <type>character(1)</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Replication action to take. U = Update, I = Insert, D = DELETE
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_cmddata</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The data needed to perform the log action
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-log-2"
+ xreflabel="schemadoc.sl_log_2">
+ <title id="schemadoc.table.sl-log-2-title">
+ Table:
+
+ <structname>sl_log_2</structname>
+ </title>
+
+
+ <para>
+ Stores each change to be propagated to subscriber nodes
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_log_2</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>log_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Origin node from which the change came
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_xid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Transaction ID on the origin node
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_tableid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The table ID (from sl_table.tab_id) that this log entry is to affect
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_actionseq</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_cmdtype</structfield></term>
+ <listitem><para>
+ <type>character(1)</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Replication action to take. U = Update, I = Insert, D = DELETE
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>log_cmddata</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The data needed to perform the log action
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-node"
+ xreflabel="schemadoc.sl_node">
+ <title id="schemadoc.table.sl-node-title">
+ Table:
+
+ <structname>sl_node</structname>
+ </title>
+
+
+ <para>
+ Holds the list of nodes associated with this namespace.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_node</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>no_id</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The unique ID number for the node
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>no_active</structfield></term>
+ <listitem><para>
+ <type>boolean</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Is the node active in replication yet?
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>no_comment</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ A human-oriented description of the node
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>no_spool</structfield></term>
+ <listitem><para>
+ <type>boolean</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+ <itemizedlist>
+ <title>
+ Tables referencing sl_listen via Foreign Key Constraints
+ </title>
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-listen"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-path"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-set"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-setsync"/>
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-path"
+ xreflabel="schemadoc.sl_path">
+ <title id="schemadoc.table.sl-path-title">
+ Table:
+
+ <structname>sl_path</structname>
+ </title>
+
+
+ <para>
+ Holds connection information for the paths between nodes, and the synchronisation delay
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_path</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>pa_server</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-node"/>
+
+
+
+
+ </para>
+
+ <para>
+ The Node ID # (from sl_node.no_id) of the data source
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>pa_client</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-node"/>
+
+
+
+
+ </para>
+
+ <para>
+ The Node ID # (from sl_node.no_id) of the data target
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>pa_conninfo</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The PostgreSQL connection string used to connect to the source node.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>pa_connretry</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The synchronisation delay, in seconds
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+ <itemizedlist>
+ <title>
+ Tables referencing sl_listen via Foreign Key Constraints
+ </title>
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-listen"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-subscribe"/>
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.view.sl-seqlastvalue"
+ xreflabel="schemadoc.sl_seqlastvalue">
+ <title id="schemadoc.view.sl-seqlastvalue-title">
+ View:
+
+ <structname>sl_seqlastvalue</structname>
+ </title>
+
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_seqlastvalue</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>seq_id</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_set</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_reloid</structfield></term>
+ <listitem><para>
+ <type>oid</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_last_value</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+ <figure>
+ <title>Definition of view sl_seqlastvalue</title>
+ <programlisting>
+SELECT sq.seq_id
+, sq.seq_set
+, sq.seq_reloid
+, s.set_origin AS seq_origin
+, schemadoc.sequencelastvalue
+(
+ (
+ (quote_ident
+ (
+ (pgn.nspname)::text
+ ) || '.'::text
+ ) || quote_ident
+ (
+ (pgc.relname)::text
+ )
+ )
+) AS seq_last_value
+FROM schemadoc.sl_sequence sq
+, schemadoc.sl_set s
+, pg_class pgc
+, pg_namespace pgn
+WHERE (
+ (
+ (s.set_id = sq.seq_set)
+ AND (pgc.oid = sq.seq_reloid)
+ )
+ AND (pgn.oid = pgc.relnamespace)
+);</programlisting>
+ </figure>
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-seqlog"
+ xreflabel="schemadoc.sl_seqlog">
+ <title id="schemadoc.table.sl-seqlog-title">
+ Table:
+
+ <structname>sl_seqlog</structname>
+ </title>
+
+
+ <para>
+ Log of Sequence updates
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_seqlog</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>seql_seqid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Sequence ID
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seql_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Publisher node at which the sequence originates
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seql_ev_seqno</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Slony-I Event with which this sequence update is associated
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seql_last_value</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Last value published for this sequence
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+ <variablelist>
+ <title>Indexes on sl_seqlog</title>
+
+ <varlistentry>
+ <term>sl_seqlog_idx</term>
+ <listitem><para>seql_origin, seql_ev_seqno, seql_seqid</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-sequence"
+ xreflabel="schemadoc.sl_sequence">
+ <title id="schemadoc.table.sl-sequence-title">
+ Table:
+
+ <structname>sl_sequence</structname>
+ </title>
+
+
+ <para>
+ Similar to sl_table, each entry identifies a sequence being replicated.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_sequence</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>seq_id</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ An internally-used ID for Slony-I to use in its sequencing of updates
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_reloid</structfield></term>
+ <listitem><para>
+ <type>oid</type>
+
+
+
+
+ <literal>UNIQUE</literal>
+
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The OID of the sequence object
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_relname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The name of the sdequence in pg_catalog.pg_class.relname used to recover from a dump/restore cycle
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_nspname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The name of the schema in pg_catalog.pg_namespace.nspname used to recover from a dump/restore cycle
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_set</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-set"/>
+
+
+ </para>
+
+ <para>
+ Indicates which replication set the object is in
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>seq_comment</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ A human-oriented comment
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-set"
+ xreflabel="schemadoc.sl_set">
+ <title id="schemadoc.table.sl-set-title">
+ Table:
+
+ <structname>sl_set</structname>
+ </title>
+
+
+ <para>
+ Holds definitions of replication sets.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_set</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>set_id</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ A unique ID number for the set.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>set_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-node"/>
+
+
+ </para>
+
+ <para>
+ The ID number of the source node for the replication set.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>set_locked</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Indicates whether or not the set is locked.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>set_comment</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ A human-oriented description of the set.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+ <itemizedlist>
+ <title>
+ Tables referencing sl_sequence via Foreign Key Constraints
+ </title>
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-sequence"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-setsync"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-subscribe"/>
+ </para>
+ </listitem>
+
+
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-table"/>
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-setsync"
+ xreflabel="schemadoc.sl_setsync">
+ <title id="schemadoc.table.sl-setsync-title">
+ Table:
+
+ <structname>sl_setsync</structname>
+ </title>
+
+
+ <para>
+ SYNC information
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_setsync</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>ssy_setid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-set"/>
+
+
+ </para>
+
+ <para>
+ ID number of the replication set
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_origin</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-node"/>
+
+
+ </para>
+
+ <para>
+ ID number of the node
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_seqno</structfield></term>
+ <listitem><para>
+ <type>bigint</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Slony-I sequence number
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_minxid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Earliest XID in provider system affected by SYNC
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_maxxid</structfield></term>
+ <listitem><para>
+ <type>schemadoc.xxid</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Latest XID in provider system affected by SYNC
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_xip</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Contains the list of XIDs in progress at SYNC time
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>ssy_action_list</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ action list used during the subscription process. At the time a subscriber copies over data from the origin, it sees all tables in a state somewhere between two SYNC events. Therefore this list must contains all XIDs that are visible at that time, whose operations have therefore already been included in the data copied at the time the initial data copy is done. Those actions may therefore be filtered out of the first SYNC done after subscribing.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-subscribe"
+ xreflabel="schemadoc.sl_subscribe">
+ <title id="schemadoc.table.sl-subscribe-title">
+ Table:
+
+ <structname>sl_subscribe</structname>
+ </title>
+
+
+ <para>
+ Holds a list of subscriptions on sets
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_subscribe</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>sub_set</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-set"/>
+
+
+ </para>
+
+ <para>
+ ID # (from sl_set) of the set being subscribed to
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>sub_provider</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-path"/>
+
+
+ </para>
+
+ <para>
+ ID# (from sl_node) of the node providing data
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>sub_receiver</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-path"/>
+
+
+ </para>
+
+ <para>
+ ID# (from sl_node) of the node receiving data from the provider
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>sub_forward</structfield></term>
+ <listitem><para>
+ <type>boolean</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Does this provider keep data in sl_log_1/sl_log_2 to allow it to be a provider for other nodes?
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>sub_active</structfield></term>
+ <listitem><para>
+ <type>boolean</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Has this subscription been activated? This is not set until the subscriber has received COPY data from the provider
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-table"
+ xreflabel="schemadoc.sl_table">
+ <title id="schemadoc.table.sl-table-title">
+ Table:
+
+ <structname>sl_table</structname>
+ </title>
+
+
+ <para>
+ Holds information about the tables being replicated.
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_table</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>tab_id</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Unique key for Slony-I to use to identify the table
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_reloid</structfield></term>
+ <listitem><para>
+ <type>oid</type>
+
+
+
+
+ <literal>UNIQUE</literal>
+
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ The OID of the table in pg_catalog.pg_class.oid
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_relname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The name of the table in pg_catalog.pg_class.relname used to recover from a dump/restore cycle
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_nspname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The name of the schema in pg_catalog.pg_namespace.nspname used to recover from a dump/restore cycle
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_set</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-set"/>
+
+
+ </para>
+
+ <para>
+ ID of the replication set the table is in
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_idxname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ The name of the primary index of the table
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_altered</structfield></term>
+ <listitem><para>
+ <type>boolean</type>
+
+
+
+ <literal>NOT NULL</literal>
+
+
+
+
+
+ </para>
+
+ <para>
+ Has the table been modified for replication?
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>tab_comment</structfield></term>
+ <listitem><para>
+ <type>text</type>
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Human-oriented description of the table
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+ <itemizedlist>
+ <title>
+ Tables referencing sl_trigger via Foreign Key Constraints
+ </title>
+
+ <listitem>
+ <para>
+ <xref linkend="schemadoc.table.sl-trigger"/>
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+
+
+
+
+
+ </para>
+ </section>
+
+ <section id="schemadoc.table.sl-trigger"
+ xreflabel="schemadoc.sl_trigger">
+ <title id="schemadoc.table.sl-trigger-title">
+ Table:
+
+ <structname>sl_trigger</structname>
+ </title>
+
+
+ <para>
+ Holds information about triggers on tables managed using Slony-I
+ </para>
+
+
+ <para>
+ <variablelist>
+ <title>
+ Structure of <structname>sl_trigger</structname>
+ </title>
+
+
+ <varlistentry>
+ <term><structfield>trig_tabid</structfield></term>
+ <listitem><para>
+ <type>integer</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <literal>REFERENCES</literal> <xref linkend="schemadoc.table.sl-table"/>
+
+
+ </para>
+
+ <para>
+ Slony-I ID number of table the trigger is on
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><structfield>trig_tgname</structfield></term>
+ <listitem><para>
+ <type>name</type>
+
+
+ <literal>PRIMARY KEY</literal>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </para>
+
+ <para>
+ Indicates the name of a trigger
+ </para>
+
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+
+
+
+
+
+
+
+
+
+ </para>
+ </section>
+
+
+
+<!-- Function altertableforreplication( integer ) -->
+ <section id="schemadoc.function.altertableforreplication-integer"
+ xreflabel="schemadocaltertableforreplication( integer )">
+ <title id="schemadoc.function.altertableforreplication-integer-title">
+ altertableforreplication( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.altertableforreplication-integer-titleabbrev">
+ altertableforreplication( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ alterTableForReplication(tab_id)
+
+Sets up a table for replication.
+On the origin, this involves adding the "logTrigger()" trigger to the
+table.
+
+On a subscriber node, this involves disabling triggers and rules, and
+adding in the trigger that denies write access to replicated tables.
+ <programlisting>
+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;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get our local node ID
+ -- ----
+ v_no_id := schemadoc.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,
+ "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) as tab_fqname
+ into v_tab_row
+ from schemadoc.sl_table T, schemadoc.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: 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: Table % is already in altered state',
+ v_tab_fqname;
+ end if;
+
+ v_tab_attkind := schemadoc.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
+ schemadoc.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.
+ -- ----
+
+
+ -- ----
+ -- 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 schemadoc.sl_table TAB,
+ schemadoc.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
+ schemadoc.denyAccess (''_schemadoc'');';
+ end if;
+
+ -- ----
+ -- Mark the table altered in our configuration
+ -- ----
+ update schemadoc.sl_table
+ set tab_altered = true where tab_id = p_tab_id;
+
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function altertablerestore( integer ) -->
+ <section id="schemadoc.function.altertablerestore-integer"
+ xreflabel="schemadocaltertablerestore( integer )">
+ <title id="schemadoc.function.altertablerestore-integer-title">
+ altertablerestore( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.altertablerestore-integer-titleabbrev">
+ altertablerestore( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ alterTableRestore (tab_id)
+
+Restores table tab_id from being replicated.
+
+On the origin, this simply involves dropping the "logtrigger" trigger.
+
+On subscriber nodes, this involves dropping the "denyaccess" trigger,
+and restoring user triggers and rules.
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ v_no_id int4;
+ v_tab_row record;
+ v_tab_fqname text;
+ v_n int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get our local node ID
+ -- ----
+ v_no_id := schemadoc.getLocalNodeId('_schemadoc');
+
+ -- ----
+ -- Get the sl_table row and the current tables origin. Check
+ -- that the table currently IS in altered state.
+ -- ----
+ select T.tab_reloid, T.tab_set, T.tab_altered,
+ S.set_origin, PGX.indexrelid,
+ "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) as tab_fqname
+ into v_tab_row
+ from schemadoc.sl_table T, schemadoc.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: Table with id % not found', p_tab_id;
+ end if;
+ v_tab_fqname = v_tab_row.tab_fqname;
+ if not v_tab_row.tab_altered then
+ raise exception 'Slony-I: Table % is not in altered state',
+ v_tab_fqname;
+ end if;
+
+ 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 just drop the trigger we originally added
+ -- ----
+ execute 'drop trigger "_schemadoc_logtrigger_' ||
+ p_tab_id || '" on ' || v_tab_fqname;
+ else
+ -- ----
+ -- On the subscriber drop the denyAccess trigger
+ -- ----
+ execute 'drop trigger "_schemadoc_denyaccess_' ||
+ p_tab_id || '" on ' || v_tab_fqname;
+
+ -- ----
+ -- Restore all original triggers
+ -- ----
+ update "pg_catalog".pg_trigger
+ set tgrelid = v_tab_row.tab_reloid
+ where tgrelid = v_tab_row.indexrelid;
+ 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;
+
+ -- ----
+ -- Restore all original rewrite rules
+ -- ----
+ update "pg_catalog".pg_rewrite
+ set ev_class = v_tab_row.tab_reloid
+ where ev_class = v_tab_row.indexrelid;
+ get diagnostics v_n = row_count;
+ if v_n > 0 then
+ update "pg_catalog".pg_class
+ set relhasrules = true
+ where oid = v_tab_row.tab_reloid;
+ end if;
+
+ end if;
+
+ -- ----
+ -- Mark the table not altered in our configuration
+ -- ----
+ update schemadoc.sl_table
+ set tab_altered = false where tab_id = p_tab_id;
+
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function cleanupevent( ) -->
+ <section id="schemadoc.function.cleanupevent"
+ xreflabel="schemadoccleanupevent( )">
+ <title id="schemadoc.function.cleanupevent-title">
+ cleanupevent( )
+ </title>
+ <titleabbrev id="schemadoc.function.cleanupevent-titleabbrev">
+ cleanupevent( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ cleaning old data out of sl_confirm, sl_event. Removes all but the
+last sl_confirm row per (origin,receiver), and then removes all events
+that are confirmed by all nodes in the whole cluster up to the last
+SYNC.
+ <programlisting>
+declare
+ v_max_row record;
+ v_min_row record;
+ v_max_sync int8;
+begin
+ -- ----
+ -- First remove all but the oldest confirm row per origin,receiver pair
+ -- ----
+ delete from schemadoc.sl_confirm
+ where con_origin not in (select no_id from schemadoc.sl_node);
+ delete from schemadoc.sl_confirm
+ where con_received not in (select no_id from schemadoc.sl_node);
+ -- ----
+ -- Next remove all but the oldest confirm row per origin,receiver pair.
+ -- Ignore confirmations that are younger than 10 minutes. We currently
+ -- have an not confirmed suspicion that a possibly lost transaction due
+ -- to a server crash might have been visible to another session, and
+ -- that this led to log data that is needed again got removed.
+ -- ----
+ for v_max_row in select con_origin, con_received, max(con_seqno) as con_seqno
+ from schemadoc.sl_confirm
+ where con_timestamp < (CURRENT_TIMESTAMP - '10 min'::interval)
+ group by con_origin, con_received
+ loop
+ delete from schemadoc.sl_confirm
+ where con_origin = v_max_row.con_origin
+ and con_received = v_max_row.con_received
+ and con_seqno < v_max_row.con_seqno;
+ end loop;
+
+ -- ----
+ -- Then remove all events that are confirmed by all nodes in the
+ -- whole cluster up to the last SYNC
+ -- ----
+ for v_min_row in select con_origin, min(con_seqno) as con_seqno
+ from schemadoc.sl_confirm
+ group by con_origin
+ loop
+ select coalesce(max(ev_seqno), 0) into v_max_sync
+ from schemadoc.sl_event
+ where ev_origin = v_min_row.con_origin
+ and ev_seqno <= v_min_row.con_seqno
+ and ev_type = 'SYNC';
+ if v_max_sync > 0 then
+ delete from schemadoc.sl_event
+ where ev_origin = v_min_row.con_origin
+ and ev_seqno < v_max_sync;
+ end if;
+ end loop;
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function cleanuplistener( ) -->
+ <section id="schemadoc.function.cleanuplistener"
+ xreflabel="schemadoccleanuplistener( )">
+ <title id="schemadoc.function.cleanuplistener-title">
+ cleanuplistener( )
+ </title>
+ <titleabbrev id="schemadoc.function.cleanuplistener-titleabbrev">
+ cleanuplistener( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ look for stale pg_listener entries and submit Async_Unlisten() to them
+ <programlisting>_Slony_I_cleanupListener</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text ) -->
+ <section id="schemadoc.function.createevent-name-text"
+ xreflabel="schemadoccreateevent( name, text )">
+ <title id="schemadoc.function.createevent-name-text-title">
+ createevent( name, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-titleabbrev">
+ createevent( name, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text"
+ xreflabel="schemadoccreateevent( name, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-title">
+ createevent( name, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-titleabbrev">
+ createevent( name, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-title">
+ createevent( name, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-titleabbrev">
+ createevent( name, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-title">
+ createevent( name, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-text-title">
+ createevent( name, text, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-text-text-title">
+ createevent( name, text, text, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-title">
+ createevent( name, text, text, text, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text-title">
+ createevent( name, text, text, text, text, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function createevent( name, text, text, text, text, text, text, text, text, text ) -->
+ <section id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text-text"
+ xreflabel="schemadoccreateevent( name, text, text, text, text, text, text, text, text, text )">
+ <title id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text-text-title">
+ createevent( name, text, text, text, text, text, text, text, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.createevent-name-text-text-text-text-text-text-text-text-text-titleabbrev">
+ createevent( name, text, text, text, text, text, text, text, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION createEvent (cluster_name, ev_type [, ev_data [...]])
+
+Create an sl_event entry
+ <programlisting>_Slony_I_createEvent</programlisting>
+ </para>
+ </section>
+
+<!-- Function ddlscript( integer, text, integer ) -->
+ <section id="schemadoc.function.ddlscript-integer-text-integer"
+ xreflabel="schemadocddlscript( integer, text, integer )">
+ <title id="schemadoc.function.ddlscript-integer-text-integer-title">
+ ddlscript( integer, text, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.ddlscript-integer-text-integer-titleabbrev">
+ ddlscript( integer, text, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ ddlScript(set_id, script, only_on_node)
+
+Generates a SYNC event, runs the script on the origin, and then
+generates a DDL_SCRIPT event to request it to be run on replicated
+slaves.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_script alias for $2;
+ p_only_on_node alias for $3;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the set exists and originates here
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_origin <> schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+
+ -- ----
+ -- Create a SYNC event, run the script and generate the DDL_SCRIPT event
+ -- ----
+ perform schemadoc.createEvent('_schemadoc', 'SYNC', NULL);
+ perform schemadoc.ddlScript_int(p_set_id, p_script, p_only_on_node);
+ perform schemadoc.updateRelname(p_set_id, p_only_on_node);
+ return schemadoc.createEvent('_schemadoc', 'DDL_SCRIPT',
+ p_set_id, p_script, p_only_on_node);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function ddlscript_int( integer, text, integer ) -->
+ <section id="schemadoc.function.ddlscript-int-integer-text-integer"
+ xreflabel="schemadocddlscript_int( integer, text, integer )">
+ <title id="schemadoc.function.ddlscript-int-integer-text-integer-title">
+ ddlscript_int( integer, text, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.ddlscript-int-integer-text-integer-titleabbrev">
+ ddlscript_int( integer, text, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ ddlScript_int(set_id, script, only_on_node)
+
+Processes the DDL_SCRIPT event. On slave nodes, this restores
+original triggers/rules, runs the script, and then puts tables back
+into replicated mode.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_script alias for $2;
+ p_only_on_node alias for $3;
+ v_set_origin int4;
+ v_no_id int4;
+ v_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we either are the set origin or a current
+ -- subscriber of the set.
+ -- ----
+ v_no_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_origin <> v_no_id
+ and not exists (select 1 from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = v_no_id)
+ then
+ return 0;
+ end if;
+
+ -- ----
+ -- If execution on only one node is requested, check that
+ -- we are that node.
+ -- ----
+ if p_only_on_node > 0 and p_only_on_node <> v_no_id then
+ return 0;
+ end if;
+
+ -- ----
+ -- Restore all original triggers and rules
+ -- ----
+ for v_row in select * from schemadoc.sl_table
+ where tab_set = p_set_id
+ loop
+ perform schemadoc.alterTableRestore(v_row.tab_id);
+ end loop;
+
+ -- ----
+ -- Run the script
+ -- ----
+ execute p_script;
+
+ -- ----
+ -- Put all tables back into replicated mode
+ -- ----
+ for v_row in select * from schemadoc.sl_table
+ where tab_set = p_set_id
+ loop
+ perform schemadoc.alterTableForReplication(v_row.tab_id);
+ end loop;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function denyaccess( ) -->
+ <section id="schemadoc.function.denyaccess"
+ xreflabel="schemadocdenyaccess( )">
+ <title id="schemadoc.function.denyaccess-title">
+ denyaccess( )
+ </title>
+ <titleabbrev id="schemadoc.function.denyaccess-titleabbrev">
+ denyaccess( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>"trigger"</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Trigger function to prevent modifications to a table on a subscriber
+ <programlisting>_Slony_I_denyAccess</programlisting>
+ </para>
+ </section>
+
+<!-- Function determineattkindserial( text ) -->
+ <section id="schemadoc.function.determineattkindserial-text"
+ xreflabel="schemadocdetermineattkindserial( text )">
+ <title id="schemadoc.function.determineattkindserial-text-title">
+ determineattkindserial( text )
+ </title>
+ <titleabbrev id="schemadoc.function.determineattkindserial-text-titleabbrev">
+ determineattkindserial( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ determineAttKindSerial (tab_fqname)
+
+A table was that was specified without a primary key is added to the
+replication. Assume that tableAddKey() was called before and finish
+the creation of the serial column. The return an attkind according to
+that.
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ v_attkind text default '';
+ v_attrow record;
+ v_have_serial bool default 'f';
+begin
+ --
+ -- Loop over the attributes of this relation
+ -- and add a "v" for every user column, and a "k"
+ -- if we find the Slony-I special serial column.
+ --
+ for v_attrow in select PGA.attnum, PGA.attname
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_attribute PGA
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGA.attrelid = PGC.oid
+ and not PGA.attisdropped
+ and PGA.attnum > 0
+ order by attnum
+ loop
+ if v_attrow.attname = '_Slony-I_schemadoc_rowID' then
+ v_attkind := v_attkind || 'k';
+ v_have_serial := 't';
+ else
+ v_attkind := v_attkind || 'v';
+ end if;
+ end loop;
+
+ --
+ -- A table must have at least one attribute, so not finding
+ -- anything means the table does not exist.
+ --
+ if not found then
+ raise exception 'Slony-I: table % not found', p_tab_fqname;
+ end if;
+
+ --
+ -- If it does not have the special serial column, we
+ -- should not have been called in the first place.
+ --
+ if not v_have_serial then
+ raise exception 'Slony-I: table % does not have the serial key',
+ p_tab_fqname;
+ end if;
+
+ execute 'update ' || p_tab_fqname ||
+ ' set "_Slony-I_schemadoc_rowID" =' ||
+ ' "pg_catalog".nextval(''schemadoc.sl_rowid_seq'');';
+ execute 'alter table only ' || p_tab_fqname ||
+ ' add unique ("_Slony-I_schemadoc_rowID");';
+ execute 'alter table only ' || p_tab_fqname ||
+ ' alter column "_Slony-I_schemadoc_rowID" ' ||
+ ' set not null;';
+
+ --
+ -- Return the resulting Slony-I attkind
+ --
+ return v_attkind;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function determineattkindunique( text, name ) -->
+ <section id="schemadoc.function.determineattkindunique-text-name"
+ xreflabel="schemadocdetermineattkindunique( text, name )">
+ <title id="schemadoc.function.determineattkindunique-text-name-title">
+ determineattkindunique( text, name )
+ </title>
+ <titleabbrev id="schemadoc.function.determineattkindunique-text-name-titleabbrev">
+ determineattkindunique( text, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ determineAttKindUnique (tab_fqname, indexname)
+
+Given a tablename, return the Slony-I specific attkind (used for the
+log trigger) of the table. Use the specified unique index or the
+primary key (if indexname is NULL).
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ p_idx_name alias for $2;
+ v_idxrow record;
+ v_attrow record;
+ v_i integer;
+ v_attno int2;
+ v_attkind text default '';
+ v_attfound bool;
+begin
+ --
+ -- Lookup the tables primary key or the specified unique index
+ --
+ if p_idx_name isnull then
+ raise exception 'Slony-I: index name must be specified';
+ else
+ select PGXC.relname, PGX.indexrelid, PGX.indkey
+ into v_idxrow
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_index PGX,
+ "pg_catalog".pg_class PGXC
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGX.indrelid = PGC.oid
+ and PGX.indexrelid = PGXC.oid
+ and PGX.indisunique
+ and PGXC.relname = p_idx_name;
+ if not found then
+ raise exception 'Slony-I: table % has no unique index %',
+ p_tab_fqname, p_idx_name;
+ end if;
+ end if;
+
+ --
+ -- Loop over the tables attributes and check if they are
+ -- index attributes. If so, add a "k" to the return value,
+ -- otherwise add a "v".
+ --
+ for v_attrow in select PGA.attnum, PGA.attname
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_attribute PGA
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGA.attrelid = PGC.oid
+ and not PGA.attisdropped
+ and PGA.attnum > 0
+ order by attnum
+ loop
+ v_attfound = 'f';
+
+ v_i := 0;
+ loop
+ select indkey[v_i] into v_attno from "pg_catalog".pg_index
+ where indexrelid = v_idxrow.indexrelid;
+ if v_attno = 0 then
+ exit;
+ end if;
+ if v_attrow.attnum = v_attno then
+ v_attfound = 't';
+ exit;
+ end if;
+ v_i := v_i + 1;
+ end loop;
+
+ if v_attfound then
+ v_attkind := v_attkind || 'k';
+ else
+ v_attkind := v_attkind || 'v';
+ end if;
+ end loop;
+
+ --
+ -- Return the resulting attkind
+ --
+ return v_attkind;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function determineidxnameserial( text ) -->
+ <section id="schemadoc.function.determineidxnameserial-text"
+ xreflabel="schemadocdetermineidxnameserial( text )">
+ <title id="schemadoc.function.determineidxnameserial-text-title">
+ determineidxnameserial( text )
+ </title>
+ <titleabbrev id="schemadoc.function.determineidxnameserial-text-titleabbrev">
+ determineidxnameserial( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>name</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ determineIdxnameSerial (tab_fqname)
+
+Given a tablename, construct the index name of the serial column.
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ v_row record;
+begin
+ --
+ -- Lookup the table name alone
+ --
+ select PGC.relname
+ into v_row
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace;
+ if not found then
+ raise exception 'Slony-I: table % not found',
+ p_tab_fqname;
+ end if;
+
+ --
+ -- Return the found index name
+ --
+ return v_row.relname || '__Slony-I_schemadoc_rowID_key';
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function determineidxnameunique( text, name ) -->
+ <section id="schemadoc.function.determineidxnameunique-text-name"
+ xreflabel="schemadocdetermineidxnameunique( text, name )">
+ <title id="schemadoc.function.determineidxnameunique-text-name-title">
+ determineidxnameunique( text, name )
+ </title>
+ <titleabbrev id="schemadoc.function.determineidxnameunique-text-name-titleabbrev">
+ determineidxnameunique( text, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>name</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION determineIdxnameUnique (tab_fqname, indexname)
+
+Given a tablename, tab_fqname, check that the unique index, indexname,
+exists or return the primary key index name for the table. If there
+is no unique index, it raises an exception.
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ p_idx_name alias for $2;
+ v_idxrow record;
+begin
+ --
+ -- Lookup the tables primary key or the specified unique index
+ --
+ if p_idx_name isnull then
+ select PGXC.relname
+ into v_idxrow
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_index PGX,
+ "pg_catalog".pg_class PGXC
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGX.indrelid = PGC.oid
+ and PGX.indexrelid = PGXC.oid
+ and PGX.indisprimary;
+ if not found then
+ raise exception 'Slony-I: table % has no primary key',
+ p_tab_fqname;
+ end if;
+ else
+ select PGXC.relname
+ into v_idxrow
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_index PGX,
+ "pg_catalog".pg_class PGXC
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGX.indrelid = PGC.oid
+ and PGX.indexrelid = PGXC.oid
+ and PGX.indisunique
+ and PGXC.relname = p_idx_name;
+ if not found then
+ raise exception 'Slony-I: table % has no unique index %',
+ p_tab_fqname, p_idx_name;
+ end if;
+ end if;
+
+ --
+ -- Return the found index name
+ --
+ return v_idxrow.relname;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function disablenode( integer ) -->
+ <section id="schemadoc.function.disablenode-integer"
+ xreflabel="schemadocdisablenode( integer )">
+ <title id="schemadoc.function.disablenode-integer-title">
+ disablenode( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.disablenode-integer-titleabbrev">
+ disablenode( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ process DISABLE_NODE event for node no_id
+
+NOTE: This is not yet implemented!
+ <programlisting>
+declare
+ p_no_id alias for $1;
+begin
+ -- **** TODO ****
+ raise exception 'Slony-I: disableNode() not implemented';
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function disablenode_int( integer ) -->
+ <section id="schemadoc.function.disablenode-int-integer"
+ xreflabel="schemadocdisablenode_int( integer )">
+ <title id="schemadoc.function.disablenode-int-integer-title">
+ disablenode_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.disablenode-int-integer-titleabbrev">
+ disablenode_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_no_id alias for $1;
+begin
+ -- **** TODO ****
+ raise exception 'Slony-I: disableNode_int() not implemented';
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droplisten( integer, integer, integer ) -->
+ <section id="schemadoc.function.droplisten-integer-integer-integer"
+ xreflabel="schemadocdroplisten( integer, integer, integer )">
+ <title id="schemadoc.function.droplisten-integer-integer-integer-title">
+ droplisten( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.droplisten-integer-integer-integer-titleabbrev">
+ droplisten( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ dropListen (li_origin, li_provider, li_receiver)
+
+Generate the DROP_LISTEN event.
+ <programlisting>
+declare
+ p_li_origin alias for $1;
+ p_li_provider alias for $2;
+ p_li_receiver alias for $3;
+begin
+ return -1;
+
+ perform schemadoc.dropListen_int(p_li_origin,
+ p_li_provider, p_li_receiver);
+
+ return schemadoc.createEvent ('_schemadoc', 'DROP_LISTEN',
+ p_li_origin, p_li_provider, p_li_receiver);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droplisten_int( integer, integer, integer ) -->
+ <section id="schemadoc.function.droplisten-int-integer-integer-integer"
+ xreflabel="schemadocdroplisten_int( integer, integer, integer )">
+ <title id="schemadoc.function.droplisten-int-integer-integer-integer-title">
+ droplisten_int( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.droplisten-int-integer-integer-integer-titleabbrev">
+ droplisten_int( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ dropListen (li_origin, li_provider, li_receiver)
+
+Process the DROP_LISTEN event, deleting the sl_listen entry for
+the indicated (origin,provider,receiver) combination.
+ <programlisting>
+declare
+ p_li_origin alias for $1;
+ p_li_provider alias for $2;
+ p_li_receiver alias for $3;
+begin
+ return -1;
+
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ delete from schemadoc.sl_listen
+ where li_origin = p_li_origin
+ and li_provider = p_li_provider
+ and li_receiver = p_li_receiver;
+ if found then
+ return 1;
+ else
+ return 0;
+ end if;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function dropnode( integer ) -->
+ <section id="schemadoc.function.dropnode-integer"
+ xreflabel="schemadocdropnode( integer )">
+ <title id="schemadoc.function.dropnode-integer-title">
+ dropnode( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.dropnode-integer-titleabbrev">
+ dropnode( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ generate DROP_NODE event to drop node node_id from replication
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ v_node_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that this got called on a different node
+ -- ----
+ if p_no_id = schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: DROP_NODE cannot initiate on the dropped node';
+ end if;
+
+ select * into v_node_row from schemadoc.sl_node
+ where no_id = p_no_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: unknown node ID %', p_no_id;
+ end if;
+
+ -- ----
+ -- Make sure we do not break other nodes subscriptions with this
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe
+ where sub_provider = p_no_id)
+ then
+ raise exception 'Slony-I: Node % is still configured as data provider',
+ p_no_id;
+ end if;
+
+ -- ----
+ -- Make sure no set originates there any more
+ -- ----
+ if exists (select true from schemadoc.sl_set
+ where set_origin = p_no_id)
+ then
+ raise exception 'Slony-I: Node % is still origin of one or more sets',
+ p_no_id;
+ end if;
+
+ -- ----
+ -- Call the internal drop functionality and generate the event
+ -- ----
+ perform schemadoc.dropNode_int(p_no_id);
+ return schemadoc.createEvent('_schemadoc', 'DROP_NODE',
+ p_no_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function dropnode_int( integer ) -->
+ <section id="schemadoc.function.dropnode-int-integer"
+ xreflabel="schemadocdropnode_int( integer )">
+ <title id="schemadoc.function.dropnode-int-integer-title">
+ dropnode_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.dropnode-int-integer-titleabbrev">
+ dropnode_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ internal function to process DROP_NODE event to drop node node_id from replication
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- If the dropped node is a remote node, clean the configuration
+ -- from all traces for it.
+ -- ----
+ if p_no_id <> schemadoc.getLocalNodeId('_schemadoc') then
+ delete from schemadoc.sl_subscribe
+ where sub_receiver = p_no_id;
+ delete from schemadoc.sl_listen
+ where li_origin = p_no_id
+ or li_provider = p_no_id
+ or li_receiver = p_no_id;
+ delete from schemadoc.sl_path
+ where pa_server = p_no_id
+ or pa_client = p_no_id;
+ delete from schemadoc.sl_confirm
+ where con_origin = p_no_id
+ or con_received = p_no_id;
+ delete from schemadoc.sl_event
+ where ev_origin = p_no_id;
+ delete from schemadoc.sl_node
+ where no_id = p_no_id;
+
+ return p_no_id;
+ end if;
+
+ -- ----
+ -- This is us ... deactivate the node for now, the daemon
+ -- will call uninstallNode() in a separate transaction.
+ -- ----
+ update schemadoc.sl_node
+ set no_active = false
+ where no_id = p_no_id;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return p_no_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droppath( integer, integer ) -->
+ <section id="schemadoc.function.droppath-integer-integer"
+ xreflabel="schemadocdroppath( integer, integer )">
+ <title id="schemadoc.function.droppath-integer-integer-title">
+ droppath( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.droppath-integer-integer-titleabbrev">
+ droppath( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Generate DROP_PATH event to drop path from pa_server to pa_client
+ <programlisting>
+declare
+ p_pa_server alias for $1;
+ p_pa_client alias for $2;
+ v_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- There should be no existing subscriptions. Auto unsubscribing
+ -- is considered too dangerous.
+ -- ----
+ for v_row in select sub_set, sub_provider, sub_receiver
+ from schemadoc.sl_subscribe
+ where sub_provider = p_pa_server
+ and sub_receiver = p_pa_client
+ loop
+ raise exception
+ 'Slony-I: Path cannot be dropped, subscription of set % needs it',
+ v_row.sub_set;
+ end loop;
+
+ -- ----
+ -- Drop all sl_listen entries that depend on this path
+ -- ----
+ for v_row in select li_origin, li_provider, li_receiver
+ from schemadoc.sl_listen
+ where li_provider = p_pa_server
+ and li_receiver = p_pa_client
+ loop
+ perform schemadoc.dropListen(
+ v_row.li_origin, v_row.li_provider, v_row.li_receiver);
+ end loop;
+
+ -- ----
+ -- Now drop the path and create the event
+ -- ----
+ perform schemadoc.dropPath_int(p_pa_server, p_pa_client);
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return schemadoc.createEvent ('_schemadoc', 'DROP_PATH',
+ p_pa_server, p_pa_client);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droppath_int( integer, integer ) -->
+ <section id="schemadoc.function.droppath-int-integer-integer"
+ xreflabel="schemadocdroppath_int( integer, integer )">
+ <title id="schemadoc.function.droppath-int-integer-integer-title">
+ droppath_int( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.droppath-int-integer-integer-titleabbrev">
+ droppath_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Process DROP_PATH event to drop path from pa_server to pa_client
+ <programlisting>
+declare
+ p_pa_server alias for $1;
+ p_pa_client alias for $2;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Remove any dangling sl_listen entries with the server
+ -- as provider and the client as receiver. This must have
+ -- been cleared out before, but obviously was not.
+ -- ----
+ delete from schemadoc.sl_listen
+ where li_provider = p_pa_server
+ and li_receiver = p_pa_client;
+
+ delete from schemadoc.sl_path
+ where pa_server = p_pa_server
+ and pa_client = p_pa_client;
+
+ if found then
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return 1;
+ else
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return 0;
+ end if;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function dropset( integer ) -->
+ <section id="schemadoc.function.dropset-integer"
+ xreflabel="schemadocdropset( integer )">
+ <title id="schemadoc.function.dropset-integer-title">
+ dropset( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.dropset-integer-titleabbrev">
+ dropset( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Process DROP_SET event to drop replication of set set_id. This involves:
+- Restoring original triggers and rules
+- Removing all traces of the set configuration, including sequences, tables, subscribers, syncs, and the set itself
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ v_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the set exists and originates here
+ -- ----
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+
+ -- ----
+ -- Call the internal drop set functionality and generate the event
+ -- ----
+ perform schemadoc.dropSet_int(p_set_id);
+ return schemadoc.createEvent('_schemadoc', 'DROP_SET',
+ p_set_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function dropset_int( integer ) -->
+ <section id="schemadoc.function.dropset-int-integer"
+ xreflabel="schemadocdropset_int( integer )">
+ <title id="schemadoc.function.dropset-int-integer-title">
+ dropset_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.dropset-int-integer-titleabbrev">
+ dropset_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Restore all tables original triggers and rules and remove
+ -- our replication stuff.
+ -- ----
+ for v_tab_row in select tab_id from schemadoc.sl_table
+ where tab_set = p_set_id
+ order by tab_id
+ loop
+ perform schemadoc.alterTableRestore(v_tab_row.tab_id);
+ perform schemadoc.tableDropKey(v_tab_row.tab_id);
+ end loop;
+
+ -- ----
+ -- Remove all traces of the set configuration
+ -- ----
+ delete from schemadoc.sl_sequence
+ where seq_set = p_set_id;
+ delete from schemadoc.sl_table
+ where tab_set = p_set_id;
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_set_id;
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_set_id;
+ delete from schemadoc.sl_set
+ where set_id = p_set_id;
+
+ -- Regenerate sl_listen since we revised the subscriptions
+ perform schemadoc.RebuildListenEntries();
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droptrigger( integer, name ) -->
+ <section id="schemadoc.function.droptrigger-integer-name"
+ xreflabel="schemadocdroptrigger( integer, name )">
+ <title id="schemadoc.function.droptrigger-integer-name-title">
+ droptrigger( integer, name )
+ </title>
+ <titleabbrev id="schemadoc.function.droptrigger-integer-name-titleabbrev">
+ droptrigger( integer, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ dropTrigger (trig_tabid, trig_tgname)
+
+Submits DROP_TRIGGER event to indicate that trigger trig_tgname on
+replicated table trig_tabid WILL be disabled.
+ <programlisting>
+declare
+ p_trig_tabid alias for $1;
+ p_trig_tgname alias for $2;
+begin
+ perform schemadoc.dropTrigger_int(p_trig_tabid, p_trig_tgname);
+ return schemadoc.createEvent('_schemadoc', 'DROP_TRIGGER',
+ p_trig_tabid, p_trig_tgname);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function droptrigger_int( integer, name ) -->
+ <section id="schemadoc.function.droptrigger-int-integer-name"
+ xreflabel="schemadocdroptrigger_int( integer, name )">
+ <title id="schemadoc.function.droptrigger-int-integer-name-title">
+ droptrigger_int( integer, name )
+ </title>
+ <titleabbrev id="schemadoc.function.droptrigger-int-integer-name-titleabbrev">
+ droptrigger_int( integer, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ dropTrigger_int (trig_tabid, trig_tgname)
+
+Processes DROP_TRIGGER event to make sure that trigger trig_tgname on
+replicated table trig_tabid IS disabled.
+ <programlisting>
+declare
+ p_trig_tabid alias for $1;
+ p_trig_tgname alias for $2;
+ v_tab_altered boolean;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get the current table status (altered or not)
+ -- ----
+ select tab_altered into v_tab_altered
+ from schemadoc.sl_table where tab_id = p_trig_tabid;
+ if not found then
+ -- ----
+ -- Not found is no hard error here, because that might
+ -- mean that we are not subscribed to that set
+ -- ----
+ return 0;
+ end if;
+
+ -- ----
+ -- If the table is modified for replication, restore the original state
+ -- ----
+ if v_tab_altered then
+ perform schemadoc.alterTableRestore(p_trig_tabid);
+ end if;
+
+ -- ----
+ -- Remove the entry from sl_trigger
+ -- ----
+ delete from schemadoc.sl_trigger
+ where trig_tabid = p_trig_tabid
+ and trig_tgname = p_trig_tgname;
+
+ -- ----
+ -- Put the table back into replicated state if it was
+ -- ----
+ if v_tab_altered then
+ perform schemadoc.alterTableForReplication(p_trig_tabid);
+ end if;
+
+ return p_trig_tabid;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function enablenode( integer ) -->
+ <section id="schemadoc.function.enablenode-integer"
+ xreflabel="schemadocenablenode( integer )">
+ <title id="schemadoc.function.enablenode-integer-title">
+ enablenode( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.enablenode-integer-titleabbrev">
+ enablenode( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ no_id - Node ID #
+
+Generate the ENABLE_NODE event for node no_id
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ v_local_node_id int4;
+ v_node_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we are the node to activate and that we are
+ -- currently disabled.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select * into v_node_row
+ from schemadoc.sl_node
+ where no_id = p_no_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: node % not found', p_no_id;
+ end if;
+ if v_node_row.no_active then
+ raise exception 'Slony-I: node % is already active', p_no_id;
+ end if;
+
+ -- ----
+ -- Activate this node and generate the ENABLE_NODE event
+ -- ----
+ perform schemadoc.enableNode_int (p_no_id);
+ return schemadoc.createEvent('_schemadoc', 'ENABLE_NODE',
+ p_no_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function enablenode_int( integer ) -->
+ <section id="schemadoc.function.enablenode-int-integer"
+ xreflabel="schemadocenablenode_int( integer )">
+ <title id="schemadoc.function.enablenode-int-integer-title">
+ enablenode_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.enablenode-int-integer-titleabbrev">
+ enablenode_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ no_id - Node ID #
+
+Internal function to process the ENABLE_NODE event for node no_id
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ v_local_node_id int4;
+ v_node_row record;
+ v_sub_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the node is inactive
+ -- ----
+ select * into v_node_row
+ from schemadoc.sl_node
+ where no_id = p_no_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: node % not found', p_no_id;
+ end if;
+ if v_node_row.no_active then
+ return p_no_id;
+ end if;
+
+ -- ----
+ -- Activate the node and generate sl_confirm status rows for it.
+ -- ----
+ update schemadoc.sl_node
+ set no_active = 't'
+ where no_id = p_no_id;
+ insert into schemadoc.sl_confirm
+ (con_origin, con_received, con_seqno)
+ select no_id, p_no_id, 0 from schemadoc.sl_node
+ where no_id != p_no_id
+ and no_active;
+ insert into schemadoc.sl_confirm
+ (con_origin, con_received, con_seqno)
+ select p_no_id, no_id, 0 from schemadoc.sl_node
+ where no_id != p_no_id
+ and no_active;
+
+ -- ----
+ -- Generate ENABLE_SUBSCRIPTION events for all sets that
+ -- origin here and are subscribed by the just enabled node.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ for v_sub_row in select SUB.sub_set, SUB.sub_provider from
+ schemadoc.sl_set S,
+ schemadoc.sl_subscribe SUB
+ where S.set_origin = v_local_node_id
+ and S.set_id = SUB.sub_set
+ and SUB.sub_receiver = p_no_id
+ for update of S
+ loop
+ perform schemadoc.enableSubscription (v_sub_row.sub_set,,
+ v_sub_row.sub_provider, p_no_id);
+ end loop;
+
+ return p_no_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function enablesubscription( integer, integer, integer ) -->
+ <section id="schemadoc.function.enablesubscription-integer-integer-integer"
+ xreflabel="schemadocenablesubscription( integer, integer, integer )">
+ <title id="schemadoc.function.enablesubscription-integer-integer-integer-title">
+ enablesubscription( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.enablesubscription-integer-integer-integer-titleabbrev">
+ enablesubscription( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ enableSubscription (sub_set, sub_provider, sub_receiver)
+
+Indicates that sub_receiver intends subscribing to set sub_set from
+sub_provider. Work is all done by the internal function
+enableSubscription_int (sub_set, sub_provider, sub_receiver).
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_provider alias for $2;
+ p_sub_receiver alias for $3;
+begin
+ return schemadoc.enableSubscription_int (p_sub_set,
+ p_sub_provider, p_sub_receiver);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function enablesubscription_int( integer, integer, integer ) -->
+ <section id="schemadoc.function.enablesubscription-int-integer-integer-integer"
+ xreflabel="schemadocenablesubscription_int( integer, integer, integer )">
+ <title id="schemadoc.function.enablesubscription-int-integer-integer-integer-title">
+ enablesubscription_int( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.enablesubscription-int-integer-integer-integer-titleabbrev">
+ enablesubscription_int( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ enableSubscription_int (sub_set, sub_provider, sub_receiver)
+
+Internal function to enable subscription of node sub_receiver to set
+sub_set via node sub_provider.
+
+slon does most of the work; all we need do here is to remember that it
+happened. The function updates sl_subscribe, indicating that the
+subscription has become active.
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_provider alias for $2;
+ p_sub_receiver alias for $3;
+ v_n int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- The real work is done in the replication engine. All
+ -- we have to do here is remembering that it happened.
+ -- ----
+
+ -- ----
+ -- Well, not only ... we might be missing an important event here
+ -- ----
+ if not exists (select true from schemadoc.sl_path
+ where pa_server = p_sub_provider
+ and pa_client = p_sub_receiver)
+ then
+ insert into schemadoc.sl_path
+ (pa_server, pa_client, pa_conninfo, pa_connretry)
+ values
+ (p_sub_provider, p_sub_receiver,
+ '<event pending>', 10);
+ end if;
+
+ update schemadoc.sl_subscribe
+ set sub_active = 't'
+ where sub_set = p_sub_set
+ and sub_receiver = p_sub_receiver;
+ get diagnostics v_n = row_count;
+ if v_n = 0 then
+ insert into schemadoc.sl_subscribe
+ (sub_set, sub_provider, sub_receiver,
+ sub_forward, sub_active)
+ values
+ (p_sub_set, p_sub_provider, p_sub_receiver,
+ false, true);
+ end if;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return p_sub_set;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function failednode( integer, integer ) -->
+ <section id="schemadoc.function.failednode-integer-integer"
+ xreflabel="schemadocfailednode( integer, integer )">
+ <title id="schemadoc.function.failednode-integer-integer-title">
+ failednode( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.failednode-integer-integer-titleabbrev">
+ failednode( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Initiate failover from failed_node to backup_node. This function must be called on all nodes,
+and then waited for the restart of all node daemons.
+ <programlisting>
+declare
+ p_failed_node alias for $1;
+ p_backup_node alias for $2;
+ v_row record;
+ v_row2 record;
+ v_n int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- All consistency checks first
+ -- Check that every system that has a path to the failed node
+ -- also has a path to the backup node.
+ -- ----
+ for v_row in select P.pa_client
+ from schemadoc.sl_path P
+ where P.pa_server = p_failed_node
+ and P.pa_client <> p_backup_node
+ and not exists (select true from schemadoc.sl_path PP
+ where PP.pa_server = p_backup_node
+ and PP.pa_client = P.pa_client)
+ loop
+ raise exception 'Slony-I: cannot failover - node % has no path to the backup node',
+ v_row.pa_client;
+ end loop;
+
+ -- ----
+ -- Check all sets originating on the failed node
+ -- ----
+ for v_row in select set_id
+ from schemadoc.sl_set
+ where set_origin = p_failed_node
+ loop
+ -- ----
+ -- Check that the backup node is subscribed to all sets
+ -- that origin on the failed node
+ -- ----
+ select into v_row2 sub_forward, sub_active
+ from schemadoc.sl_subscribe
+ where sub_set = v_row.set_id
+ and sub_receiver = p_backup_node;
+ if not found then
+ raise exception 'Slony-I: cannot failover - node % is not subscribed to set %',
+ p_backup_node, v_row.set_id;
+ end if;
+
+ -- ----
+ -- Check that the subscription is active
+ -- ----
+ if not v_row2.sub_active then
+ raise exception 'Slony-I: cannot failover - subscription for set % is not active',
+ v_row.set_id;
+ end if;
+
+ -- ----
+ -- If there are other subscribers, the backup node needs to
+ -- be a forwarder too.
+ -- ----
+ select into v_n count(*)
+ from schemadoc.sl_subscribe
+ where sub_set = v_row.set_id
+ and sub_receiver <> p_backup_node;
+ if v_n > 0 and not v_row2.sub_forward then
+ raise exception 'Slony-I: cannot failover - node % is not a forwarder of set %',
+ p_backup_node, v_row.set_id;
+ end if;
+ end loop;
+
+ -- ----
+ -- Terminate all connections of the failed node the hard way
+ -- ----
+ perform schemadoc.terminateNodeConnections(
+ '_schemadoc_Node_' || p_failed_node);
+
+-- Note that the following code should all become obsolete in the wake
+-- of the availability of RebuildListenEntries()...
+
+if false then
+ -- ----
+ -- Let every node that listens for something on the failed node
+ -- listen for that on the backup node instead.
+ -- ----
+ for v_row in select * from schemadoc.sl_listen
+ where li_provider = p_failed_node
+ and li_receiver <> p_backup_node
+ loop
+ perform schemadoc.storeListen_int(v_row.li_origin,
+ p_backup_node, v_row.li_receiver);
+ end loop;
+
+ -- ----
+ -- Let the backup node listen for all events where the
+ -- failed node did listen for it.
+ -- ----
+ for v_row in select li_origin, li_provider
+ from schemadoc.sl_listen
+ where li_receiver = p_failed_node
+ and li_provider <> p_backup_node
+ loop
+ perform schemadoc.storeListen_int(v_row.li_origin,
+ v_row.li_provider, p_backup_node);
+ end loop;
+
+ -- ----
+ -- Remove all sl_listen entries that receive anything from the
+ -- failed node.
+ -- ----
+ delete from schemadoc.sl_listen
+ where li_provider = p_failed_node
+ or li_receiver = p_failed_node;
+end if;
+
+ -- ----
+ -- Move the sets
+ -- ----
+ for v_row in select S.set_id, (select count(*)
+ from schemadoc.sl_subscribe SUB
+ where S.set_id = SUB.sub_set
+ and SUB.sub_receiver <> p_backup_node
+ and SUB.sub_provider = p_failed_node)
+ as num_direct_receivers
+ from schemadoc.sl_set S
+ where S.set_origin = p_failed_node
+ for update
+ loop
+ -- ----
+ -- If the backup node is the only direct subscriber ...
+ -- ----
+ if v_row.num_direct_receivers = 0 then
+raise notice 'failedNode: set % has no other direct receivers - move now', v_row.set_id;
+ -- ----
+ -- backup_node is the only direct subscriber, move the set
+ -- right now. On the backup node itself that includes restoring
+ -- all user mode triggers, removing the protection trigger,
+ -- adding the log trigger, removing the subscription and the
+ -- obsolete setsync status.
+ -- ----
+ if p_backup_node = schemadoc.getLocalNodeId('_schemadoc') then
+ for v_row2 in select * from schemadoc.sl_table
+ where tab_set = v_row.set_id
+ loop
+ perform schemadoc.alterTableRestore(v_row2.tab_id);
+ end loop;
+ end if;
+
+ update schemadoc.sl_set set set_origin = p_backup_node
+ where set_id = v_row.set_id;
+
+ if p_backup_node = schemadoc.getLocalNodeId('_schemadoc') then
+ delete from schemadoc.sl_setsync
+ where ssy_setid = v_row.set_id;
+
+ for v_row2 in select * from schemadoc.sl_table
+ where tab_set = v_row.set_id
+ loop
+ perform schemadoc.alterTableForReplication(v_row2.tab_id);
+ end loop;
+ end if;
+
+ delete from schemadoc.sl_subscribe
+ where sub_set = v_row.set_id
+ and sub_receiver = p_backup_node;
+ else
+raise notice 'failedNode: set % has other direct receivers - change providers only', v_row.set_id;
+ -- ----
+ -- Backup node is not the only direct subscriber. This
+ -- means that at this moment, we redirect all direct
+ -- subscribers to receive from the backup node, and the
+ -- backup node itself to receive from another one.
+ -- The admin utility will wait for the slon engine to
+ -- restart and then call failedNode2() on the node with
+ -- the highest SYNC and redirect this to it on
+ -- backup node later.
+ -- ----
+ update schemadoc.sl_subscribe
+ set sub_provider = (select min(SS.sub_receiver)
+ from schemadoc.sl_subscribe SS
+ where SS.sub_set = v_row.set_id
+ and SS.sub_provider = p_failed_node
+ and SS.sub_receiver <> p_backup_node
+ and SS.sub_forward)
+ where sub_set = v_row.set_id
+ and sub_receiver = p_backup_node;
+ update schemadoc.sl_subscribe
+ set sub_provider = p_backup_node
+ where sub_set = v_row.set_id
+ and sub_provider = p_failed_node
+ and sub_receiver <> p_backup_node;
+ end if;
+ end loop;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ -- ----
+ -- Make sure the node daemon will restart
+ -- ----
+ notify "_schemadoc_Restart";
+
+ -- ----
+ -- That is it - so far.
+ -- ----
+ return p_failed_node;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function failednode2( integer, integer, integer, bigint, bigint ) -->
+ <section id="schemadoc.function.failednode2-integer-integer-integer-bigint-bigint"
+ xreflabel="schemadocfailednode2( integer, integer, integer, bigint, bigint )">
+ <title id="schemadoc.function.failednode2-integer-integer-integer-bigint-bigint-title">
+ failednode2( integer, integer, integer, bigint, bigint )
+ </title>
+ <titleabbrev id="schemadoc.function.failednode2-integer-integer-integer-bigint-bigint-titleabbrev">
+ failednode2( integer, integer, integer, bigint, bigint )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION failedNode2 (failed_node, backup_node, set_id, ev_seqno, ev_seqfake)
+
+On the node that has the highest sequence number of the failed node,
+fake the FAILED_NODE event.
+ <programlisting>
+declare
+ p_failed_node alias for $1;
+ p_backup_node alias for $2;
+ p_set_id alias for $3;
+ p_ev_seqno alias for $4;
+ p_ev_seqfake alias for $5;
+ v_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ select * into v_row
+ from schemadoc.sl_event
+ where ev_origin = p_failed_node
+ and ev_seqno = p_ev_seqno;
+ if not found then
+ raise exception 'Slony-I: event %,% not found',
+ p_failed_node, p_ev_seqno;
+ end if;
+
+ insert into schemadoc.sl_event
+ (ev_origin, ev_seqno, ev_timestamp,
+ ev_minxid, ev_maxxid, ev_xip,
+ ev_type, ev_data1, ev_data2, ev_data3)
+ values
+ (p_failed_node, p_ev_seqfake, CURRENT_TIMESTAMP,
+ v_row.ev_minxid, v_row.ev_maxxid, v_row.ev_xip,
+ 'FAILOVER_SET', p_failed_node::text, p_backup_node::text,
+ p_set_id::text);
+ insert into schemadoc.sl_confirm
+ (con_origin, con_received, con_seqno, con_timestamp)
+ values
+ (p_failed_node, schemadoc.getLocalNodeId('_schemadoc'),
+ p_ev_seqfake, CURRENT_TIMESTAMP);
+ notify "_schemadoc_Event";
+ notify "_schemadoc_Confirm";
+ notify "_schemadoc_Restart";
+
+ perform schemadoc.failoverSet_int(p_failed_node,
+ p_backup_node, p_set_id);
+
+ return p_ev_seqfake;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function failoverset_int( integer, integer, integer ) -->
+ <section id="schemadoc.function.failoverset-int-integer-integer-integer"
+ xreflabel="schemadocfailoverset_int( integer, integer, integer )">
+ <title id="schemadoc.function.failoverset-int-integer-integer-integer-title">
+ failoverset_int( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.failoverset-int-integer-integer-integer-titleabbrev">
+ failoverset_int( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION failoverSet_int (failed_node, backup_node, set_id)
+
+Finish failover for one set.
+ <programlisting>
+declare
+ p_failed_node alias for $1;
+ p_backup_node alias for $2;
+ p_set_id alias for $3;
+ v_row record;
+ v_last_sync int8;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Change the origin of the set now to the backup node.
+ -- On the backup node this includes changing all the
+ -- trigger and protection stuff
+ -- ----
+ if p_backup_node = schemadoc.getLocalNodeId('_schemadoc') then
+ for v_row in select * from schemadoc.sl_table
+ where tab_set = p_set_id
+ loop
+ perform schemadoc.alterTableRestore(v_row.tab_id);
+ end loop;
+
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_set_id;
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = p_backup_node;
+ update schemadoc.sl_set
+ set set_origin = p_backup_node
+ where set_id = p_set_id;
+
+ for v_row in select * from schemadoc.sl_table
+ where tab_set = p_set_id
+ loop
+ perform schemadoc.alterTableForReplication(v_row.tab_id);
+ end loop;
+ else
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = p_backup_node;
+ update schemadoc.sl_set
+ set set_origin = p_backup_node
+ where set_id = p_set_id;
+ end if;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ -- ----
+ -- If we are a subscriber of the set ourself, change our
+ -- setsync status to reflect the new set origin.
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = schemadoc.getLocalNodeId(
+ '_schemadoc'))
+ then
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_set_id;
+
+ select coalesce(max(ev_seqno), 0) into v_last_sync
+ from schemadoc.sl_event
+ where ev_origin = p_backup_node
+ and ev_type = 'SYNC';
+ if v_last_sync > 0 then
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ select p_set_id, p_backup_node, v_last_sync,
+ ev_minxid, ev_maxxid, ev_xip, NULL
+ from schemadoc.sl_event
+ where ev_origin = p_backup_node
+ and ev_seqno = v_last_sync;
+ else
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ values (p_set_id, p_backup_node, '0',
+ '0', '0', '', NULL);
+ end if;
+
+ end if;
+
+ return p_failed_node;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function forwardconfirm( integer, integer, bigint, timestamp without time zone ) -->
+ <section id="schemadoc.function.forwardconfirm-integer-integer-bigint-timestamp-without-time-zone"
+ xreflabel="schemadocforwardconfirm( integer, integer, bigint, timestamp without time zone )">
+ <title id="schemadoc.function.forwardconfirm-integer-integer-bigint-timestamp-without-time-zone-title">
+ forwardconfirm( integer, integer, bigint, timestamp without time zone )
+ </title>
+ <titleabbrev id="schemadoc.function.forwardconfirm-integer-integer-bigint-timestamp-without-time-zone-titleabbrev">
+ forwardconfirm( integer, integer, bigint, timestamp without time zone )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ forwardConfirm (p_con_origin, p_con_received, p_con_seqno, p_con_timestamp)
+
+Confirms (recorded in sl_confirm) that items from p_con_origin up to
+p_con_seqno have been received by node p_con_received as of
+p_con_timestamp, and raises an event to forward this confirmation.
+ <programlisting>
+declare
+ p_con_origin alias for $1;
+ p_con_received alias for $2;
+ p_con_seqno alias for $3;
+ p_con_timestamp alias for $4;
+ v_max_seqno bigint;
+begin
+ select into v_max_seqno coalesce(max(con_seqno), 0)
+ from schemadoc.sl_confirm
+ where con_origin = p_con_origin
+ and con_received = p_con_received;
+ if v_max_seqno < p_con_seqno then
+ insert into schemadoc.sl_confirm
+ (con_origin, con_received, con_seqno, con_timestamp)
+ values (p_con_origin, p_con_received, p_con_seqno,
+ p_con_timestamp);
+ notify "_schemadoc_Confirm";
+ v_max_seqno = p_con_seqno;
+ end if;
+
+ return v_max_seqno;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function generate_sync_event( interval ) -->
+ <section id="schemadoc.function.generate-sync-event-interval"
+ xreflabel="schemadocgenerate_sync_event( interval )">
+ <title id="schemadoc.function.generate-sync-event-interval-title">
+ generate_sync_event( interval )
+ </title>
+ <titleabbrev id="schemadoc.function.generate-sync-event-interval-titleabbrev">
+ generate_sync_event( interval )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Generate a sync event if there has not been one in 30 seconds.
+ <programlisting>
+declare
+ p_interval alias for $1;
+ v_node_row record;
+
+BEGIN
+ select 1 into v_node_row from schemadoc.sl_event
+ where ev_type = 'SYNC' and ev_origin = schemadoc.getLocalNodeId('schemadoc')
+ and ev_timestamp > now() - p_interval limit 1;
+ if not found then
+ -- If there has been no SYNC in the last interval, then push one
+ perform schemadoc.createEvent('schemadoc', 'SYNC', NULL);
+ return 1;
+ else
+ return 0;
+ end if;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function getlocalnodeid( name ) -->
+ <section id="schemadoc.function.getlocalnodeid-name"
+ xreflabel="schemadocgetlocalnodeid( name )">
+ <title id="schemadoc.function.getlocalnodeid-name-title">
+ getlocalnodeid( name )
+ </title>
+ <titleabbrev id="schemadoc.function.getlocalnodeid-name-titleabbrev">
+ getlocalnodeid( name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the node ID of the node being serviced on the local database
+ <programlisting>_Slony_I_getLocalNodeId</programlisting>
+ </para>
+ </section>
+
+<!-- Function getmoduleversion( ) -->
+ <section id="schemadoc.function.getmoduleversion"
+ xreflabel="schemadocgetmoduleversion( )">
+ <title id="schemadoc.function.getmoduleversion-title">
+ getmoduleversion( )
+ </title>
+ <titleabbrev id="schemadoc.function.getmoduleversion-titleabbrev">
+ getmoduleversion( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the compiled-in version number of the Slony-I shared object
+ <programlisting>_Slony_I_getModuleVersion</programlisting>
+ </para>
+ </section>
+
+<!-- Function getsessionrole( name ) -->
+ <section id="schemadoc.function.getsessionrole-name"
+ xreflabel="schemadocgetsessionrole( name )">
+ <title id="schemadoc.function.getsessionrole-name-title">
+ getsessionrole( name )
+ </title>
+ <titleabbrev id="schemadoc.function.getsessionrole-name-titleabbrev">
+ getsessionrole( name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ not yet documented
+ <programlisting>_Slony_I_getSessionRole</programlisting>
+ </para>
+ </section>
+
+<!-- Function initializelocalnode( integer, text ) -->
+ <section id="schemadoc.function.initializelocalnode-integer-text"
+ xreflabel="schemadocinitializelocalnode( integer, text )">
+ <title id="schemadoc.function.initializelocalnode-integer-text-title">
+ initializelocalnode( integer, text )
+ </title>
+ <titleabbrev id="schemadoc.function.initializelocalnode-integer-text-titleabbrev">
+ initializelocalnode( integer, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ no_id - Node ID #
+no_comment - Human-oriented comment
+
+Initializes the new node, no_id
+ <programlisting>
+declare
+ p_local_node_id alias for $1;
+ p_comment alias for $2;
+ v_old_node_id int4;
+ v_first_log_no int4;
+ v_event_seq int8;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Make sure this node is uninitialized or got reset
+ -- ----
+ select last_value::int4 into v_old_node_id from schemadoc.sl_local_node_id;
+ if v_old_node_id != -1 then
+ raise exception 'Slony-I: This node is already initialized';
+ end if;
+
+ -- ----
+ -- Set sl_local_node_id to the requested value and add our
+ -- own system to sl_node.
+ -- ----
+ perform setval('schemadoc.sl_local_node_id', p_local_node_id);
+ perform setval('schemadoc.sl_rowid_seq',
+ p_local_node_id::int8 * '1000000000000000'::int8);
+ perform schemadoc.storeNode_int (p_local_node_id, p_comment, false);
+
+ return p_local_node_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function lockedset( ) -->
+ <section id="schemadoc.function.lockedset"
+ xreflabel="schemadoclockedset( )">
+ <title id="schemadoc.function.lockedset-title">
+ lockedset( )
+ </title>
+ <titleabbrev id="schemadoc.function.lockedset-titleabbrev">
+ lockedset( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>"trigger"</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Trigger function to prevent modifications to a table before and after a moveSet()
+ <programlisting>_Slony_I_lockedSet</programlisting>
+ </para>
+ </section>
+
+<!-- Function lockset( integer ) -->
+ <section id="schemadoc.function.lockset-integer"
+ xreflabel="schemadoclockset( integer )">
+ <title id="schemadoc.function.lockset-integer-title">
+ lockset( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.lockset-integer-titleabbrev">
+ lockset( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ lockSet(set_id)
+
+Add a special trigger to all tables of a set that disables access to
+it.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ v_local_node_id int4;
+ v_set_row record;
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the set exists and that we are the origin
+ -- and that it is not already locked.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select * into v_set_row from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_row.set_origin <> v_local_node_id then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+ if v_set_row.set_locked notnull then
+ raise exception 'Slony-I: set % is already locked', p_set_id;
+ end if;
+
+ -- ----
+ -- Place the lockedSet trigger on all tables in the set.
+ -- ----
+ for v_tab_row in select T.tab_id,
+ "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) as tab_fqname
+ from schemadoc.sl_table T,
+ "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN
+ where T.tab_set = p_set_id
+ and T.tab_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid
+ order by tab_id
+ loop
+ execute 'create trigger "_schemadoc_lockedset_' ||
+ v_tab_row.tab_id ||
+ '" before insert or update or delete on ' ||
+ v_tab_row.tab_fqname || ' for each row execute procedure
+ schemadoc.lockedSet (''_schemadoc'');';
+ end loop;
+
+ -- ----
+ -- Remember our snapshots xmax as for the set locking
+ -- ----
+ update schemadoc.sl_set
+ set set_locked = schemadoc.getMaxXid()
+ where set_id = p_set_id;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function logtrigger( ) -->
+ <section id="schemadoc.function.logtrigger"
+ xreflabel="schemadoclogtrigger( )">
+ <title id="schemadoc.function.logtrigger-title">
+ logtrigger( )
+ </title>
+ <titleabbrev id="schemadoc.function.logtrigger-titleabbrev">
+ logtrigger( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>"trigger"</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ This is the trigger that is executed on the origin node that causes
+updates to be recorded in sl_log_1/sl_log_2.
+ <programlisting>_Slony_I_logTrigger</programlisting>
+ </para>
+ </section>
+
+<!-- Function mergeset( integer, integer ) -->
+ <section id="schemadoc.function.mergeset-integer-integer"
+ xreflabel="schemadocmergeset( integer, integer )">
+ <title id="schemadoc.function.mergeset-integer-integer-title">
+ mergeset( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.mergeset-integer-integer-titleabbrev">
+ mergeset( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Generate MERGE_SET event to request that sets be merged together.
+
+Both sets must exist, and originate on the same node. They must be
+subscribed by the same set of nodes.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_add_id alias for $2;
+ v_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that both sets exist and originate here
+ -- ----
+ if p_set_id = p_add_id then
+ raise exception 'Slony-I: merged set ids cannot be identical';
+ end if;
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = p_add_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_add_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_add_id;
+ end if;
+
+ -- ----
+ -- Check that both sets are subscribed by the same set of nodes
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = p_set_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = p_add_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ p_set_id, p_add_id;
+ end if;
+
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = p_add_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = p_set_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ p_add_id, p_set_id;
+ end if;
+
+ -- ----
+ -- Create a SYNC event, merge the sets, create a MERGE_SET event
+ -- ----
+ perform schemadoc.createEvent('_schemadoc', 'SYNC', NULL);
+ perform schemadoc.mergeSet_int(p_set_id, p_add_id);
+ return schemadoc.createEvent('_schemadoc', 'MERGE_SET',
+ p_set_id, p_add_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function mergeset_int( integer, integer ) -->
+ <section id="schemadoc.function.mergeset-int-integer-integer"
+ xreflabel="schemadocmergeset_int( integer, integer )">
+ <title id="schemadoc.function.mergeset-int-integer-integer-title">
+ mergeset_int( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.mergeset-int-integer-integer-titleabbrev">
+ mergeset_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ mergeSet_int(set_id, add_id) - Perform MERGE_SET event, merging all objects from
+set add_id into set set_id.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_add_id alias for $2;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ update schemadoc.sl_sequence
+ set seq_set = p_set_id
+ where seq_set = p_add_id;
+ update schemadoc.sl_table
+ set tab_set = p_set_id
+ where tab_set = p_add_id;
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_add_id;
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_add_id;
+ delete from schemadoc.sl_set
+ where set_id = p_add_id;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function moveset( integer, integer ) -->
+ <section id="schemadoc.function.moveset-integer-integer"
+ xreflabel="schemadocmoveset( integer, integer )">
+ <title id="schemadoc.function.moveset-integer-integer-title">
+ moveset( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.moveset-integer-integer-titleabbrev">
+ moveset( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ moveSet(set_id, new_origin)
+
+Generate MOVE_SET event to request that the origin for set set_id be moved to node new_origin
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_new_origin alias for $2;
+ v_local_node_id int4;
+ v_set_row record;
+ v_sub_row record;
+ v_sync_seqno int8;
+ v_lv_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the set is locked and that this locking
+ -- happened long enough ago.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select * into v_set_row from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_row.set_origin <> v_local_node_id then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+ if v_set_row.set_locked isnull then
+ raise exception 'Slony-I: set % is not locked', p_set_id;
+ end if;
+ if v_set_row.set_locked > schemadoc.getMinXid() then
+ raise exception 'Slony-I: cannot move set % yet, transactions < % are still in progress',
+ p_set_id, v_set_row.set_locked;
+ end if;
+
+ -- ----
+ -- Unlock the set
+ -- ----
+ perform schemadoc.unlockSet(p_set_id);
+
+ -- ----
+ -- Check that the new_origin is an active subscriber of the set
+ -- ----
+ select * into v_sub_row from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = p_new_origin;
+ if not found then
+ raise exception 'Slony-I: set % is not subscribed by node %',
+ p_set_id, p_new_origin;
+ end if;
+ if not v_sub_row.sub_active then
+ raise exception 'Slony-I: subsctiption of node % for set % is inactive',
+ p_new_origin, p_set_id;
+ end if;
+
+ -- ----
+ -- Reconfigure everything
+ -- ----
+ perform schemadoc.moveSet_int(p_set_id, v_local_node_id,
+ p_new_origin);
+
+ perform schemadoc.RebuildListenEntries();
+
+ -- ----
+ -- At this time we hold access exclusive locks for every table
+ -- in the set. But we did move the set to the new origin, so the
+ -- createEvent() we are doing now will not record the sequences.
+ -- ----
+ v_sync_seqno := schemadoc.createEvent('_schemadoc', 'SYNC');
+ insert into schemadoc.sl_seqlog
+ (seql_seqid, seql_origin, seql_ev_seqno, seql_last_value)
+ select seq_id, v_local_node_id, v_sync_seqno, seq_last_value
+ from schemadoc.sl_seqlastvalue
+ where seq_set = p_set_id;
+
+ -- ----
+ -- Finally we generate the real event
+ -- ----
+ return schemadoc.createEvent('_schemadoc', 'MOVE_SET',
+ p_set_id, v_local_node_id, p_new_origin);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function moveset_int( integer, integer, integer ) -->
+ <section id="schemadoc.function.moveset-int-integer-integer-integer"
+ xreflabel="schemadocmoveset_int( integer, integer, integer )">
+ <title id="schemadoc.function.moveset-int-integer-integer-integer-title">
+ moveset_int( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.moveset-int-integer-integer-integer-titleabbrev">
+ moveset_int( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ moveSet(set_id, old_origin, new_origin)
+
+Process MOVE_SET event to request that the origin for set set_id be
+moved from old_origin to node new_origin
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_old_origin alias for $2;
+ p_new_origin alias for $3;
+ v_local_node_id int4;
+ v_tab_row record;
+ v_sub_row record;
+ v_sub_node int4;
+ v_sub_last int4;
+ v_sub_next int4;
+ v_last_sync int8;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get our local node ID
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+
+ -- ----
+ -- If we are the old or new origin of the set, we need to
+ -- remove the log trigger from all tables first.
+ -- ----
+ if v_local_node_id = p_old_origin or v_local_node_id = p_new_origin then
+ for v_tab_row in select tab_id from schemadoc.sl_table
+ where tab_set = p_set_id
+ order by tab_id
+ loop
+ perform schemadoc.alterTableRestore(v_tab_row.tab_id);
+ end loop;
+ end if;
+
+ -- ----
+ -- Next we have to reverse the subscription path
+ -- ----
+ v_sub_last = p_new_origin;
+ select sub_provider into v_sub_node
+ from schemadoc.sl_subscribe
+ where sub_receiver = p_new_origin;
+ if not found then
+ raise exception 'Slony-I: subscription path broken in moveSet_int';
+ end if;
+ while v_sub_node <> p_old_origin loop
+ -- ----
+ -- Tracing node by node, the old receiver is now in
+ -- v_sub_last and the old provider is in v_sub_node.
+ -- ----
+
+ -- ----
+ -- Get the current provider of this node as next
+ -- and change the provider to the previous one in
+ -- the reverse chain.
+ -- ----
+ select sub_provider into v_sub_next
+ from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = v_sub_node
+ for update;
+ if not found then
+ raise exception 'Slony-I: subscription path broken in moveSet_int';
+ end if;
+ update schemadoc.sl_subscribe
+ set sub_provider = v_sub_last
+ where sub_set = p_set_id
+ and sub_receiver = v_sub_node;
+
+ v_sub_last = v_sub_node;
+ v_sub_node = v_sub_next;
+ end loop;
+
+ -- ----
+ -- This includes creating a subscription for the old origin
+ -- ----
+ insert into schemadoc.sl_subscribe
+ (sub_set, sub_provider, sub_receiver,
+ sub_forward, sub_active)
+ values (p_set_id, v_sub_last, p_old_origin, true, true);
+ if v_local_node_id = p_old_origin then
+ select coalesce(max(ev_seqno), 0) into v_last_sync
+ from schemadoc.sl_event
+ where ev_origin = p_new_origin
+ and ev_type = 'SYNC';
+ if v_last_sync > 0 then
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ select p_set_id, p_new_origin, v_last_sync,
+ ev_minxid, ev_maxxid, ev_xip, NULL
+ from schemadoc.sl_event
+ where ev_origin = p_new_origin
+ and ev_seqno = v_last_sync;
+ else
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ values (p_set_id, p_new_origin, '0',
+ '0', '0', '', NULL);
+ end if;
+ end if;
+
+ -- ----
+ -- Now change the ownership of the set.
+ -- ----
+ update schemadoc.sl_set
+ set set_origin = p_new_origin
+ where set_id = p_set_id;
+
+ -- ----
+ -- On the new origin, delete the obsolete setsync information
+ -- and the subscription.
+ -- ----
+ if v_local_node_id = p_new_origin then
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_set_id;
+ else
+ if v_local_node_id <> p_old_origin then
+ --
+ -- On every other node, change the setsync so that it will
+ -- pick up from the new origins last known sync.
+ --
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_set_id;
+ select coalesce(max(ev_seqno), 0) into v_last_sync
+ from schemadoc.sl_event
+ where ev_origin = p_new_origin
+ and ev_type = 'SYNC';
+ if v_last_sync > 0 then
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ select p_set_id, p_new_origin, v_last_sync,
+ ev_minxid, ev_maxxid, ev_xip, NULL
+ from schemadoc.sl_event
+ where ev_origin = p_new_origin
+ and ev_seqno = v_last_sync;
+ else
+ insert into schemadoc.sl_setsync
+ (ssy_setid, ssy_origin, ssy_seqno,
+ ssy_minxid, ssy_maxxid, ssy_xip, ssy_action_list)
+ values (p_set_id, p_new_origin, '0',
+ '0', '0', '', NULL);
+ end if;
+ end if;
+ end if;
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = p_new_origin;
+
+ -- Regenerate sl_listen since we revised the subscriptions
+ perform schemadoc.RebuildListenEntries();
+
+ -- ----
+ -- If we are the new or old origin, we have to
+ -- put all the tables into altered state again.
+ -- ----
+ if v_local_node_id = p_old_origin or v_local_node_id = p_new_origin then
+ for v_tab_row in select tab_id from schemadoc.sl_table
+ where tab_set = p_set_id
+ order by tab_id
+ loop
+ perform schemadoc.alterTableForReplication(v_tab_row.tab_id);
+ end loop;
+ end if;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function rebuildlistenentries( ) -->
+ <section id="schemadoc.function.rebuildlistenentries"
+ xreflabel="schemadocrebuildlistenentries( )">
+ <title id="schemadoc.function.rebuildlistenentries-title">
+ rebuildlistenentries( )
+ </title>
+ <titleabbrev id="schemadoc.function.rebuildlistenentries-titleabbrev">
+ rebuildlistenentries( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ RebuildListenEntries(p_provider, p_receiver)
+
+Invoked by various subscription and path modifying functions, this
+rewrites the sl_listen entries, adding in all the ones required to
+allow communications between nodes in the Slony-I cluster.
+ <programlisting>
+declare
+ v_row record;
+begin
+ -- First remove the entire configuration
+ delete from schemadoc.sl_listen;
+
+ -- The loop over every possible pair of origin, receiver
+ for v_row in select N1.no_id as origin, N2.no_id as receiver
+ from schemadoc.sl_node N1, schemadoc.sl_node N2
+ where N1.no_id <> N2.no_id
+ loop
+ perform schemadoc.RebuildListenEntriesOne(v_row.origin, v_row.receiver);
+ end loop;
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function rebuildlistenentriesone( integer, integer ) -->
+ <section id="schemadoc.function.rebuildlistenentriesone-integer-integer"
+ xreflabel="schemadocrebuildlistenentriesone( integer, integer )">
+ <title id="schemadoc.function.rebuildlistenentriesone-integer-integer-title">
+ rebuildlistenentriesone( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.rebuildlistenentriesone-integer-integer-titleabbrev">
+ rebuildlistenentriesone( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ RebuildListenEntriesOne(p_origin, p_receiver)
+
+Rebuilding of sl_listen entries for one origin, receiver pair.
+ <programlisting>
+declare
+ p_origin alias for $1;
+ p_receiver alias for $2;
+ v_row record;
+begin
+ -- 1. If the receiver is subscribed to any set from the origin,
+ -- listen on the same provider(s).
+ for v_row in select distinct sub_provider
+ from schemadoc.sl_subscribe, schemadoc.sl_set,
+ schemadoc.sl_path
+ where sub_set = set_id
+ and set_origin = p_origin
+ and sub_receiver = p_receiver
+ and sub_provider = pa_server
+ and sub_receiver = pa_client
+ loop
+ perform schemadoc.storeListen_int(p_origin,
+ v_row.sub_provider, p_receiver);
+ end loop;
+ if found then
+ return 1;
+ end if;
+
+ -- 2. If the receiver has a direct path to the provider,
+ -- use that.
+ if exists (select true
+ from schemadoc.sl_path
+ where pa_server = p_origin
+ and pa_client = p_receiver)
+ then
+ perform schemadoc.storeListen_int(p_origin, p_origin, p_receiver);
+ return 1;
+ end if;
+
+ -- 3. Listen on every node that is either provider for the
+ -- receiver or is using the receiver as provider (follow the
+ -- normal subscription routes).
+ for v_row in select distinct provider from (
+ select sub_provider as provider
+ from schemadoc.sl_subscribe
+ where sub_receiver = p_receiver
+ union
+ select sub_receiver as provider
+ from schemadoc.sl_subscribe
+ where sub_provider = p_receiver
+ and exists (select true from schemadoc.sl_path
+ where pa_server = sub_receiver
+ and pa_client = sub_provider)
+ ) as S
+ loop
+ perform schemadoc.storeListen_int(p_origin,
+ v_row.provider, p_receiver);
+ end loop;
+ if found then
+ return 1;
+ end if;
+
+ -- 4. If all else fails - meaning there are no subscriptions to
+ -- guide us to the right path - use every node we have a path
+ -- to as provider. This normally only happens when the cluster
+ -- is built or a new node added. This brute force fallback
+ -- ensures that events will propagate if possible at all.
+ for v_row in select pa_server as provider
+ from schemadoc.sl_path
+ where pa_client = p_receiver
+ loop
+ perform schemadoc.storeListen_int(p_origin,
+ v_row.provider, p_receiver);
+ end loop;
+ if found then
+ return 1;
+ end if;
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function sequencelastvalue( text ) -->
+ <section id="schemadoc.function.sequencelastvalue-text"
+ xreflabel="schemadocsequencelastvalue( text )">
+ <title id="schemadoc.function.sequencelastvalue-text-title">
+ sequencelastvalue( text )
+ </title>
+ <titleabbrev id="schemadoc.function.sequencelastvalue-text-titleabbrev">
+ sequencelastvalue( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_seqname alias for $1;
+ v_seq_row record;
+begin
+ for v_seq_row in execute 'select last_value from ' || p_seqname
+ loop
+ return v_seq_row.last_value;
+ end loop;
+
+ -- not reached
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function sequencesetvalue( integer, integer, bigint, bigint ) -->
+ <section id="schemadoc.function.sequencesetvalue-integer-integer-bigint-bigint"
+ xreflabel="schemadocsequencesetvalue( integer, integer, bigint, bigint )">
+ <title id="schemadoc.function.sequencesetvalue-integer-integer-bigint-bigint-title">
+ sequencesetvalue( integer, integer, bigint, bigint )
+ </title>
+ <titleabbrev id="schemadoc.function.sequencesetvalue-integer-integer-bigint-bigint-titleabbrev">
+ sequencesetvalue( integer, integer, bigint, bigint )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ sequenceSetValue (seq_id, seq_origin, ev_seqno, last_value)
+Set sequence seq_id to have new value last_value.
+
+ <programlisting>
+declare
+ p_seq_id alias for $1;
+ p_seq_origin alias for $2;
+ p_ev_seqno alias for $3;
+ p_last_value alias for $4;
+ v_fqname text;
+begin
+ -- ----
+ -- Get the sequences fully qualified name
+ -- ----
+ select "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) into v_fqname
+ from schemadoc.sl_sequence SQ,
+ "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN
+ where SQ.seq_id = p_seq_id
+ and SQ.seq_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+ if not found then
+ raise exception 'Slony-I: sequence % not found', p_seq_id;
+ end if;
+
+ -- ----
+ -- Update it to the new value
+ -- ----
+ execute 'select setval(''' || v_fqname ||
+ ''', ''' || p_last_value || ''')';
+
+ insert into schemadoc.sl_seqlog
+ (seql_seqid, seql_origin, seql_ev_seqno, seql_last_value)
+ values (p_seq_id, p_seq_origin, p_ev_seqno, p_last_value);
+
+ return p_seq_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setaddsequence( integer, integer, text, text ) -->
+ <section id="schemadoc.function.setaddsequence-integer-integer-text-text"
+ xreflabel="schemadocsetaddsequence( integer, integer, text, text )">
+ <title id="schemadoc.function.setaddsequence-integer-integer-text-text-title">
+ setaddsequence( integer, integer, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.setaddsequence-integer-integer-text-text-titleabbrev">
+ setaddsequence( integer, integer, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setAddSequence (set_id, seq_id, seq_fqname, seq_comment)
+
+On the origin node for set set_id, add sequence seq_fqname to the
+replication set, and raise SET_ADD_SEQUENCE to cause this to replicate
+to subscriber nodes.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_seq_id alias for $2;
+ p_fqname alias for $3;
+ p_seq_comment alias for $4;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we are the origin of the set
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: setAddSequence(): set % not found', p_set_id;
+ end if;
+ if v_set_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: setAddSequence(): set % has remote origin', p_set_id;
+ end if;
+
+ if exists (select true from schemadoc.sl_subscribe
+ where sub_set = p_set_id)
+ then
+ raise exception 'Slony-I: cannot add sequence to currently subscribed set %',
+ p_set_id;
+ end if;
+
+ -- ----
+ -- Add the sequence to the set and generate the SET_ADD_SEQUENCE event
+ -- ----
+ perform schemadoc.setAddSequence_int(p_set_id, p_seq_id, p_fqname,
+ p_seq_comment);
+ return schemadoc.createEvent('_schemadoc', 'SET_ADD_SEQUENCE',
+ p_set_id, p_seq_id, p_fqname, p_seq_comment);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setaddsequence_int( integer, integer, text, text ) -->
+ <section id="schemadoc.function.setaddsequence-int-integer-integer-text-text"
+ xreflabel="schemadocsetaddsequence_int( integer, integer, text, text )">
+ <title id="schemadoc.function.setaddsequence-int-integer-integer-text-text-title">
+ setaddsequence_int( integer, integer, text, text )
+ </title>
+ <titleabbrev id="schemadoc.function.setaddsequence-int-integer-integer-text-text-titleabbrev">
+ setaddsequence_int( integer, integer, text, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setAddSequence_int (set_id, seq_id, seq_fqname, seq_comment)
+
+This processes the SET_ADD_SEQUENCE event. On remote nodes that
+subscribe to set_id, add the sequence to the replication set.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_seq_id alias for $2;
+ p_fqname alias for $3;
+ p_seq_comment alias for $4;
+ v_local_node_id int4;
+ v_set_origin int4;
+ v_sub_provider int4;
+ v_relkind char;
+ v_seq_reloid oid;
+ v_seq_relname name;
+ v_seq_nspname name;
+ v_sync_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- For sets with a remote origin, check that we are subscribed
+ -- to that set. Otherwise we ignore the sequence because it might
+ -- not even exist in our database.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: setAddSequence_int(): set % not found',
+ p_set_id;
+ end if;
+ if v_set_origin != v_local_node_id then
+ select sub_provider into v_sub_provider
+ from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = schemadoc.getLocalNodeId('_schemadoc');
+ if not found then
+ return 0;
+ end if;
+ end if;
+
+ -- ----
+ -- Get the sequences OID and check that it is a sequence
+ -- ----
+ select PGC.oid, PGC.relkind, PGC.relname, PGN.nspname
+ into v_seq_reloid, v_relkind, v_seq_relname, v_seq_nspname
+ from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN
+ where PGC.relnamespace = PGN.oid
+ and p_fqname = "pg_catalog".quote_ident(PGN.nspname) ||
+ '.' || "pg_catalog".quote_ident(PGC.relname);
+ if not found then
+ raise exception 'Slony-I: setAddSequence_int(): sequence % not found',
+ p_fqname;
+ end if;
+ if v_relkind != 'S' then
+ raise exception 'Slony-I: setAddSequence_int(): % is not a sequence',
+ p_fqname;
+ end if;
+
+ -- ----
+ -- Add the sequence to sl_sequence
+ -- ----
+ insert into schemadoc.sl_sequence
+ (seq_id, seq_reloid, seq_relname, seq_nspname, seq_set, seq_comment)
+ values
+ (p_seq_id, v_seq_reloid, v_seq_relname, v_seq_nspname, p_set_id, p_seq_comment);
+
+ -- ----
+ -- On the set origin, fake a sl_seqlog row for the last sync event
+ -- ----
+ if v_set_origin = v_local_node_id then
+ for v_sync_row in select coalesce (max(ev_seqno), 0) as ev_seqno
+ from schemadoc.sl_event
+ where ev_origin = v_local_node_id
+ and ev_type = 'SYNC'
+ loop
+ insert into schemadoc.sl_seqlog
+ (seql_seqid, seql_origin, seql_ev_seqno,
+ seql_last_value) values
+ (p_seq_id, v_local_node_id, v_sync_row.ev_seqno,
+ schemadoc.sequenceLastValue(p_fqname));
+ end loop;
+ end if;
+
+ return p_seq_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setaddtable( integer, integer, text, name, text ) -->
+ <section id="schemadoc.function.setaddtable-integer-integer-text-name-text"
+ xreflabel="schemadocsetaddtable( integer, integer, text, name, text )">
+ <title id="schemadoc.function.setaddtable-integer-integer-text-name-text-title">
+ setaddtable( integer, integer, text, name, text )
+ </title>
+ <titleabbrev id="schemadoc.function.setaddtable-integer-integer-text-name-text-titleabbrev">
+ setaddtable( integer, integer, text, name, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setAddTable (set_id, tab_id, tab_fqname, tab_idxname, tab_comment)
+
+Add table tab_fqname to replication set on origin node, and generate
+SET_ADD_TABLE event to allow this to propagate to other nodes.
+
+Note that the table id, tab_id, must be unique ACROSS ALL SETS.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_tab_id alias for $2;
+ p_fqname alias for $3;
+ p_tab_idxname alias for $4;
+ p_tab_comment alias for $5;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we are the origin of the set
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: setAddTable(): set % not found', p_set_id;
+ end if;
+ if v_set_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: setAddTable(): set % has remote origin', p_set_id;
+ end if;
+
+ if exists (select true from schemadoc.sl_subscribe
+ where sub_set = p_set_id)
+ then
+ raise exception 'Slony-I: cannot add table to currently subscribed set %',
+ p_set_id;
+ end if;
+
+ -- ----
+ -- Add the table to the set and generate the SET_ADD_TABLE event
+ -- ----
+ perform schemadoc.setAddTable_int(p_set_id, p_tab_id, p_fqname,
+ p_tab_idxname, p_tab_comment);
+ return schemadoc.createEvent('_schemadoc', 'SET_ADD_TABLE',
+ p_set_id, p_tab_id, p_fqname,
+ p_tab_idxname, p_tab_comment);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setaddtable_int( integer, integer, text, name, text ) -->
+ <section id="schemadoc.function.setaddtable-int-integer-integer-text-name-text"
+ xreflabel="schemadocsetaddtable_int( integer, integer, text, name, text )">
+ <title id="schemadoc.function.setaddtable-int-integer-integer-text-name-text-title">
+ setaddtable_int( integer, integer, text, name, text )
+ </title>
+ <titleabbrev id="schemadoc.function.setaddtable-int-integer-integer-text-name-text-titleabbrev">
+ setaddtable_int( integer, integer, text, name, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setAddTable_int (set_id, tab_id, tab_fqname, tab_idxname, tab_comment)
+
+This function processes the SET_ADD_TABLE event on remote nodes,
+adding a table to replication if the remote node is subscribing to its
+replication set.
+ <programlisting>
+declare
+
+ p_set_id alias for $1;
+ p_tab_id alias for $2;
+ p_fqname alias for $3;
+ p_tab_idxname alias for $4;
+ p_tab_comment alias for $5;
+ v_tab_relname name;
+ v_tab_nspname name;
+ v_local_node_id int4;
+ v_set_origin int4;
+ v_sub_provider int4;
+ v_relkind char;
+ v_tab_reloid oid;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- For sets with a remote origin, check that we are subscribed
+ -- to that set. Otherwise we ignore the table because it might
+ -- not even exist in our database.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id;
+ if not found then
+ raise exception 'Slony-I: setAddTable_int(): set % not found',
+ p_set_id;
+ end if;
+ if v_set_origin != v_local_node_id then
+ select sub_provider into v_sub_provider
+ from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = schemadoc.getLocalNodeId('_schemadoc');
+ if not found then
+ return 0;
+ end if;
+ end if;
+
+ -- ----
+ -- Get the tables OID and check that it is a real table
+ -- ----
+ select PGC.oid, PGC.relkind, PGC.relname, PGN.nspname into v_tab_reloid, v_relkind, v_tab_relname, v_tab_nspname
+ from "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN
+ where PGC.relnamespace = PGN.oid
+ and p_fqname = "pg_catalog".quote_ident(PGN.nspname) ||
+ '.' || "pg_catalog".quote_ident(PGC.relname);
+ if not found then
+ raise exception 'Slony-I: setAddTable(): table % not found',
+ p_fqname;
+ end if;
+ if v_relkind != 'r' then
+ raise exception 'Slony-I: setAddTable(): % is not a regular table',
+ p_fqname;
+ end if;
+
+ if not exists (select indexrelid
+ from "pg_catalog".pg_index PGX, "pg_catalog".pg_class PGC
+ where PGX.indrelid = v_tab_reloid
+ and PGX.indexrelid = PGC.oid
+ and PGC.relname = p_tab_idxname)
+ then
+ raise exception 'Slony-I: setAddTable(): table % has no index %',
+ p_fqname, p_tab_idxname;
+ end if;
+
+ -- ----
+ -- Add the table to sl_table and create the trigger on it.
+ -- ----
+ insert into schemadoc.sl_table
+ (tab_id, tab_reloid, tab_relname, tab_nspname,
+ tab_set, tab_idxname, tab_altered, tab_comment)
+ values
+ (p_tab_id, v_tab_reloid, v_tab_relname, v_tab_nspname,
+ p_set_id, p_tab_idxname, false, p_tab_comment);
+ perform schemadoc.alterTableForReplication(p_tab_id);
+
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setdropsequence( integer ) -->
+ <section id="schemadoc.function.setdropsequence-integer"
+ xreflabel="schemadocsetdropsequence( integer )">
+ <title id="schemadoc.function.setdropsequence-integer-title">
+ setdropsequence( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setdropsequence-integer-titleabbrev">
+ setdropsequence( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setDropSequence (seq_id)
+
+On the origin node for the set, drop sequence seq_id from replication
+set, and raise SET_DROP_SEQUENCE to cause this to replicate to
+subscriber nodes.
+ <programlisting>
+declare
+ p_seq_id alias for $1;
+ v_set_id int4;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Determine set id for this sequence
+ -- ----
+ select seq_set into v_set_id from schemadoc.sl_sequence where seq_id = p_seq_id;
+
+ -- ----
+ -- Ensure sequence exists
+ -- ----
+ if not found then
+ raise exception 'Slony-I: setDropSequence_int(): sequence % not found',
+ p_seq_id;
+ end if;
+
+ -- ----
+ -- Check that we are the origin of the set
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = v_set_id;
+ if not found then
+ raise exception 'Slony-I: setDropSequence(): set % not found', v_set_id;
+ end if;
+ if v_set_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: setDropSequence(): set % has remote origin', v_set_id;
+ end if;
+
+ -- ----
+ -- Add the sequence to the set and generate the SET_ADD_SEQUENCE event
+ -- ----
+ perform schemadoc.setDropSequence_int(p_seq_id);
+ return schemadoc.createEvent('_schemadoc', 'SET_DROP_SEQUENCE',
+ p_seq_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setdropsequence_int( integer ) -->
+ <section id="schemadoc.function.setdropsequence-int-integer"
+ xreflabel="schemadocsetdropsequence_int( integer )">
+ <title id="schemadoc.function.setdropsequence-int-integer-title">
+ setdropsequence_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setdropsequence-int-integer-titleabbrev">
+ setdropsequence_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setDropSequence_int (seq_id)
+
+This processes the SET_DROP_SEQUENCE event. On remote nodes that
+subscribe to the set containing sequence seq_id, drop the sequence
+from the replication set.
+ <programlisting>
+declare
+ p_seq_id alias for $1;
+ v_set_id int4;
+ v_local_node_id int4;
+ v_set_origin int4;
+ v_sub_provider int4;
+ v_relkind char;
+ v_sync_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Determine set id for this sequence
+ -- ----
+ select seq_set into v_set_id from schemadoc.sl_sequence where seq_id = p_seq_id;
+
+ -- ----
+ -- Ensure sequence exists
+ -- ----
+ if not found then
+ return 0;
+ end if;
+
+ -- ----
+ -- For sets with a remote origin, check that we are subscribed
+ -- to that set. Otherwise we ignore the sequence because it might
+ -- not even exist in our database.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = v_set_id;
+ if not found then
+ raise exception 'Slony-I: setDropSequence_int(): set % not found',
+ v_set_id;
+ end if;
+ if v_set_origin != v_local_node_id then
+ select sub_provider into v_sub_provider
+ from schemadoc.sl_subscribe
+ where sub_set = v_set_id
+ and sub_receiver = schemadoc.getLocalNodeId('_schemadoc');
+ if not found then
+ return 0;
+ end if;
+ end if;
+
+ -- ----
+ -- drop the sequence from sl_sequence, sl_seqlog
+ -- ----
+ delete from schemadoc.sl_seqlog where seql_seqid = p_seq_id;
+ delete from schemadoc.sl_sequence where seq_id = p_seq_id;
+
+ return p_seq_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setdroptable( integer ) -->
+ <section id="schemadoc.function.setdroptable-integer"
+ xreflabel="schemadocsetdroptable( integer )">
+ <title id="schemadoc.function.setdroptable-integer-title">
+ setdroptable( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setdroptable-integer-titleabbrev">
+ setdroptable( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setDropTable (tab_id)
+
+Drop table tab_id from set on origin node, and generate SET_DROP_TABLE
+event to allow this to propagate to other nodes.
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ v_set_id int4;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Determine the set_id
+ -- ----
+ select tab_set into v_set_id from schemadoc.sl_table where tab_id = p_tab_id;
+
+ -- ----
+ -- Ensure table exists
+ -- ----
+ if not found then
+ raise exception 'Slony-I: setDropTable_int(): table % not found',
+ p_tab_id;
+ end if;
+
+ -- ----
+ -- Check that we are the origin of the set
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = v_set_id;
+ if not found then
+ raise exception 'Slony-I: setDropTable(): set % not found', v_set_id;
+ end if;
+ if v_set_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: setDropTable(): set % has remote origin', v_set_id;
+ end if;
+
+ -- ----
+ -- Drop the table from the set and generate the SET_ADD_TABLE event
+ -- ----
+ perform schemadoc.setDropTable_int(p_tab_id);
+ return schemadoc.createEvent('_schemadoc', 'SET_DROP_TABLE', p_tab_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setdroptable_int( integer ) -->
+ <section id="schemadoc.function.setdroptable-int-integer"
+ xreflabel="schemadocsetdroptable_int( integer )">
+ <title id="schemadoc.function.setdroptable-int-integer-title">
+ setdroptable_int( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setdroptable-int-integer-titleabbrev">
+ setdroptable_int( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ setDropTable_int (tab_id)
+
+This function processes the SET_DROP_TABLE event on remote nodes,
+dropping a table from replication if the remote node is subscribing to
+its replication set.
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ v_set_id int4;
+ v_local_node_id int4;
+ v_set_origin int4;
+ v_sub_provider int4;
+ v_tab_reloid oid;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Determine the set_id
+ -- ----
+ select tab_set into v_set_id from schemadoc.sl_table where tab_id = p_tab_id;
+
+ -- ----
+ -- Ensure table exists
+ -- ----
+ if not found then
+ return 0;
+ end if;
+
+ -- ----
+ -- For sets with a remote origin, check that we are subscribed
+ -- to that set. Otherwise we ignore the table because it might
+ -- not even exist in our database.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = v_set_id;
+ if not found then
+ raise exception 'Slony-I: setDropTable_int(): set % not found',
+ v_set_id;
+ end if;
+ if v_set_origin != v_local_node_id then
+ select sub_provider into v_sub_provider
+ from schemadoc.sl_subscribe
+ where sub_set = v_set_id
+ and sub_receiver = schemadoc.getLocalNodeId('_schemadoc');
+ if not found then
+ return 0;
+ end if;
+ end if;
+
+ -- ----
+ -- Drop the table from sl_table and drop trigger from it.
+ -- ----
+ perform schemadoc.alterTableRestore(p_tab_id);
+ perform schemadoc.tableDropKey(p_tab_id);
+ delete from schemadoc.sl_table where tab_id = p_tab_id;
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setmovesequence( integer, integer ) -->
+ <section id="schemadoc.function.setmovesequence-integer-integer"
+ xreflabel="schemadocsetmovesequence( integer, integer )">
+ <title id="schemadoc.function.setmovesequence-integer-integer-title">
+ setmovesequence( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setmovesequence-integer-integer-titleabbrev">
+ setmovesequence( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_seq_id alias for $1;
+ p_new_set_id alias for $2;
+ v_old_set_id int4;
+ v_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get the sequences current set
+ -- ----
+ select seq_set into v_old_set_id from schemadoc.sl_sequence
+ where seq_id = p_seq_id;
+ if not found then
+ raise exception 'Slony-I: sequence %d not found', p_seq_id;
+ end if;
+
+ -- ----
+ -- Check that both sets exist and originate here
+ -- ----
+ if p_new_set_id = v_old_set_id then
+ raise exception 'Slony-I: set ids cannot be identical';
+ end if;
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = p_new_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_new_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_new_set_id;
+ end if;
+
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = v_old_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', v_old_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ v_old_set_id;
+ end if;
+
+ -- ----
+ -- Check that both sets are subscribed by the same set of nodes
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = p_new_set_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = v_old_set_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ p_new_set_id, v_old_set_id;
+ end if;
+
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = v_old_set_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = p_new_set_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ v_old_set_id, p_new_set_id;
+ end if;
+
+ -- ----
+ -- Change the set the sequence belongs to
+ -- ----
+ perform schemadoc.setMoveSequence_int(p_seq_id, p_new_set_id);
+ return schemadoc.createEvent('_schemadoc', 'SET_MOVE_SEQUENCE',
+ p_seq_id, p_new_set_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setmovesequence_int( integer, integer ) -->
+ <section id="schemadoc.function.setmovesequence-int-integer-integer"
+ xreflabel="schemadocsetmovesequence_int( integer, integer )">
+ <title id="schemadoc.function.setmovesequence-int-integer-integer-title">
+ setmovesequence_int( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setmovesequence-int-integer-integer-titleabbrev">
+ setmovesequence_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_seq_id alias for $1;
+ p_new_set_id alias for $2;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Move the sequence to the new set
+ -- ----
+ update schemadoc.sl_sequence
+ set seq_set = p_new_set_id
+ where seq_id = p_seq_id;
+
+ return p_seq_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setmovetable( integer, integer ) -->
+ <section id="schemadoc.function.setmovetable-integer-integer"
+ xreflabel="schemadocsetmovetable( integer, integer )">
+ <title id="schemadoc.function.setmovetable-integer-integer-title">
+ setmovetable( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setmovetable-integer-integer-titleabbrev">
+ setmovetable( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ This processes the SET_MOVE_TABLE event. The table is moved
+to the destination set.
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ p_new_set_id alias for $2;
+ v_old_set_id int4;
+ v_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get the tables current set
+ -- ----
+ select tab_set into v_old_set_id from schemadoc.sl_table
+ where tab_id = p_tab_id;
+ if not found then
+ raise exception 'Slony-I: table %d not found', p_tab_id;
+ end if;
+
+ -- ----
+ -- Check that both sets exist and originate here
+ -- ----
+ if p_new_set_id = v_old_set_id then
+ raise exception 'Slony-I: set ids cannot be identical';
+ end if;
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = p_new_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_new_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_new_set_id;
+ end if;
+
+ select set_origin into v_origin from schemadoc.sl_set
+ where set_id = v_old_set_id;
+ if not found then
+ raise exception 'Slony-I: set % not found', v_old_set_id;
+ end if;
+ if v_origin != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: set % does not originate on local node',
+ v_old_set_id;
+ end if;
+
+ -- ----
+ -- Check that both sets are subscribed by the same set of nodes
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = p_new_set_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = v_old_set_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ p_new_set_id, v_old_set_id;
+ end if;
+
+ if exists (select true from schemadoc.sl_subscribe SUB1
+ where SUB1.sub_set = v_old_set_id
+ and SUB1.sub_receiver not in (select SUB2.sub_receiver
+ from schemadoc.sl_subscribe SUB2
+ where SUB2.sub_set = p_new_set_id))
+ then
+ raise exception 'Slony-I: subscriber lists of set % and % are different',
+ v_old_set_id, p_new_set_id;
+ end if;
+
+ -- ----
+ -- Change the set the table belongs to
+ -- ----
+ perform schemadoc.createEvent('_schemadoc', 'SYNC', NULL);
+ perform schemadoc.setMoveTable_int(p_tab_id, p_new_set_id);
+ return schemadoc.createEvent('_schemadoc', 'SET_MOVE_TABLE',
+ p_tab_id, p_new_set_id);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setmovetable_int( integer, integer ) -->
+ <section id="schemadoc.function.setmovetable-int-integer-integer"
+ xreflabel="schemadocsetmovetable_int( integer, integer )">
+ <title id="schemadoc.function.setmovetable-int-integer-integer-title">
+ setmovetable_int( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.setmovetable-int-integer-integer-titleabbrev">
+ setmovetable_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ p_new_set_id alias for $2;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Move the table to the new set
+ -- ----
+ update schemadoc.sl_table
+ set tab_set = p_new_set_id
+ where tab_id = p_tab_id;
+
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function setsessionrole( name, text ) -->
+ <section id="schemadoc.function.setsessionrole-name-text"
+ xreflabel="schemadocsetsessionrole( name, text )">
+ <title id="schemadoc.function.setsessionrole-name-text-title">
+ setsessionrole( name, text )
+ </title>
+ <titleabbrev id="schemadoc.function.setsessionrole-name-text-titleabbrev">
+ setsessionrole( name, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ not yet documented
+ <programlisting>_Slony_I_setSessionRole</programlisting>
+ </para>
+ </section>
+
+<!-- Function slonyversion( ) -->
+ <section id="schemadoc.function.slonyversion"
+ xreflabel="schemadocslonyversion( )">
+ <title id="schemadoc.function.slonyversion-title">
+ slonyversion( )
+ </title>
+ <titleabbrev id="schemadoc.function.slonyversion-titleabbrev">
+ slonyversion( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the version number of the slony schema
+ <programlisting>
+begin
+ return '' || schemadoc.slonyVersionMajor() || '.'
+ || schemadoc.slonyVersionMinor() || '.'
+ || schemadoc.slonyVersionPatchlevel();
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function slonyversionmajor( ) -->
+ <section id="schemadoc.function.slonyversionmajor"
+ xreflabel="schemadocslonyversionmajor( )">
+ <title id="schemadoc.function.slonyversionmajor-title">
+ slonyversionmajor( )
+ </title>
+ <titleabbrev id="schemadoc.function.slonyversionmajor-titleabbrev">
+ slonyversionmajor( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the major version number of the slony schema
+ <programlisting>
+begin
+ return 1;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function slonyversionminor( ) -->
+ <section id="schemadoc.function.slonyversionminor"
+ xreflabel="schemadocslonyversionminor( )">
+ <title id="schemadoc.function.slonyversionminor-title">
+ slonyversionminor( )
+ </title>
+ <titleabbrev id="schemadoc.function.slonyversionminor-titleabbrev">
+ slonyversionminor( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the minor version number of the slony schema
+ <programlisting>
+begin
+ return 1;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function slonyversionpatchlevel( ) -->
+ <section id="schemadoc.function.slonyversionpatchlevel"
+ xreflabel="schemadocslonyversionpatchlevel( )">
+ <title id="schemadoc.function.slonyversionpatchlevel-title">
+ slonyversionpatchlevel( )
+ </title>
+ <titleabbrev id="schemadoc.function.slonyversionpatchlevel-titleabbrev">
+ slonyversionpatchlevel( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Returns the version patch level of the slony schema
+ <programlisting>
+begin
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storelisten( integer, integer, integer ) -->
+ <section id="schemadoc.function.storelisten-integer-integer-integer"
+ xreflabel="schemadocstorelisten( integer, integer, integer )">
+ <title id="schemadoc.function.storelisten-integer-integer-integer-title">
+ storelisten( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.storelisten-integer-integer-integer-titleabbrev">
+ storelisten( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION storeListen (li_origin, li_provider, li_receiver)
+
+generate STORE_LISTEN event, indicating that receiver node li_receiver
+listens to node li_provider in order to get messages coming from node
+li_origin.
+ <programlisting>
+declare
+ p_origin alias for $1;
+ p_provider alias for $2;
+ p_receiver alias for $3;
+begin
+ return -1;
+
+ perform schemadoc.storeListen_int (p_origin, p_provider, p_receiver);
+ return schemadoc.createEvent ('_schemadoc', 'STORE_LISTEN',
+ p_origin, p_provider, p_receiver);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storelisten_int( integer, integer, integer ) -->
+ <section id="schemadoc.function.storelisten-int-integer-integer-integer"
+ xreflabel="schemadocstorelisten_int( integer, integer, integer )">
+ <title id="schemadoc.function.storelisten-int-integer-integer-integer-title">
+ storelisten_int( integer, integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.storelisten-int-integer-integer-integer-titleabbrev">
+ storelisten_int( integer, integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION storeListen_int (li_origin, li_provider, li_receiver)
+
+Process STORE_LISTEN event, indicating that receiver node li_receiver
+listens to node li_provider in order to get messages coming from node
+li_origin.
+ <programlisting>
+declare
+ p_li_origin alias for $1;
+ p_li_provider alias for $2;
+ p_li_receiver alias for $3;
+ v_exists int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ select 1 into v_exists
+ from schemadoc.sl_listen
+ where li_origin = p_li_origin
+ and li_provider = p_li_provider
+ and li_receiver = p_li_receiver;
+ if not found then
+ -- ----
+ -- In case we receive STORE_LISTEN events before we know
+ -- about the nodes involved in this, we generate those nodes
+ -- as pending.
+ -- ----
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_li_origin) then
+ perform schemadoc.storeNode_int (p_li_origin, '<event pending>');
+ end if;
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_li_provider) then
+ perform schemadoc.storeNode_int (p_li_provider, '<event pending>');
+ end if;
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_li_receiver) then
+ perform schemadoc.storeNode_int (p_li_receiver, '<event pending>');
+ end if;
+
+ insert into schemadoc.sl_listen
+ (li_origin, li_provider, li_receiver) values
+ (p_li_origin, p_li_provider, p_li_receiver);
+ end if;
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storenode( integer, text, boolean ) -->
+ <section id="schemadoc.function.storenode-integer-text-boolean"
+ xreflabel="schemadocstorenode( integer, text, boolean )">
+ <title id="schemadoc.function.storenode-integer-text-boolean-title">
+ storenode( integer, text, boolean )
+ </title>
+ <titleabbrev id="schemadoc.function.storenode-integer-text-boolean-titleabbrev">
+ storenode( integer, text, boolean )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ no_id - Node ID #
+no_comment - Human-oriented comment
+no_spool - Flag for virtual spool nodes
+
+Generate the STORE_NODE event for node no_id
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ p_no_comment alias for $2;
+ p_no_spool alias for $3;
+ v_no_spool_txt text;
+begin
+ if p_no_spool then
+ v_no_spool_txt = 't';
+ else
+ v_no_spool_txt = 'f';
+ end if;
+ perform schemadoc.storeNode_int (p_no_id, p_no_comment, p_no_spool);
+ return schemadoc.createEvent('_schemadoc', 'STORE_NODE',
+ p_no_id, p_no_comment, v_no_spool_txt);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storenode_int( integer, text, boolean ) -->
+ <section id="schemadoc.function.storenode-int-integer-text-boolean"
+ xreflabel="schemadocstorenode_int( integer, text, boolean )">
+ <title id="schemadoc.function.storenode-int-integer-text-boolean-title">
+ storenode_int( integer, text, boolean )
+ </title>
+ <titleabbrev id="schemadoc.function.storenode-int-integer-text-boolean-titleabbrev">
+ storenode_int( integer, text, boolean )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ no_id - Node ID #
+no_comment - Human-oriented comment
+no_spool - Flag for virtual spool nodes
+
+Internal function to process the STORE_NODE event for node no_id
+ <programlisting>
+declare
+ p_no_id alias for $1;
+ p_no_comment alias for $2;
+ p_no_spool alias for $3;
+ v_old_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check if the node exists
+ -- ----
+ select * into v_old_row
+ from schemadoc.sl_node
+ where no_id = p_no_id
+ for update;
+ if found then
+ -- ----
+ -- Node exists, update the existing row.
+ -- ----
+ update schemadoc.sl_node
+ set no_comment = p_no_comment,
+ no_spool = p_no_spool
+ where no_id = p_no_id;
+ else
+ -- ----
+ -- New node, insert the sl_node row
+ -- ----
+ insert into schemadoc.sl_node
+ (no_id, no_active, no_comment, no_spool) values
+ (p_no_id, 'f', p_no_comment, p_no_spool);
+ end if;
+
+ return p_no_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storepath( integer, integer, text, integer ) -->
+ <section id="schemadoc.function.storepath-integer-integer-text-integer"
+ xreflabel="schemadocstorepath( integer, integer, text, integer )">
+ <title id="schemadoc.function.storepath-integer-integer-text-integer-title">
+ storepath( integer, integer, text, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.storepath-integer-integer-text-integer-titleabbrev">
+ storepath( integer, integer, text, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION storePath (pa_server, pa_client, pa_conninfo, pa_connretry)
+
+Generate the STORE_PATH event indicating that node pa_client can
+access node pa_server using DSN pa_conninfo
+ <programlisting>
+declare
+ p_pa_server alias for $1;
+ p_pa_client alias for $2;
+ p_pa_conninfo alias for $3;
+ p_pa_connretry alias for $4;
+begin
+ perform schemadoc.storePath_int(p_pa_server, p_pa_client,
+ p_pa_conninfo, p_pa_connretry);
+ return schemadoc.createEvent('_schemadoc', 'STORE_PATH',
+ p_pa_server, p_pa_client, p_pa_conninfo, p_pa_connretry);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storepath_int( integer, integer, text, integer ) -->
+ <section id="schemadoc.function.storepath-int-integer-integer-text-integer"
+ xreflabel="schemadocstorepath_int( integer, integer, text, integer )">
+ <title id="schemadoc.function.storepath-int-integer-integer-text-integer-title">
+ storepath_int( integer, integer, text, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.storepath-int-integer-integer-text-integer-titleabbrev">
+ storepath_int( integer, integer, text, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ FUNCTION storePath (pa_server, pa_client, pa_conninfo, pa_connretry)
+
+Process the STORE_PATH event indicating that node pa_client can
+access node pa_server using DSN pa_conninfo
+ <programlisting>
+declare
+ p_pa_server alias for $1;
+ p_pa_client alias for $2;
+ p_pa_conninfo alias for $3;
+ p_pa_connretry alias for $4;
+ v_dummy int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check if the path already exists
+ -- ----
+ select 1 into v_dummy
+ from schemadoc.sl_path
+ where pa_server = p_pa_server
+ and pa_client = p_pa_client
+ for update;
+ if found then
+ -- ----
+ -- Path exists, update pa_conninfo
+ -- ----
+ update schemadoc.sl_path
+ set pa_conninfo = p_pa_conninfo,
+ pa_connretry = p_pa_connretry
+ where pa_server = p_pa_server
+ and pa_client = p_pa_client;
+ else
+ -- ----
+ -- New path
+ --
+ -- In case we receive STORE_PATH events before we know
+ -- about the nodes involved in this, we generate those nodes
+ -- as pending.
+ -- ----
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_pa_server) then
+ perform schemadoc.storeNode_int (p_pa_server, '<event pending>');
+ end if;
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_pa_client) then
+ perform schemadoc.storeNode_int (p_pa_client, '<event pending>');
+ end if;
+ insert into schemadoc.sl_path
+ (pa_server, pa_client, pa_conninfo, pa_connretry) values
+ (p_pa_server, p_pa_client, p_pa_conninfo, p_pa_connretry);
+ end if;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storeset( integer, text ) -->
+ <section id="schemadoc.function.storeset-integer-text"
+ xreflabel="schemadocstoreset( integer, text )">
+ <title id="schemadoc.function.storeset-integer-text-title">
+ storeset( integer, text )
+ </title>
+ <titleabbrev id="schemadoc.function.storeset-integer-text-titleabbrev">
+ storeset( integer, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Generate STORE_SET event for set set_id with human readable comment set_comment
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_set_comment alias for $2;
+ v_local_node_id int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+
+ insert into schemadoc.sl_set
+ (set_id, set_origin, set_comment) values
+ (p_set_id, v_local_node_id, p_set_comment);
+
+ return schemadoc.createEvent('_schemadoc', 'STORE_SET',
+ p_set_id, v_local_node_id, p_set_comment);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storeset_int( integer, integer, text ) -->
+ <section id="schemadoc.function.storeset-int-integer-integer-text"
+ xreflabel="schemadocstoreset_int( integer, integer, text )">
+ <title id="schemadoc.function.storeset-int-integer-integer-text-title">
+ storeset_int( integer, integer, text )
+ </title>
+ <titleabbrev id="schemadoc.function.storeset-int-integer-integer-text-titleabbrev">
+ storeset_int( integer, integer, text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ storeSet_int (set_id, set_origin, set_comment)
+
+Process the STORE_SET event, indicating the new set with given ID,
+origin node, and human readable comment.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_set_origin alias for $2;
+ p_set_comment alias for $3;
+ v_dummy int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ select 1 into v_dummy
+ from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if found then
+ update schemadoc.sl_set
+ set set_comment = p_set_comment
+ where set_id = p_set_id;
+ else
+ if not exists (select 1 from schemadoc.sl_node
+ where no_id = p_set_origin) then
+ perform schemadoc.storeNode_int (p_set_origin, '<event pending>');
+ end if;
+ insert into schemadoc.sl_set
+ (set_id, set_origin, set_comment) values
+ (p_set_id, p_set_origin, p_set_comment);
+ end if;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storetrigger( integer, name ) -->
+ <section id="schemadoc.function.storetrigger-integer-name"
+ xreflabel="schemadocstoretrigger( integer, name )">
+ <title id="schemadoc.function.storetrigger-integer-name-title">
+ storetrigger( integer, name )
+ </title>
+ <titleabbrev id="schemadoc.function.storetrigger-integer-name-titleabbrev">
+ storetrigger( integer, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ storeTrigger (trig_tabid, trig_tgname)
+
+Submits STORE_TRIGGER event to indicate that trigger trig_tgname on
+replicated table trig_tabid will NOT be disabled.
+ <programlisting>
+declare
+ p_trig_tabid alias for $1;
+ p_trig_tgname alias for $2;
+begin
+ perform schemadoc.storeTrigger_int(p_trig_tabid, p_trig_tgname);
+ return schemadoc.createEvent('_schemadoc', 'STORE_TRIGGER',
+ p_trig_tabid, p_trig_tgname);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function storetrigger_int( integer, name ) -->
+ <section id="schemadoc.function.storetrigger-int-integer-name"
+ xreflabel="schemadocstoretrigger_int( integer, name )">
+ <title id="schemadoc.function.storetrigger-int-integer-name-title">
+ storetrigger_int( integer, name )
+ </title>
+ <titleabbrev id="schemadoc.function.storetrigger-int-integer-name-titleabbrev">
+ storetrigger_int( integer, name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ storeTrigger_int (trig_tabid, trig_tgname)
+
+Processes STORE_TRIGGER event to make sure that trigger trig_tgname on
+replicated table trig_tabid is NOT disabled.
+ <programlisting>
+declare
+ p_trig_tabid alias for $1;
+ p_trig_tgname alias for $2;
+ v_tab_altered boolean;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Get the current table status (altered or not)
+ -- ----
+ select tab_altered into v_tab_altered
+ from schemadoc.sl_table where tab_id = p_trig_tabid;
+ if not found then
+ -- ----
+ -- Not found is no hard error here, because that might
+ -- mean that we are not subscribed to that set
+ -- ----
+ return 0;
+ end if;
+
+ -- ----
+ -- If the table is modified for replication, restore the original state
+ -- ----
+ if v_tab_altered then
+ perform schemadoc.alterTableRestore(p_trig_tabid);
+ end if;
+
+ -- ----
+ -- Make sure that an entry for this trigger exists
+ -- ----
+ delete from schemadoc.sl_trigger
+ where trig_tabid = p_trig_tabid
+ and trig_tgname = p_trig_tgname;
+ insert into schemadoc.sl_trigger (
+ trig_tabid, trig_tgname
+ ) values (
+ p_trig_tabid, p_trig_tgname
+ );
+
+ -- ----
+ -- Put the table back into replicated state if it was
+ -- ----
+ if v_tab_altered then
+ perform schemadoc.alterTableForReplication(p_trig_tabid);
+ end if;
+
+ return p_trig_tabid;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function subscribeset( integer, integer, integer, boolean ) -->
+ <section id="schemadoc.function.subscribeset-integer-integer-integer-boolean"
+ xreflabel="schemadocsubscribeset( integer, integer, integer, boolean )">
+ <title id="schemadoc.function.subscribeset-integer-integer-integer-boolean-title">
+ subscribeset( integer, integer, integer, boolean )
+ </title>
+ <titleabbrev id="schemadoc.function.subscribeset-integer-integer-integer-boolean-titleabbrev">
+ subscribeset( integer, integer, integer, boolean )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ subscribeSet (sub_set, sub_provider, sub_receiver, sub_forward)
+
+Makes sure that the receiver is not the provider, then stores the
+subscription, and publishes the SUBSCRIBE_SET event to other nodes.
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_provider alias for $2;
+ p_sub_receiver alias for $3;
+ p_sub_forward alias for $4;
+ v_set_origin int4;
+ v_ev_seqno int8;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that this is called on the receiver node
+ -- ----
+ if p_sub_provider != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: subscribeSet() must be called on provider';
+ end if;
+
+ -- ----
+ -- Check that the origin and provider of the set are remote
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_sub_set;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_sub_set;
+ end if;
+ if v_set_origin = p_sub_receiver then
+ raise exception
+ 'Slony-I: set origin and receiver cannot be identical';
+ end if;
+ if p_sub_receiver = p_sub_provider then
+ raise exception
+ 'Slony-I: set provider and receiver cannot be identical';
+ end if;
+
+ -- ----
+ -- Create the SUBSCRIBE_SET event
+ -- ----
+ v_ev_seqno := schemadoc.createEvent('_schemadoc', 'SUBSCRIBE_SET',
+ p_sub_set, p_sub_provider, p_sub_receiver,
+ case p_sub_forward when true then 't' else 'f' end);
+
+ -- ----
+ -- Call the internal procedure to store the subscription
+ -- ----
+ perform schemadoc.subscribeSet_int(p_sub_set, p_sub_provider,
+ p_sub_receiver, p_sub_forward);
+
+ -- ----
+ -- Submit listen management events
+ -- ----
+ perform schemadoc.RebuildListenEntries();
+
+ return v_ev_seqno;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function subscribeset_int( integer, integer, integer, boolean ) -->
+ <section id="schemadoc.function.subscribeset-int-integer-integer-integer-boolean"
+ xreflabel="schemadocsubscribeset_int( integer, integer, integer, boolean )">
+ <title id="schemadoc.function.subscribeset-int-integer-integer-integer-boolean-title">
+ subscribeset_int( integer, integer, integer, boolean )
+ </title>
+ <titleabbrev id="schemadoc.function.subscribeset-int-integer-integer-integer-boolean-titleabbrev">
+ subscribeset_int( integer, integer, integer, boolean )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ subscribeSet_int (sub_set, sub_provider, sub_receiver, sub_forward)
+
+Internal actions for subscribing receiver sub_receiver to subscription
+set sub_set.
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_provider alias for $2;
+ p_sub_receiver alias for $3;
+ p_sub_forward alias for $4;
+ v_set_origin int4;
+ v_sub_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Provider change is only allowed for active sets
+ -- ----
+ if p_sub_receiver = schemadoc.getLocalNodeId('_schemadoc') then
+ select sub_active into v_sub_row from schemadoc.sl_subscribe
+ where sub_set = p_sub_set
+ and sub_receiver = p_sub_receiver;
+ if found then
+ if not v_sub_row.sub_active then
+ raise exception 'Slony-I: set % is not active, cannot change provider',
+ p_sub_set;
+ end if;
+ end if;
+ end if;
+
+ -- ----
+ -- Try to change provider and/or forward for an existing subscription
+ -- ----
+ update schemadoc.sl_subscribe
+ set sub_provider = p_sub_provider,
+ sub_forward = p_sub_forward
+ where sub_set = p_sub_set
+ and sub_receiver = p_sub_receiver;
+ if found then
+ return p_sub_set;
+ end if;
+
+ -- ----
+ -- Not found, insert a new one
+ -- ----
+ if not exists (select true from schemadoc.sl_path
+ where pa_server = p_sub_provider
+ and pa_client = p_sub_receiver)
+ then
+ insert into schemadoc.sl_path
+ (pa_server, pa_client, pa_conninfo, pa_connretry)
+ values
+ (p_sub_provider, p_sub_receiver,
+ '<event pending>', 10);
+ end if;
+ insert into schemadoc.sl_subscribe
+ (sub_set, sub_provider, sub_receiver, sub_forward, sub_active)
+ values (p_sub_set, p_sub_provider, p_sub_receiver,
+ p_sub_forward, false);
+
+ -- ----
+ -- If the set origin is here, then enable the subscription
+ -- ----
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_sub_set;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_sub_set;
+ end if;
+
+ if v_set_origin = schemadoc.getLocalNodeId('_schemadoc') then
+ perform schemadoc.createEvent('_schemadoc', 'ENABLE_SUBSCRIPTION',
+ p_sub_set, p_sub_provider, p_sub_receiver,
+ case p_sub_forward when true then 't' else 'f' end);
+ perform schemadoc.enableSubscription(p_sub_set,
+ p_sub_provider, p_sub_receiver);
+ end if;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return p_sub_set;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function tableaddkey( text ) -->
+ <section id="schemadoc.function.tableaddkey-text"
+ xreflabel="schemadoctableaddkey( text )">
+ <title id="schemadoc.function.tableaddkey-text-title">
+ tableaddkey( text )
+ </title>
+ <titleabbrev id="schemadoc.function.tableaddkey-text-titleabbrev">
+ tableaddkey( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ tableAddKey (tab_fqname) - if the table has not got a column of the
+form _Slony-I_<clustername>_rowID, then add it as a bigint, defaulted
+to nextval() for a sequence created for the cluster.
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ v_attkind text default '';
+ v_attrow record;
+ v_have_serial bool default 'f';
+begin
+ --
+ -- Loop over the attributes of this relation
+ -- and add a "v" for every user column, and a "k"
+ -- if we find the Slony-I special serial column.
+ --
+ for v_attrow in select PGA.attnum, PGA.attname
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_attribute PGA
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGN.oid = PGC.relnamespace
+ and PGA.attrelid = PGC.oid
+ and not PGA.attisdropped
+ and PGA.attnum > 0
+ order by attnum
+ loop
+ if v_attrow.attname = '_Slony-I_schemadoc_rowID' then
+ v_attkind := v_attkind || 'k';
+ v_have_serial := 't';
+ else
+ v_attkind := v_attkind || 'v';
+ end if;
+ end loop;
+
+ --
+ -- A table must have at least one attribute, so not finding
+ -- anything means the table does not exist.
+ --
+ if not found then
+ raise exception 'Slony-I: table % not found', p_tab_fqname;
+ end if;
+
+ --
+ -- If it does not have the special serial column, we
+ -- have to add it. This will be only half way done.
+ -- The function to add the table to the set must finish
+ -- these definitions with NOT NULL and UNIQUE after
+ -- updating all existing rows.
+ --
+ if not v_have_serial then
+ execute 'lock table ' || p_tab_fqname ||
+ ' in access exclusive mode';
+ execute 'alter table only ' || p_tab_fqname ||
+ ' add column "_Slony-I_schemadoc_rowID" bigint;';
+ execute 'alter table only ' || p_tab_fqname ||
+ ' alter column "_Slony-I_schemadoc_rowID" ' ||
+ ' set default "pg_catalog".nextval(''schemadoc.sl_rowid_seq'');';
+
+ v_attkind := v_attkind || 'k';
+ end if;
+
+ --
+ -- Return the resulting Slony-I attkind
+ --
+ return v_attkind;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function tabledropkey( integer ) -->
+ <section id="schemadoc.function.tabledropkey-integer"
+ xreflabel="schemadoctabledropkey( integer )">
+ <title id="schemadoc.function.tabledropkey-integer-title">
+ tabledropkey( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.tabledropkey-integer-titleabbrev">
+ tabledropkey( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ tableDropKey (tab_id)
+
+If the specified table has a column "_Slony-I_<clustername>_rowID",
+then drop it.
+ <programlisting>
+declare
+ p_tab_id alias for $1;
+ v_tab_fqname text;
+ v_tab_oid oid;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Construct the tables fully qualified name and get its oid
+ -- ----
+ select "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname),
+ PGC.oid into v_tab_fqname, v_tab_oid
+ from schemadoc.sl_table T,
+ "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN
+ where T.tab_id = p_tab_id
+ and T.tab_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+ if not found then
+ raise exception 'Slony-I: table with ID % not found', p_tab_id;
+ end if;
+
+ -- ----
+ -- Drop the special serial ID column if the table has it
+ -- ----
+ if exists (select true from "pg_catalog".pg_attribute
+ where attrelid = v_tab_oid
+ and attname = '_Slony-I_schemadoc_rowID')
+ then
+ execute 'lock table ' || v_tab_fqname ||
+ ' in access exclusive mode';
+ execute 'alter table ' || v_tab_fqname ||
+ ' drop column "_Slony-I_schemadoc_rowID"';
+ end if;
+
+ return p_tab_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function tablehasserialkey( text ) -->
+ <section id="schemadoc.function.tablehasserialkey-text"
+ xreflabel="schemadoctablehasserialkey( text )">
+ <title id="schemadoc.function.tablehasserialkey-text-title">
+ tablehasserialkey( text )
+ </title>
+ <titleabbrev id="schemadoc.function.tablehasserialkey-text-titleabbrev">
+ tablehasserialkey( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>boolean</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ tableHasSerialKey (tab_fqname)
+
+Checks if a table has our special serial key column that is used if
+the table has no natural unique constraint.
+ <programlisting>
+declare
+ p_tab_fqname alias for $1;
+ v_attnum int2;
+begin
+ select PGA.attnum into v_attnum
+ from "pg_catalog".pg_class PGC,
+ "pg_catalog".pg_namespace PGN,
+ "pg_catalog".pg_attribute PGA
+ where "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) = p_tab_fqname
+ and PGC.relnamespace = PGN.oid
+ and PGA.attrelid = PGC.oid
+ and PGA.attname = '_Slony-I_schemadoc_rowID'
+ and not PGA.attisdropped;
+ return found;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function terminatenodeconnections( name ) -->
+ <section id="schemadoc.function.terminatenodeconnections-name"
+ xreflabel="schemadocterminatenodeconnections( name )">
+ <title id="schemadoc.function.terminatenodeconnections-name-title">
+ terminatenodeconnections( name )
+ </title>
+ <titleabbrev id="schemadoc.function.terminatenodeconnections-name-titleabbrev">
+ terminatenodeconnections( name )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>C</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ terminates connections to the node and terminates the process
+ <programlisting>_Slony_I_terminateNodeConnections</programlisting>
+ </para>
+ </section>
+
+<!-- Function uninstallnode( ) -->
+ <section id="schemadoc.function.uninstallnode"
+ xreflabel="schemadocuninstallnode( )">
+ <title id="schemadoc.function.uninstallnode-title">
+ uninstallnode( )
+ </title>
+ <titleabbrev id="schemadoc.function.uninstallnode-titleabbrev">
+ uninstallnode( )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Reset the whole database to standalone by removing the whole
+replication system.
+ <programlisting>
+declare
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- This is us ... time for suicide! Restore all tables to
+ -- their original status.
+ -- ----
+ for v_tab_row in select * from schemadoc.sl_table loop
+ perform schemadoc.alterTableRestore(v_tab_row.tab_id);
+ perform schemadoc.tableDropKey(v_tab_row.tab_id);
+ end loop;
+
+ raise notice 'Slony-I: Please drop schema "_schemadoc"';
+ return 0;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function unlockset( integer ) -->
+ <section id="schemadoc.function.unlockset-integer"
+ xreflabel="schemadocunlockset( integer )">
+ <title id="schemadoc.function.unlockset-integer-title">
+ unlockset( integer )
+ </title>
+ <titleabbrev id="schemadoc.function.unlockset-integer-titleabbrev">
+ unlockset( integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Remove the special trigger from all tables of a set that disables access to it.
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ v_local_node_id int4;
+ v_set_row record;
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that the set exists and that we are the origin
+ -- and that it is not already locked.
+ -- ----
+ v_local_node_id := schemadoc.getLocalNodeId('_schemadoc');
+ select * into v_set_row from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_row.set_origin <> v_local_node_id then
+ raise exception 'Slony-I: set % does not originate on local node',
+ p_set_id;
+ end if;
+ if v_set_row.set_locked isnull then
+ raise exception 'Slony-I: set % is not locked', p_set_id;
+ end if;
+
+ -- ----
+ -- Drop the lockedSet trigger from all tables in the set.
+ -- ----
+ for v_tab_row in select T.tab_id,
+ "pg_catalog".quote_ident(PGN.nspname) || '.' ||
+ "pg_catalog".quote_ident(PGC.relname) as tab_fqname
+ from schemadoc.sl_table T,
+ "pg_catalog".pg_class PGC, "pg_catalog".pg_namespace PGN
+ where T.tab_set = p_set_id
+ and T.tab_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid
+ order by tab_id
+ loop
+ execute 'drop trigger "_schemadoc_lockedset_' ||
+ v_tab_row.tab_id || '" on ' || v_tab_row.tab_fqname;
+ end loop;
+
+ -- ----
+ -- Clear out the set_locked field
+ -- ----
+ update schemadoc.sl_set
+ set set_locked = NULL
+ where set_id = p_set_id;
+
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function unsubscribeset( integer, integer ) -->
+ <section id="schemadoc.function.unsubscribeset-integer-integer"
+ xreflabel="schemadocunsubscribeset( integer, integer )">
+ <title id="schemadoc.function.unsubscribeset-integer-integer-title">
+ unsubscribeset( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.unsubscribeset-integer-integer-titleabbrev">
+ unsubscribeset( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>bigint</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ unsubscribeSet (sub_set, sub_receiver)
+
+Unsubscribe node sub_receiver from subscription set sub_set. This is
+invoked on the receiver node. It verifies that this does not break
+any chains (e.g. - where sub_receiver is a provider for another node),
+then restores tables, drops Slony-specific keys, drops table entries
+for the set, drops the subscription, and generates an UNSUBSCRIBE_SET
+node to publish that the node is being dropped.
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_receiver alias for $2;
+ v_tab_row record;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that this is called on the receiver node
+ -- ----
+ if p_sub_receiver != schemadoc.getLocalNodeId('_schemadoc') then
+ raise exception 'Slony-I: unsubscribeSet() must be called on receiver';
+ end if;
+
+ -- ----
+ -- Check that this does not break any chains
+ -- ----
+ if exists (select true from schemadoc.sl_subscribe
+ where sub_set = p_sub_set
+ and sub_provider = p_sub_receiver)
+ then
+ raise exception 'Slony-I: Cannot unsubscibe set % while being provider',
+ p_sub_set;
+ end if;
+
+ -- ----
+ -- Restore all tables original triggers and rules and remove
+ -- our replication stuff.
+ -- ----
+ for v_tab_row in select tab_id from schemadoc.sl_table
+ where tab_set = p_sub_set
+ order by tab_id
+ loop
+ perform schemadoc.alterTableRestore(v_tab_row.tab_id);
+ perform schemadoc.tableDropKey(v_tab_row.tab_id);
+ end loop;
+
+ -- ----
+ -- Remove the setsync status. This will also cause the
+ -- worker thread to ignore the set and stop replicating
+ -- right now.
+ -- ----
+ delete from schemadoc.sl_setsync
+ where ssy_setid = p_sub_set;
+
+ -- ----
+ -- Remove all sl_table and sl_sequence entries for this set.
+ -- Should we ever subscribe again, the initial data
+ -- copy process will create new ones.
+ -- ----
+ delete from schemadoc.sl_table
+ where tab_set = p_sub_set;
+ delete from schemadoc.sl_sequence
+ where seq_set = p_sub_set;
+
+ -- ----
+ -- Call the internal procedure to drop the subscription
+ -- ----
+ perform schemadoc.unsubscribeSet_int(p_sub_set, p_sub_receiver);
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ -- ----
+ -- Create the UNSUBSCRIBE_SET event
+ -- ----
+ return schemadoc.createEvent('_schemadoc', 'UNSUBSCRIBE_SET',
+ p_sub_set, p_sub_receiver);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function unsubscribeset_int( integer, integer ) -->
+ <section id="schemadoc.function.unsubscribeset-int-integer-integer"
+ xreflabel="schemadocunsubscribeset_int( integer, integer )">
+ <title id="schemadoc.function.unsubscribeset-int-integer-integer-title">
+ unsubscribeset_int( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.unsubscribeset-int-integer-integer-titleabbrev">
+ unsubscribeset_int( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ unsubscribeSet_int (sub_set, sub_receiver)
+
+All the REAL work of removing the subscriber is done before the event
+is generated, so this function just has to drop the references to the
+subscription in sl_subscribe.
+ <programlisting>
+declare
+ p_sub_set alias for $1;
+ p_sub_receiver alias for $2;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- All the real work is done before event generation on the
+ -- subscriber.
+ -- ----
+ delete from schemadoc.sl_subscribe
+ where sub_set = p_sub_set
+ and sub_receiver = p_sub_receiver;
+
+ -- Rewrite sl_listen table
+ perform schemadoc.RebuildListenEntries();
+
+ return p_sub_set;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function updaterelname( integer, integer ) -->
+ <section id="schemadoc.function.updaterelname-integer-integer"
+ xreflabel="schemadocupdaterelname( integer, integer )">
+ <title id="schemadoc.function.updaterelname-integer-integer-title">
+ updaterelname( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.updaterelname-integer-integer-titleabbrev">
+ updaterelname( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ updateRelname(set_id, only_on_node)
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_only_on_node alias for $2;
+ v_no_id int4;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we either are the set origin or a current
+ -- subscriber of the set.
+ -- ----
+ v_no_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_origin <> v_no_id
+ and not exists (select 1 from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = v_no_id)
+ then
+ return 0;
+ end if;
+
+ -- ----
+ -- If execution on only one node is requested, check that
+ -- we are that node.
+ -- ----
+ if p_only_on_node > 0 and p_only_on_node <> v_no_id then
+ return 0;
+ end if;
+ update schemadoc.sl_table set
+ tab_relname = PGC.relname, tab_nspname = PGN.nspname
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where schemadoc.sl_table.tab_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+ update schemadoc.sl_sequence set
+ seq_relname = PGC.relname, seq_nspname = PGN.nspname
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where schemadoc.sl_sequence.seq_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+ return p_set_id;
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function updatereloid( integer, integer ) -->
+ <section id="schemadoc.function.updatereloid-integer-integer"
+ xreflabel="schemadocupdatereloid( integer, integer )">
+ <title id="schemadoc.function.updatereloid-integer-integer-title">
+ updatereloid( integer, integer )
+ </title>
+ <titleabbrev id="schemadoc.function.updatereloid-integer-integer-titleabbrev">
+ updatereloid( integer, integer )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>integer</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ updateReloid(set_id, only_on_node)
+
+Updates the respective reloids in sl_table and sl_seqeunce based on
+their respective FQN
+ <programlisting>
+declare
+ p_set_id alias for $1;
+ p_only_on_node alias for $2;
+ v_no_id int4;
+ v_set_origin int4;
+begin
+ -- ----
+ -- Grab the central configuration lock
+ -- ----
+ lock table schemadoc.sl_config_lock;
+
+ -- ----
+ -- Check that we either are the set origin or a current
+ -- subscriber of the set.
+ -- ----
+ v_no_id := schemadoc.getLocalNodeId('_schemadoc');
+ select set_origin into v_set_origin
+ from schemadoc.sl_set
+ where set_id = p_set_id
+ for update;
+ if not found then
+ raise exception 'Slony-I: set % not found', p_set_id;
+ end if;
+ if v_set_origin <> v_no_id
+ and not exists (select 1 from schemadoc.sl_subscribe
+ where sub_set = p_set_id
+ and sub_receiver = v_no_id)
+ then
+ return 0;
+ end if;
+
+ -- ----
+ -- If execution on only one node is requested, check that
+ -- we are that node.
+ -- ----
+ if p_only_on_node > 0 and p_only_on_node <> v_no_id then
+ return 0;
+ end if;
+ update schemadoc.sl_table set
+ tab_reloid = PGC.oid
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where pg_catalog.quote_ident(schemadoc.sl_table.tab_relname) = pg_catalog.quote_ident(PGC.relname)
+ and PGC.relnamespace = PGN.oid
+ and pg_catalog.quote_ident(PGN.nspname) = pg_catalog.quote_ident(schemadoc.sl_table.tab_nspname);
+
+ update schemadoc.sl_sequence set
+ seq_reloid = PGC.oid
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where pg_catalog.quote_ident(schemadoc.sl_sequence.seq_relname) = pg_catalog.quote_ident(PGC.relname)
+ and PGC.relnamespace = PGN.oid
+ and pg_catalog.quote_ident(PGN.nspname) = pg_catalog.quote_ident(schemadoc.sl_sequence.seq_nspname);
+
+ return schemadoc.createEvent('_schemadoc', 'RESET_CONFIG',
+ p_set_id, p_only_on_node);
+end;
+</programlisting>
+ </para>
+ </section>
+
+<!-- Function upgradeschema( text ) -->
+ <section id="schemadoc.function.upgradeschema-text"
+ xreflabel="schemadocupgradeschema( text )">
+ <title id="schemadoc.function.upgradeschema-text-title">
+ upgradeschema( text )
+ </title>
+ <titleabbrev id="schemadoc.function.upgradeschema-text-titleabbrev">
+ upgradeschema( text )
+ </titleabbrev>
+
+ <para>
+ <segmentedlist>
+ <title>Function Properties</title>
+ <?dbhtml list-presentation="list"?>
+ <segtitle>Language</segtitle>
+ <segtitle>Return Type</segtitle>
+ <seglistitem>
+ <seg>PLPGSQL</seg>
+ <seg>text</seg>
+ </seglistitem>
+ </segmentedlist>
+
+ Called during "update functions" by slonik to perform schema changes
+ <programlisting>
+
+declare
+ p_old alias for $1;
+begin
+ -- upgrade sl_table
+ if p_old = '1.0.2' or p_old = '1.0.5' then
+ -- Add new column(s) sl_table.tab_relname, sl_table.tab_nspname
+ execute 'alter table schemadoc.sl_table add column tab_relname name';
+ execute 'alter table schemadoc.sl_table add column tab_nspname name';
+
+ -- populate the colums with data
+ update schemadoc.sl_table set
+ tab_relname = PGC.relname, tab_nspname = PGN.nspname
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where schemadoc.sl_table.tab_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+
+ -- constrain the colums
+ execute 'alter table schemadoc.sl_table alter column tab_relname set NOT NULL';
+ execute 'alter table schemadoc.sl_table alter column tab_nspname set NOT NULL';
+
+ end if;
+
+ -- upgrade sl_sequence
+ if p_old = '1.0.2' or p_old = '1.0.5' then
+ -- Add new column(s) sl_sequence.seq_relname, sl_sequence.seq_nspname
+ execute 'alter table schemadoc.sl_sequence add column seq_relname name';
+ execute 'alter table schemadoc.sl_sequence add column seq_nspname name';
+
+ -- populate the columns with data
+ update schemadoc.sl_sequence set
+ seq_relname = PGC.relname, seq_nspname = PGN.nspname
+ from pg_catalog.pg_class PGC, pg_catalog.pg_namespace PGN
+ where schemadoc.sl_sequence.seq_reloid = PGC.oid
+ and PGC.relnamespace = PGN.oid;
+
+ -- constrain the data
+ execute 'alter table schemadoc.sl_sequence alter column seq_relname set NOT NULL';
+ execute 'alter table schemadoc.sl_sequence alter column seq_nspname set NOT NULL';
+ end if;
+
+ -- ----
+ -- Changes from 1.0.x to 1.1.0
+ -- ----
+ if p_old = '1.0.2' or p_old = '1.0.5' then
+ -- Add new column sl_node.no_spool for virtual spool nodes
+ execute 'alter table schemadoc.sl_node add column no_spool boolean';
+ update schemadoc.sl_node set no_spool = false;
+ end if;
+
+ return p_old;
+end;
+</programlisting>
+ </para>
+ </section>
+
+ </chapter>
+
+</book>
+
--- /dev/null
+++ doc/adminguide/localxid.sql
@@ -0,0 +1,9 @@
+-- $Id: localxid.sql,v 1.1 2004/12/17 23:30:02 darcyb Exp $
+
+-- Creates a "placeholder" XXID domain, used just to generate
+-- documentation.
+
+-- In reality, XXID is a type defined in C, but that isn't important
+-- for the documentation.
+
+create domain @NAMESPACE at .xxid integer not null;
\ No newline at end of file
Index: slony.sgml
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/doc/adminguide/slony.sgml,v
retrieving revision 1.3
retrieving revision 1.4
diff -Ldoc/adminguide/slony.sgml -Ldoc/adminguide/slony.sgml -u -w -r1.3 -r1.4
--- doc/adminguide/slony.sgml
+++ doc/adminguide/slony.sgml
@@ -1,6 +1,4 @@
-<!--
-$PostgreSQL: pgsql/doc/src/sgml/postgres.sgml,v 1.68 2004/12/03 05:50:18 momjian Exp $
--->
+<!-- $Id$ -->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" [
@@ -13,13 +11,14 @@
<book id="slony">
<title>Slony-I 1.1 Administration</title>
-
<bookinfo>
<corpauthor>The Slony Global Development Group</corpauthor>
<author> <firstname>Christopher</firstname> <surname>Browne</surname> </author>
&legal;
</bookinfo>
-<article id="slonyintro"> <title>Slony-I Introduction</title>
+
+ <article id="slonyintro">
+ <title>Slony-I Introduction</title>
&intro;
&prerequisites;
@@ -31,7 +30,8 @@
&reference;
-<article id="slonyadmin"> <title> Slony-I Administration </title>
+ <article id="slonyadmin">
+ <title>Slony-I Administration</title>
&adminscripts;
&startslons;
@@ -46,11 +46,9 @@
&ddlchanges;
&firstdb;
&help;
-
</article>
<article id="faq"><title> Slony-I FAQ </title>
-
<articleinfo><title>Slony-I FAQ</title>
<corpauthor>The Slony Global Development Group</corpauthor>
<author>
@@ -64,11 +62,22 @@
worth documenting</emphasis>.</para>
&faq;
+ </article>
-<!-- &errcodes; -->
+ <article id="developer"><title>Slony-I Internals</title>
+ <articleinfo>
+ <title>Slony-I Internals</title>
+ <corpauthor>The Slony Global Development Group</corpauthor>
+ <author>
+ <firstname>Christopher</firstname>
+ <surname>Browne</surname>
+ </author>
+ </articleinfo>
-<!-- </part> -->
+ &schemadoc;
+ </article>
+<!-- &errcodes; -->
<!-- &biblio; -->
<!-- &bookindex; -->
Index: filelist.sgml
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/doc/adminguide/filelist.sgml,v
retrieving revision 1.4
retrieving revision 1.5
diff -Ldoc/adminguide/filelist.sgml -Ldoc/adminguide/filelist.sgml -u -w -r1.4 -r1.5
--- doc/adminguide/filelist.sgml
+++ doc/adminguide/filelist.sgml
@@ -25,6 +25,7 @@
<!entity slonik SYSTEM "slonik.sgml">
<!entity slonikref SYSTEM "slonik_ref.sgml">
<!entity slon SYSTEM "slon.sgml">
+<!entity schemadoc SYSTEM "schemadoc.xml">
<!entity history SYSTEM "history.sgml">
<!entity legal SYSTEM "legal.sgml">
- Previous message: [Slony1-commit] By darcyb: Add schemadoc building support
- Next message: [Slony1-commit] By darcyb: collateindex is handled by ./configure no need to attempt to
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Slony1-commit mailing list