17. Embedding Slonik in Shell Scripts

As mentioned earlier, there are numerous Slony-I test scripts in src/ducttape that embed the generation of Slonik inside the shell script.

They mostly don't do this in a terribly sophisticated way. Typically, they use the following sort of structure:

DB1=slony_test1
DB2=slony_test2
slonik <<_EOF_
	cluster name = T1;
	node 1 admin conninfo = 'dbname=$DB1';
	node 2 admin conninfo = 'dbname=$DB2';

	try {
		table add key (node id = 1, fully qualified name = 
                               'public.history');
	}
	on error {
		exit 1;
	}

	try {
		create set (id = 1, origin = 1, comment = 
                            'Set 1 - pgbench tables');
		set add table (set id = 1, origin = 1,
			id = 1, fully qualified name = 'public.accounts',
			comment = 'Table accounts');
		set add table (set id = 1, origin = 1,
			id = 2, fully qualified name = 'public.branches',
			comment = 'Table branches');
		set add table (set id = 1, origin = 1,
			id = 3, fully qualified name = 'public.tellers',
			comment = 'Table tellers');
		set add table (set id = 1, origin = 1,
			id = 4, fully qualified name = 'public.history',
			key = serial, comment = 'Table accounts');
	}
	on error {
		exit 1;
	}
_EOF_

A more sophisticated approach might involve defining some common components, notably the "preamble" that consists of the CLUSTER NAME ADMIN CONNINFO commands that are common to every Slonik script, thus:

CLUSTER=T1
DB1=slony_test1
DB2=slony_test2
PREAMBLE="cluster name = $CLUSTER
node 1 admin conninfo = 'dbname=$DB1';
node 2 admin conninfo = 'dbname=$DB2';
"

The PREAMBLE value could then be reused over and over again if the shell script invokes slonik multiple times. You might also consider using INCLUDE and place the preamble in a file that is included.

Shell variables provide a simple way to assign names to sets and nodes:

origin=1
subscriber=2
mainset=1
slonik <<_EOF_
$PREAMBLE
try {
    table add key (node id = $origin, fully qualified name = 
                   'public.history');
} on error {
    exit 1;
}
try {
	create set (id = $mainset, origin = $origin, 
                    comment = 'Set $mainset - pgbench tables');
	set add table (set id = $mainset, origin = $origin,
		id = 1, fully qualified name = 'public.accounts',
		comment = 'Table accounts');
	set add table (set id = $mainset, origin = $origin,
		id = 2, fully qualified name = 'public.branches',
		comment = 'Table branches');
	set add table (set id = $mainset, origin = $origin,
		id = 3, fully qualified name = 'public.tellers',
		comment = 'Table tellers');
	set add table (set id = $mainset, origin = $origin,
		id = 4, fully qualified name = 'public.history',
		key = serial, comment = 'Table accounts');
} on error {
	exit 1;
}
_EOF_

The script might be further enhanced to loop through the list of tables as follows:

# Basic configuration
origin=1
subscriber=2
mainset=1
# List of tables to replicate
TABLES="accounts branches tellers history"
ADDTABLES=""
tnum=1
for table in `echo $TABLES`; do
  ADDTABLES="$ADDTABLES
   set add table ($set id = $mainset, origin = $origin,
   id = $tnum, fully qualified name = 'public.$table',
   comment = 'Table $tname');
"
  let "tnum=tnum+1"
done
slonik <<_EOF_
$PREAMBLE
try {
    table add key (node id = $origin, fully qualified name = 
                   'public.history');
} on error {
    exit 1;
}
try {
	create set (id = $mainset, origin = $origin, 
                    comment = 'Set $mainset - pgbench tables');
$ADDTABLES
} on error {
	exit 1;
}
_EOF_

That is of somewhat dubious value if you only have 4 tables, but eliminating errors resulting from enumerating large lists of configuration by hand will make this pretty valuable for the larger examples you'll find in "real life."

You can do even more sophisticated things than this if your scripting language supports things like:

If you can depend on having Bash, zsh, or Korn shell available, well, those are all shells with extensions supporting reasonably sophisticated data structures and module systems. On Linux, Bash is fairly ubiquitous; on commercial UNIX™, Korn shell is fairly ubiquitous; on BSD, "sophisticated" shells are an option rather than a default.

At that point, it makes sense to start looking at other scripting languages, of which Perl is the most ubiquitous, being widely available on Linux, UNIX™, and BSD.