session_common.tcl 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. proc do_changeset_test {tn session res} {
  2. set r [list]
  3. foreach x $res {lappend r $x}
  4. uplevel do_test $tn [list [subst -nocommands {
  5. set x [list]
  6. sqlite3session_foreach c [$session changeset] { lappend x [set c] }
  7. set x
  8. }]] [list $r]
  9. }
  10. proc do_patchset_test {tn session res} {
  11. set r [list]
  12. foreach x $res {lappend r $x}
  13. uplevel do_test $tn [list [subst -nocommands {
  14. set x [list]
  15. sqlite3session_foreach c [$session patchset] { lappend x [set c] }
  16. set x
  17. }]] [list $r]
  18. }
  19. proc do_changeset_invert_test {tn session res} {
  20. set r [list]
  21. foreach x $res {lappend r $x}
  22. uplevel do_test $tn [list [subst -nocommands {
  23. set x [list]
  24. set changeset [sqlite3changeset_invert [$session changeset]]
  25. sqlite3session_foreach c [set changeset] { lappend x [set c] }
  26. set x
  27. }]] [list $r]
  28. }
  29. proc do_conflict_test {tn args} {
  30. set O(-tables) [list]
  31. set O(-sql) [list]
  32. set O(-conflicts) [list]
  33. set O(-policy) "OMIT"
  34. array set V $args
  35. foreach key [array names V] {
  36. if {![info exists O($key)]} {error "no such option: $key"}
  37. }
  38. array set O $args
  39. proc xConflict {args} [subst -nocommands {
  40. lappend ::xConflict [set args]
  41. return $O(-policy)
  42. }]
  43. proc bgerror {args} { set ::background_error $args }
  44. sqlite3session S db main
  45. S object_config rowid 1
  46. foreach t $O(-tables) { S attach $t }
  47. execsql $O(-sql)
  48. set ::xConflict [list]
  49. sqlite3changeset_apply db2 [S changeset] xConflict
  50. set conflicts [list]
  51. foreach c $O(-conflicts) {
  52. lappend conflicts $c
  53. }
  54. after 1 {set go 1}
  55. vwait go
  56. uplevel do_test $tn [list { set ::xConflict }] [list $conflicts]
  57. S delete
  58. }
  59. proc do_common_sql {sql} {
  60. execsql $sql db
  61. execsql $sql db2
  62. }
  63. proc changeset_from_sql {sql {dbname main}} {
  64. if {$dbname == "main"} {
  65. return [sql_exec_changeset db $sql]
  66. }
  67. set rc [catch {
  68. sqlite3session S db $dbname
  69. S object_config rowid 1
  70. db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
  71. S attach $name
  72. }
  73. db eval $sql
  74. S changeset
  75. } changeset]
  76. catch { S delete }
  77. if {$rc} {
  78. error $changeset
  79. }
  80. return $changeset
  81. }
  82. proc patchset_from_sql {sql {dbname main}} {
  83. set rc [catch {
  84. sqlite3session S db $dbname
  85. db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
  86. S attach $name
  87. }
  88. db eval $sql
  89. S patchset
  90. } patchset]
  91. catch { S delete }
  92. if {$rc} {
  93. error $patchset
  94. }
  95. return $patchset
  96. }
  97. # Usage: do_then_apply_sql ?-ignorenoop? SQL ?DBNAME?
  98. #
  99. proc do_then_apply_sql {args} {
  100. set bIgnoreNoop 0
  101. set a1 [lindex $args 0]
  102. if {[string length $a1]>1 && [string first $a1 -ignorenoop]==0} {
  103. set bIgnoreNoop 1
  104. set args [lrange $args 1 end]
  105. }
  106. if {[llength $args]!=1 && [llength $args]!=2} {
  107. error "usage: do_then_apply_sql ?-ignorenoop? SQL ?DBNAME?"
  108. }
  109. set sql [lindex $args 0]
  110. if {[llength $args]==1} {
  111. set dbname main
  112. } else {
  113. set dbname [lindex $args 1]
  114. }
  115. set ::n_conflict 0
  116. proc xConflict args { incr ::n_conflict ; return "OMIT" }
  117. set rc [catch {
  118. sqlite3session S db $dbname
  119. S object_config rowid 1
  120. db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
  121. S attach $name
  122. }
  123. db eval $sql
  124. set ::changeset [S changeset]
  125. sqlite3changeset_apply db2 $::changeset xConflict
  126. } msg]
  127. catch { S delete }
  128. if {$rc} {error $msg}
  129. if {$bIgnoreNoop} {
  130. set nSave $::n_conflict
  131. set ::n_conflict 0
  132. proc xConflict args { incr ::n_conflict ; return "OMIT" }
  133. sqlite3changeset_apply_v2 -ignorenoop db2 $::changeset xConflict
  134. if {$::n_conflict!=$nSave} {
  135. error "-ignorenoop problem ($::n_conflict $nSave)..."
  136. }
  137. }
  138. }
  139. proc do_iterator_test {tn tbl_list sql res} {
  140. sqlite3session S db main
  141. S object_config rowid 1
  142. if {[llength $tbl_list]==0} { S attach * }
  143. foreach t $tbl_list {S attach $t}
  144. execsql $sql
  145. set r [list]
  146. foreach v $res { lappend r $v }
  147. set x [list]
  148. # set ::c [S changeset] ; execsql_pp { SELECT quote($::c) }
  149. sqlite3session_foreach c [S changeset] { lappend x $c }
  150. uplevel do_test $tn [list [list set {} $x]] [list $r]
  151. S delete
  152. }
  153. # Compare the contents of all tables in [db1] and [db2]. Throw an error if
  154. # they are not identical, or return an empty string if they are.
  155. #
  156. proc compare_db {db1 db2} {
  157. set sql {SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name}
  158. set lot1 [$db1 eval $sql]
  159. set lot2 [$db2 eval $sql]
  160. if {$lot1 != $lot2} {
  161. puts $lot1
  162. puts $lot2
  163. error "databases contain different tables"
  164. }
  165. foreach tbl $lot1 {
  166. set col1 [list]
  167. set col2 [list]
  168. $db1 eval "PRAGMA table_info = $tbl" { lappend col1 $name }
  169. $db2 eval "PRAGMA table_info = $tbl" { lappend col2 $name }
  170. if {$col1 != $col2} { error "table $tbl schema mismatch" }
  171. set sql "SELECT * FROM $tbl ORDER BY [join $col1 ,]"
  172. set data1 [$db1 eval $sql]
  173. set data2 [$db2 eval $sql]
  174. if {$data1 != $data2} {
  175. puts "$db1: $data1"
  176. puts "$db2: $data2"
  177. error "table $tbl data mismatch"
  178. }
  179. }
  180. return ""
  181. }
  182. proc changeset_to_list {c} {
  183. set list [list]
  184. sqlite3session_foreach elem $c { lappend list $elem }
  185. lsort $list
  186. }
  187. set ones {zero one two three four five six seven eight nine
  188. ten eleven twelve thirteen fourteen fifteen sixteen seventeen
  189. eighteen nineteen}
  190. set tens {{} ten twenty thirty forty fifty sixty seventy eighty ninety}
  191. proc number_name {n} {
  192. if {$n>=1000} {
  193. set txt "[number_name [expr {$n/1000}]] thousand"
  194. set n [expr {$n%1000}]
  195. } else {
  196. set txt {}
  197. }
  198. if {$n>=100} {
  199. append txt " [lindex $::ones [expr {$n/100}]] hundred"
  200. set n [expr {$n%100}]
  201. }
  202. if {$n>=20} {
  203. append txt " [lindex $::tens [expr {$n/10}]]"
  204. set n [expr {$n%10}]
  205. }
  206. if {$n>0} {
  207. append txt " [lindex $::ones $n]"
  208. }
  209. set txt [string trim $txt]
  210. if {$txt==""} {set txt zero}
  211. return $txt
  212. }
  213. proc scksum {db dbname} {
  214. if {$dbname=="temp"} {
  215. set master sqlite_temp_master
  216. } else {
  217. set master $dbname.sqlite_master
  218. }
  219. set alltab [$db eval "SELECT name FROM $master WHERE type='table'"]
  220. set txt [$db eval "SELECT * FROM $master ORDER BY type,name,sql"]
  221. foreach tab $alltab {
  222. set cols [list]
  223. db eval "PRAGMA $dbname.table_info = $tab" x {
  224. lappend cols "quote($x(name))"
  225. }
  226. set cols [join $cols ,]
  227. append txt [db eval "SELECT $cols FROM $dbname.$tab ORDER BY $cols"]
  228. }
  229. return [md5 $txt]
  230. }
  231. proc do_diff_test {tn setup} {
  232. reset_db
  233. forcedelete test.db2
  234. execsql { ATTACH 'test.db2' AS aux }
  235. execsql $setup
  236. sqlite3session S db main
  237. S object_config rowid 1
  238. foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
  239. S attach $tbl
  240. S diff aux $tbl
  241. }
  242. set C [S changeset]
  243. S delete
  244. sqlite3 db2 test.db2
  245. sqlite3changeset_apply db2 $C ""
  246. uplevel do_test $tn.1 [list {execsql { PRAGMA integrity_check } db2}] ok
  247. db2 close
  248. set cksum [scksum db main]
  249. uplevel do_test $tn.2 [list {scksum db aux}] [list $cksum]
  250. }