libdb/test/tcl/sql001.tcl
2011-09-13 13:44:24 -04:00

379 lines
14 KiB
Tcl

# See the file LICENSE for redistribution information.
#
# Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
#
# $Id$
#
# TEST sql001
# TEST Test db_replicate using a simple SQL app.
# TEST
# TEST Start db_replicate on master side and client side,
# TEST and do various operations using dbsql on master side.
# TEST After every operation, we will check the records on both sides,
# TEST to make sure we get same results from both sides.
# TEST Also try an insert operation on client side; it should fail.
proc sql001 { {nentries 1000} {tnum "001"} args} {
source ./include.tcl
global EXE
if { [file exists $util_path/dbsql$EXE] == 0 } {
puts "Skipping Sql$tnum with dbsql. Is it built?"
return
}
env_cleanup $testdir
puts "Sql$tnum: Test db_replicate with a simple SQL application."
# Set up the directories and configuration files.
set dbname sql001.db
set envname $dbname-journal
set masterdir $testdir/MASTERDIR
set clientdir $testdir/CLIENTDIR.1
file mkdir $masterdir
file mkdir $masterdir/$envname
file mkdir $clientdir
file mkdir $clientdir/$envname
foreach {porta portb} [available_ports 2] {}
set confa [open $masterdir/$envname/DB_CONFIG w]
set confb [open $clientdir/$envname/DB_CONFIG w]
puts $confa "add_data_dir .."
puts $confa "set_create_dir .."
puts $confa "set_open_flags db_init_rep"
puts $confa "repmgr_site localhost $porta db_local_site on db_group_creator on "
puts $confa "repmgr_site localhost $portb"
puts $confa "set_open_flags db_thread"
puts $confa "set_open_flags db_register"
puts $confb "add_data_dir .."
puts $confb "set_create_dir .."
puts $confb "set_open_flags db_init_rep"
puts $confb "repmgr_site localhost $portb db_local_site on"
puts $confb "repmgr_site localhost $porta db_bootstrap_helper on"
puts $confb "set_open_flags db_thread"
puts $confb "set_open_flags db_register"
close $confa
close $confb
set tmpsql "$testdir/sql001.sql"
set masterfile "$testdir/master.sqlresults"
set clientfile "$testdir/client.sqlresults"
# For dbsql, to create the environment, we must first create a table.
# And it is fine if we drop it right after creation.
puts "\tSql$tnum.a:\
Create the environment on master and client side."
build_sql_file $tmpsql [list \
"create table if not exists tempdb(f1, f2, f3);" \
"drop table if exists tempdb;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql > $masterfile}} res]
error_check_good dbsql.a.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql > $clientfile}} res]
error_check_good dbsql.a.2 $ret 0
set env_cmd(M) "berkdb_env_noerr -home $masterdir/$envname \
-errpfx MASTER -lock -log -txn"
set masterenv [eval $env_cmd(M)]
set env_cmd(C) "berkdb_env_noerr -home $clientdir/$envname \
-errpfx CLIENT -lock -log -txn"
set clientenv [eval $env_cmd(C)]
# Start the db_replicate program.
set dpid(M) [eval {exec $util_path/db_replicate \
-h $masterdir/$envname -M -t 5 >& $testdir/master.log &}]
set dpid(C) [eval {exec $util_path/db_replicate \
-h $clientdir/$envname -t 5 >& $testdir/client.log &}]
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]}
# We create two tables on master side and sleep a while.
# It is supposed that they will be on client side after replication.
puts "\tSql$tnum.b: Create two tables on master side."
set tab_fields {
{"t1" {f11 f12 f13} }
{"t2" {f21 f22 f23 f24} }
}
set sql_list {}
for {set i 0} {$i < [llength $tab_fields]} {incr i} {
set tablename [lindex [lindex $tab_fields $i] 0]
set fields [lindex [lindex $tab_fields $i] 1]
set fields_cnt [llength $fields]
set sql_str "create table if not exists $tablename ("
for {set j 0} {$j < $fields_cnt} {incr j} {
set field [lindex $fields $j]
if {$j < $fields_cnt - 1} {
set sql_str "${sql_str}$field,"
} else {
set sql_str "${sql_str}$field);"
}
}
lappend sql_list $sql_str
}
build_sql_file $tmpsql $sql_list
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.b $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]}
puts "\tSql$tnum.c: Query table list on both sides."
build_sql_file $tmpsql ".tables"
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.c.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.c.2 $ret 0
error_check_good result_compare.1 [filecmp $masterfile $clientfile] 0
# Insert some records on master side and check them on both sides.
puts "\tSql$tnum.d: Insert records on master side."
set sql_list {}
for {set i 1} {$i <= $nentries} {incr i} {
lappend sql_list "insert into t1 \
values(\"$i\", \"vf12_$i\", \"vf13_$i\");"
lappend sql_list "insert into t2 \
values(\"$i\", \"vf22_$i\", \"vf23_$i\", \"vf24_$i\");"
}
build_sql_file $tmpsql $sql_list
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >& masterfile}} res]
error_check_good dbsql.d.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]} 100
puts "\tSql$tnum.e: Query the records on both sides."
build_sql_file $tmpsql [list "select * from t1;" "select * from t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.e.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.e.2 $ret 0
error_check_good result_compare.2 [filecmp $masterfile $clientfile] 0
# Update first-half of the records on master side and check the records
# on both sides.
puts "\tSql$tnum.f: Update some records on master side."
set sql_list {}
for {set i 1} {$i < $nentries / 2} {incr i 4} {
lappend sql_list "update t1 set f12=\"vf12_${i}_$i\" , \
f13=\"vf13_${i}_$i\" where f11=\"$i\";"
lappend sql_list "update t2 set f22=\"vf22_${i}_new\", \
f23=\"vf23_${i}_new\", f24=\"vf24_${i}_new\" \
where f21=\"$i\";"
}
build_sql_file $tmpsql $sql_list
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql > $masterfile}} res]
error_check_good dbsql.f.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]} 100
puts "\tSql$tnum.g: Query the records on both sides."
build_sql_file $tmpsql [list "select * from t1;" "select * from t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.g.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.g.2 $ret 0
error_check_good result_compare.3 [filecmp $masterfile $clientfile] 0
# Delete second-half of the records on master side, and then check the
# records on both sides.
puts "\tSql$tnum.h: Delete some records on master side."
set sql_list {}
for {set i [expr $nentries / 2]} {$i <= $nentries} {incr i 4} {
lappend sql_list "delete from t1 where f11=\"$i\";"
lappend sql_list "delete from t2 where f21=\"$i\";"
}
build_sql_file $tmpsql $sql_list
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql > $masterfile}} res]
error_check_good dbsql.h.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]} 100
puts "\tSql$tnum.i: Query the records on both sides."
build_sql_file $tmpsql [list "select * from t1;" "select * from t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.i.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.i.2 $ret 0
error_check_good result_compare.3 [filecmp $masterfile $clientfile] 0
# Data changes should be forbidden on client side.
# So here, we are trying to insert some records on client side,
# and we suppose dbsql return a non-zero code.
# The records on client sides should keep unchanged.
puts "\tSql$tnum.j: Insert records on client side."
set sql_list {}
for {set i [expr $nentries + 1]} {$i <= [expr $nentries + 500]} \
{incr i} {
lappend sql_list "insert into t1 \
values(\"$i\", \"vf12_$i\", \"vf13_$i\");"
lappend sql_list "insert into t2 \
values(\"$i\", \"vf22_$i\", \"vf23_$i\", \"vf24_$i\");"
}
build_sql_file $tmpsql $sql_list
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql > $masterfile.1 }} res]
error_check_bad dbsql.j.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]}
puts "\tSql$tnum.k: Query the records on both sides."
build_sql_file $tmpsql [list "select * from t1;" "select * from t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile.1}} res]
error_check_good dbsql.k.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile.1}} res]
error_check_good dbsql.k.2 $ret 0
error_check_good result_compare.4.1 \
[filecmp $masterfile.1 $clientfile.1] 0
error_check_good result_compare.4.2 \
[filecmp $masterfile.1 $masterfile] 0
# We execute some queries on both sides, and we suppose we will get
# same results on both sides for these queries
puts "\tSql$tnum.l: Execute some queries on both sides."
set queries [list \
"select * from t1 where f11 >= [expr $nentries / 2];" \
"select * from t2 where f21 >= [expr $nentries / 2];" \
"select * from t1 where f11 <= [expr $nentries / 3];" \
"select * from t2 where f21 <= [expr $nentries / 3];"]
set query_len [llength $queries]
for {set i 0} {$i < $query_len} {incr i} {
build_sql_file $tmpsql [lindex $queries $i]
set ret [catch {eval {exec $util_path/dbsql \
$masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.l.$i.1 $ret 0
set ret [catch {eval {exec $util_path/dbsql \
$clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.l.$i.2 $ret 0
error_check_good result_compare.5.$i \
[filecmp $masterfile $clientfile] 0
}
# Here, we create two views, and suppose they will be on client side.
# Also, we try to do query on these views on both sides, and we
# suppose they will return same records.
puts "\tSql$tnum.m: Create two views on master side."
build_sql_file $tmpsql [list \
"create view if not exists view_t1 as select f11, f12 from t1;" \
"create view if not exists view_t2 as select f22, f23 from t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.m.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]}
puts "\tSql$tnum.n: Query the table list on both sides."
build_sql_file $tmpsql ".tables"
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.n.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.n.2 $ret 0
puts "\tSql$tnum.o: Query the records from views on both sides."
build_sql_file $tmpsql [list \
"select * from view_t1;" "select * from view_t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.o.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.o.2 $ret 0
error_check_good result_compare.6 [filecmp $masterfile $clientfile] 0
# Drop all the tables, views from master side, and we suppose
# They will disappear on client side too.
# After that, running .tables should return nothing.
puts "\tSql$tnum.p: Drop all the tables and views on master side."
build_sql_file $tmpsql [list \
"drop view if exists view_t1;" "drop view if exists view_t2;" \
"drop table if exists t1;" "drop table if exists t2;"]
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.p.1 $ret 0
await_condition \
{[stat_field $masterenv rep_stat "Next LSN expected"] == \
[stat_field $clientenv rep_stat "Next LSN expected"]}
puts "\tSql$tnum.q: Query the table list on both sides."
set outf [open $masterfile.1 w]
close $outf
build_sql_file $tmpsql ".tables"
set ret [catch {eval {exec \
$util_path/dbsql $masterdir/$dbname < $tmpsql >$masterfile}} res]
error_check_good dbsql.q.1 $ret 0
set ret [catch {eval {exec \
$util_path/dbsql $clientdir/$dbname < $tmpsql >$clientfile}} res]
error_check_good dbsql.q.2 $ret 0
error_check_good result_compare.7.1 [filecmp $masterfile $clientfile] 0
error_check_good result_compare.7.2 \
[filecmp $masterfile $masterfile.1] 0
# Kill the processes for db_replicate.
tclkill $dpid(C)
tclkill $dpid(M)
error_check_good masterenv_close [$masterenv close] 0
error_check_good clientenv_close [$clientenv close] 0
}
proc build_sql_file {sqlfile stmt_list} {
set sqlf [open $sqlfile w]
foreach stmt $stmt_list {
puts $sqlf $stmt
}
close $sqlf
}