<article id="slonikref">
<title>Slonik Command Summary</title>
   <sect1><title>Introduction</title>
    
    <para>
     <application>Slonik</application> is a command line utility designed
     specifically to setup and modify configurations of the
     &slony1; replication system.
    </para>
   
   <sect2 id="outline">
    <title>General outline</title>
    
    <para>
     The <application>slonik</application> commandline utility is
     supposed to be used embedded into shell scripts and reads
     commands from files or stdin (via here documents for
     example). Nearly all of the <emphasis>real</emphasis>
     configuration work is done by calling stored procedures after
     loading the &slony1; support base into
     a database.  You may find documentation for those procedures in
     the <ulink url="schemadoc">&slony1;
     Schema Documentation</ulink>, as well as in comments associated
     with them in the database.
    </para>

    <para>
     <application>Slonik</application> was created because:
     <itemizedlist>
      
      <listitem><para>The stored procedures have special requirements
	as to on which particular node in the replication system they
	are called,</para></listitem>
      
      <listitem><para>The lack of named parameters for stored
	procedures makes it rather difficult to do this from the
	<application>psql</application> prompt, and</para></listitem>
      
      <listitem><para><application>psql</application>lacks the ability
	to maintain multiple connections with open
	transactions.</para></listitem>
     </itemizedlist>
    </para>
    <para>
     
    </para>
    <sect3><title>Commands</title>
     <para>
      The slonik command language is format free. Commands begin with
      keywords and are terminated with a semicolon. Most commands have
      a list of parameters, some of which have default values and are
      therefore optional. The parameters of commands are enclosed in
      parentheses. Each option consists of one or more keywords,
      followed by an equal sign, followed by a value. Multiple options
      inside the parentheses are separated by commas. All keywords are
      case insensitive.  The language should remind the reader of SQL.
     </para>
     <para>
      Option values may be:
      <itemizedlist>
       <listitem><para>integer values</para></listitem>
       <listitem><para>string literals enclosed in single quotes</para></listitem>
       <listitem><para>boolean values {TRUE|ON|YES} or {FALSE|OFF|NO}</para></listitem>
       <listitem><para>keywords for special cases</para></listitem>
      </itemizedlist>
     </para></sect3>
    <sect3><title>Comments</title>
     <para>
      Comments begin at a hash sign (#) and extend to the end of the line.
     </para></sect3>
    <sect3><title>Command groups</title>
     <para>
      Commands can be combined into groups of commands with optional
      <command>on error</command> and <command>on success</command> conditionals.
      The syntax for this is:
      <programlisting>
       try {
       commands;
       } 
       [on error { commands; }
       [on success { commands; }
      </programlisting></para>

     <para> Those commands are grouped together into one transaction
      per participating node. </para>
<!-- ************************************************************ --></sect3></sect2></sect1></article>

 <reference id="metacmds">
  <title>Slonik Meta Commands</title>
  <partintro>
   <para>
     The following commands may be used to somewhat abstract the
     definitions of components of Slonik scripts; <xref
     linkend="stmtinclude"> grouping configuration into central files
     that may be reused, and <xref linkend="stmtdefine"> allowing
     mnemonic identifiers to replace cryptic numeric object IDs.
   </para>
  </partintro>
  <!-- **************************************** -->
  <refentry id ="stmtinclude"><refmeta><refentrytitle>INCLUDE</refentrytitle> </refmeta>
   
   <refnamediv><refname>INCLUDE</refname>
    
    <refpurpose> pulling in slonik code from another file </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>include </command>
     <arg><replaceable class="parameter"> &lt;pathname&gt;</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
      This draws the specified slonik script inline into the present
      script.  If the <option>pathname</option> specifies a relative
      path, <xref linkend="slonik"> will search relative to the
      current working directory.
    </para>

    <para>
      Nested include files are supported.  The scanner and parser
      report the proper file names and line numbers when they run into
      an error.  </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     include &lt;/tmp/preamble.slonik&gt;;
    </programlisting>
   </refsect1>
  </refentry>
  <!-- **************************************** -->
  <refentry id ="stmtdefine"><refmeta><refentrytitle>DEFINE</refentrytitle> </refmeta>
   
   <refnamediv><refname>DEFINE</refname>
    
    <refpurpose> Defining a named symbol </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>define </command>
     <arg><replaceable class="parameter"> name </replaceable></arg>
     <arg><replaceable class="parameter"> value </replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
      This defines a named symbol.  Symbol names must follow the
      slonik rules for constructing identifiers, by starting with a
      letter, followed by letters, numbers, and underscores.
    </para>

    <para>
      Symbol values may contain spaces and may recursively contain
      symbol references.
    </para>

    <para>
      Symbols are referenced by using a <quote>@</quote> followed by
      the symbol name.  Note that symbol referencing is suppressed
      inside string literals.
    </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
define    cluster movies;
define    sakai   1;
define    chen    2;
define    fqn     fully qualified name;

cluster name = @cluster;
node @sakai admin conninfo = 'service=sakai-replication';
node @chen  admin conninfo = 'service=chen-replication';
define setMovies    id = 1;
define sakaiMovies  @setMovies, origin = @sakai;

create set ( @sakaiMovies, comment = 'movies' );

set add table( set @sakaiMovies, id = 1, @fqn = 'public.customers', comment = 'sakai customers' );
set add table( set @sakaiMovies, id = 2, @fqn = 'public.tapes',     comment = 'sakai tapes' );
echo 'But @sakaiMovies will display as a string, and is not expanded';
    </programlisting>
   </refsect1>
  </refentry>

 </reference>  
  
<!-- **************************************** -->

 <reference id="hdrcmds"> 
  <title>Slonik Preamble Commands</title>
  <partintro>
   <para>
    The following commands must appear as a <quote>preamble</quote> at
    the beginning of each <application>slonik</application> command
    script. They do not cause any direct action on any of the nodes in
    the replication system, but affect the execution of the entire
    script.
   </para>
  </partintro>
  <!-- **************************************** -->
  
  <refentry id ="clustername"><refmeta><refentrytitle>CLUSTER NAME</refentrytitle> </refmeta>
   
   <refnamediv><refname>CLUSTER NAME</refname>
    
    <refpurpose> preamble - identifying &slony1; cluster </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>CLUSTER NAME = </command>
     <arg><replaceable class="parameter"> 'clustername';</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
     Must be the very first statement in every
     <application>slonik</application> script. It defines the
     namespace in which all &slony1;
     specific functions, procedures, tables and sequences are
     defined. The namespace name is built by prefixing the given
     string literal with an underscore. This namespace will be
     identical in all databases that participate in the same
     replication group.
    </para>
    
    <para>
     No user objects are supposed to live in this namespace, and the
     namespace is not allowed to exist prior to adding a database to
     the replication system.  Thus, if you add a new node using
     <command> pg_dump -s </command> on a database that is already in
     the cluster of replicated databases, you will need to drop the
     namespace via the SQL command <command> DROP SCHEMA _testcluster
     CASCADE; </command>.
    </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     CLUSTER NAME = 'testcluster';
    </programlisting>
   </refsect1>
  </refentry>
  
  
<!-- **************************************** -->

  <refentry id ="admconninfo"><refmeta><refentrytitle>ADMIN CONNINFO</refentrytitle> </refmeta>
   
   <refnamediv><refname>ADMIN CONNINFO</refname>
    
    <refpurpose> preamble - identifying <productname>PostgreSQL</productname> database </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>NODE ival ADMIN CONNINFO = 'DSN';</command>
     <arg><replaceable class="parameter"> ival;</replaceable></arg>
     <arg><replaceable class="parameter"> 'conninfo'</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
     Describes how the <application>slonik</application> utility can
     reach a nodes database in the cluster from where it is run
     (likely the DBA's workstation). The conninfo string is the string
     agrument given to the <function>PQconnectdb()</function> libpq
     function. The user used to connect must be the special
     replication superuser, as some of the actions performed later may
     include operations that are strictly reserved for database
     superusers by PostgreSQL.
    </para>

    <para>
     The <application>slonik</application> utility will not try to
     connect to a given database unless some subsequent command
     requires the connection.
    </para>

   <note> <para>
     As mentioned in the original documents,
     &slony1; is designed as an enterprise
     replication system for data centers. It has been assumed
     throughout the entire development that the database servers and
     administrative workstations involved in replication and/or setup
     and configuration activities can use simple authentication
     schemes like <quote>trust</quote>.  Alternatively, libpq can read
     passwords from <filename> .pgpass </filename>.
    </para>
   </note>
   <note>
    <para>
    If you need to change the DSN information for a node, as would
    happen if the IP address for a host were to change, you must
    submit the new information using the <xref
    linkend="stmtstorepath"> command, and that configuration will be
    propagated.  Existing <application> slon </application> processes
    may need to be restarted in order to become aware of the
    configuration change.
    </para>
   </note>

   <para> For more details on the distinction between this and <xref
   linkend="stmtstorepath">, see <xref linkend="plainpaths">.</para>

   </Refsect1>
   <Refsect1><Title>Example</Title>
    <Programlisting>
     NODE 1 ADMIN CONNINFO = 'dbname=testdb host=server1 user=slony';
    </Programlisting>
   </Refsect1>
  </Refentry>
 </reference>
<!-- ************************************************************ -->
 
<!-- **************************************** -->
 <reference id="cmds">
  <title>Configuration and Action commmands</title>
<!-- **************************************** -->
  
  <refentry id ="stmtecho"><refmeta><refentrytitle>ECHO</refentrytitle> </refmeta>
   
   <refnamediv><refname>ECHO</refname>
    
    <refpurpose> Generic output tool </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>echo </command>
     <arg><replaceable class="parameter"> 'string'</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
     Prints the string literal on standard output.
    </para>
   </Refsect1>
   <Refsect1><Title>Example</Title>
    <Programlisting>
     ECHO 'Node 1 initialized successfully';
    </Programlisting>
   </Refsect1>
  </Refentry>
  
  <!-- **************************************** -->
  
  <refentry id ="stmtexit"><refmeta><refentrytitle>EXIT</refentrytitle> </refmeta>
   
   <refnamediv><refname>EXIT</refname>
    
    <refpurpose> Terminate Slonik script with signal </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>exit</command>
     <arg><replaceable class="parameter"> [-]ival</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    <para>
     Terminates script execution immediately, rolling back every
     open transaction on all database connections. The
     <application>slonik</application> utility
     will return the given value as its program termination code.
    </para>
   </Refsect1>
   <Refsect1><Title>Example</Title>
    <Programlisting>
     EXIT 0;
    </Programlisting>
   </Refsect1>
  </Refentry>

  <refentry id="stmtinitcluster">
   <refmeta>
    <refentrytitle>INIT CLUSTER</refentrytitle>
   </refmeta>
   <refnamediv>
    <refname>INIT CLUSTER</refname>
    <refpurpose>Initialize &slony1; cluster</refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>INIT CLUSTER</command> 
     <arg>ID = <replaceable class="parameter">integer</replaceable></arg>
     <arg>COMMENT = <replaceable class="parameter">'string'</replaceable></arg>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title> 

    <para> Initialize the first node in a new
    &slony1; replication cluster.  The
    initialization process consists of creating the cluster namespace,
    loading all the base tables, functions, procedures and
    initializing the node, using <xref
    linkend="function.initializelocalnode-integer-text"> and <xref
    linkend= "function.enablenode-integer">.
     
     <variablelist>
      <varlistentry><term><literal>ID</literal></term>
       <listitem><para>The unique, numeric ID number of the node.</para></listitem>
      </varlistentry>
      
      <varlistentry><term><literal>COMMENT = 'comment
      text'</literal></term> <listitem><para> A descriptive text added
      to the node entry in the table <xref linkend="table.sl-node">.
      </para></listitem>
      </varlistentry>
     </variablelist>
     
    </para>
    
    <para> For this process to work, the SQL scripts of the
    &slony1; system must be installed on the
    DBA workstation (the computer currently executing the
    <application>slonik</application> utility), while on the system
    where the node database is running the shared objects of the
    &slony1; system must be installed in the
    PostgreSQL library directory. Also the procedural language
    PL/pgSQL is assumed to already be installed in the target
    database.</para>
   </refsect1>
   <refsect1>
    <title>Example</title>
    <programlisting>
INIT CLUSTER (
   ID = 1,
   COMMENT = 'Node 1'
);
    </programlisting>

   <note> <para> This command functions very similarly to <xref
   linkend="stmtstorenode">, the difference being that <command>INIT
   CLUSTER </command> does not need to draw configuration from other
   existing nodes.

   </para> </note>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id ="stmtstorenode"><refmeta><refentrytitle>STORE NODE</refentrytitle> </refmeta>
   
   <refnamediv><refname>STORE NODE</refname>
    <refpurpose> Initialize &slony1; node </refpurpose>
   </refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>STORE NODE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Initialize a new node and add it to the configuration of an
    existing cluster.</para>

    <para> The initialization process consists of creating the cluster
    namespace in the new node (the database itself must already
    exist), loading all the base tables, functions, procedures and
    initializing the node.  The existing configuration of the rest of
    the cluster is copied from the <quote>event node</quote>.
     
     <variablelist>
      <varlistentry><term><literal>ID = ival</literal></term>
      <listitem><para> The unique, numeric ID number of the new
      node.</para></listitem>
      </varlistentry>
      
      <varlistentry><term><literal> COMMENT = 'description' </literal></term>
       <listitem><para> A descriptive text added to the node entry in the table <xref linkend="table.sl-node"></para></listitem>
      </varlistentry>
      
      <varlistentry><term><literal> SPOOLNODE = boolean </literal></term>
       
       <listitem><para>Specifies that the new node is a virtual spool
	 node for file archiving of replication log. If true
	 <application>slonik</application> will not attempt to initialize a database
	 with the replication schema.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> EVENT NODE = ival </literal></term>
       
       <listitem><para> The ID of the node used to create the configuration
	 event that tells all existing nodes about the new node. Default
	 value is 1.</para></listitem>
      </varlistentry>
     </variablelist>
    </para>

    <para> This uses <xref linkend=
    "function.initializelocalnode-integer-text"> and <xref linkend=
    "function.enablenode-integer">. </para>
    
   </Refsect1>
   <Refsect1><Title>Example</Title>
    <Programlisting>
     STORE NODE ( ID = 2, COMMENT = 'Node 2');
    </Programlisting>
   </Refsect1>
  </Refentry>
  
<!-- **************************************** -->
  <refentry id="stmtdropnode"><refmeta><refentrytitle>DROP NODE</refentrytitle> </refmeta>
   
   <refnamediv><refname>DROP NODE</refname>
    
    <refpurpose> Decommission &slony1; node </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>DROP NODE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     Drop a node. This command removes the specified node entirely
     from the replication systems configuration. If the replication
     daemon is still running on that node (and processing events), it
     will attempt to uninstall the replication system and terminate
     itself.

     <variablelist>
      <varlistentry><term><literal> ID  = ival </literal></term>
       <listitem><para> Node ID of the node to remove.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> EVENT NODE = ival </literal></term>
       <listitem><para> Node ID of the node to generate the event.</para></listitem>
      </varlistentry>
     </variablelist>
    </para>

    <para> This uses <xref linkend=
    "function.dropnode-integer">. </para>

    <para> When you invoke <command>DROP NODE</command>, one of the
    steps is to run <command>UNINSTALL NODE</command>.</para>

   <warning><para> If you are using connections that cache query plans
   (this is particularly common for Java application frameworks with
   connection pools), the connections may cache query plans that
   include the pre-<command>DROP NODE</command> state of things, and
   you will get <link linkend="missingoids"> error messages indicating
   missing OIDs</link>.</para>

   <para>After dropping a node, you may also need to recycle
   connections in your application.</para></warning>

   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     DROP NODE ( ID = 2 );
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->
  <refentry id="stmtuninstallnode"><refmeta><refentrytitle>UNINSTALL NODE</refentrytitle> </refmeta>
   
   <refnamediv><refname>UNINSTALL NODE</refname>
    
    <refpurpose> Decommission &slony1; node </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>UNINSTALL NODE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Restores all tables to the unlocked state, with all
     original user triggers, constraints and rules, eventually added
     &slony1; specific serial key columns
     dropped and the &slony1; schema
     dropped. The node becomes a standalone database. The data is left
     untouched.
     
     <variablelist>
      <varlistentry><term><literal> ID  = ival </literal></term>
       <listitem><para> Node ID of the node to uninstall.</para></listitem>
      </varlistentry>
     </variablelist>
    </para>

    <para> This uses <xref linkend= "function.uninstallnode">. </para>

    <para> The difference between <command>UNINSTALL NODE</command>
    and <command>DROP NODE</command> is that all <command>UNINSTALL
    NODE</command> does is to remove the &slony1; configuration; it
    doesn't drop the node's configuration from replication.</para>

   <warning><para> If you are using connections that cache query plans
   (this is particularly common for Java application frameworks with
   connection pools), the connections may cache query plans that
   include the pre-<command>UNINSTALL NODE</command> state of things,
   and you will get <link linkend="missingoids"> error messages
   indicating missing OIDs</link>.</para>

   <para>After dropping a node, you may also need to recycle
   connections in your application.</para></warning>

   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
  UNINSTALL NODE ( ID = 2 );
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtrestartnode"><refmeta><refentrytitle>RESTART NODE</refentrytitle> </refmeta>
   
   <refnamediv><refname>RESTART NODE</refname>

    <refpurpose> Restart &slony1; node </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>RESTART NODE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Causes an eventually running replication daemon on the
    specified node to shutdown and restart itself.  Theoretically,
    this command should be obsolete. In practice, TCP timeouts can
    delay critical configuration changes to actually happen in the
    case where a former forwarding node failed and needs to be
    bypassed by subscribers.
     
     <variablelist>
      <varlistentry><term><literal> ID  = ival </literal></term>
       <listitem><para> Node ID of the node to restart.</para></listitem>
      </varlistentry>
     </variablelist>
    </para>

   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
  RESTART NODE ( ID = 2 );
    </programlisting>
   </refsect1>
  </refentry>
  

  <!-- **************************************** -->

  <refentry id="stmtstorepath"><refmeta><refentrytitle>STORE
     PATH</refentrytitle> </refmeta>
   
   <refnamediv><refname>STORE PATH</refname>
    
    <refpurpose> Configure &slony1; node connection </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>STORE PATH (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Configures how the replication daemon of one node connects
     to the database of another node. If the replication system is
     supposed to use a special backbone network segment, this is the
     place to user the special IP addresses or hostnames. An existing
     configuration can be overwritten.</para>
    
    <para> The conninfo string must contain all information to connect
     to the database as the replication superuser. The names
     <quote>server</quote> or <quote>client</quote> have nothing to do
     with the particular role of a node within the cluster
     configuration. It should be simply viewed as <quote>the
      server</quote> has the message or data that <quote>the client is
      supposed to get.</quote> For a simple 2 node setup, paths into
     both directions must be configured.
    </para>
    <para> It does not do any harm to configure path information from
     every node to every other node (full cross product). The
     connections are not established unless they are required to
     actually transfer events or confirmations because of
     <emphasis>listen</emphasis> entries or data because of
     <emphasis>subscriptions</emphasis>.
     
     <variablelist>
      <varlistentry><term><literal> SERVER  = ival </literal></term>
       <listitem><para> Node ID of the database to connect to.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> CLIENT  = ival </literal></term>
       <listitem><para> Node ID of the replication daemon connecting.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> CONNINFO  = string </literal></term>
       <listitem><para> <function>PQconnectdb()</function> argument to establish the connection.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> CONNRETRY  = ival </literal></term>
       <listitem><para> Number of seconds to wait before another attempt to
	 connect is made in case the server is unavailable. Default is 10.
	</para></listitem>
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.storepath-integer-integer-text-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
STORE PATH ( SERVER = 1, CLIENT = 2, 
             CONNINFO = 'dbname=testdb host=server1 user=slony'
           );
    </programlisting>
   </refsect1>
  </refentry>


<!-- **************************************** -->

  <refentry id="stmtdroppath"><refmeta><refentrytitle>DROP PATH</refentrytitle> </refmeta>
   
   <refnamediv><refname>DROP PATH</refname>
    
    <refpurpose> Delete &slony1; connection information </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>DROP PATH (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> 	Remove the connection information between <quote>server</quote> and
     <quote>client</quote>.</para>
     
     <variablelist>
      <varlistentry><term><literal> SERVER  = ival </literal></term>
       <listitem><para> Node ID of the database to connect to.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> CLIENT  = ival </literal></term>
       <listitem><para> Node ID of the replication daemon connecting.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> EVENT NODE = ival </literal></term>
       
       <listitem><para> The ID of the node used to create the configuration
	 event that tells all existing nodes about dropping the path.
	 Defaults to the <quote>client</quote>, if omitted.
	</para></listitem>
      </varlistentry>
      </variablelist>
      </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
  DROP PATH ( SERVER = 1, CLIENT = 2 );
    </programlisting>
   </refsect1>
  </refentry>
  

<!-- **************************************** -->

  <refentry id="stmtstorelisten"><refmeta><refentrytitle>STORE LISTEN</refentrytitle> </refmeta>
   
   <refnamediv><refname>STORE LISTEN</refname>
    
    <refpurpose> Configure &slony1; node to
    indicate where to listen for events </refpurpose></refnamediv>
    
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>STORE LISTEN (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> A <quote>listen</quote> entry causes a node (receiver) to query an
     event provider for events that originate from a specific node, as
     well as confirmations from every existing node. It requires a
     <quote>path</quote> to exist so that the receiver (as client) can connect
     to the provider (as server).</para>

    <para> Every node in the system must listen for events from every
    other node in the system. As a general rule of thumb, a subscriber
    (see <xref linkend="stmtsubscribeset">) should listen for events
    of the set's origin on the same provider, where it receives the
    data from. In turn, the origin of the data set should listen for
    events from the origin in the opposite direction. A node can
    listen for events from one and the same origin on different
    providers at the same time. However, to process
    <command>SYNC</command> events from that origin, all data
    providers must have the same or higher sync status, so this will
    not result in any faster replication behaviour.
    </para>

    <variablelist>
     <varlistentry><term><literal> ORIGIN  = ival </literal></term>
      <listitem><para> Node ID of the event origin the receiver is listening for.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> PROVIDER = ival </literal></term>
     <listitem><para> Node ID of the node from which the receiver gets
	events that come from the origin.  If not specified, default is
	the origin.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> RECEIVER = ival </literal></term>
      
      <listitem><para> The ID of the node receiving the events.</para></listitem>
     </varlistentry>
    </variablelist>

    <para> This uses <xref linkend= "function.storelisten-integer-integer-integer">. </para>
    <para> For more details, see <xref linkend="listenpaths">.</para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     STORE LISTEN ( ORIGIN = 1, RECEIVER = 2, PROVIDER = 3 );
    </programlisting>
   </refsect1>
  </refentry>
  <refentry id="stmtdroplisten"><refmeta><refentrytitle>DROP LISTEN</refentrytitle> </refmeta>
   
   <refnamediv><refname>DROP LISTEN</refname>
    
    <refpurpose> Eliminate configuration indicating how
    &slony1; node listens for events
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>DROP LISTEN (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Remove a <quote>listen</quote> configuration entry. </para>
    
    <variablelist>
     <varlistentry><term><literal> ORIGIN  = ival </literal></term>
      <listitem><para> Node ID of the event origin the receiver is listening for.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> PROVIDER = ival </literal></term>
     <listitem><para> Node ID of the node from which the receiver gets
     events that come from the origin.  If not specified, default is
     the origin.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> RECEIVER = ival </literal></term>
      
      <listitem><para> The ID of the node receiving the events.</para></listitem>
     </varlistentry>
    </variablelist>
    
    <para> This uses <xref linkend= "function.droplisten-integer-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     DROP LISTEN ( ORIGIN = 1, RECEIVER = 2, PROVIDER = 3 );
    </programlisting>
   </refsect1>
  </refentry>


<!-- **************************************** -->

<refentry id="stmttableaddkey"><refmeta><refentrytitle>TABLE ADD KEY</refentrytitle> </refmeta>
   
   <refnamediv><refname>TABLE ADD KEY</refname>
    
    <refpurpose> Add primary key for use by
    &slony1; for a table with no suitable
    key </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>TABLE ADD KEY (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     In the &slony1; replication system,
     every replicated table is required to have at least one
     <command>UNIQUE</command> constraint whose columns are
     declared <command>NOT NULL.</command> Any primary key
     satisfies this requirement.
    </para>
    <para>
     As a last resort, this command can be used to add such an
     attribute to a table that does not have a primary key. Since
     this modification can have unwanted side effects, <emphasis>it is
      strongly recommended that users add a unique and not null
      attribute by other means.</emphasis>
    </para>

    <variablelist>
     <varlistentry><term><literal> NODE ID = ival </literal></term>
      <listitem><para> Node ID of the set origin where the table will be
	added as a set member. (See <xref linkend="stmtsetaddtable">.)</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> FULLY QUALIFIED NAME  = 'string' </literal></term>
      <listitem><para> The full name of the table consisting of the schema
	and table name as the SQL expression <command>quote_ident(nspname)
	 || '.' || quote_ident(relname)</command>
	would return it.</para></listitem>
     </varlistentry>
    </variablelist>

    <note><para> There is a limitation at present; you can create a
    &postgres; table with no columns, as with <command> create table
    real_short (); </command>.  &slony1; will refuse to handle such a
    table.  This isn't presently regarded as a serious limitation, as
    we can't see there being terribly much interest in replicating
    tables that contain no application data.</para> </note>
    
    <para> This uses <xref linkend= "function.tableaddkey-text">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     TABLE ADD KEY ( NODE ID = 1, 
     FULLY QUALIFIED NAME = 'public.history' );
    </programlisting>
   </refsect1>
  </refentry>
  

<!-- **************************************** -->

  <refentry id="stmtcreateset"><refmeta><refentrytitle>CREATE SET</refentrytitle> </refmeta>
   
   <refnamediv><refname>CREATE SET</refname>
    
    <refpurpose> Create &slony1; replication
    set </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>CREATE SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     In the &slony1; replication system,
     replicated tables are organized in sets. As a general rule of
     thumb, a set should contain all the tables of one application,
     that have relationships.  In a well designed application, this is
     equal to all the tables in one schema.
    </para>
    <para>
     The smallest unit one node can subscribe for replication from
     another node is a set. A set always has an origin. In
     classical replication terms, that would be the <quote>master.</quote>
     Since in &slony1; a node can be the <quote>master</quote> over one set,
     while receiving replication data in the <quote>slave</quote> role for
     another at the same time, this terminology may easily become
     misleading and should therefore be replaced with <quote>set
      origin</quote> and <quote>subscriber</quote>.
    </para>
    
    
    <variablelist>
     <varlistentry><term><literal> ID = ival </literal></term>
      <listitem><para> ID of the set to be created.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> ORIGIN = ival </literal></term>
      <listitem><para> Initial origin node of the set.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> COMMENT = 'string' </literal></term>
      <listitem><para> A descriptive text added to the set entry.</para></listitem>
     </varlistentry>
    </variablelist>
    
    <para> This uses <xref linkend= "function.storeset-integer-text">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     CREATE SET ( ID = 1, 
               ORIGIN = 1,
               COMMENT = 'Tables for ticketing system' );
    </programlisting>
   </refsect1>
  </refentry>


<!-- **************************************** -->

  <refentry id="stmtdropset"><refmeta><refentrytitle>DROP SET</refentrytitle> </refmeta>

   <refnamediv><refname>DROP SET</refname>
    
    <refpurpose> Discard &slony1;
    replication set </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>DROP SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     Drop a set of tables from the &slony1;
     configuration. This automatically unsubscribes all nodes from the
     set and restores the original triggers and rules on all
     subscribers.
    </para>
    
    <variablelist>
     <varlistentry><term><literal> ID = ival </literal></term>
      <listitem><para> ID of the set to be dropped.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> ORIGIN = ival </literal></term>
      <listitem><para> Current origin node of the set.</para></listitem>
     </varlistentry>
    </variablelist>
    
       <para> This uses <xref linkend= "function.dropset-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
  DROP SET ( ID = 5, 
             ORIGIN = 2 );
    </programlisting>
   </refsect1>
  </refentry>
 
<!-- **************************************** -->

  <refentry id="stmtmergeset"><refmeta><refentrytitle>MERGE
     SET</refentrytitle> </refmeta>
   
   <refnamediv><refname>MERGE SET</refname>
    
    <refpurpose> Merge &slony1; replication
    sets together </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>MERGE SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Merge a set of tables and sequences into another one. This
     function is a workaround for the problem that it is not possible
     to add tables/sequences to already-subscribed sets. One may create
     a temporary set, add the new objects to that, subscribe all nodes
     currently subscribed to the other set to this new one, and then
     merge the two together.
    </para>
    <para>
     This request will fail if the two sets do not have
     <emphasis>exactly</emphasis> the same set of subscribers.  </para>
    
    <variablelist>
     <varlistentry><term><literal> ID = ival </literal></term>
      <listitem><para> Unique ID of the set to contain the union of the two separate sets.</para></listitem>
     </varlistentry>
     <varlistentry><term><literal> ADD ID = ival </literal></term>
      <listitem><para> Unique ID of the set whose objects should be transferred.  </para></listitem>
     </varlistentry>
     <varlistentry><term><literal> ORIGIN = ival </literal></term>
      <listitem><para> Current origin node for both sets.  </para></listitem>
     </varlistentry>
    </variablelist>
    
       <para> This uses <xref linkend= "function.mergeset-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     MERGE SET ( ID = 2, 
     ADD ID = 9999,
     ORIGIN = 1 );
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtsetaddtable"><refmeta><refentrytitle>SET ADD TABLE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET ADD TABLE</refname>
    
    <refpurpose> Add a table to a &slony1;
    replication set </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET ADD TABLE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Add an existing user table to a replication set. The set
    cannot currently be subscribed by any other node - that
    functionality is supported by the <xref linkend="stmtmergeset">
    command.
     
     <variablelist>
      <varlistentry><term><literal> SET ID = ival </literal></term>
       <listitem><para> ID of the set to which the table is to be added.  </para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Origin node for the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>

       <listitem><para> Unique ID of the table. These ID's are not
	 only used to uniquely identify the individual table within the
	 replication system. The numeric value of this ID also
	 determines the order in which the tables are locked in a <xref
	  linkend="stmtlockset"> command for example. So
	 these numbers should represent any applicable table hierarchy
	 to make sure the <application>slonik</application> command
	 scripts do not deadlock at any critical
	 moment.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> FULLY QUALIFIED NAME = 'string' </literal></term>
       <listitem><para> The full table name as described in
	 <xref linkend="stmttableaddkey">.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> KEY = { 'string' | SERIAL }
	</literal></term> <listitem><para>
	 <emphasis>(Optional)</emphasis> The index name that covers the
	 unique and not null column set to be used as the row identifier
	 for replication purposes. Or the keyword SERIAL to use the
	 special column added with a previous <xref
	  linkend="stmttableaddkey"> command. Default
	 is to use the table's primary key.  The index name is <emphasis>
	  not </emphasis> fully qualified; you must omit the
	 namespace.</para></listitem>

      </varlistentry>
      <varlistentry><term><literal> COMMENT = 'string' </literal></term>
       <listitem><para> A descriptive text added to the table entry.  </para></listitem>
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setaddtable-integer-integer-text-name-text">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
SET ADD TABLE (
    SET ID = 1,
    ORIGIN = 1,
    ID = 20,
    FULLY QUALIFIED NAME = 'public.tracker_ticket',
    COMMENT = 'Support ticket'
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtsetaddsequence"><refmeta><refentrytitle>SET ADD SEQUENCE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET ADD SEQUENCE</refname>
    
    <refpurpose> Add a sequence to a
    &slony1; replication set
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET ADD SEQUENCE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
<refsect1>
    <title>Description</title>
    
    <para>
     Add an existing user sequence to a replication set. The set
     cannot currently be subscribed by any other node - that
     functionality is supported by the <xref linkend="stmtmergeset">
     command.
     
     <variablelist>
      <varlistentry><term><literal> SET ID = ival </literal></term>
       <listitem><para> ID of the set to which the sequence is to be added.
	</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Origin node for the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>
       
       <listitem><para> Unique ID of the sequence.  <note><para> Note
	   that this ID needs to be unique <emphasis>across
	    sequences</emphasis> throughout the cluster; the numbering of
	   tables is separate, so you might have a table with ID 20 and a
	   sequence with ID 20, and they would be recognized as
	   separate.</para> </note></para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> FULLY QUALIFIED NAME = 'string' </literal></term>
       <listitem><para> The full sequence name as described in
	 < linkend="stmttableaddkey">.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> COMMENT = 'string' </literal></term>
       <listitem><para> A descriptive text added to the sequence entry.  </para></listitem>
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setaddsequence-integer-integer-text-text">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     SET ADD SEQUENCE (
     SET ID = 1,
     ORIGIN = 1,
     ID = 20,
     FULLY QUALIFIED NAME = 'public.tracker_ticket_id_seq',
     COMMENT = 'Support ticket ID sequence'
     );
    </programlisting>
   </refsect1>
  </refentry>
  
<!-- **************************************** -->

  <refentry id="stmtsetdroptable"><refmeta><refentrytitle>SET DROP TABLE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET DROP TABLE</refname>
    
    <refpurpose> Remove a table from a
    &slony1; replication set
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET DROP TABLE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     Drop a table from a replication set.
    </para>
    <para>
     Note that this action will <emphasis> not </emphasis> drop a
     candidate primary key created using <xref
     linkend="stmttableaddkey">.
     
     <variablelist>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Origin node for the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>
       
  <listitem><para> Unique ID of the table.</para></listitem></varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setdroptable-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
     SET DROP TABLE (
     ORIGIN = 1,
     ID = 20,
     );
    </programlisting>
   </refsect1>
  </refentry>
  
<!-- **************************************** -->

  <refentry id="stmtsetdropsequence"><refmeta><refentrytitle>SET DROP SEQUENCE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET DROP SEQUENCE</refname>
    
    <refpurpose> Remove a sequence from a
    &slony1; replication set
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET DROP SEQUENCE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     Drops an existing user sequence from a replication set.
     <variablelist>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Origin node for the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>
       
       <listitem><para> Unique ID of the sequence.</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setdropsequence-integer">. </para>
   </refsect1>
<refsect1><title>Example</title>
    <programlisting>
     SET DROP SEQUENCE (
     ORIGIN = 1,
     ID = 20,
     );
</programlisting>
   </refsect1>
  </refentry>
  
<!-- **************************************** -->
  
  <refentry id="stmtsetmovetable"><refmeta><refentrytitle>SET MOVE
     TABLE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET MOVE TABLE</refname>

    <refpurpose> Move a table from one
    &slony1; replication set to another
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET MOVE TABLE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     Change the set a table belongs to. The current set and the new
     set must origin on the same node and subscribed by the same
     nodes.  <caution><para> Due to the way subscribing to new sets
       works make absolutely sure that the subscription of all nodes to
       the sets is completely processed before moving tables. Moving a
       table too early to a new set causes the subscriber to try and add
       the table already during the subscription process, which fails
       with a duplicate key error and breaks
       replication.</para></caution>
     
     <variablelist>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Current origin of the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>

       <listitem><para> Unique ID of the table.</para></listitem></varlistentry>
      <varlistentry><term><literal> NEW SET = ival </literal></term>
       
  <listitem><para> Unique ID of the set to which the table should be added.</para></listitem></varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setmovetable-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
SET MOVE TABLE (
    ORIGIN = 1,
    ID = 20,
    NEW SET = 3
);
    </programlisting>
   </refsect1>
</refentry>
  

<!-- **************************************** -->

  <refentry id="stmtsetmovesequence"><refmeta><refentrytitle>SET MOVE SEQUENCE</refentrytitle> </refmeta>
   
   <refnamediv><refname>SET MOVE SEQUENCE</refname>
    
    <refpurpose> Move a sequence from one
    &slony1; replication set to another
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SET MOVE SEQUENCE (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>

    <para>
     Change the set a sequence belongs to. The current set and the new
     set must originate on the same node and subscribed by the same
     nodes.

     <caution><para> Due to the way subscribing to new sets works make
       absolutely sure that the subscription of all nodes to the sets
       is completely processed before moving sequences. Moving a sequence too
       early to a new set causes the subscriber to try and add the sequence
       already during the subscription process, which fails with a duplicate
       key error and breaks replication.</para></caution>
     
     <variablelist>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       <listitem><para> Origin node for the set.  A future version of <application>slonik</application>
	 might figure out this information by itself.</para></listitem>
      </varlistentry>
      <varlistentry><term><literal> ID = ival </literal></term>
       
       <listitem><para> Unique ID of the sequence.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> NEW SET = ival </literal></term>
       
       <listitem><para> Unique ID of the set to which the sequence should be moved.</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.setmovesequence-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
SET MOVE SEQUENCE (
    ORIGIN = 1,
    ID = 20,
    NEW SET = 3
);
    </programlisting>
   </refsect1>
  </refentry>


<!-- **************************************** -->

  <refentry id="stmtstoretrigger"><refmeta><refentrytitle>STORE TRIGGER</refentrytitle> </refmeta>

   <refnamediv><refname>STORE TRIGGER</refname>
    
    <refpurpose> Indicate that a trigger should not be disabled by
    &slony1; on a subscriber node
    </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>STORE TRIGGER (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> By default, all user defined triggers and constraints are
     disabled on all subscriber nodes while a table is replicated. This
     command can be used to explicitly exclude a trigger from being
     disabled.

     <variablelist>
      <varlistentry><term><literal> TABLE ID = ival </literal></term>
       <listitem><para> The unique, numeric ID number of the table the trigger is defined for.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> TRIGGER NAME = 'string' </literal></term>
       
       <listitem><para> The name of the trigger as it appears in the
	 <envar>pg_trigger</envar> system catalog.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> EVENT NODE = ival </literal></term>
       
       <listitem><para> (Optional) The ID of the node used to create
       the configuration event that tells all existing nodes about the
	 special trigger. Default value is 1.</para></listitem>

      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.storetrigger-integer-name">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
STORE TRIGGER (
    TABLE ID = 2,
    TRIGGER NAME = 'cache_invalidation'
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtdroptrigger"><refmeta><refentrytitle>DROP TRIGGER</refentrytitle> </refmeta>
   
   <refnamediv><refname>DROP TRIGGER</refname>
    
    <refpurpose> Return a trigger to default behavior, where it will
    not fire on subscriber nodes </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>DROP TRIGGER (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Remove the special handling for the specified trigger.

     <variablelist>
      <varlistentry><term><literal> TABLE ID = ival </literal></term>
      <listitem><para> The unique, numeric ID number of the table the
      trigger is defined for.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> TRIGGER NAME = 'string' </literal></term>
       
       <listitem><para> The name of the trigger as it appears in the
	 <envar>pg_trigger</envar> system catalog.</para></listitem>

      </varlistentry>
      <varlistentry><term><literal> EVENT NODE = ival </literal></term>
       
       <listitem><para> (Optional) The ID of the node used to create
	 the configuration event that tells all existing nodes about the
	 special trigger. Default value is 1.</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.droptrigger-integer-name">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
DROP TRIGGER (
    TABLE ID = 2,
    TRIGGER NAME = 'cache_invalidation'
);
    </programlisting>
   </refsect1>
  </refentry>
  
<!-- **************************************** -->
  <refentry id="stmtsubscribeset"><refmeta><refentrytitle>SUBSCRIBE SET</refentrytitle> </refmeta>

   <refnamediv><refname>SUBSCRIBE SET</refname>
    
    <refpurpose> Start replication of &slony1; set </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>SUBSCRIBE SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Causes a node (subscriber) to start replicating a set of
    tables either from the origin or from another provider node, which
    must itself already be be an active, forwarding subscriber.</para>
    
    <para> The application tables contained in the set must already
     exist and should ideally be empty. The current version of
     &slony1; will <emphasis>not</emphasis>
     attempt to copy the schema of the set. The replication daemon will
     start copying the current content of the set from the given
     provider and then try to catch up with any update activity that
     happened during that copy process. After successful subscription,
     the tables are guarded on the subscriber, using triggers, against
     accidental updates by the application.
    </para>
    
    <para> If the tables on the subscriber are <emphasis>not</emphasis> empty, then
     the <command>COPY SET</command> process winds up doing more work than should be
     strictly necessary:
     <itemizedlist>
      
      <listitem><para> It deletes all <quote>old</quote> entries in
      the table</para></listitem>

      <listitem><para> Those old entries
	clutter up the table until it is next
	<command>VACUUM</command>ed <emphasis>after</emphasis> the
	subscription process is complete</para></listitem>
      
      <listitem><para> The indices for the table will contain entries
	for the old, deleted entries, which will slow the process of
	inserting new entries into the index.</para></listitem>
     </itemizedlist>
     

     <note><para> If you need to revise subscription information for a
       node, you <emphasis>also</emphasis> submit the new information
       using this command, and the new configuration will be propagated
       throughout the replication network.  The normal reason to revise
       this information is that you want a node to subscribe to a
       <emphasis> different </emphasis> provider node, or for a node to
       become a <quote>forwarding</quote> subscriber so it may later
       become the provider for a later subscriber.</para> </note>

     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       <listitem><para> ID of the set to subscribe</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> PROVIDER = ival </literal></term>
       
       <listitem><para> Node ID of the data provider from which this
       node draws data.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> RECEIVER = ival </literal></term>
       
       <listitem><para> Node ID of the new subscriber</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> FORWARD = boolean </literal></term>
       
       <listitem><para> Flag whether or not the new subscriber should
	 store the log information during replication to make it
	 possible candidate for the provider role for future
	 nodes.</para></listitem>

      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.subscribeset-integer-integer-integer-boolean">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
SUBSCRIBE SET (
   ID = 1,
   PROVIDER = 1,
   RECEIVER = 3,
   FORWARD = YES
);
    </programlisting>
   </refsect1>
  </refentry>
  
<!-- **************************************** -->

  <refentry id="stmtunsubscribeset"><refmeta><refentrytitle>UNSUBSCRIBE SET</refentrytitle> </refmeta>
   
   <refnamediv><refname>UNSUBSCRIBE SET</refname>

    <refpurpose> End replication of &slony1; set </refpurpose></refnamediv>
   
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>UNSUBSCRIBE SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>

    <para> Stops the subscriber from replicating the set. The tables
     are opened up for full access by the client application on the
     former subscriber. The tables are not truncated or otherwise
     modified. All original triggers, rules and constraints are
     restored.
     
     <warning><para> Resubscribing an unsubscribed set requires a
       <emphasis>complete fresh copy</emphasis> of data from the
       provider to be transferred since the tables have been subject to
       possible independent modifications.  </para></warning>
     
     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       <listitem><para> ID of the set to unsubscribe</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> RECEIVER = ival </literal></term>
       
       <listitem><para> Node ID of the (former) subscriber</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.unsubscribeset-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
UNSUBSCRIBE SET (
   ID = 1,
   RECEIVER = 3
);
    </programlisting>
   </refsect1>
  </refentry>

  
<!-- **************************************** -->

  <refentry id ="stmtlockset"><refmeta><refentrytitle>LOCK SET</refentrytitle> </refmeta>

   <refnamediv><refname>LOCK SET</refname>
    
    <refpurpose> Guard &slony1; replication
    set to prepare for <command>MOVE SET</command>
    </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>LOCK SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Guards a replication set against client application updates
    in preparation for a <xref linkend="stmtmoveset"> command.
    </para>

    <para> This command must be the first in a possible statement
    group (<command>try</command>).  The reason for this is that it
    needs to commit the changes made to the tables (adding a special
    trigger function) before it can wait for every concurrent
    transaction to finish. At the same time it cannot hold an open
    transaction to the same database itself since this would result in
    blocking itself forever.</para>

    <para> Note that this is a <link linkend="locking"> locking
    operation, </link> which means that it can get stuck behind other
    database activity.
     
     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       <listitem><para> ID of the set to lock</para></listitem>
	 
      </varlistentry>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       
       <listitem><para> Node ID of the current set origin</para></listitem>
	 
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.lockset-integer">. </para>
   </Refsect1>
   <Refsect1><Title>Example</Title>
    <Programlisting>
LOCK SET (
   ID = 1,
   RECEIVER = 3
);
    </Programlisting>
   </Refsect1>
  </Refentry>

<!-- **************************************** -->

  <refentry id="stmtunlockset"><refmeta><refentrytitle>UNLOCK SET</refentrytitle> </refmeta>
   
   <refnamediv><refname>UNLOCK SET</refname>
    
    <refpurpose> Unlock a &slony1; set that was locked </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>UNLOCK SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> 
     Unlocks a previously locked set.
     
     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       <listitem><para> ID of the set to unlock</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> ORIGIN = ival </literal></term>
       
       <listitem><para> Node ID of the current set origin</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.unlockset-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
UNLOCK SET (
   ID = 1,
   RECEIVER = 3
);
    </programlisting>
   </refsect1>
  </refentry>
  

<!-- **************************************** -->

  <refentry id="stmtmoveset"><refmeta><refentrytitle>MOVE SET</refentrytitle> </refmeta>
   
   <refnamediv><refname>MOVE SET</refname>
    
    <refpurpose> Change origin of a &slony1;
    replication set </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>MOVE SET (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Changes the origin of a set from one node to another. The
    new origin must be a current subscriber of the set. The set must
    currently be locked on the old origin. </para>
    
    <para> After this command, the set cannot be unlocked on the old
     origin any more. The old origin will continue as a forwarding
     subscriber of the set and the subscription chain from the old
     origin to the new origin will be reversed, hop by hop. As soon as
     the new origin has finished processing the event (that includes
     any outstanding sync events that happened before,
     <emphasis>i.e.</emphasis> fully catching up), the new origin will
     take over and open all tables in the set for client application
     update activity.
    </para>

    <para> This is <emphasis>not</emphasis> failover, as it requires a
     functioning old origin node (you needed to lock the set on the old
     origin).  You would probably prefer to <command>MOVE SET</command>
     instead of <command>FAILOVER</command>, if at all possible, as
     <command>FAILOVER</command> winds up discarding the old origin
     node as being corrupted.</para>
     
    <para> Note that this is a <link linkend="locking"> locking
    operation, </link> which means that it can get stuck behind other
    database activity.
     
     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       <listitem><para> ID of the set to transfer</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> OLD ORIGIN = ival </literal></term>
       
       <listitem><para> Node ID of the current set origin</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> NEW ORIGIN = ival </literal></term>
       
  <listitem><para> Node ID of the new set origin</para></listitem>
       
      </varlistentry>
     </variablelist>
    </para>
    <para> This uses <xref linkend= "function.moveset-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
MOVE SET (
   ID = 1,
   OLD ORIGIN = 1,
   NEW ORIGIN = 3
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtfailover"><refmeta><refentrytitle>FAILOVER</refentrytitle> </refmeta>
   
   <refnamediv><refname>FAILOVER</refname>
    
    <refpurpose> Fail a broken replication set over to a backup node
    </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>FAILOVER (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para>
     The <command>FAILOVER</command> command causes the backup node to take over all sets
     that currently originate on the failed
     node. <application>slonik</application> will contact all other
     direct subscribers of the failed node to determine which node has
     the highest sync status for each set. If another node has a
     higher sync status than the backup node, the replication will
     first be redirected so that the backup node replicates against
     that other node, before assuming the origin role and allowing
     update activity.
    </para>

    <para>
     After successful failover, all former direct subscribers of the
     failed node become direct subscribers of the backup node. The
     failed node is abandoned, and can and should be removed from the
     configuration with <xref linkend="stmtdropnode">.
    </para>
    
    <warning><para> This command will abandon the status of the failed
    node.  There is no possibility to let the failed node join the
    cluster again without rebuilding it from scratch as a slave.  If
    at all possible, you would likely prefer to use <xref
    linkend="stmtmoveset"> instead, as that does
    <emphasis>not</emphasis> abandon the failed node.
    </para></warning>
    
    <variablelist>
     <varlistentry><term><literal> ID = ival </literal></term>
      <listitem><para> ID of the failed node</para></listitem>
      
     </varlistentry>
     <varlistentry><term><literal> BACKUP NODE = ival </literal></term>
      
      <listitem><para> Node ID of the node that will take over all
      sets originating on the failed node</para></listitem>

     </varlistentry>
    </variablelist>
    
    <para> This uses <xref linkend= "function.failednode-integer-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
FAILOVER (
   ID = 1,
   BACKUP NODE = 2
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtddlscript"><refmeta><refentrytitle>EXECUTE SCRIPT</refentrytitle> </refmeta>
   
   <refnamediv><refname>EXECUTE SCRIPT</refname>
    
    <refpurpose> Execute SQL/DDL script  </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>EXECUTE SCRIPT (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Executes a script containing arbitrary SQL statements on
     all nodes that are subscribed to a set at a common controlled
     point within the replication transaction stream.</para>
    
    <para> The specified event origin must be the origin of the set.
     The script file must not contain any <command>START</command> or
     <command>COMMIT TRANSACTION</command> calls.  (This may change in
     PostgreSQL 8.0 once nested transactions, aka savepoints, are
     supported) In addition, non-deterministic DML statements (like
     updating a field with <function>CURRENT_TIMESTAMP</function>) must
     be avoided, since the data changes done by the script are
     explicitly not replicated. </para>

    <variablelist>
     <varlistentry><term><literal> SET ID = ival </literal></term>
      <listitem><para> The unique numeric ID number of the set affected by the script</para></listitem>
      
     </varlistentry>
     <varlistentry><term><literal> FILENAME = '/path/to/file' </literal></term>
      
      <listitem><para> The name of the file containing the SQL script to
	execute.  This might be a relative path, relative to the location of
	the <application>slonik</application> instance you are running, or, preferably,
	an absolute path on the system where <application>slonik</application> is to run.</para>
       
       <para> The <emphasis>contents</emphasis> of the file are propagated as part of
	the event, so the file does not need to be accessible on any of the
	nodes.</para></listitem>
      
     </varlistentry>
     <varlistentry><term><literal> EVENT NODE = ival </literal></term>
      <listitem><para> (Optional) The ID of the current origin of the set.  Default value is 1.</para></listitem>
      
     </varlistentry>
     <varlistentry><term><literal> EXECUTE ONLY ON = ival
       </literal></term> <listitem><para> (Optional) The ID of the only
	node to actually execute the script.  This option causes the
	script to be propagated by all nodes but executed only by one.
	The default is to execute the script on all nodes that are
	subscribed to the set.</para></listitem>
      
     </varlistentry>
    </variablelist>
    
    <para> See also the warnings in <xref linkend="ddlchanges">.</para>

    <para> Note that this is a <link linkend="locking"> locking
    operation, </link> which means that it can get stuck behind other
    database activity.</para>
     
    <para> At the start of this event, all tables in the specified set
    are unlocked via the function
    <function>alterTableRestore(tab_id)</function>.  After the SQL
    script has run, they are returned to <quote>replicating
    state</quote> using
    <function>alterTableForReplication(tab_id)</function>.  This means
    that all of these tables are locked by this <application> slon
    </application> process for the duration of the SQL script
    execution.</para>

    <para> If a table's columns are modified, it is very important
    that the triggers be regenerated, otherwise they may be
    inappropriate for the new form of the table schema.</para>

    <para> This uses <xref linkend= "function.ddlscript-integer-text-integer">. </para>
   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
EXECUTE SCRIPT (
   SET ID = 1,
   FILENAME = '/tmp/changes_2004-05-01.sql',
   EVENT NODE = 1
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtupdatefunctions"><refmeta><refentrytitle>UPDATE FUNCTIONS</refentrytitle> </refmeta>

   <refnamediv><refname>UPDATE FUNCTIONS</refname>
    
    <refpurpose> Reload stored functions </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>UPDATE FUNCTIONS (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Reloads stored functions for a node.</para>
    
    <para>Reloads all stored procedure and function definitions in the
    &slony1; schema for the specified node. This command is usually
    part of the &slony1; software upgrade procedure.
    </para>

     <variablelist>
      <varlistentry><term><literal> ID = ival </literal></term>
       
       <listitem><para> The node to refresh.</para></listitem>
       
      </varlistentry>
     </variablelist>

   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
UPDATE FUNCTIONS (
    ID = 3        # Update functions on node 3
);
    </programlisting>
   </refsect1>
  </refentry>

<!-- **************************************** -->

  <refentry id="stmtwaitevent"><refmeta><refentrytitle>WAIT FOR EVENT</refentrytitle> </refmeta>

   <refnamediv><refname>WAIT FOR EVENT</refname>
    
    <refpurpose> Have Slonik script wait for previous event to
    complete </refpurpose></refnamediv>
   <refsynopsisdiv>
    <cmdsynopsis>
     <command>WAIT FOR EVENT (options);</command>
    </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
    <title>Description</title>
    
    <para> Waits for event Confirmation.</para>
    
    <para> <application>Slonik</application> remembers the last event
     generated on every node during script execution (events generated
     by earlier calls are currently not checked). In certain situations
     it is necessary that events generated on one node (such as
     <command>CREATE SET</command>) are processed on another node
     before issuing more commands (for instance, <xref
      linkend="stmtsubscribeset">).  <command>WAIT FOR EVENT</command> may be
     used to cause the <application>slonik</application> script to wait
     until the subscriber node is ready for the next action.
    </para>
    
    <para> <command>WAIT FOR EVENT</command> must be called outside of
    any <command>try</command> block in order to work, since new
    confirm messages don't become visible within a transaction.

     <variablelist>
      <varlistentry><term><literal> ORIGIN = ival | ALL </literal></term>
       <listitem><para> The origin of the event(s) to wait for.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> CONFIRMED = ival | ALL </literal></term>
       
       <listitem><para> The node ID of the receiver that must confirm the event(s).</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> WAIT ON = ival </literal></term>
       <listitem><para> The ID of the node where the <xref linkend="table.sl-confirm"> table
	 is to be checked.  The default value is 1.</para></listitem>
       
      </varlistentry>
      <varlistentry><term><literal> TIMEOUT = ival </literal></term>
       
       <listitem><para> The number of seconds to wait.  Default is 600
       (10 minutes).  <command>TIMEOUT = 0</command> causes the script
	 to wait indefinitely.</para></listitem>
       
      </varlistentry>
     </variablelist></para>

   </refsect1>
   <refsect1><title>Example</title>
    <programlisting>
WAIT FOR EVENT (
  ORIGIN = ALL,
  CONFIRMED = ALL,
  WAIT ON = 1
);
    </programlisting>
   </refsect1>
  </refentry>
 </reference>
<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:"book.sgml"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
