#!/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 }