available elsewhere (including a descendant project on gborg).
-# $PostgreSQL: pgsql/contrib/Makefile,v 1.49 2004/06/01 05:15:47 tgl Exp $
+# $PostgreSQL: pgsql/contrib/Makefile,v 1.50 2004/08/28 21:36:24 tgl Exp $
subdir = contrib
top_builddir = ..
pgbench \
pgcrypto \
pgstattuple \
- rserv \
rtree_gist \
seg \
spi \
Reindexes a database
by Shaun Thomas <sthomas@townnews.com>
-rserv -
- Replication server
- by Vadim B. Mikheev <vadim4o@email.com>
-
rtree_gist -
Support for emulating RTREE indexing in GiST
by Oleg Bartunov <oleg@sai.msu.su> and Teodor Sigaev <teodor@sigaev.ru>
+++ /dev/null
-# -*- perl -*-
-## ApplySnapshot
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-use IO::File;
-use RServ;
-use Getopt::Long;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $snapshot = $opt_snapshot || "__Snapshot";
-
-if (defined($opt_help) || (scalar(@ARGV) < 1)) {
- print "Usage: $0 --host=name --user=name --password=string slavedb\n";
- exit ((scalar(@ARGV) < 1)? 1:0);
-}
-
-my $slave = $ARGV[0] || "slave";
-
-my $sinfo = "dbname=$slave";
-$sinfo = "$sinfo host=$opt_host" if (defined($opt_host));
-$sinfo = "$sinfo user=$opt_user" if (defined($opt_user));
-$sinfo = "$sinfo password=$opt_password" if (defined($opt_password));
-
-my $conn = Pg::connectdb($sinfo);
-
-my $inpf = new IO::File;
-$inpf = STDIN;
-
-$RServ::quiet = !$verbose;
-
-$res = ApplySnapshot ($conn, $inpf);
-
-if ($res > 0)
-{
- printf STDERR "Snapshot applied\n";
-}
-elsif ($res != 0)
-{
- printf STDERR "ERROR\n";
- exit(1);
-}
-
-exit(0);
+++ /dev/null
-# -*- perl -*-
-## CleanLog
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-
-use Getopt::Long;
-use RServ;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help", "snapshot=s",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $snapshot = $opt_snapshot || "__Snapshot";
-
-if (defined($opt_help) || (scalar(@ARGV) < 2) || ($ARGV[1] !~ /^\d+$/)) {
- print "Usage: $PROGRAM_NAME --host=name --user=name --password=string masterdb syncid\n";
- exit ((scalar(@ARGV) < 2)? 1: 0);
-}
-
-my $dbname = $ARGV[0];
-my $howold = $ARGV[1];
-
-my $minfo = "dbname=$dbname";
-$minfo = "$minfo host=$opt_host" if (defined($opt_host));
-$minfo = "$minfo user=$opt_user" if (defined($opt_user));
-$minfo = "$minfo password=$opt_password" if (defined($opt_password));
-
-print "Master connection is $minfo\n" if ($debug);
-print "Slave connection is $sinfo\n" if ($debug);
-
-my $conn = Pg::connectdb($minfo);
-
-$RServ::quiet = !$verbose;
-
-$res = CleanLog($conn, $howold);
-
-exit(1) if $res < 0;
-
-printf STDERR "Deleted %d log records\n", $res if $res > 0;
-
-exit(0);
+++ /dev/null
-# -*- perl -*-
-## GetSyncID
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-
-use Pg;
-use Getopt::Long;
-use RServ;
-
-$| = 1;
-
-my $verbose = 1;
-
-$result = GetOptions("debug!", "verbose!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose if (defined($opt_verbose));
-
-if (defined($opt_help) || (scalar(@ARGV) < 1)) {
- print "Usage: $0 --host=name --user=name --password=string slavedb\n";
- exit ((scalar(@ARGV) < 1)? 1: 0);
-}
-
-my $dbname = $ARGV[0];
-
-my $sinfo = "dbname=$dbname";
-$sinfo = "$sinfo host=$opt_host" if (defined($opt_host));
-$sinfo = "$sinfo user=$opt_user" if (defined($opt_user));
-$sinfo = "$sinfo password=$opt_password" if (defined($opt_password));
-
-print("Connecting to '$sinfo'\n") if ($debug || $verbose);
-my $conn = Pg::connectdb($sinfo);
-
-$RServ::quiet = !$verbose;
-
-$res = GetSyncID($conn);
-
-die "ERROR\n" if $res < 0;
-
-if (! defined $res)
-{
- printf STDERR "No SyncID found\n";
-}
-else
-{
- print("Last SyncID applied: ") if ($verbose);
- printf "%d", $res;
- print("\n") if ($verbose);
-}
-
-exit(0);
+++ /dev/null
-#!/bin/sh
-## InitRservTest
-# erServer demonstration implementation
-# (c) 2000 Vadim Mikheev, PostgreSQL Inc.
-
-[ -n "$RSERV_PERL" ] || RSERV_PERL=@LIBDIR@
-[ -n "$RSERV_SQL" ] || RSERV_SQL=@SQLDIR@
-[ -n "$RSERV_BIN" ] || RSERV_BIN=@BINDIR@
-export RSERV_PERL
-export RSERV_SQL
-export RSERV_BIN
-
-pargs=
-
-while [[ $1 == -* ]]; do
- case "$1" in
- --user)
- shift
- pargs="$pargs -U $1"
- ;;
- --host)
- shift
- pargs="$pargs -h $1"
- ;;
- *)
- echo "Usage: $0 --user name --host name masterdb slavedb"
- exit 1
- ;;
- esac
- shift
-done
-
-masterdb=$1
-slavedb=$2
-
-[ "${masterdb}" != "" ] || masterdb=master
-[ "${slavedb}" != "" ] || slavedb=slave
-
-echo "Master -> $masterdb"
-echo "Slave -> $slavedb"
-
-############################################################################
-
-fill()
-{
- table="create table test (i text, k int, l int);
-copy test from stdin;
-Line: 1 1 1
-Line: 2 2 2
-Line: 3 3 3
-Line: 4 4 4
-Line: 5 5 5
-Line: 6 6 6
-Line: 7 7 7
-Line: 8 8 8
-Line: 9 9 9
-Line: 10 10 10
-Line: 11 11 11
-Line: 12 12 12
-Line: 13 13 13
-Line: 14 14 14
-Line: 15 15 15
-Line: 16 16 16
-Line: 17 17 17
-Line: 18 18 18
-Line: 19 19 19
-Line: 20 20 20
-Line: 21 21 21
-Line: 22 22 22
-Line: 23 23 23
-Line: 24 24 24
-Line: 25 25 25
-Line: 26 26 26
-Line: 27 27 27
-Line: 28 28 28
-Line: 29 29 29
-Line: 30 30 30
-Line: 31 31 31
-Line: 32 32 32
-Line: 33 33 33
-Line: 34 34 34
-Line: 35 35 35
-Line: 36 36 36
-Line: 37 37 37
-Line: 38 38 38
-Line: 39 39 39
-Line: 40 40 40
-Line: 41 41 41
-Line: 42 42 42
-Line: 43 43 43
-Line: 44 44 44
-Line: 45 45 45
-Line: 46 46 46
-Line: 47 47 47
-Line: 48 48 48
-Line: 49 49 49
-Line: 50 50 50
-Line: 51 51 51
-Line: 52 52 52
-Line: 53 53 53
-Line: 54 54 54
-Line: 55 55 55
-Line: 56 56 56
-Line: 57 57 57
-Line: 58 58 58
-Line: 59 59 59
-Line: 60 60 60
-Line: 61 61 61
-Line: 62 62 62
-Line: 63 63 63
-Line: 64 64 64
-Line: 65 65 65
-Line: 66 66 66
-Line: 67 67 67
-Line: 68 68 68
-Line: 69 69 69
-Line: 70 70 70
-Line: 71 71 71
-Line: 72 72 72
-Line: 73 73 73
-Line: 74 74 74
-Line: 75 75 75
-Line: 76 76 76
-Line: 77 77 77
-Line: 78 78 78
-Line: 79 79 79
-Line: 80 80 80
-Line: 81 81 81
-Line: 82 82 82
-Line: 83 83 83
-Line: 84 84 84
-Line: 85 85 85
-Line: 86 86 86
-Line: 87 87 87
-Line: 88 88 88
-Line: 89 89 89
-Line: 90 90 90
-Line: 91 91 91
-Line: 92 92 92
-Line: 93 93 93
-Line: 94 94 94
-Line: 95 95 95
-Line: 96 96 96
-Line: 97 97 97
-Line: 98 98 98
-Line: 99 99 99
-Line: 100 100 100
-\\.";
- echo "$table" | psql $pargs $1 || exit
- if [ "$1" = "$masterdb" ]
- then
- rm -rf __tmpf__
- psql $pargs -c "select * into table testoid from test" $1 || exit
- psql $pargs -c "copy testoid with oids to '`pwd`/__tmpf__'" $1 || exit
- psql $pargs -c "select * into table teststr from test" $1 || exit
- else
- psql $pargs -c "select * into table testoid from test where k < 0" $1 || exit
- psql $pargs -c "copy testoid with oids from '`pwd`/__tmpf__'" $1 || exit
- psql $pargs -c "select * into table teststr from test" $1 || exit
- rm -rf __tmpf__
- fi
- psql $pargs -c "create unique index i_test on test (k)" $1 || exit
- psql $pargs -c "create unique index i_testoid on testoid (oid)" $1 || exit
- psql $pargs -c "create unique index i_teststr on teststr (i)" $1 || exit
- psql $pargs -c vacuum $1 || exit
-}
-
-############################################################################
-
-echo
-echo
-echo ' ATTENTION'
-echo
-echo This script will destroy databases with names MASTER and SLAVE
-echo
-echo -n "Are you going to continue ? [Y/N] "
-
-read answ
-
-case $answ in
- Y*|y*)
- ;;
- *)
- exit
- ;;
-esac
-
-echo
-echo
-
-sql="drop database $masterdb"
-echo $sql
-psql $pargs -c "$sql" template1
-sql="create database $masterdb"
-echo $sql
-psql $pargs -c "$sql" template1 || exit
-
-echo Setup master system
-psql $pargs $masterdb < $RSERV_SQL/master.sql || exit
-
-echo Wait for template1 to become available...
-sleep 1
-
-sql="drop database $slavedb"
-echo $sql
-psql $pargs -c "$sql" template1
-sql="create database $slavedb"
-echo $sql
-psql $pargs -c "$sql" template1 || exit
-
-echo Setup slave system
-psql $pargs $slavedb < $RSERV_SQL/slave.sql || exit
-
-echo Create and fill test, testoid and teststr tables in master db
-fill $masterdb
-echo
-echo Register test, testoid and teststr tables for replication on master
-echo
-$RSERV_BIN/MasterAddTable $masterdb test k
-$RSERV_BIN/MasterAddTable $masterdb testoid oid
-$RSERV_BIN/MasterAddTable $masterdb teststr i
-
-echo Create and fill test, testoid and teststr tables in slave db
-fill $slavedb
-echo
-echo Register test, testoid and teststr tables for replication on slave
-echo
-$RSERV_BIN/SlaveAddTable $slavedb test k
-$RSERV_BIN/SlaveAddTable $slavedb testoid oid
-$RSERV_BIN/SlaveAddTable $slavedb teststr i
-
-echo
-echo
-echo
-echo
-echo
-echo
-echo
-echo
-echo " Now make changes in $masterdb db and run"
-echo
-echo " Replicate $masterdb $slavedb"
-echo
-echo " to replicate the master on the slave."
-echo
-echo " You may also use the RservTest tcl utility"
-echo " to demonstrate this functionality."
-echo
-echo
-echo
-echo
-echo
-echo
-echo
-echo
-
-exit
-
-############################################################################
+++ /dev/null
-# Makefile for erServer demonstration implementation
-# (c) 2000 Vadim Mikheev, PostgreSQL Inc.
-
-NAME = rserv
-MODULES = rserv
-DATA = RServ.pm
-DATA_built = master.sql slave.sql
-SQLS = $(DATA_built)
-DOCS = README.rserv
-SCRIPTS_built = RservTest
-SCRIPTS_built += MasterInit MasterAddTable Replicate MasterSync CleanLog
-SCRIPTS_built += SlaveInit SlaveAddTable GetSyncID
-SCRIPTS_built += PrepareSnapshot ApplySnapshot
-SCRIPTS_built += InitRservTest
-
-
-ifdef USE_PGXS
-PGXS = $(shell pg_config --pgxs)
-include $(PGXS)
-else
-subdir = contrib/rserv
-top_builddir = ../..
-include $(top_builddir)/src/Makefile.global
-include $(top_srcdir)/contrib/contrib-global.mk
-endif
-
-
-$(SQLS): %.sql: %.sql.in
- sed 's,@MODULE_FILENAME@,$$libdir/$(NAME),g' $< >$@
-
-$(SCRIPTS_built): %: %.in
- sed -e 's,@MODULE_FILENAME@,$$libdir/$(NAME),g' \
- -e 's:@SQLDIR@:$(datadir)/contrib:g' \
- -e 's:@BINDIR@:$(bindir):g' \
- -e 's:@LIBDIR@:$(datadir)/contrib:g' $< >$@
- chmod a+x $@
+++ /dev/null
-# -*- perl -*-
-## MasterAddTable
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use Pg;
-use Getopt::Long;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-
-if (defined($opt_help) || (scalar(@ARGV) < 3)) {
- print "Usage: $0 --host=name --user=name --password=string masterdb table column\n";
- exit ((scalar(@ARGV) < 3)? 1: 0);
-}
-
-my $dbname = $ARGV[0];
-my $table = $ARGV[1];
-my $keyname = $ARGV[2];
-
-my $minfo = "dbname=$dbname";
-$minfo = "$minfo host=$opt_host" if (defined($opt_host));
-$minfo = "$minfo user=$opt_user" if (defined($opt_user));
-$minfo = "$minfo password=$opt_password" if (defined($opt_password));
-
-my $conn = Pg::connectdb($minfo);
-
-my $result = $conn->exec("BEGIN");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-$result = $conn->exec("select pgc.oid, pga.attnum from pg_class pgc" .
- ", pg_attribute pga where pgc.relname = '$table'" .
- " and pgc.oid = pga.attrelid" .
- " and pga.attname = '$keyname'");
-die $conn->errorMessage if $result->resultStatus ne PGRES_TUPLES_OK;
-
-my @row = $result->fetchrow;
-die "Can't find table/key\n" if ! defined $row[0] || ! defined $row[1];
-
-$result = $conn->exec("create trigger _RSERV_TRIGGER_T_ after" .
- " insert or update or delete on $table" .
- " for each row execute procedure" .
- " _rserv_log_('$row[1]')");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-$result = $conn->exec("insert into _RSERV_TABLES_ (tname, cname, reloid, key)" .
- " values ('$table', '$keyname', $row[0], $row[1])");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-$result = $conn->exec("COMMIT");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-exit(0);
+++ /dev/null
-# -*- perl -*-
-## MasterInit
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use Pg;
-use Getopt::Long;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-
-if (defined($opt_help) || (scalar(@ARGV) < 1)) {
- print "Usage: $0 --host=name --user=name --password=string masterdb\n";
- exit ((scalar(@ARGV) < 1)? 1:0);
-}
-
-my $module_filename = '@MODULE_FILENAME@';
-
-my $master = $ARGV[0] || "master";
-
-my $minfo = "dbname=$master";
-$minfo = "$minfo host=$opt_host" if (defined($opt_host));
-$minfo = "$minfo user=$opt_user" if (defined($opt_user));
-$minfo = "$minfo password=$opt_password" if (defined($opt_password));
-
-sub RollbackAndQuit {
- $conn = shift @_;
-
- print STDERR "Error in query: ", $conn->errorMessage;
- $conn->exec("ROLLBACK");
- exit (-1);
-}
-
-my $conn = Pg::connectdb($minfo);
-if ($conn->status != PGRES_CONNECTION_OK) {
- print STDERR "Failed opening $minfo\n";
- exit 1;
-}
-
-my $result = $conn->exec("BEGIN");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("set transaction isolation level serializable");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# List of slave servers
-$result = $conn->exec("create table _RSERV_SERVERS_" .
- " (server serial, host text, post int4, dbase text)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# List of replicated tables
-$result = $conn->exec("create table _RSERV_TABLES_" .
- " (tname name, cname name, reloid oid, key int4)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# Bookkeeping log for row replication
-$result = $conn->exec("create table _RSERV_LOG_" .
- " (reloid oid, logid int4, logtime timestamp, deleted int4, key text)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# This is to speedup lookup of deleted tuples
-$result = $conn->exec("create index _RSERV_LOG_INDX_DLT_ID_ on _RSERV_LOG_ (deleted, logid)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# This is to speedup cleanup
-$result = $conn->exec("create index _RSERV_LOG_INDX_TM_ID_ on _RSERV_LOG_ (logtime, logid)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# This is to speedup trigger and lookup of updated tuples
-$result = $conn->exec("create index _RSERV_LOG_INDX_REL_KEY_ on _RSERV_LOG_ (reloid, key)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# Sync point for each slave server
-$result = $conn->exec("create table _RSERV_SYNC_" .
- " (server int4, syncid int4, synctime timestamp" .
- ", status int4, minid int4, maxid int4, active text)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("create index _RSERV_SYNC_INDX_SRV_ID_ on _RSERV_SYNC_ (server, syncid)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-# Sync point reference numbers
-$result = $conn->exec("create sequence _rserv_sync_seq_");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("CREATE FUNCTION _rserv_log_() RETURNS trigger" .
- " AS '$module_filename' LANGUAGE 'c'");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("CREATE FUNCTION _rserv_sync_(int4) RETURNS int4" .
- " AS '$module_filename' LANGUAGE 'c'");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("CREATE FUNCTION _rserv_debug_(int4) RETURNS int4" .
- " AS '$module_filename' LANGUAGE 'c'");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("COMMIT");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-exit (0);
+++ /dev/null
-# -*- perl -*-
-## MasterSync
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-
-use Getopt::Long;
-use RServ;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "quiet!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $quiet = $opt_quiet || 0;
-
-if (defined($opt_help) || (scalar(@ARGV) < 2) || ($ARGV[1] !~ /^\d+$/)) {
- print "Usage: $0 --host=name --user=name --password=string masterdb syncid\n";
- exit ((scalar(@ARGV) < 2)? 1:0);
-}
-
-my $master = $ARGV[0] || "master";
-my $server = 0;
-my $syncid = $ARGV[1] || die "SyncID not specified";
-
-my $minfo = "dbname=$master";
-$minfo = "$minfo host=$opt_host" if (defined($opt_host));
-$minfo = "$minfo user=$opt_user" if (defined($opt_user));
-$minfo = "$minfo password=$opt_password" if (defined($opt_password));
-
-my $conn = Pg::connectdb($minfo);
-
-$RServ::quiet = !$verbose;
-
-$res = SyncSyncID($conn, $server, $syncid);
-
-if ($res == 0)
-{
- printf STDERR "SyncID updated on $master\n" if ($verbose);
- exit(0);
-}
-
-printf STDERR "ERROR\n" unless ($quiet);
-exit(1);
+++ /dev/null
-# -*- perl -*-
-## PrepareSnapshot
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-
-use IO::File;
-use Getopt::Long;
-use RServ;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help", "snapshot=s",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $snapshot = $opt_snapshot || "__Snapshot";
-
-if (defined($opt_help) || (scalar(@ARGV) < 1)) {
- print "Usage: $0 --snapshot=file --host=name --user=name --password=string masterdb\n";
- exit ((scalar(@ARGV) < 1)? 1:0);
-}
-
-my $master = $ARGV[0] || "master";
-my $server = 0;
-
-my $minfo = "dbname=$master";
-$minfo = "$minfo host=$opt_host" if (defined($opt_host));
-$minfo = "$minfo user=$opt_user" if (defined($opt_user));
-$minfo = "$minfo password=$opt_password" if (defined($opt_password));
-
-my $conn = Pg::connectdb($minfo);
-
-my $outf = new IO::File;
-$outf = STDOUT;
-
-$RServ::quiet = !$verbose;
-
-$res = PrepareSnapshot ($conn, $outf, $server);
-
-if ($res == 0)
-{
- printf STDERR "Sync-ed\n";
- exit(0);
-}
-if ($res > 0)
-{
- printf STDERR "Snapshot dumped to STDOUT\n";
- exit(0);
-}
-
-printf STDERR "ERROR\n";
-exit(1);
+++ /dev/null
-erServer demonstration implementation
-(c) 2000, Vadim Mikheev and Thomas Lockhart, PostgreSQL Inc.
-
-Version 0.1:
- Replicates a master database to a single slave database.
- Tested under Linux (Mandrake 7.2).
-
-Requirements:
-
-- PostgreSQL >= 7.0.X
- A separate Makefile is required for PostgreSQL 7.0.x and earlier
-- Perl5 and the PostgreSQL perl interface
-- TCL and the PostgreSQL tcl interface (for demo only)
-
-
-How to compile:
-
-- make all
-- make install
-
-Scripts and libraries are installed in places which are consistant
-with the way other contrib/ code is installed; underneath the core
-items in a contrib/ directory.
-
-
-The toolset:
-
-MasterInit dbname
- sets up structures and user-defined functions for a master
- database.
-
-SlaveInit dbname
- sets up structures for a slave database. Does not include triggers,
- but only bookkeeping tables.
-
-MasterAddTable dbname table column
- sets up triggers for the specified table and column. Note that this
- column must be updated for replication to occur.
-
-SlaveAddTable dbname table column
- sets up bookkeeping for the specified table and column.
-
-Replicate masterdb slavedb
- actually replicate changes from a master to single slave. Note that
- this must be repeated to replicate to multiple slaves, but the
- bookkeeping for each slave is handled separately so each can be
- updated at different times and with different sets of changes.
-
-GetSyncID [--noverbose] slavedb
- returns the last syncid the specified slave has seen. May be used
- in conjunction with SyncSyncID and CleanLog using the --noverbose
- option.
-
-MasterSync masterdb syncid
- registers a syncid with the specified master database. Used to
- propagate replication success back to the master database.
-
-CleanLog masterdb syncid
- removes obsolete entries in the master database replication log
- table up to the specified replication sequence number.
-
-Other utilities:
-
-PrepareSnapshot
- build a file of replication information from the specified masterdb.
-
-ApplySnapshot
- use a file of replication information to apply to the specified
- slavedb.
-
-
-How to run a demo:
-
-Run the InitRservTest script. It will create two local databases
-'master' & 'slave' with table 'test' in them. It accepts the following
-arguments:
- --help
- Print a usage message and quit.
- --user name
- Access the database with another username.
- --host name
- Access a remote database. Note that the shared library *must* be
- visible in the same path as installed on the build machine.
- masterdb
- slavedb
- Names of test databases. Defaults to 'master' and 'slave',
- respectively.
-
-Once the test databases are set up, simply updating the master table
-is sufficient to log a replication event. You can update the table
-test then run "Replicate master slave", or you can use the demo
-program RservTest.
-
-Run the tcl/tk GUI demo program, RservTest. It has a single window,
-which has four buttons and three data entry boxes.
-
- --------------------------------------------------
- | PostgreSQL Asynchronous Replication |
- | Master Slave |
- | < master > < slave > |
- | |
- | [ Update ] < > |
- | [ Replicate ] |
- | [ Show ] ____________ |
- | |
- | [ Quit ] |
- | |
- --------------------------------------------------
-
-The demo has the following behaviors:
-
-If you enter a string into the data entry field to the right of
-[Update], then that string will be used to either update the master
-database or to query the slave database.
-
-If you click [Update], then the string in the data entry box will be
-entered into the master database.
-
-If you click [Replicate], then all changes since the last replication
-will be propagated to the slave database.
-
-If you click [Show], then the slave database will be queried to find
-the string in the data entry box to the right of the [Update]
-button. If the string does not (yet) exist in the slave database, then
-"n/a" will appear to the right of the [Show] button. If the string
-does exist in the slave database, then it will be printed to the right
-of the [Show] button.
-
-
-Todo:
-1. Support for multiple slave servers.
-2. Explicit support for master/slave failover.
-3. More docs.
+++ /dev/null
-# -*- perl -*-
-# RServ.pm
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-package RServ;
-
-require Exporter;
-@ISA = qw(Exporter);
-@EXPORT = qw(PrepareSnapshot ApplySnapshot GetSyncID SyncSyncID CleanLog);
-@EXPORT_OK = qw();
-
-use Pg;
-
-$debug = 0;
-$quiet = 1;
-
-my %Mtables = ();
-my %Stables = ();
-
-sub PrepareSnapshot
-{
- my ($conn, $outf, $server) = @_; # (@_[0], @_[1], @_[2]);
-
- my $result = $conn->exec("BEGIN");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- $result = $conn->exec("set transaction isolation level serializable");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- # MAP oid --> tabname, keyname
- $result = $conn->exec("select pgc.oid, pgc.relname, pga.attname" .
- " from _RSERV_TABLES_ rt, pg_class pgc, pg_attribute pga" .
- " where pgc.oid = rt.reloid and pga.attrelid = rt.reloid" .
- " and pga.attnum = rt.key");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- my @row;
- while (@row = $result->fetchrow)
- {
- # printf "$row[0], $row[1], $row[2]\n";
- push @{$Mtables{$row[0]}}, $row[1], $row[2];
- }
-
- # Read last succeeded sync
- $sql = "select syncid, synctime, minid, maxid, active from _RSERV_SYNC_" .
- " where server = $server and syncid = (select max(syncid) from" .
- " _RSERV_SYNC_ where server = $server and status > 0)";
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- my @lastsync = $result->fetchrow;
-
- my $sinfo = "";
- if ($lastsync[3] ne '') # sync info
- {
- $sinfo = "and (l.logid >= $lastsync[3]";
- $sinfo .= " or l.logid in ($lastsync[4])" if $lastsync[4] ne '';
- $sinfo .= ")";
- }
-
- my $havedeal = 0;
-
- # DELETED rows
- $sql = "select l.reloid, l.key from _RSERV_LOG_ l" .
- " where l.deleted = 1 $sinfo order by l.reloid";
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- $lastoid = '';
- while (@row = $result->fetchrow)
- {
- next unless exists $Mtables{$row[0]};
- if ($lastoid != $row[0])
- {
- if ($lastoid eq '')
- {
- my $syncid = GetSYNCID($conn, $outf);
- return($syncid) if $syncid < 0;
- $havedeal = 1;
- }
- else
- {
- printf $outf "\\.\n";
- }
- printf $outf "-- DELETE $Mtables{$row[0]}[0]\n";
- $lastoid = $row[0];
- }
- if (! defined $row[1])
- {
- print STDERR "NULL key\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- printf $outf "%s\n", OutputValue($row[1]);
- }
- printf $outf "\\.\n" if $lastoid ne '';
-
- # UPDATED rows
-
- my ($taboid, $tabname, $tabkey);
- foreach $taboid (keys %Mtables)
- {
- ($tabname, $tabkey) = @{$Mtables{$taboid}};
- my $oidkey = ($tabkey eq 'oid') ? "_$tabname.oid," : '';
- $sql = sprintf "select $oidkey _$tabname.* from _RSERV_LOG_ l," .
- " $tabname _$tabname where l.reloid = $taboid and l.deleted = 0 $sinfo" .
- " and l.key = _$tabname.${tabkey}::text";
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- printf $outf "-- ERROR\n" if $havedeal;
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- next if $result->ntuples <= 0;
- if (! $havedeal)
- {
- my $syncid = GetSYNCID($conn, $outf);
- return($syncid) if $syncid < 0;
- $havedeal = 1;
- }
- printf $outf "-- UPDATE $tabname\n";
- while (@row = $result->fetchrow)
- {
- for ($i = 0; $i <= $#row; $i++)
- {
- printf $outf " " if $i;
- printf $outf "%s", OutputValue($row[$i]);
- }
- printf $outf "\n";
- }
- printf $outf "\\.\n";
- }
-
- unless ($havedeal)
- {
- $conn->exec("ROLLBACK");
- return(0);
- }
-
- # Remember this snapshot info
- $result = $conn->exec("select _rserv_sync_($server)");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- printf $outf "-- ERROR\n";
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- $result = $conn->exec("COMMIT");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- printf $outf "-- ERROR\n";
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- printf $outf "-- OK\n";
-
- return(1);
-
-}
-
-sub OutputValue
-{
- my ($val) = @_; # @_[0];
-
- return("\\N") unless defined $val;
-
- $val =~ s/\\/\\\\/g;
- $val =~ s/ /\\011/g;
- $val =~ s/\n/\\012/g;
- $val =~ s/\'/\\047/g;
-
- return($val);
-}
-
-# Get syncid for new snapshot
-sub GetSYNCID
-{
- my ($conn, $outf) = @_; # (@_[0], @_[1]);
-
- my $result = $conn->exec("select nextval('_rserv_sync_seq_')");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- my @row = $result->fetchrow;
-
- printf $outf "-- SYNCID $row[0]\n";
- return($row[0]);
-}
-
-
-sub CleanLog
-{
- my ($conn, $howold) = @_; # (@_[0], @_[1]);
-
- my $result = $conn->exec("BEGIN");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- my $sql = "select rs.maxid, rs.active from _RSERV_SYNC_ rs" .
- " where rs.syncid = (select max(rs2.syncid) from _RSERV_SYNC_ rs2" .
- " where rs2.server = rs.server and rs2.status > 0) order by rs.maxid";
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
- my $maxid = '';
- my %active = ();
- while (my @row = $result->fetchrow)
- {
- $maxid = $row[0] if $maxid eq '';
- last if $row[0] > $maxid;
- my @ids = split(/[ ]+,[ ]+/, $row[1]);
- foreach $aid (@ids)
- {
- $active{$aid} = 1 unless exists $active{$aid};
- }
- }
- if ($maxid eq '')
- {
- print STDERR "No Sync IDs\n" unless ($quiet);
- return(0);
- }
- my $alist = join(',', keys %active);
- my $sinfo = "logid < $maxid";
- $sinfo .= " and logid not in ($alist)" if $alist ne '';
-
- $sql = "delete from _RSERV_LOG_ where " .
- "logtime < now() - '$howold second'::interval and $sinfo";
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- $maxid = $result->cmdTuples;
-
- $result = $conn->exec("COMMIT");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- return($maxid);
-}
-
-sub ApplySnapshot
-{
- my ($conn, $inpf) = @_; # (@_[0], @_[1]);
-
- my $result = $conn->exec("BEGIN");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- $result = $conn->exec("SET CONSTRAINTS ALL DEFERRED");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- # MAP name --> oid, keyname, keynum
- my $sql = "select pgc.oid, pgc.relname, pga.attname, rt.key" .
- " from _RSERV_SLAVE_TABLES_ rt, pg_class pgc, pg_attribute pga" .
- " where pgc.oid = rt.reloid and pga.attrelid = rt.reloid" .
- " and pga.attnum = rt.key";
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- while (@row = $result->fetchrow)
- {
- # printf " %s %s\n", $row[1], $row[0];
- push @{$Stables{$row[1]}}, $row[0], $row[2], $row[3];
- }
-
- my $ok = 0;
- my $syncid = '';
- while(<$inpf>)
- {
- $_ =~ s/\n//;
- my ($cmt, $cmd, $prm) = split (/[ ]+/, $_, 3);
- if ($cmt ne '--')
- {
- printf STDERR "Invalid format\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- if ($cmd eq 'DELETE')
- {
- if ($syncid eq '')
- {
- printf STDERR "Sync ID unspecified\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- $result = DoDelete($conn, $inpf, $prm);
- if ($result)
- {
- $conn->exec("ROLLBACK");
- return($result);
- }
- }
- elsif ($cmd eq 'UPDATE')
- {
- if ($syncid eq '')
- {
- printf STDERR "Sync ID unspecified\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- $result = DoUpdate($conn, $inpf, $prm);
- if ($result)
- {
- $conn->exec("ROLLBACK");
- return($result);
- }
- }
- elsif ($cmd eq 'SYNCID')
- {
- if ($syncid ne '')
- {
- printf STDERR "Second Sync ID ?!\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- if ($prm !~ /^\d+$/)
- {
- printf STDERR "Invalid Sync ID $prm\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- $syncid = $prm;
-
- printf STDERR "Sync ID $syncid\n" unless ($quiet);
-
- $result = $conn->exec("select syncid, synctime from " .
- "_RSERV_SLAVE_SYNC_ where syncid = " .
- "(select max(syncid) from _RSERV_SLAVE_SYNC_)");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- my @row = $result->fetchrow;
- if (! defined $row[0])
- {
- $result = $conn->exec("insert into" .
- " _RSERV_SLAVE_SYNC_(syncid, synctime) values ($syncid, now())");
- }
- elsif ($row[0] >= $prm)
- {
- printf STDERR "Sync-ed to ID $row[0] ($row[1])\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(0);
- }
- else
- {
- $result = $conn->exec("update _RSERV_SLAVE_SYNC_" .
- " set syncid = $syncid, synctime = now()");
- }
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- }
- elsif ($cmd eq 'OK')
- {
- $ok = 1;
- last;
- }
- elsif ($cmd eq 'ERROR')
- {
- printf STDERR "ERROR signaled\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- else
- {
- printf STDERR "Unknown command $cmd\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
- }
-
- if (! $ok)
- {
- printf STDERR "No OK flag in input\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-2);
- }
-
- $result = $conn->exec("COMMIT");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- return(1);
-}
-
-sub DoDelete
-{
- my ($conn, $inpf, $tabname) = @_; # (@_[0], @_[1], @_[2]);
-
- my $ok = 0;
- while(<$inpf>)
- {
- if ($_ !~ /\n$/)
- {
- printf STDERR "Invalid format\n" unless ($quiet);
- return(-2);
- }
- my $key = $_;
- $key =~ s/\n//;
- if ($key eq '\.')
- {
- $ok = 1;
- last;
- }
-
- my $sql = "delete from $tabname where $Stables{$tabname}->[1] = '$key'";
-
- printf "$sql\n" if $debug;
-
- my $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
- }
-
- if (! $ok)
- {
- printf STDERR "No end of input in DELETE section\n" unless ($quiet);
- return(-2);
- }
-
- return(0);
-}
-
-
-sub DoUpdate
-{
- my ($conn, $inpf, $tabname) = @_; # (@_[0], @_[1], @_[2]);
- my $oidkey = ($Stables{$tabname}->[2] < 0) ? 1 : 0;
-
- my @CopyBuf = ();
- my $CBufLen = 0;
- my $CBufMax = 16 * 1024 * 1024; # max size of buf for copy
-
- my $sql = "select attnum, attname from pg_attribute" .
- " where attrelid = $Stables{$tabname}->[0] and attnum > 0";
-
- my $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
-
- my @anames = ();
- while (@row = $result->fetchrow)
- {
- $anames[$row[0]] = $row[1];
- }
-
- my $istring;
- my $ok = 0;
- while(<$inpf>)
- {
- if ($_ !~ /\n$/)
- {
- printf STDERR "Invalid format\n" unless ($quiet);
- return(-2);
- }
- $istring = $_;
- $istring =~ s/\n//;
- if ($istring eq '\.')
- {
- $ok = 1;
- last;
- }
- my @vals = split(/ /, $istring);
- if ($oidkey)
- {
- if ($vals[0] !~ /^\d+$/ || $vals[0] <= 0)
- {
- printf STDERR "Invalid OID\n" unless ($quiet);
- return(-2);
- }
- $oidkey = $vals[0];
- }
- else
- {
- unshift @vals, '';
- }
-
- $sql = "update $tabname set ";
- my $ocnt = 0;
- for (my $i = 1; $i <= $#anames; $i++)
- {
- if ($vals[$i] eq '\N')
- {
- if ($i == $Stables{$tabname}->[2])
- {
- printf STDERR "NULL key\n" unless ($quiet);
- return(-2);
- }
- $vals[$i] = 'null';
- }
- else
- {
- $vals[$i] = "'" . $vals[$i] . "'";
- next if $i == $Stables{$tabname}->[2];
- }
- $ocnt++;
- $sql .= ', ' if $ocnt > 1;
- $sql .= "$anames[$i] = $vals[$i]";
- }
- if ($oidkey)
- {
- $sql .= " where $Stables{$tabname}->[1] = $oidkey";
- }
- else
- {
- $sql .= " where $Stables{$tabname}->[1] = $vals[$Stables{$tabname}->[2]]";
- }
-
- printf "$sql\n" if $debug;
-
- $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
- next if $result->cmdTuples == 1; # updated
-
- if ($result->cmdTuples > 1)
- {
- printf STDERR "Duplicate keys\n" unless ($quiet);
- return(-2);
- }
-
- # no key - copy
- push @CopyBuf, "$istring\n";
- $CBufLen += length($istring);
-
- if ($CBufLen >= $CBufMax)
- {
- $result = DoCopy($conn, $tabname, $oidkey, \@CopyBuf);
- return($result) if $result;
- @CopyBuf = ();
- $CBufLen = 0;
- }
- }
-
- if (! $ok)
- {
- printf STDERR "No end of input in UPDATE section\n" unless ($quiet);
- return(-2);
- }
-
- if ($CBufLen)
- {
- $result = DoCopy($conn, $tabname, $oidkey, \@CopyBuf);
- return($result) if $result;
- }
-
- return(0);
-}
-
-
-sub DoCopy
-{
- my ($conn, $tabname, $withoids, $CBuf) = @_; # (@_[0], @_[1], @_[2], @_[3]);
-
- my $sql = "COPY $tabname " . (($withoids) ? "WITH OIDS " : '') .
-"FROM STDIN";
- my $result = $conn->exec($sql);
- if ($result->resultStatus ne PGRES_COPY_IN)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
-
- foreach $str (@{$CBuf})
- {
- $conn->putline($str);
- }
-
- $conn->putline("\\.\n");
-
- if ($conn->endcopy)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
-
- return(0);
-
-}
-
-
-#
-# Returns last SyncID applied on Slave
-#
-sub GetSyncID
-{
- my ($conn) = @_; # (@_[0]);
-
- my $result = $conn->exec("select max(syncid) from _RSERV_SLAVE_SYNC_");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- return(-1);
- }
- my @row = $result->fetchrow;
- return(undef) unless defined $row[0]; # null
- return($row[0]);
-}
-
-#
-# Updates _RSERV_SYNC_ on Master with Slave SyncID
-#
-sub SyncSyncID
-{
- my ($conn, $server, $syncid) = @_; # (@_[0], @_[1], @_[2]);
-
- my $result = $conn->exec("BEGIN");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- $result = $conn->exec("select synctime, status from _RSERV_SYNC_" .
- " where server = $server and syncid = $syncid" .
- " for update");
- if ($result->resultStatus ne PGRES_TUPLES_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- my @row = $result->fetchrow;
- if (! defined $row[0])
- {
- printf STDERR "No SyncID $syncid found for server $server\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(0);
- }
- if ($row[1] > 0)
- {
- printf STDERR "SyncID $syncid for server $server already updated\n" unless ($quiet);
- $conn->exec("ROLLBACK");
- return(0);
- }
- $result = $conn->exec("update _RSERV_SYNC_" .
- " set synctime = now(), status = 1" .
- " where server = $server and syncid = $syncid");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
- $result = $conn->exec("delete from _RSERV_SYNC_" .
- " where server = $server and syncid < $syncid");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- $result = $conn->exec("COMMIT");
- if ($result->resultStatus ne PGRES_COMMAND_OK)
- {
- print STDERR $conn->errorMessage unless ($quiet);
- $conn->exec("ROLLBACK");
- return(-1);
- }
-
- return(1);
-}
-
-1;
+++ /dev/null
-# -*- perl -*-
-## Replicate
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use lib "@LIBDIR@";
-
-use IO::File;
-use Getopt::Long;
-use RServ;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help", "snapshot=s",
- "masterhost=s", "slavehost=s", "host=s",
- "masteruser=s", "slaveuser=s", "user=s",
- "masterpassword=s", "slavepassword=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $snapshot = $opt_snapshot || "__Snapshot";
-
-if (defined($opt_help) || (scalar(@ARGV) < 2)) {
- print "Usage: $0 --snapshot=file --host=name --user=name --password=string masterdb slavedb\n";
- print "\t--masterhost=name --masteruser=name --masterpassword=string\n";
- print "\t--slavehost=name --slaveuser=name --slavepassword=string\n";
- exit ((scalar(@ARGV) < 2)? 1:0);
-}
-
-my $master = $ARGV[0] || "master";
-my $slave = $ARGV[1] || "slave";
-my $server = 0;
-
-my $minfo = "dbname=$master";
-$minfo = "$minfo host=$opt_masterhost" if (defined($opt_masterhost));
-$minfo = "$minfo user=$opt_masteruser" if (defined($opt_masteruser));
-$minfo = "$minfo password=$opt_masterpassword" if (defined($opt_masterpassword));
-my $sinfo = "dbname=$slave";
-$sinfo = "$sinfo host=$opt_slavehost" if (defined($opt_slavehost));
-$sinfo = "$sinfo user=$opt_slaveuser" if (defined($opt_slaveuser));
-$sinfo = "$sinfo password=$opt_slavepassword" if (defined($opt_slavepassword));
-
-print "Master connection is $minfo\n" if ($debug);
-print "Slave connection is $sinfo\n" if ($debug);
-
-my $mconn = Pg::connectdb($minfo);
-my $sconn = Pg::connectdb($sinfo);
-
-$RServ::quiet = !$verbose;
-
-SyncSync($mconn, $sconn);
-
-my $outf = new IO::File;
-open $outf, ">$snapshot";
-print "\n>>>>>>>>>>>>> Prepare Snapshot\n\n" if ($verbose);
-$res = PrepareSnapshot($mconn, $outf, $server);
-close $outf;
-die "\n>>>>>>>>>>>>> ERROR\n" if $res < 0;
-if ($res == 0)
-{
- print "\n>>>>>>>>>>>>> DBases are sync-ed\n" if ($verbose);
- exit(0);
-}
-
-my $inpf = new IO::File;
-open $inpf, "<$snapshot";
-print "\n>>>>>>>>>>>>> Apply Snapshot\n\n" if ($verbose);
-$res = ApplySnapshot($sconn, $inpf);
-close $inpf;
-die "\n>>>>>>>>>>>>> ERROR\n" if $res < 0;
-
-if ($res > 0)
-{
- print "Snapshot applied\n" if ($verbose);
- unlink $snapshot unless ($debug);
- SyncSync($mconn, $sconn);
-}
-
-exit(0);
-
-###########################################################################
-
-sub SyncSync
-{
- ($mconn, $sconn) = @_;
-
- print "\n>>>>>>>>>>>>> Sync SyncID\n\n" if ($verbose);
- print "Get last SyncID from Slave DB\n" if ($verbose);
- $syncid = GetSyncID($sconn);
- if ($syncid > 0)
- {
- print "Last SyncID applied: $syncid\n" if ($verbose);
- print "Sync SyncID\n" if ($verbose);
-
- $res = SyncSyncID($mconn, $server, $syncid);
-
- print "Succeeded\n" if (($res > 0) && ($verbose));
- }
-}
+++ /dev/null
-#!/bin/sh
-## pgserv.tcl
-# (c) 2000 Thomas Lockhart, PostgreSQL Inc.
-# The next line will reinvoke as wish *DO NOT REMOVE OR ALTER* \
-exec wish "$0" "$@"
-
-puts "Starting Replication Server demo"
-
-set RSERV_BIN "@BINDIR@"
-
-# Bring in the interfaces we will be using...
-
-#package require Pgtcl
-load libpgtcl[info sharedlibextension]
-
-# elog
-# Information or error log and exit handler
-proc {elog} {level message} {
- global show
- switch -exact -- $level {
- DEBUG {
- if {$show(debug)} {
- puts "DEBUG $message"
- }
- }
- ERROR {
- if {$show(error)} {
- puts "ERROR $message"
- }
- FATAL {
- if ($show(error)} {
- puts "FATAL $message"
- }
- exit 1
- }
- default {
- puts "INFO $message"
- }
- }
-}
-
-proc {ShowUsage} {} {
- global argv0
- puts "Usage: $argv0 --host name --user name --password string masterdb slavedb"
- puts "\t--masterhost name --masteruser name --masterpassword string"
- puts "\t--slavehost name --slaveuser name --slavepassword string"
-}
-
-# Initial values for database access
-# master, slave variables are tied to text input boxes,
-# and will be updated on user input
-proc {SetDbInfo} {db name {host ""} {user ""} {pass ""}} {
- global dbinfo
- set dbinfo($db,name) $name
- set dbinfo($db,host) $host
- set dbinfo($db,user) $user
- set dbinfo($db,pass) $pass
-}
-
-# ConnInfo
-# Connection information for pgtcl library
-proc {ConnInfo} {{db master}} {
- global dbinfo
- set ci "dbname=$dbinfo($db,name)"
- if {[string length $dbinfo($db,host)] > 0} {
- set ci "$ci host=$dbinfo($db,host)"
- }
- if {[string length $dbinfo($db,user)] > 0} {
- set ci "$ci user=$dbinfo($db,user)"
- }
- if {[string length $dbinfo($db,pass)] > 0} {
- set ci "$ci password=$dbinfo($db,pass)"
- }
-# puts "Construct conninfo $ci"
- return $ci
-}
-
-# ConnInfoParams
-# Connection information for (perl) callable programs
-proc {ConnInfoParams} {{db master}} {
- global dbinfo
- set ci ""
- if {[string length $dbinfo($db,host)] > 0} {
- set ci "$ci --host=$dbinfo($db,host)"
- }
- if {[string length $dbinfo($db,user)] > 0} {
- set ci "$ci --user=$dbinfo($db,user)"
- }
- if {[string length $dbinfo($db,pass)] > 0} {
- set ci "$ci --password=$dbinfo($db,pass)"
- }
-# puts "Construct conninfo $ci"
- return $ci
-}
-
-# ConnInfoMaster
-# Connection information for (perl) callable programs
-proc {ConnInfoMaster} {{db master}} {
- global dbinfo
- set ci $dbinfo($db,name)
- if {[string length $dbinfo($db,host)] > 0} {
- set ci "$ci --masterhost=$dbinfo($db,host)"
- }
- if {[string length $dbinfo($db,user)] > 0} {
- set ci "$ci --masteruser=$dbinfo($db,user)"
- }
- if {[string length $dbinfo($db,pass)] > 0} {
- set ci "$ci --masterpassword=$dbinfo($db,pass)"
- }
-# puts "Construct conninfo $ci"
- return $ci
-}
-
-# ConnInfoSlave
-# Connection information for (perl) callable programs
-proc {ConnInfoSlave} {{db slave}} {
- global dbinfo
- set ci $dbinfo($db,name)
- if {[string length $dbinfo($db,host)] > 0} {
- set ci "$ci --slavehost=$dbinfo($db,host)"
- }
- if {[string length $dbinfo($db,user)] > 0} {
- set ci "$ci --slaveuser=$dbinfo($db,user)"
- }
- if {[string length $dbinfo($db,pass)] > 0} {
- set ci "$ci --slavepassword=$dbinfo($db,pass)"
- }
-# puts "Construct conninfo $ci"
- return $ci
-}
-
-
-SetDbInfo master master localhost
-SetDbInfo slave slave localhost
-set dbinfo(snapshot,name) "__Snapshot"
-
-set update ""
-
-set show(debug) 1
-set show(error) 1
-
-set argi 0
-while {$argi < $argc} {
-# puts "argi is $argi; argc is $argc"
- set arg [lindex $argv $argi]
- switch -glob -- $arg {
- -h -
- --host {
- incr argi
- set dbinfo(master,host) [lindex $argv $argi]
- set dbinfo(slave,host) [lindex $argv $argi]
- }
- --masterhost {
- incr argi
- set dbinfo(master,host) [lindex $argv $argi]
- }
- --slavehost {
- incr argi
- set dbinfo(slave,host) [lindex $argv $argi]
- }
- -u -
- --user {
- incr argi
- set dbinfo(master,user) [lindex $argv $argi]
- set dbinfo(slave,user) [lindex $argv $argi]
- }
- --masteruser {
- incr argi
- set dbinfo(master,user) [lindex $argv $argi]
- }
- --slaveuser {
- incr argi
- set dbinfo(slave,user) [lindex $argv $argi]
- }
- -s -
- --snapshot {
- incr argi
- set dbinfo(snapshot,name) [lindex $argv $argi]
- }
- -* {
- elog ERROR "$argv0: invalid parameter '$arg'"
- ShowUsage
- exit 1
- }
- default {
- break
- }
- }
- incr argi
-}
-
-if {$argi < $argc} {
- set dbinfo(master,name) [lindex $argv $argi]
- incr argi
-}
-if {$argi < $argc} {
- set dbinfo(slave,name) [lindex $argv $argi]
- incr argi
-}
-if {$argi < $argc} {
- elog "$argv0: too many parameters"
- ShowUsage
- exit 1
-}
-
-elog DEBUG "User is $dbinfo(master,user) $dbinfo(slave,user)"
-elog DEBUG "Host is $dbinfo(master,host) $dbinfo(slave,host)"
-
-#
-# TK layout
-#
-
-wm title . "Async Replication"
-
-wm geom . 400x400
-
-proc {CreateResultFrame} {b l w} {
- pack [frame $b -borderwidth 10] -fill x
- pack [button $b.run -text $l -command $l -width $w] -side left
-# pack [entry $b.e -textvariable NewRow] -side left
-}
-
-set t .top
-pack [frame $t -borderwidth 10] -fill x
-pack [frame $t.h -borderwidth 10] -fill x
-pack [label $t.h.h -text "PostgreSQL Async Replication Server"]
-
-set b .b
-pack [frame $b -borderwidth 10] -fill x
-pack [frame $b.l -borderwidth 10] -fill x
-pack [label $b.l.ml -text "Master"] -side left
-pack [label $b.l.sl -text "Slave"] -side right
-pack [entry $b.m -textvariable dbinfo(master,name) -width 25] -side left
-pack [entry $b.s -textvariable dbinfo(slave,name) -width 25] -side right
-
-set b .u
-pack [frame $b -borderwidth 10] -fill x
-pack [button $b.run -text update -command Update -width 10] -side left
-pack [entry $b.e -textvariable update -width 50] -side left
-
-set r [CreateResultFrame .r Replicate 10]
-
-set b .s
-pack [frame $b -borderwidth 10] -fill x
-pack [button $b.b -text Show -command Show -width 10] -side left
-pack [label $b.e -text ""] -side left
-
-set b .button
-pack [frame $b -borderwidth 10] -fill x
-
-pack [button $b.quit -text "Quit" -command Shutdown]
-
-#
-# Functions mapped to buttons
-#
-
-proc {Update} {} {
- global dbinfo
- global update
-
- elog DEBUG "Opening database [ConnInfo master]..."
- set res [catch {set db [pg_connect -conninfo "[ConnInfo master]"]} msg]
- if {$res} {
- elog ERROR "Database '$dbinfo(master,name)' is not available: $res ($msg)"
- } else {
- elog DEBUG "Insert $update into database $dbinfo(master,name)..."
- set res [pg_exec $db "insert into test select '$update', max(k)+1, max(l)+1 from test"]
- elog DEBUG [pg_result $res -status]
- catch {pg_disconnect $db}
- }
-}
-
-proc {Replicate} {} {
- global dbinfo
- global RSERV_BIN
-
- elog DEBUG "Replicating [ConnInfoCmd master]..."
- exec "$RSERV_BIN/Replicate" --snapshot=$dbinfo(snapshot,name) [ConnInfoParams] [ConnInfoMaster] [ConnInfoSlave]
-}
-
-proc {Show} {} {
- global dbinfo
- global update
-
- elog DEBUG "Opening database [ConnInfo slave]..."
- set res [catch {set db [pg_connect -conninfo "[ConnInfo slave]"]} msg]
- if {$res} {
- elog ERROR "DB $dbinfo(slave,name) not available: $res ($msg)"
- } else {
- elog DEBUG "Select $update from database $dbinfo(slave,name)..."
- set res [pg_exec $db "select i from test where i='$update'"]
- if {[pg_result $res -status] != "PGRES_TUPLES_OK"} {
- .s.e config -text "n/a"
- } else {
- set ntups [pg_result $res -numTuples]
- if {$ntups <= 0} {
- .s.e config -text "n/a"
- } else {
- for {set i 0} {$i < $ntups} {incr i} {
- set val [pg_result $res -getTuple $i]
- .s.e config -text $val
- }
- }
- pg_result $res -clear
- }
- catch {pg_disconnect $db}
- }
-}
-
-proc {Shutdown} {} {
- global dbinfo
- exit
-}
+++ /dev/null
-# -*- perl -*-
-## SlaveAddTable
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use Pg;
-use Getopt::Long;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-
-if (defined($opt_help) || (scalar(@ARGV) < 3)) {
- print "Usage: $0 --host=name --user=name --password=string slavedb table column\n";
- exit ((scalar(@ARGV) < 3)? 1: 0);
-}
-
-my $dbname = $ARGV[0];
-my $table = $ARGV[1];
-my $keyname = $ARGV[2];
-
-my $sinfo = "dbname=$dbname";
-$sinfo = "$sinfo host=$opt_host" if (defined($opt_host));
-$sinfo = "$sinfo user=$opt_user" if (defined($opt_user));
-$sinfo = "$sinfo password=$opt_password" if (defined($opt_password));
-
-my $dbname = $ARGV[0];
-my $table = $ARGV[1];
-my $keyname = $ARGV[2];
-
-my $conn = Pg::connectdb($sinfo);
-
-my $result = $conn->exec("BEGIN");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-$result = $conn->exec("select pgc.oid, pga.attnum from pg_class pgc" .
- ", pg_attribute pga" .
- " where pgc.relname = '$table' and pgc.oid = pga.attrelid" .
- " and pga.attname = '$keyname'");
-die $conn->errorMessage if $result->resultStatus ne PGRES_TUPLES_OK;
-
-my @row = $result->fetchrow;
-die "Can't find table/key\n" if ! defined $row[0] || ! defined $row[1];
-
-$result = $conn->exec("insert into _RSERV_SLAVE_TABLES_ (tname, cname, reloid, key)" .
- " values ('$table', '$keyname', $row[0], $row[1])");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-$result = $conn->exec("COMMIT");
-die $conn->errorMessage if $result->resultStatus ne PGRES_COMMAND_OK;
-
-exit(0);
+++ /dev/null
-# -*- perl -*-
-## SlaveInit
-# Vadim Mikheev, (c) 2000, PostgreSQL Inc.
-
-eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
- & eval 'exec perl -S $0 $argv:q'
- if 0;
-
-use Pg;
-use Getopt::Long;
-
-$| = 1;
-
-$result = GetOptions("debug!", "verbose!", "quiet!", "help",
- "host=s", "user=s", "password=s");
-
-my $debug = $opt_debug || 0;
-my $verbose = $opt_verbose || 0;
-my $quiet = $opt_quiet || 0;
-
-if (defined($opt_help) || (scalar(@ARGV) < 1)) {
- print "Usage: $0 --host=name --user=name --password=string slavedb\n";
- exit ((scalar(@ARGV) < 1)? 1:0);
-}
-
-my $slave = $ARGV[0] || "slave";
-
-my $sinfo = "dbname=$slave";
-$sinfo = "$sinfo host=$opt_host" if (defined($opt_host));
-$sinfo = "$sinfo user=$opt_user" if (defined($opt_user));
-$sinfo = "$sinfo password=$opt_password" if (defined($opt_password));
-
-sub RollbackAndQuit {
- my $conn = shift @_;
-
- print STDERR $conn->errorMessage;
- $conn->exec("ROLLBACK");
- exit (-1);
-}
-
-print("Connecting to $sinfo\n") if ($debug || $verbose);
-my $conn = Pg::connectdb($sinfo);
-if ($conn->status != PGRES_CONNECTION_OK) {
- print STDERR "Failed opening $sinfo\n";
- exit 1;
-}
-
-my $result = $conn->exec("BEGIN");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("set transaction isolation level serializable");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("create table _RSERV_SLAVE_TABLES_" .
- " (tname name, cname name, reloid oid, key int4)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("create table _RSERV_SLAVE_SYNC_" .
- " (syncid int4, synctime timestamp)");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-$result = $conn->exec("COMMIT");
-RollbackAndQuit($conn) if ($result->resultStatus ne PGRES_COMMAND_OK);
-
-exit (0);
+++ /dev/null
--- erServer
--- Master server setup for erServer demonstration implementation
--- (c) 2000 Vadim Mikheev, PostgreSQL Inc.
---
-
---
--- Slave servers
---
-drop table _RSERV_SERVERS_;
-
-create table _RSERV_SERVERS_
-(
- server int4, -- slave server id
- host text, -- server' host
- port int4, -- server' port
- dbase text -- db name
-);
-
-
---
--- Tables to sync
---
-drop table _RSERV_TABLES_;
-
-create table _RSERV_TABLES_
-(
- tname name, -- table name
- cname name, -- column name
- reloid oid, -- table oid
- key int4 -- key attnum
-);
-
-
---
--- Log for inserts/updates/deletes to sync-ed tables
---
-drop table _RSERV_LOG_;
-
-create table _RSERV_LOG_
-(
- reloid oid,
- logid int4, -- xid of last update xaction
- logtime timestamp, -- last update xaction start time
- deleted int4, -- deleted or inserted/updated
- key text --
-);
-
--- This is to speedup lookup deleted tuples
-create index _RSERV_LOG_INDX_DLT_ID_ on _RSERV_LOG_ (deleted, logid);
-
--- This is to speedup cleanup
-create index _RSERV_LOG_INDX_TM_ID_ on _RSERV_LOG_ (logtime, logid);
-
--- This is to speedup trigger and lookup updated tuples
-create index _RSERV_LOG_INDX_REL_KEY_ on _RSERV_LOG_ (reloid, key);
-
-
---
--- How much each slave servers are sync-ed
---
-drop table _RSERV_SYNC_;
-
-create table _RSERV_SYNC_
-(
- server int4,
- syncid int4, -- from _rserv_sync_seq_
- synctime timestamp, --
- status int4, -- prepared (0) | applied
- minid int4, -- min xid from serializable snapshot
- maxid int4, -- max xid from serializable snapshot
- active text -- list of active xactions
-);
-
-create index _RSERV_SYNC_INDX_SRV_ID_ on _RSERV_SYNC_ (server, syncid);
-
-drop sequence _rserv_sync_seq_;
-create sequence _rserv_sync_seq_;
-
-drop function _rserv_log_();
-
-CREATE FUNCTION _rserv_log_()
- RETURNS trigger
- AS '@MODULE_FILENAME@'
- LANGUAGE 'c'
-;
-
-drop function _rserv_sync_(int4);
-
-CREATE FUNCTION _rserv_sync_(int4)
- RETURNS int4
- AS '@MODULE_FILENAME@'
- LANGUAGE 'c'
-;
-
-drop function _rserv_debug_(int4);
-
-CREATE FUNCTION _rserv_debug_(int4)
- RETURNS int4
- AS '@MODULE_FILENAME@'
- LANGUAGE 'c'
-;
+++ /dev/null
-# regress.sh
-# rserv regression test script
-# (c) 2000 Thomas Lockhart, PostgreSQL Inc.
-
-dropdb master
-dropdb slave
-
-createdb master
-createdb slave
-
-MasterInit master
-SlaveInit slave
-
-psql -c "create table t1 (i int, t text, d timestamp default text 'now');" master
-MasterAddTable master t1 d
-
-psql -c "create table t1 (i int, t text, d timestamp default text 'now');" slave
-SlaveAddTable slave t1 d
-
-psql -c "insert into t1 values (1, 'one');" master
-psql -c "insert into t1 values (2, 'two');" master
-
-Replicate master slave
-MasterSync master `GetSyncID --noverbose slave`
-
-psql -c "insert into t1 values (3, 'three');" master
-psql -c "insert into t1 values (4, 'four');" master
-
-Replicate master slave
-MasterSync master `GetSyncID --noverbose slave`
-
-exit
+++ /dev/null
-/* rserv.c
- * Support functions for erServer replication.
- * (c) 2000 Vadim Mikheev, PostgreSQL Inc.
- */
-
-#include "executor/spi.h" /* this is what you need to work with SPI */
-#include "commands/trigger.h" /* -"- and triggers */
-#include "utils/tqual.h" /* -"- and SnapshotData */
-#include <ctype.h> /* tolower () */
-
-#ifdef PG_FUNCTION_INFO_V1
-#define CurrentTriggerData ((TriggerData *) fcinfo->context)
-#endif
-
-#ifdef PG_FUNCTION_INFO_V1
-PG_FUNCTION_INFO_V1(_rserv_log_);
-PG_FUNCTION_INFO_V1(_rserv_sync_);
-PG_FUNCTION_INFO_V1(_rserv_debug_);
-Datum _rserv_log_(PG_FUNCTION_ARGS);
-Datum _rserv_sync_(PG_FUNCTION_ARGS);
-Datum _rserv_debug_(PG_FUNCTION_ARGS);
-
-#else
-HeapTuple _rserv_log_(void);
-int32 _rserv_sync_(int32);
-int32 _rserv_debug_(int32);
-#endif
-
-static int debug = 0;
-
-static char *OutputValue(char *key, char *buf, int size);
-
-#ifdef PG_FUNCTION_INFO_V1
-Datum
-_rserv_log_(PG_FUNCTION_ARGS)
-#else
-HeapTuple
-_rserv_log_()
-#endif
-{
- Trigger *trigger; /* to get trigger name */
- int nargs; /* # of args specified in CREATE TRIGGER */
- char **args; /* argument: argnum */
- Relation rel; /* triggered relation */
- HeapTuple tuple; /* tuple to return */
- HeapTuple newtuple = NULL; /* tuple to return */
- TupleDesc tupdesc; /* tuple description */
- int keynum;
- char *key;
- char *okey;
- char *newkey = NULL;
- int deleted;
- char sql[8192];
- char outbuf[8192];
- char oidbuf[64];
- int ret;
-
- /* Called by trigger manager ? */
- if (!CurrentTriggerData)
- /* internal error */
- elog(ERROR, "_rserv_log_: triggers are not initialized");
-
- /* Should be called for ROW trigger */
- if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
- /* internal error */
- elog(ERROR, "_rserv_log_: can't process STATEMENT events");
-
- tuple = CurrentTriggerData->tg_trigtuple;
-
- trigger = CurrentTriggerData->tg_trigger;
- nargs = trigger->tgnargs;
- args = trigger->tgargs;
-
- if (nargs != 1) /* odd number of arguments! */
- /* internal error */
- elog(ERROR, "_rserv_log_: need in *one* argument");
-
- keynum = atoi(args[0]);
-
- if (keynum < 0 && keynum != ObjectIdAttributeNumber)
- /* internal error */
- elog(ERROR, "_rserv_log_: invalid keynum %d", keynum);
-
- rel = CurrentTriggerData->tg_relation;
- tupdesc = rel->rd_att;
-
- deleted = (TRIGGER_FIRED_BY_DELETE(CurrentTriggerData->tg_event)) ?
- 1 : 0;
-
- if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
- newtuple = CurrentTriggerData->tg_newtuple;
-
-#ifndef PG_FUNCTION_INFO_V1
-
- /*
- * Setting CurrentTriggerData to NULL prevents direct calls to trigger
- * functions in queries. Normally, trigger functions have to be called
- * by trigger manager code only.
- */
- CurrentTriggerData = NULL;
-#endif
-
- /* Connect to SPI manager */
- if ((ret = SPI_connect()) < 0)
- /* internal error */
- elog(ERROR, "_rserv_log_: SPI_connect returned %d", ret);
-
- if (keynum == ObjectIdAttributeNumber)
- {
- snprintf(oidbuf, sizeof(oidbuf), "%u", HeapTupleGetOid(tuple));
- key = oidbuf;
- }
- else
- key = SPI_getvalue(tuple, tupdesc, keynum);
-
- if (key == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_NOT_NULL_VIOLATION),
- errmsg("key must be not null")));
-
- if (newtuple && keynum != ObjectIdAttributeNumber)
- {
- newkey = SPI_getvalue(newtuple, tupdesc, keynum);
- if (newkey == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_NOT_NULL_VIOLATION),
- errmsg("key must be not null")));
- if (strcmp(newkey, key) == 0)
- newkey = NULL;
- else
- deleted = 1; /* old key was deleted */
- }
-
- if (strpbrk(key, "\\ \n'"))
- okey = OutputValue(key, outbuf, sizeof(outbuf));
- else
- okey = key;
-
- snprintf(sql, 8192, "update _RSERV_LOG_ set logid = %d, logtime = now(), "
- "deleted = %d where reloid = %u and key = '%s'",
- GetCurrentTransactionId(), deleted, rel->rd_id, okey);
-
- if (debug)
- elog(DEBUG4, "sql: %s", sql);
-
- ret = SPI_exec(sql, 0);
-
- if (ret < 0)
- ereport(ERROR,
- (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
- errmsg("SPI_exec(update) returned %d", ret)));
-
- /*
- * If no tuple was UPDATEd then do INSERT...
- */
- if (SPI_processed > 1)
- ereport(ERROR,
- (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
- errmsg("duplicate tuples")));
-
- else if (SPI_processed == 0)
- {
- snprintf(sql, 8192, "insert into _RSERV_LOG_ "
- "(reloid, logid, logtime, deleted, key) "
- "values (%u, %d, now(), %d, '%s')",
- rel->rd_id, GetCurrentTransactionId(),
- deleted, okey);
-
- if (debug)
- elog(DEBUG4, "sql: %s", sql);
-
- ret = SPI_exec(sql, 0);
-
- if (ret < 0)
- ereport(ERROR,
- (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
- errmsg("SPI_exec(insert) returned %d", ret)));
- }
-
- if (okey != key && okey != outbuf)
- pfree(okey);
-
- if (newkey)
- {
- if (strpbrk(newkey, "\\ \n'"))
- okey = OutputValue(newkey, outbuf, sizeof(outbuf));
- else
- okey = newkey;
-
- snprintf(sql, 8192, "insert into _RSERV_LOG_ "
- "(reloid, logid, logtime, deleted, key) "
- "values (%u, %d, now(), 0, '%s')",
- rel->rd_id, GetCurrentTransactionId(), okey);
-
- if (debug)
- elog(DEBUG4, "sql: %s", sql);
-
- ret = SPI_exec(sql, 0);
-
- if (ret < 0)
- ereport(ERROR,
- (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
- errmsg("SPI_exec returned %d", ret)));
-
- if (okey != newkey && okey != outbuf)
- pfree(okey);
- }
-
- SPI_finish();
-
-#ifdef PG_FUNCTION_INFO_V1
- return (PointerGetDatum(tuple));
-#else
- return (tuple);
-#endif
-}
-
-#ifdef PG_FUNCTION_INFO_V1
-Datum
-_rserv_sync_(PG_FUNCTION_ARGS)
-#else
-int32
-_rserv_sync_(int32 server)
-#endif
-{
-#ifdef PG_FUNCTION_INFO_V1
- int32 server = PG_GETARG_INT32(0);
-#endif
- char sql[8192];
- char buf[8192];
- char *active = buf;
- uint32 xcnt;
- int ret;
-
- if (SerializableSnapshot == NULL)
- /* internal error */
- elog(ERROR, "_rserv_sync_: SerializableSnapshot is NULL");
-
- buf[0] = 0;
- for (xcnt = 0; xcnt < SerializableSnapshot->xcnt; xcnt++)
- {
- snprintf(buf + strlen(buf), 8192 - strlen(buf),
- "%s%u", (xcnt) ? ", " : "",
- SerializableSnapshot->xip[xcnt]);
- }
-
- if ((ret = SPI_connect()) < 0)
- /* internal error */
- elog(ERROR, "_rserv_sync_: SPI_connect returned %d", ret);
-
- snprintf(sql, 8192, "insert into _RSERV_SYNC_ "
- "(server, syncid, synctime, status, minid, maxid, active) "
- "values (%u, currval('_rserv_sync_seq_'), now(), 0, %d, %d, '%s')",
- server, SerializableSnapshot->xmin, SerializableSnapshot->xmax, active);
-
- ret = SPI_exec(sql, 0);
-
- if (ret < 0)
- ereport(ERROR,
- (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
- errmsg("SPI_exec returned %d", ret)));
-
- SPI_finish();
-
- return (0);
-}
-
-#ifdef PG_FUNCTION_INFO_V1
-Datum
-_rserv_debug_(PG_FUNCTION_ARGS)
-#else
-int32
-_rserv_debug_(int32 newval)
-#endif
-{
-#ifdef PG_FUNCTION_INFO_V1
- int32 newval = PG_GETARG_INT32(0);
-#endif
- int32 oldval = debug;
-
- debug = newval;
-
- return (oldval);
-}
-
-#define ExtendBy 1024
-
-static char *
-OutputValue(char *key, char *buf, int size)
-{
- int i = 0;
- char *out = buf;
- char *subst = NULL;
- int slen = 0;
-
- size--;
- for (;;)
- {
- switch (*key)
- {
- case '\\':
- subst = "\\\\";
- slen = 2;
- break;
- case ' ':
- subst = "\\011";
- slen = 4;
- break;
- case '\n':
- subst = "\\012";
- slen = 4;
- break;
- case '\'':
- subst = "\\047";
- slen = 4;
- break;
- case '\0':
- out[i] = 0;
- return (out);
- default:
- slen = 1;
- break;
- }
-
- if (i + slen >= size)
- {
- if (out == buf)
- {
- out = (char *) palloc(size + ExtendBy);
- strncpy(out, buf, i);
- size += ExtendBy;
- }
- else
- {
- out = (char *) repalloc(out, size + ExtendBy);
- size += ExtendBy;
- }
- }
-
- if (slen == 1)
- out[i++] = *key;
- else
- {
- memcpy(out + i, subst, slen);
- i += slen;
- }
- key++;
- }
-
- return (out);
-
-}
+++ /dev/null
--- erServer
--- Slave server setup for erServer demonstration implementation
--- (c) 2000 Vadim Mikheev, PostgreSQL Inc.
---
-
-drop table _RSERV_SLAVE_TABLES_;
-
-create table _RSERV_SLAVE_TABLES_
-(
- tname name, -- table name
- cname name, -- column name
- reloid oid, -- table oid
- key int4 -- key attnum
-);
-
-drop table _RSERV_SLAVE_SYNC_;
-
-create table _RSERV_SLAVE_SYNC_
-(
- syncid int4,
- synctime timestamp
-);