112ca0b56Sdan
26dc29e60Sdanproc do_changeset_test {tn session res} {
36dc29e60Sdan  set r [list]
46dc29e60Sdan  foreach x $res {lappend r $x}
56dc29e60Sdan  uplevel do_test $tn [list [subst -nocommands {
66dc29e60Sdan    set x [list]
76dc29e60Sdan    sqlite3session_foreach c [$session changeset] { lappend x [set c] }
86dc29e60Sdan    set x
96dc29e60Sdan  }]] [list $r]
106dc29e60Sdan}
116dc29e60Sdan
126c39e6a8Sdanproc do_patchset_test {tn session res} {
136c39e6a8Sdan  set r [list]
146c39e6a8Sdan  foreach x $res {lappend r $x}
156c39e6a8Sdan  uplevel do_test $tn [list [subst -nocommands {
166c39e6a8Sdan    set x [list]
176c39e6a8Sdan    sqlite3session_foreach c [$session patchset] { lappend x [set c] }
186c39e6a8Sdan    set x
196c39e6a8Sdan  }]] [list $r]
206c39e6a8Sdan}
216c39e6a8Sdan
226c39e6a8Sdan
236c39e6a8Sdanproc do_changeset_invert_test {tn session res} {
246c39e6a8Sdan  set r [list]
256c39e6a8Sdan  foreach x $res {lappend r $x}
266c39e6a8Sdan  uplevel do_test $tn [list [subst -nocommands {
276c39e6a8Sdan    set x [list]
286c39e6a8Sdan    set changeset [sqlite3changeset_invert [$session changeset]]
296c39e6a8Sdan    sqlite3session_foreach c [set changeset] { lappend x [set c] }
306c39e6a8Sdan    set x
316c39e6a8Sdan  }]] [list $r]
326c39e6a8Sdan}
336c39e6a8Sdan
3412ca0b56Sdan
3512ca0b56Sdanproc do_conflict_test {tn args} {
3612ca0b56Sdan
3712ca0b56Sdan  set O(-tables)    [list]
3812ca0b56Sdan  set O(-sql)       [list]
3912ca0b56Sdan  set O(-conflicts) [list]
40ff677b20Sdan  set O(-policy)    "OMIT"
4112ca0b56Sdan
4212ca0b56Sdan  array set V $args
4312ca0b56Sdan  foreach key [array names V] {
4412ca0b56Sdan    if {![info exists O($key)]} {error "no such option: $key"}
4512ca0b56Sdan  }
4612ca0b56Sdan  array set O $args
4712ca0b56Sdan
48ff677b20Sdan  proc xConflict {args} [subst -nocommands {
49ff677b20Sdan    lappend ::xConflict [set args]
50ff677b20Sdan    return $O(-policy)
51ff677b20Sdan  }]
52ff677b20Sdan  proc bgerror {args} { set ::background_error $args }
53ff677b20Sdan
5412ca0b56Sdan  sqlite3session S db main
5512ca0b56Sdan  foreach t $O(-tables) { S attach $t }
5612ca0b56Sdan  execsql $O(-sql)
5712ca0b56Sdan
5812ca0b56Sdan  set ::xConflict [list]
5912ca0b56Sdan  sqlite3changeset_apply db2 [S changeset] xConflict
6012ca0b56Sdan
6112ca0b56Sdan  set conflicts [list]
6212ca0b56Sdan  foreach c $O(-conflicts) {
6312ca0b56Sdan    lappend conflicts $c
6412ca0b56Sdan  }
6512ca0b56Sdan
6612ca0b56Sdan  after 1 {set go 1}
6712ca0b56Sdan  vwait go
6812ca0b56Sdan
6912ca0b56Sdan  uplevel do_test $tn [list { set ::xConflict }] [list $conflicts]
7012ca0b56Sdan  S delete
7112ca0b56Sdan}
7212ca0b56Sdan
7312ca0b56Sdanproc do_common_sql {sql} {
7412ca0b56Sdan  execsql $sql db
7512ca0b56Sdan  execsql $sql db2
7612ca0b56Sdan}
7712ca0b56Sdan
787aa469cdSdanproc changeset_from_sql {sql {dbname main}} {
79a87070a2Sdan  if {$dbname == "main"} {
80a87070a2Sdan    return [sql_exec_changeset db $sql]
81a87070a2Sdan  }
827aa469cdSdan  set rc [catch {
837aa469cdSdan    sqlite3session S db $dbname
847aa469cdSdan    db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
857aa469cdSdan      S attach $name
867aa469cdSdan    }
877aa469cdSdan    db eval $sql
887aa469cdSdan    S changeset
897aa469cdSdan  } changeset]
907aa469cdSdan  catch { S delete }
917aa469cdSdan
927aa469cdSdan  if {$rc} {
937aa469cdSdan    error $changeset
947aa469cdSdan  }
957aa469cdSdan  return $changeset
967aa469cdSdan}
977aa469cdSdan
9844748f27Sdanproc patchset_from_sql {sql {dbname main}} {
9944748f27Sdan  set rc [catch {
10044748f27Sdan    sqlite3session S db $dbname
10144748f27Sdan    db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
10244748f27Sdan      S attach $name
10344748f27Sdan    }
10444748f27Sdan    db eval $sql
10544748f27Sdan    S patchset
10644748f27Sdan  } patchset]
10744748f27Sdan  catch { S delete }
10844748f27Sdan
10944748f27Sdan  if {$rc} {
11044748f27Sdan    error $patchset
11144748f27Sdan  }
11244748f27Sdan  return $patchset
11344748f27Sdan}
11444748f27Sdan
11512ca0b56Sdanproc do_then_apply_sql {sql {dbname main}} {
11612ca0b56Sdan  proc xConflict args { return "OMIT" }
11712ca0b56Sdan  set rc [catch {
11812ca0b56Sdan    sqlite3session S db $dbname
11912ca0b56Sdan    db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
12012ca0b56Sdan      S attach $name
12112ca0b56Sdan    }
12212ca0b56Sdan    db eval $sql
12312ca0b56Sdan    sqlite3changeset_apply db2 [S changeset] xConflict
12412ca0b56Sdan  } msg]
12512ca0b56Sdan
12612ca0b56Sdan  catch { S delete }
12712ca0b56Sdan
12812ca0b56Sdan  if {$rc} {error $msg}
12912ca0b56Sdan}
13012ca0b56Sdan
13112ca0b56Sdanproc do_iterator_test {tn tbl_list sql res} {
13212ca0b56Sdan  sqlite3session S db main
133ff4d0f41Sdan  if {[llength $tbl_list]==0} { S attach * }
13412ca0b56Sdan  foreach t $tbl_list {S attach $t}
135ff4d0f41Sdan
13612ca0b56Sdan  execsql $sql
13712ca0b56Sdan
13812ca0b56Sdan  set r [list]
13912ca0b56Sdan  foreach v $res { lappend r $v }
14012ca0b56Sdan
14112ca0b56Sdan  set x [list]
14212ca0b56Sdan  sqlite3session_foreach c [S changeset] { lappend x $c }
14312ca0b56Sdan  uplevel do_test $tn [list [list set {} $x]] [list $r]
14412ca0b56Sdan
14512ca0b56Sdan  S delete
14612ca0b56Sdan}
14712ca0b56Sdan
14812ca0b56Sdan# Compare the contents of all tables in [db1] and [db2]. Throw an error if
14912ca0b56Sdan# they are not identical, or return an empty string if they are.
15012ca0b56Sdan#
15112ca0b56Sdanproc compare_db {db1 db2} {
15212ca0b56Sdan
15312ca0b56Sdan  set sql {SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name}
15412ca0b56Sdan  set lot1 [$db1 eval $sql]
15512ca0b56Sdan  set lot2 [$db2 eval $sql]
15612ca0b56Sdan
157db04571cSdan  if {$lot1 != $lot2} {
158db04571cSdan    puts $lot1
159db04571cSdan    puts $lot2
160db04571cSdan    error "databases contain different tables"
161db04571cSdan  }
16212ca0b56Sdan
16312ca0b56Sdan  foreach tbl $lot1 {
16412ca0b56Sdan    set col1 [list]
16512ca0b56Sdan    set col2 [list]
16612ca0b56Sdan
16712ca0b56Sdan    $db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name }
16812ca0b56Sdan    $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name }
16912ca0b56Sdan    if {$col1 != $col2} { error "table $tbl schema mismatch" }
17012ca0b56Sdan
17112ca0b56Sdan    set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]"
17212ca0b56Sdan    set data1 [$db1 eval $sql]
17312ca0b56Sdan    set data2 [$db2 eval $sql]
1747aa469cdSdan    if {$data1 != $data2} {
175*5d237bfaSdan      puts "$db1: $data1"
176*5d237bfaSdan      puts "$db2: $data2"
1777aa469cdSdan      error "table $tbl data mismatch"
1787aa469cdSdan    }
17912ca0b56Sdan  }
18012ca0b56Sdan
18112ca0b56Sdan  return ""
18212ca0b56Sdan}
18312ca0b56Sdan
1841756ae10Sdanproc changeset_to_list {c} {
1851756ae10Sdan  set list [list]
1861756ae10Sdan  sqlite3session_foreach elem $c { lappend list $elem }
1871756ae10Sdan  lsort $list
1881756ae10Sdan}
189bd45374cSdan
1903e259bcdSdanset ones {zero one two three four five six seven eight nine
1913e259bcdSdan          ten eleven twelve thirteen fourteen fifteen sixteen seventeen
1923e259bcdSdan          eighteen nineteen}
1933e259bcdSdanset tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety}
1943e259bcdSdanproc number_name {n} {
1953e259bcdSdan  if {$n>=1000} {
1963e259bcdSdan    set txt "[number_name [expr {$n/1000}]] thousand"
1973e259bcdSdan    set n [expr {$n%1000}]
1983e259bcdSdan  } else {
1993e259bcdSdan    set txt {}
2003e259bcdSdan  }
2013e259bcdSdan  if {$n>=100} {
2023e259bcdSdan    append txt " [lindex $::ones [expr {$n/100}]] hundred"
2033e259bcdSdan    set n [expr {$n%100}]
2043e259bcdSdan  }
2053e259bcdSdan  if {$n>=20} {
2063e259bcdSdan    append txt " [lindex $::tens [expr {$n/10}]]"
2073e259bcdSdan    set n [expr {$n%10}]
2083e259bcdSdan  }
2093e259bcdSdan  if {$n>0} {
2103e259bcdSdan    append txt " [lindex $::ones $n]"
2113e259bcdSdan  }
2123e259bcdSdan  set txt [string trim $txt]
2133e259bcdSdan  if {$txt==""} {set txt zero}
2143e259bcdSdan  return $txt
2153e259bcdSdan}
216