diff --git a/clustertest/disorder/tests/LogShipping.js b/clustertest/disorder/tests/LogShipping.js new file mode 100644 index 53f6b09..405ab22 *** a/clustertest/disorder/tests/LogShipping.js --- b/clustertest/disorder/tests/LogShipping.js *************** LogShipping.prototype.runTest = function *** 94,100 **** var logShippingDaemon = this.coordinator.createLogShippingDaemon('db6',this.logdirectoryFile); ! logShippingDaemon.run(); --- 94,100 ---- var logShippingDaemon = this.coordinator.createLogShippingDaemon('db6',this.logdirectoryFile); ! logShippingDaemon.run(); *************** LogShipping.prototype.runTest = function *** 118,123 **** --- 118,125 ---- this.coordinator.log("LogShipping.prototype.runTest - compare db4,6"); this.compareDb('db4','db6'); this.truncateTest(); + this.ddlTest(); + this.coordinator.log("LogShipping.prototype.runTest - shut down slons"); this.coordinator.log("Shutting down slons"); *************** LogShipping.prototype.truncateTest = fun *** 192,195 **** --- 194,243 ---- stat.close(); db6Con.close(); } + } + + /** + * test DDL - EXECUTE SCRIPT. + * We want to make sure that EXECUTE SCRIPT, scripts get applied to log shipping nodes. + */ + LogShipping.prototype.ddlTest = function() { + var db6Con = this.coordinator.createJdbcConnection('db6'); + + var slonikPreamble = this.getSlonikPreamble(); + var slonikScript = 'echo \'LogShipping.prototype.ddlTest\';\n' + + "EXECUTE SCRIPT(event node=1, SQL='CREATE TABLE not_replicated(a int4); INSERT INTO not_replicated values (1);');"; + + var slonik = this.coordinator.createSlonik('CREATE TABLE', slonikPreamble, + slonikScript); + slonik.run(); + this.coordinator.join(slonik); + this.testResults.assertCheck('slonik executed create table okay', slonik + .getReturnCode(), 0); + this.slonikSync(1,1); + java.lang.Thread.sleep(30*1000); + + var stat = db6Con.createStatement(); + try { + var rs = stat.executeQuery("select count(*) FROM not_replicated;"); + rs.next(); + this.testResults.assertCheck('logshipping ddl replicated', + rs.getInt(1),1); + rs.close(); + } + catch (e) { + this.assertResults.assertCheck('select count threw an exception:' + e.getMessage(),true,false); + } + finally { + stat.close(); + db6Con.close(); + } + + slonikScript = 'echo \'LogShipping.prototype.ddlTest\';\n' + + "EXECUTE SCRIPT(event node=1, SQL='DROP TABLE not_replicated;');"; + slonik = this.coordinator.createSlonik('DROP TABLE', slonikPreamble, + slonikScript); + slonik.run(); + this.coordinator.join(slonik); + this.testResults.assertCheck('slonik executed drop table okay', slonik + .getReturnCode(), 0); } \ No newline at end of file diff --git a/doc/adminguide/slonik_ref.sgml b/doc/adminguide/slonik_ref.sgml new file mode 100644 index 66b53e8..d0ec7b4 *** a/doc/adminguide/slonik_ref.sgml --- b/doc/adminguide/slonik_ref.sgml *************** FAILOVER( *** 2778,2800 **** all nodes that are subscribed to a set at a common controlled point within the replication transaction stream. ! The specified event origin must be the origin of the set. The script file must not contain any START or ! COMMIT TRANSACTION calls. (This changes ! somewhat in &postgres; 8.0 once nested transactions, aka ! savepoints, are supported) In addition, non-deterministic DML statements (like updating a field with ! CURRENT_TIMESTAMP) must be avoided, since the ! data changes done by the script are explicitly not ! replicated. - SET ID = ival - The unique numeric ID number of the set - affected by the script - - FILENAME = '/path/to/file' The name of the file containing the SQL script to --- 2778,2793 ---- all nodes that are subscribed to a set at a common controlled point within the replication transaction stream. ! The specified event origin must be an origin of a set. The script file must not contain any START or ! COMMIT TRANSACTION calls but SAVEPOINTS are allowed. ! In addition, non-deterministic DML statements (like updating a field with ! CURRENT_TIMESTAMP) should be avoided, since the ! data changes done by the script will be different on each node. FILENAME = '/path/to/file' The name of the file containing the SQL script to *************** FAILOVER( *** 2849,2855 **** Example EXECUTE SCRIPT ( - SET ID = 1, FILENAME = '/tmp/changes_2008-04-01.sql', EVENT NODE = 1 ); --- 2842,2847 ---- *************** EXECUTE SCRIPT ( *** 2862,2870 **** replication triggers; after the DDL script completes, those locks will be cleared. In the 2.0 branch this is no longer the case. EXECUTE SCRIPT won't obtain any locks on your application tables ! though the script that you executing probably will. Due to bug #137 ! you should avoid concurrent writes to the tables being ! modified by the script while the script is running. After the DDL script has run on the origin node, it will then run on subscriber nodes, where replicated tables will be --- 2854,2860 ---- replication triggers; after the DDL script completes, those locks will be cleared. In the 2.0 branch this is no longer the case. EXECUTE SCRIPT won't obtain any locks on your application tables ! though the script that you executing probably will. After the DDL script has run on the origin node, it will then run on subscriber nodes, where replicated tables will be *************** EXECUTE SCRIPT ( *** 2924,2929 **** --- 2914,2921 ---- repair_log_triggers(only_locked boolean) may be used manually to correct the triggers on those tables. + As of version 2.2 the DDL performed by an EXECUTE SCRIPT is stored in + the sl_log_script table instead of sl_event. diff --git a/src/slony_logshipper/slony_logshipper.c b/src/slony_logshipper/slony_logshipper.c new file mode 100644 index be52c00..019f5e2 *** a/src/slony_logshipper/slony_logshipper.c --- b/src/slony_logshipper/slony_logshipper.c *************** get_current_at_counter(void) *** 1287,1293 **** slon_mkquery(&ds, "select at_counter from %s.sl_archive_tracking;", namespace); res = PQexec(dbconn, dstring_data(&ds)); ! if (PQresultStatus(res) != PGRES_TUPLES_OK) { errlog(LOG_ERROR, "cannot retrieve archive tracking status: %s\n", PQresultErrorMessage(res)); --- 1287,1293 ---- slon_mkquery(&ds, "select at_counter from %s.sl_archive_tracking;", namespace); res = PQexec(dbconn, dstring_data(&ds)); ! if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res)==0 ) { errlog(LOG_ERROR, "cannot retrieve archive tracking status: %s\n", PQresultErrorMessage(res)); diff --git a/tools/slony1_dump.sh b/tools/slony1_dump.sh new file mode 100755 index f07db21..2c249fc *** a/tools/slony1_dump.sh --- b/tools/slony1_dump.sh *************** begin *** 280,286 **** --- 280,289 ---- execute v_command; end if; + if NEW.log_cmdtype = 'S' then + execute NEW.log_cmdargs[1]; + end if; if NEW.log_cmdtype = 'T' then execute 'TRUNCATE TABLE ONLY ' || $clname.slon_quote_brute(NEW.log_tablenspname) || '.' || diff --git a/tools/test_slony_state-dbi.pl b/tools/test_slony_state-dbi.pl new file mode 100644 index a43cc01..7f592a5 *** a/tools/test_slony_state-dbi.pl --- b/tools/test_slony_state-dbi.pl *************** necessary. *** 214,220 **** while (my @row = $res->fetchrow_array) { my ($origin, $minsync, $maxsync, $minage, $maxage, $agehi) = @row; printf "%7s %9d %9d %12s %12s %4s\n", $origin, $minsync, $maxsync, $minage, $maxage, $agehi; ! if ($agehi eq 't') { add_problem($origin, "Events not propagating to node $origin", qq{Events not propagating quickly in sl_event - For origin node $origin, earliest propagated event of age $minage > $WANTAGE --- 214,220 ---- while (my @row = $res->fetchrow_array) { my ($origin, $minsync, $maxsync, $minage, $maxage, $agehi) = @row; printf "%7s %9d %9d %12s %12s %4s\n", $origin, $minsync, $maxsync, $minage, $maxage, $agehi; ! if ($agehi eq '1') { add_problem($origin, "Events not propagating to node $origin", qq{Events not propagating quickly in sl_event - For origin node $origin, earliest propagated event of age $minage > $WANTAGE *************** Could listen paths be missing so that ev *** 248,254 **** while (my @row = $res->fetchrow_array) { my ($origin, $receiver, $minsync, $maxsync, $minage, $maxage, $agehi) = @row; printf "%9s %9s %9s %9s %12s %12s %4s\n", $origin, $receiver, $minsync, $maxsync, $minage, $maxage, $agehi; ! if ($agehi eq 't') { add_problem($origin, "Confirmations not propagating from $origin to $receiver", qq{Confirmations not propagating quickly in sl_confirm - --- 248,254 ---- while (my @row = $res->fetchrow_array) { my ($origin, $receiver, $minsync, $maxsync, $minage, $maxage, $agehi) = @row; printf "%9s %9s %9s %9s %12s %12s %4s\n", $origin, $receiver, $minsync, $maxsync, $minage, $maxage, $agehi; ! if ($agehi eq '1') { add_problem($origin, "Confirmations not propagating from $origin to $receiver", qq{Confirmations not propagating quickly in sl_confirm - *************** Could listen paths be missing so that co *** 269,279 **** print "================================================================================\n"; my $ELDERLY_TXN = "01:30:00"; my $old_conn_query = qq{ ! select datname, procpid, usename, date_trunc('minutes', now() - query_start), substr(current_query,0,20) from pg_stat_activity where (now() - query_start) > '$ELDERLY_TXN'::interval and ! current_query <> '' order by query_start; }; --- 269,291 ---- print "================================================================================\n"; my $ELDERLY_TXN = "01:30:00"; + my $pid_column=''; + my $query_column=''; + if ($dbh->{private_dbdpg}{version}>=90200) + { + $pid_column='pid'; + $query_column='query'; + + } + else { + $pid_column='procpid'; + $query_column='current_query'; + } my $old_conn_query = qq{ ! select datname, $pid_column, usename, date_trunc('minutes', now() - query_start), substr($query_column,0,20) from pg_stat_activity where (now() - query_start) > '$ELDERLY_TXN'::interval and ! $query_column <> '' order by query_start; };