112ca0b56Sdan# 2011 Mar 21 212ca0b56Sdan# 312ca0b56Sdan# The author disclaims copyright to this source code. In place of 412ca0b56Sdan# a legal notice, here is a blessing: 512ca0b56Sdan# 612ca0b56Sdan# May you do good and not evil. 712ca0b56Sdan# May you find forgiveness for yourself and forgive others. 812ca0b56Sdan# May you share freely, never taking more than you give. 912ca0b56Sdan# 1012ca0b56Sdan#*********************************************************************** 1112ca0b56Sdan# 1212ca0b56Sdan# The focus of this file is testing the session module. 1312ca0b56Sdan# 1412ca0b56Sdan 1512ca0b56Sdanif {![info exists testdir]} { 1612ca0b56Sdan set testdir [file join [file dirname [info script]] .. .. test] 1712ca0b56Sdan} 1812ca0b56Sdansource [file join [file dirname [info script]] session_common.tcl] 1912ca0b56Sdansource $testdir/tester.tcl 20*05accd22Sdanifcapable !session {finish_test; return} 2112ca0b56Sdan 2212ca0b56Sdanset testprefix sessionfault 2312ca0b56Sdan 2412ca0b56Sdanforcedelete test.db2 2512ca0b56Sdansqlite3 db2 test.db2 2612ca0b56Sdando_common_sql { 2712ca0b56Sdan CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)); 2812ca0b56Sdan INSERT INTO t1 VALUES(1, 2, 3); 2912ca0b56Sdan INSERT INTO t1 VALUES(4, 5, 6); 3012ca0b56Sdan} 3112ca0b56Sdanfaultsim_save_and_close 3212ca0b56Sdandb2 close 3312ca0b56Sdan 347aa469cdSdan#------------------------------------------------------------------------- 3512ca0b56Sdan# Test OOM error handling when collecting and applying a simple changeset. 3612ca0b56Sdan# 37245b49b2Sdan# Test 1.1 attaches tables individually by name to the session object. 38245b49b2Sdan# Whereas test 1.2 passes NULL to sqlite3session_attach() to attach all 39245b49b2Sdan# tables. 40245b49b2Sdan# 41b4480e94Sdando_faultsim_test 1.1 -faults oom-* -prep { 4212ca0b56Sdan catch {db2 close} 4312ca0b56Sdan catch {db close} 4412ca0b56Sdan faultsim_restore_and_reopen 4512ca0b56Sdan sqlite3 db2 test.db2 4612ca0b56Sdan} -body { 4712ca0b56Sdan do_then_apply_sql { 48e5754eecSdan INSERT INTO t1 VALUES('a string value', 8, 9); 4912ca0b56Sdan UPDATE t1 SET c = 10 WHERE a = 1; 5012ca0b56Sdan DELETE FROM t1 WHERE a = 4; 5112ca0b56Sdan } 5212ca0b56Sdan} -test { 5312ca0b56Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 5412ca0b56Sdan faultsim_integrity_check 5512ca0b56Sdan if {$testrc==0} { compare_db db db2 } 5612ca0b56Sdan} 5712ca0b56Sdan 58b4480e94Sdando_faultsim_test 1.2 -faults oom-* -prep { 59245b49b2Sdan catch {db2 close} 60245b49b2Sdan catch {db close} 61245b49b2Sdan faultsim_restore_and_reopen 62245b49b2Sdan} -body { 63245b49b2Sdan sqlite3session S db main 64245b49b2Sdan S attach * 65245b49b2Sdan execsql { 66e5754eecSdan INSERT INTO t1 VALUES('a string value', 8, 9); 67245b49b2Sdan UPDATE t1 SET c = 10 WHERE a = 1; 68245b49b2Sdan DELETE FROM t1 WHERE a = 4; 69245b49b2Sdan } 70245b49b2Sdan set ::changeset [S changeset] 71245b49b2Sdan set {} {} 72245b49b2Sdan} -test { 73245b49b2Sdan catch { S delete } 74245b49b2Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 75245b49b2Sdan faultsim_integrity_check 76245b49b2Sdan if {$testrc==0} { 77245b49b2Sdan proc xConflict {args} { return "OMIT" } 78245b49b2Sdan sqlite3 db2 test.db2 79245b49b2Sdan sqlite3changeset_apply db2 $::changeset xConflict 80245b49b2Sdan compare_db db db2 81245b49b2Sdan } 82245b49b2Sdan} 83245b49b2Sdan 847aa469cdSdan#------------------------------------------------------------------------- 85b4480e94Sdan# The following block of tests - 2.* - are designed to check 867aa469cdSdan# the handling of faults in the sqlite3changeset_apply() function. 877aa469cdSdan# 887aa469cdSdancatch {db close} 897aa469cdSdancatch {db2 close} 907aa469cdSdanforcedelete test.db2 test.db 917aa469cdSdansqlite3 db2 test.db2 927aa469cdSdansqlite3 db test.db 937aa469cdSdando_common_sql { 947aa469cdSdan CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)); 957aa469cdSdan INSERT INTO t1 VALUES('apple', 'orange', 'pear'); 967aa469cdSdan 977aa469cdSdan CREATE TABLE t2(x PRIMARY KEY, y); 987aa469cdSdan} 997aa469cdSdandb2 close 1007aa469cdSdanfaultsim_save_and_close 1017aa469cdSdan 1027aa469cdSdan 1037aa469cdSdanforeach {tn conflict_policy sql sql2} { 1047aa469cdSdan 1 OMIT { INSERT INTO t1 VALUES('one text', 'two text', X'00ff00') } {} 1057aa469cdSdan 2 OMIT { DELETE FROM t1 WHERE a = 'apple' } {} 1067aa469cdSdan 3 OMIT { UPDATE t1 SET c = 'banana' WHERE b = 'orange' } {} 1077aa469cdSdan 4 REPLACE { INSERT INTO t2 VALUES('keyvalue', 'value 1') } { 1087aa469cdSdan INSERT INTO t2 VALUES('keyvalue', 'value 2'); 1097aa469cdSdan } 1107aa469cdSdan} { 1117aa469cdSdan proc xConflict args [list return $conflict_policy] 1127aa469cdSdan 113b4480e94Sdan do_faultsim_test 2.$tn -faults oom-transient -prep { 1147aa469cdSdan catch {db2 close} 1157aa469cdSdan catch {db close} 1167aa469cdSdan faultsim_restore_and_reopen 1177aa469cdSdan set ::changeset [changeset_from_sql $::sql] 1187aa469cdSdan sqlite3 db2 test.db2 1197aa469cdSdan sqlite3_db_config_lookaside db2 0 0 0 1207aa469cdSdan execsql $::sql2 db2 1217aa469cdSdan } -body { 1227aa469cdSdan sqlite3changeset_apply db2 $::changeset xConflict 1237aa469cdSdan } -test { 1247aa469cdSdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 1257aa469cdSdan faultsim_integrity_check 1267aa469cdSdan if {$testrc==0} { compare_db db db2 } 1277aa469cdSdan } 1287aa469cdSdan} 1297aa469cdSdan 1307aa469cdSdan#------------------------------------------------------------------------- 13112ca0b56Sdan# This test case is designed so that a malloc() failure occurs while 13212ca0b56Sdan# resizing the session object hash-table from 256 to 512 buckets. This 13312ca0b56Sdan# is not an error, just a sub-optimal condition. 13412ca0b56Sdan# 135b4480e94Sdando_faultsim_test 3 -faults oom-* -prep { 13612ca0b56Sdan catch {db2 close} 13712ca0b56Sdan catch {db close} 13812ca0b56Sdan faultsim_restore_and_reopen 13912ca0b56Sdan sqlite3 db2 test.db2 14012ca0b56Sdan 14112ca0b56Sdan sqlite3session S db main 14212ca0b56Sdan S attach t1 14312ca0b56Sdan execsql { BEGIN } 14412ca0b56Sdan for {set i 0} {$i < 125} {incr i} { 14512ca0b56Sdan execsql {INSERT INTO t1 VALUES(10+$i, 10+$i, 10+$i)} 14612ca0b56Sdan } 14712ca0b56Sdan} -body { 14812ca0b56Sdan for {set i 125} {$i < 133} {incr i} { 14912ca0b56Sdan execsql {INSERT INTO t1 VALUES(10+$i, 10+$i, 1-+$i)} 15012ca0b56Sdan } 15112ca0b56Sdan S changeset 15212ca0b56Sdan set {} {} 15312ca0b56Sdan} -test { 15412ca0b56Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 15512ca0b56Sdan if {$testrc==0} { 15612ca0b56Sdan sqlite3changeset_apply db2 [S changeset] xConflict 15712ca0b56Sdan compare_db db db2 15812ca0b56Sdan } 15912ca0b56Sdan catch { S delete } 16012ca0b56Sdan faultsim_integrity_check 16112ca0b56Sdan} 16212ca0b56Sdan 163db04571cSdancatch { db close } 164db04571cSdancatch { db2 close } 165db04571cSdanforcedelete test.db2 test.db 166db04571cSdansqlite3 db2 test.db2 167db04571cSdansqlite3 db test.db 168db04571cSdan 169db04571cSdanproc xConflict {op tbl type args} { 170db04571cSdan if { $type=="CONFLICT" || $type=="DATA" } { 171db04571cSdan return "REPLACE" 172db04571cSdan } 173db04571cSdan return "OMIT" 174db04571cSdan} 175db04571cSdan 1767aa469cdSdando_test 4.0 { 177db04571cSdan execsql { 178db04571cSdan PRAGMA encoding = 'utf16'; 179db04571cSdan CREATE TABLE t1(a PRIMARY KEY, b); 180db04571cSdan INSERT INTO t1 VALUES(5, 32); 181db04571cSdan } 182db04571cSdan execsql { 183db04571cSdan PRAGMA encoding = 'utf16'; 184db04571cSdan CREATE TABLE t1(a PRIMARY KEY, b NOT NULL); 185db04571cSdan INSERT INTO t1 VALUES(1, 2); 186db04571cSdan INSERT INTO t1 VALUES(2, 4); 187db04571cSdan INSERT INTO t1 VALUES(4, 16); 188db04571cSdan } db2 189db04571cSdan} {} 190db04571cSdan 191db04571cSdanfaultsim_save_and_close 192db04571cSdandb2 close 193db04571cSdan 194b4480e94Sdando_faultsim_test 4 -faults oom-* -prep { 195db04571cSdan catch {db2 close} 196db04571cSdan catch {db close} 197db04571cSdan faultsim_restore_and_reopen 198db04571cSdan sqlite3 db2 test.db2 199db04571cSdan sqlite3session S db main 200db04571cSdan S attach t1 201db04571cSdan execsql { 202db04571cSdan INSERT INTO t1 VALUES(1, 45); 203db04571cSdan INSERT INTO t1 VALUES(2, 55); 204db04571cSdan INSERT INTO t1 VALUES(3, 55); 205db04571cSdan UPDATE t1 SET a = 4 WHERE a = 5; 206db04571cSdan } 207db04571cSdan} -body { 208db04571cSdan sqlite3changeset_apply db2 [S changeset] xConflict 209db04571cSdan} -test { 210db04571cSdan catch { S delete } 211db04571cSdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 212db04571cSdan if {$testrc==0} { compare_db db db2 } 213db04571cSdan} 214db04571cSdan 2157aa469cdSdan#------------------------------------------------------------------------- 2167aa469cdSdan# This block of tests verifies that OOM faults in the 2177aa469cdSdan# sqlite3changeset_invert() function are handled correctly. 2187aa469cdSdan# 2197aa469cdSdancatch {db close} 2207aa469cdSdancatch {db2 close} 2217aa469cdSdanforcedelete test.db 2227aa469cdSdansqlite3 db test.db 2237aa469cdSdanexecsql { 2247aa469cdSdan CREATE TABLE t1(a, b, PRIMARY KEY(b)); 2257aa469cdSdan CREATE TABLE t2(a PRIMARY KEY, b); 2267aa469cdSdan INSERT INTO t1 VALUES('string', 1); 2277aa469cdSdan INSERT INTO t1 VALUES(4, 2); 2287aa469cdSdan INSERT INTO t1 VALUES(X'FFAAFFAAFFAA', 3); 2297aa469cdSdan} 2307aa469cdSdanset changeset [changeset_from_sql { 2317aa469cdSdan INSERT INTO t1 VALUES('xxx', 'yyy'); 2327aa469cdSdan DELETE FROM t1 WHERE a = 'string'; 2337aa469cdSdan UPDATE t1 SET a = 20 WHERE b = 2; 2347aa469cdSdan}] 2357aa469cdSdandb close 2367aa469cdSdan 237e8fa8c96Sdando_faultsim_test 5.1 -faults oom* -body { 2387aa469cdSdan set ::inverse [sqlite3changeset_invert $::changeset] 2397aa469cdSdan set {} {} 2407aa469cdSdan} -test { 2417aa469cdSdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 2427aa469cdSdan if {$testrc==0} { 2437aa469cdSdan set x [list] 2447aa469cdSdan sqlite3session_foreach c $::inverse { lappend x $c } 2457aa469cdSdan foreach c { 246244593c8Sdan {DELETE t1 0 .X {t xxx t yyy} {}} 247244593c8Sdan {INSERT t1 0 .X {} {t string i 1}} 2481e556c3fSdan {UPDATE t1 0 .X {i 20 i 2} {i 4 {} {}}} 2497aa469cdSdan } { lappend y $c } 2507aa469cdSdan if {$x != $y} { error "changeset no good" } 2517aa469cdSdan } 2527aa469cdSdan} 2537aa469cdSdan 254e8fa8c96Sdancatch {db close} 255e8fa8c96Sdancatch {db2 close} 256e8fa8c96Sdanforcedelete test.db 257e8fa8c96Sdansqlite3 db test.db 258e8fa8c96Sdanexecsql { 259e8fa8c96Sdan CREATE TABLE t2(a PRIMARY KEY, b); 260e8fa8c96Sdan INSERT INTO t2 VALUES(1, 'abc'); 261e8fa8c96Sdan INSERT INTO t2 VALUES(2, 'def'); 262e8fa8c96Sdan} 263e8fa8c96Sdanset changeset [changeset_from_sql { 264e8fa8c96Sdan UPDATE t2 SET b = (b || b || b || b); 265e8fa8c96Sdan UPDATE t2 SET b = (b || b || b || b); 266e8fa8c96Sdan UPDATE t2 SET b = (b || b || b || b); 267e8fa8c96Sdan UPDATE t2 SET b = (b || b || b || b); 268e8fa8c96Sdan}] 269e8fa8c96Sdandb close 270e8fa8c96Sdanset abc [string repeat abc 256] 271e8fa8c96Sdanset def [string repeat def 256] 272e8fa8c96Sdan 273e8fa8c96Sdando_faultsim_test 5.2 -faults oom-tra* -body { 274e8fa8c96Sdan set ::inverse [sqlite3changeset_invert $::changeset] 275e8fa8c96Sdan set {} {} 276e8fa8c96Sdan} -test { 277e8fa8c96Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 278e8fa8c96Sdan if {$testrc==0} { 279e8fa8c96Sdan set x [list] 280e8fa8c96Sdan sqlite3session_foreach c $::inverse { lappend x $c } 281e8fa8c96Sdan foreach c " 282e8fa8c96Sdan {UPDATE t2 0 X. {i 1 t $::abc} {{} {} t abc}} 283e8fa8c96Sdan {UPDATE t2 0 X. {i 2 t $::def} {{} {} t def}} 284e8fa8c96Sdan " { lappend y $c } 285e8fa8c96Sdan if {$x != $y} { error "changeset no good" } 286e8fa8c96Sdan } 287e8fa8c96Sdan} 288e8fa8c96Sdan 289f05ac112Sdancatch {db close} 290f05ac112Sdancatch {db2 close} 291f05ac112Sdanforcedelete test.db 292f05ac112Sdansqlite3 db test.db 293f05ac112Sdanset abc [string repeat abc 256] 294f05ac112Sdanset def [string repeat def 256] 295f05ac112Sdanexecsql " 296f05ac112Sdan CREATE TABLE t2(a PRIMARY KEY, b); 297f05ac112Sdan INSERT INTO t2 VALUES(1, '$abc'); 298f05ac112Sdan" 299f05ac112Sdanset changeset [changeset_from_sql " 300f05ac112Sdan INSERT INTO t2 VALUES(2, '$def'); 301f05ac112Sdan DELETE FROM t2 WHERE a = 1; 302f05ac112Sdan"] 303f05ac112Sdandb close 304f05ac112Sdan 305f05ac112Sdando_faultsim_test 5.3 -faults oom-tra* -body { 306f05ac112Sdan set ::inverse [sqlite3changeset_invert $::changeset] 307f05ac112Sdan set {} {} 308f05ac112Sdan} -test { 309f05ac112Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 310f05ac112Sdan if {$testrc==0} { 311f05ac112Sdan set x [list] 312f05ac112Sdan sqlite3session_foreach c $::inverse { lappend x $c } 313f05ac112Sdan foreach c " 314f05ac112Sdan {INSERT t2 0 X. {} {i 1 t $::abc}} 315f05ac112Sdan {DELETE t2 0 X. {i 2 t $::def} {}} 316f05ac112Sdan " { lappend y $c } 317f05ac112Sdan if {$x != $y} { error "changeset no good" } 318f05ac112Sdan } 319f05ac112Sdan} 320f05ac112Sdan 3211756ae10Sdan#------------------------------------------------------------------------- 3221756ae10Sdan# Test that OOM errors in sqlite3changeset_concat() are handled correctly. 3231756ae10Sdan# 3241756ae10Sdancatch {db close} 3251756ae10Sdanforcedelete test.db 3261756ae10Sdansqlite3 db test.db 3271756ae10Sdando_execsql_test 5.prep1 { 3281756ae10Sdan CREATE TABLE t1(a, b, PRIMARY KEY(b)); 3291756ae10Sdan CREATE TABLE t2(a PRIMARY KEY, b); 3301756ae10Sdan INSERT INTO t1 VALUES('string', 1); 3311756ae10Sdan INSERT INTO t1 VALUES(4, 2); 3321756ae10Sdan INSERT INTO t1 VALUES(X'FFAAFFAAFFAA', 3); 3331756ae10Sdan} 3341756ae10Sdan 3356734007dSdando_test 6.prep2 { 3361756ae10Sdan sqlite3session M db main 3371756ae10Sdan M attach * 3381756ae10Sdan set ::c2 [changeset_from_sql { 3391756ae10Sdan INSERT INTO t2 VALUES(randomblob(1000), randomblob(1000)); 3401756ae10Sdan INSERT INTO t2 VALUES('one', 'two'); 3411756ae10Sdan INSERT INTO t2 VALUES(1, NULL); 3421756ae10Sdan UPDATE t1 SET a = 5 WHERE a = 2; 3431756ae10Sdan }] 3441756ae10Sdan set ::c1 [changeset_from_sql { 3451756ae10Sdan DELETE FROM t2 WHERE a = 1; 3461756ae10Sdan UPDATE t1 SET a = 4 WHERE a = 2; 3471756ae10Sdan INSERT INTO t2 VALUES('x', 'y'); 3481756ae10Sdan }] 3491756ae10Sdan set ::total [changeset_to_list [M changeset]] 3501756ae10Sdan M delete 3511756ae10Sdan} {} 3521756ae10Sdan 3531756ae10Sdando_faultsim_test 6 -faults oom-* -body { 3541756ae10Sdan set ::result [sqlite3changeset_concat $::c1 $::c2] 3551756ae10Sdan set {} {} 3561756ae10Sdan} -test { 3571756ae10Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 3581756ae10Sdan if {$testrc==0} { 3591756ae10Sdan set v [changeset_to_list $::result] 3601756ae10Sdan if {$v != $::total} { error "result no good" } 3611756ae10Sdan } 3621756ae10Sdan} 3631756ae10Sdan 3646734007dSdanfaultsim_delete_and_reopen 3656fee7958Sdando_execsql_test 7.prep1 { 3666734007dSdan CREATE TABLE t1(a, b, PRIMARY KEY(a)); 3676734007dSdan} 3686734007dSdanfaultsim_save_and_close 3696734007dSdan 3706734007dSdanset res [list] 3716734007dSdanfor {set ::i 0} {$::i < 480} {incr ::i 4} { 3726734007dSdan lappend res "INSERT t1 0 X. {} {i $::i i $::i}" 3736734007dSdan} 3746734007dSdanset res [lsort $res] 3756734007dSdando_faultsim_test 7 -faults oom-transient -prep { 3766fee7958Sdan catch { S delete } 3776734007dSdan faultsim_restore_and_reopen 3786734007dSdan sqlite3session S db main 3796734007dSdan S attach * 3806734007dSdan} -body { 3816734007dSdan for {set ::i 0} {$::i < 480} {incr ::i 4} { 3826734007dSdan execsql {INSERT INTO t1 VALUES($::i, $::i)} 3836734007dSdan } 3846734007dSdan} -test { 3856734007dSdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 3866734007dSdan if {$testrc==0} { 3876734007dSdan set cres [list [catch {changeset_to_list [S changeset]} msg] $msg] 3886734007dSdan S delete 3896734007dSdan if {$cres != "1 SQLITE_NOMEM" && $cres != "0 {$::res}"} { 3906734007dSdan error "Expected {0 $::res} Got {$cres}" 3916734007dSdan } 3926734007dSdan } else { 393a66e3862Sdan catch { S changeset } 394a66e3862Sdan catch { S delete } 3956734007dSdan } 3966734007dSdan} 3976734007dSdan 3986734007dSdanfaultsim_delete_and_reopen 3996734007dSdando_test 8.prep { 4006734007dSdan sqlite3session S db main 4016734007dSdan S attach * 4026734007dSdan execsql { 4036734007dSdan CREATE TABLE t1(a, b, PRIMARY KEY(a)); 4046734007dSdan INSERT INTO t1 VALUES(1, 2); 4056734007dSdan INSERT INTO t1 VALUES(3, 4); 4066734007dSdan INSERT INTO t1 VALUES(5, 6); 4076734007dSdan } 4086734007dSdan set ::changeset [S changeset] 4096734007dSdan S delete 4106734007dSdan} {} 4116734007dSdan 4126734007dSdanset expected [normalize_list { 4136734007dSdan {INSERT t1 0 X. {} {i 1 i 2}} 4146734007dSdan {INSERT t1 0 X. {} {i 3 i 4}} 4156734007dSdan {INSERT t1 0 X. {} {i 5 i 6}} 4166734007dSdan}] 4176734007dSdando_faultsim_test 8.1 -faults oom* -body { 4186734007dSdan set ::res [list] 4196734007dSdan sqlite3session_foreach -next v $::changeset { lappend ::res $v } 4206734007dSdan normalize_list $::res 4216734007dSdan} -test { 4226734007dSdan faultsim_test_result [list 0 $::expected] {1 SQLITE_NOMEM} 4236734007dSdan} 4246734007dSdando_faultsim_test 8.2 -faults oom* -body { 4256734007dSdan set ::res [list] 4266734007dSdan sqlite3session_foreach v $::changeset { lappend ::res $v } 4276734007dSdan normalize_list $::res 4286734007dSdan} -test { 4296734007dSdan faultsim_test_result [list 0 $::expected] {1 SQLITE_NOMEM} 4306734007dSdan} 4316734007dSdan 4326734007dSdanfaultsim_delete_and_reopen 43380fe2d93Sdando_test 9.1.prep { 4346734007dSdan execsql { 4356734007dSdan PRAGMA encoding = 'utf16'; 4366734007dSdan CREATE TABLE t1(a PRIMARY KEY, b); 4376734007dSdan } 4386734007dSdan} {} 4396734007dSdanfaultsim_save_and_close 4406734007dSdan 44140eaa086Sdrhset answers [list {0 {}} {1 SQLITE_NOMEM} \ 44240eaa086Sdrh {1 {callback requested query abort}} \ 44340eaa086Sdrh {1 {abort due to ROLLBACK}}] 44480fe2d93Sdando_faultsim_test 9.1 -faults oom-transient -prep { 4456734007dSdan catch { unset ::c } 4466734007dSdan faultsim_restore_and_reopen 4476734007dSdan sqlite3session S db main 4486734007dSdan S attach * 4496734007dSdan} -body { 4506734007dSdan execsql { 4516734007dSdan INSERT INTO t1 VALUES('abcdefghijklmnopqrstuv', 'ABCDEFGHIJKLMNOPQRSTUV'); 4526734007dSdan } 4536734007dSdan set ::c [S changeset] 4546734007dSdan set {} {} 4556734007dSdan} -test { 4566734007dSdan S delete 45780fe2d93Sdan eval faultsim_test_result $::answers 4586734007dSdan if {[info exists ::c]} { 45980fe2d93Sdan set expected [normalize_list { 46080fe2d93Sdan {INSERT t1 0 X. {} {t abcdefghijklmnopqrstuv t ABCDEFGHIJKLMNOPQRSTUV}} 46180fe2d93Sdan }] 4626734007dSdan if { [changeset_to_list $::c] != $expected } { 4636734007dSdan error "changeset mismatch" 4646734007dSdan } 4656734007dSdan } 4666734007dSdan} 4676734007dSdan 46880fe2d93Sdanfaultsim_delete_and_reopen 46980fe2d93Sdando_test 9.2.prep { 47080fe2d93Sdan execsql { 47180fe2d93Sdan PRAGMA encoding = 'utf16'; 47280fe2d93Sdan CREATE TABLE t1(a PRIMARY KEY, b); 47380fe2d93Sdan INSERT INTO t1 VALUES('abcdefghij', 'ABCDEFGHIJKLMNOPQRSTUV'); 47480fe2d93Sdan } 47580fe2d93Sdan} {} 47680fe2d93Sdanfaultsim_save_and_close 47780fe2d93Sdan 47840eaa086Sdrhset answers [list {0 {}} {1 SQLITE_NOMEM} \ 47940eaa086Sdrh {1 {callback requested query abort}} \ 48040eaa086Sdrh {1 {abort due to ROLLBACK}}] 48180fe2d93Sdando_faultsim_test 9.2 -faults oom-transient -prep { 48280fe2d93Sdan catch { unset ::c } 48380fe2d93Sdan faultsim_restore_and_reopen 48480fe2d93Sdan sqlite3session S db main 48580fe2d93Sdan S attach * 48680fe2d93Sdan} -body { 48780fe2d93Sdan execsql { 48880fe2d93Sdan UPDATE t1 SET b = 'xyz'; 48980fe2d93Sdan } 49080fe2d93Sdan set ::c [S changeset] 49180fe2d93Sdan set {} {} 49280fe2d93Sdan} -test { 49380fe2d93Sdan S delete 49480fe2d93Sdan eval faultsim_test_result $::answers 49580fe2d93Sdan if {[info exists ::c]} { 49680fe2d93Sdan set expected [normalize_list { 49780fe2d93Sdan {UPDATE t1 0 X. {t abcdefghij t ABCDEFGHIJKLMNOPQRSTUV} {{} {} t xyz}} 49880fe2d93Sdan }] 49980fe2d93Sdan if { [changeset_to_list $::c] != $expected } { 50080fe2d93Sdan error "changeset mismatch" 50180fe2d93Sdan } 50280fe2d93Sdan } 50380fe2d93Sdan} 50480fe2d93Sdan 505082c96dfSdan#------------------------------------------------------------------------- 506082c96dfSdan# Test that if a conflict-handler encounters an OOM in 507082c96dfSdan# sqlite3_value_text() but goes on to return SQLITE_CHANGESET_REPLACE 508082c96dfSdan# anyway, the OOM is picked up by the sessions module. 509082c96dfSdanset bigstr [string repeat abcdefghij 100] 510082c96dfSdanfaultsim_delete_and_reopen 511082c96dfSdando_test 10.prep.1 { 512082c96dfSdan execsql { 513082c96dfSdan CREATE TABLE t1(a PRIMARY KEY, b); 514082c96dfSdan INSERT INTO t1 VALUES($bigstr, $bigstr); 515082c96dfSdan } 516082c96dfSdan 517082c96dfSdan sqlite3session S db main 518082c96dfSdan S attach * 519082c96dfSdan execsql { UPDATE t1 SET b = b||'x' } 520082c96dfSdan set C [S changeset] 521082c96dfSdan S delete 522082c96dfSdan execsql { UPDATE t1 SET b = b||'xyz' } 523082c96dfSdan} {} 524082c96dfSdanfaultsim_save_and_close 525082c96dfSdan 526082c96dfSdanfaultsim_restore_and_reopen 527082c96dfSdando_test 10.prep.2 { 528082c96dfSdan proc xConflict {args} { return "ABORT" } 529082c96dfSdan list [catch { sqlite3changeset_apply db $C xConflict } msg] $msg 530082c96dfSdan} {1 SQLITE_ABORT} 531082c96dfSdando_execsql_test 10.prep.3 { SELECT b=$bigstr||'x' FROM t1 } 0 532082c96dfSdando_test 10.prep.4 { 533082c96dfSdan proc xConflict {args} { return "REPLACE" } 534082c96dfSdan list [catch { sqlite3changeset_apply db $C xConflict } msg] $msg 535082c96dfSdan} {0 {}} 536082c96dfSdando_execsql_test 10.prep.5 { SELECT b=$bigstr||'x' FROM t1 } 1 537082c96dfSdandb close 538082c96dfSdan 539082c96dfSdando_faultsim_test 10 -faults oom-tra* -prep { 540082c96dfSdan faultsim_restore_and_reopen 541082c96dfSdan} -body { 542082c96dfSdan sqlite3changeset_apply_replace_all db $::C 543082c96dfSdan} -test { 544082c96dfSdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 545082c96dfSdan if {$testrc==0} { 546082c96dfSdan if {[db one {SELECT b=$bigstr||'x' FROM t1}]==0} { 547082c96dfSdan error "data does not look right" 548082c96dfSdan } 549082c96dfSdan } 550082c96dfSdan} 551082c96dfSdan 552f05ac112Sdan#------------------------------------------------------------------------- 553f05ac112Sdan# Test an OOM with an sqlite3changeset_apply() filter callback. 554f05ac112Sdan# 555f05ac112Sdanreset_db 556f05ac112Sdando_test 11.prep { 557f05ac112Sdan execsql { 558f05ac112Sdan CREATE TABLE t1(a PRIMARY KEY, b); 559f05ac112Sdan CREATE TABLE t2(x PRIMARY KEY, y); 560f05ac112Sdan BEGIN; 561f05ac112Sdan } 562082c96dfSdan 563f05ac112Sdan set ::cs [changeset_from_sql { 564f05ac112Sdan INSERT INTO t1 VALUES(1, 2); 565f05ac112Sdan INSERT INTO t2 VALUES('x', 'y'); 566f05ac112Sdan }] 567f05ac112Sdan 568f05ac112Sdan execsql ROLLBACK 569f05ac112Sdan set {} {} 570f05ac112Sdan} {} 571f05ac112Sdan 572f05ac112Sdanproc filter {x} { return [string equal t1 $x] } 573f05ac112Sdanfaultsim_save_and_close 574f05ac112Sdan 575f05ac112Sdando_faultsim_test 11 -faults oom-tra* -prep { 576f05ac112Sdan faultsim_restore_and_reopen 577f05ac112Sdan} -body { 578f05ac112Sdan sqlite3changeset_apply db $::cs {} filter 579f05ac112Sdan} -test { 580f05ac112Sdan faultsim_test_result {0 {}} {1 SQLITE_NOMEM} 581f05ac112Sdan if {$testrc==0} { 582f05ac112Sdan if {[db eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2}] != "1 2"} { 583f05ac112Sdan error "data does not look right" 584f05ac112Sdan } 585f05ac112Sdan } 586f05ac112Sdan} 58780fe2d93Sdan 5886734007dSdan 58912ca0b56Sdanfinish_test 590