123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817 |
- # 2010 June 15
- #
- # The author disclaims copyright to this source code. In place of
- # a legal notice, here is a blessing:
- #
- # May you do good and not evil.
- # May you find forgiveness for yourself and forgive others.
- # May you share freely, never taking more than you give.
- #
- #***********************************************************************
- #
- set testdir [file dirname $argv0]
- source $testdir/tester.tcl
- source $testdir/lock_common.tcl
- source $testdir/malloc_common.tcl
- source $testdir/wal_common.tcl
- set testprefix pager1
- # Do not use a codec for tests in this file, as the database file is
- # manipulated directly using tcl scripts (using the [hexio_write] command).
- #
- do_not_use_codec
- #
- # pager1-1.*: Test inter-process locking (clients in multiple processes).
- #
- # pager1-2.*: Test intra-process locking (multiple clients in this process).
- #
- # pager1-3.*: Savepoint related tests.
- #
- # pager1-4.*: Hot-journal related tests.
- #
- # pager1-5.*: Cases related to multi-file commits.
- #
- # pager1-6.*: Cases related to "PRAGMA max_page_count"
- #
- # pager1-7.*: Cases specific to "PRAGMA journal_mode=TRUNCATE"
- #
- # pager1-8.*: Cases using temporary and in-memory databases.
- #
- # pager1-9.*: Tests related to the backup API.
- #
- # pager1-10.*: Test that the assumed file-system sector-size is limited to
- # 64KB.
- #
- # pager1-12.*: Tests involving "PRAGMA page_size"
- #
- # pager1-13.*: Cases specific to "PRAGMA journal_mode=PERSIST"
- #
- # pager1-14.*: Cases specific to "PRAGMA journal_mode=OFF"
- #
- # pager1-15.*: Varying sqlite3_vfs.szOsFile
- #
- # pager1-16.*: Varying sqlite3_vfs.mxPathname
- #
- # pager1-17.*: Tests related to "PRAGMA omit_readlock"
- # (The omit_readlock pragma has been removed and so have
- # these tests.)
- #
- # pager1-18.*: Test that the pager layer responds correctly if the b-tree
- # requests an invalid page number (due to db corruption).
- #
- proc recursive_select {id table {script {}}} {
- set cnt 0
- db eval "SELECT rowid, * FROM $table WHERE rowid = ($id-1)" {
- recursive_select $rowid $table $script
- incr cnt
- }
- if {$cnt==0} { eval $script }
- }
- set a_string_counter 1
- proc a_string {n} {
- global a_string_counter
- incr a_string_counter
- string range [string repeat "${a_string_counter}." $n] 1 $n
- }
- db func a_string a_string
- do_multiclient_test tn {
- # Create and populate a database table using connection [db]. Check
- # that connections [db2] and [db3] can see the schema and content.
- #
- do_test pager1-$tn.1 {
- sql1 {
- CREATE TABLE t1(a PRIMARY KEY, b);
- CREATE INDEX i1 ON t1(b);
- INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two');
- }
- } {}
- do_test pager1-$tn.2 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
- do_test pager1-$tn.3 { sql3 { SELECT * FROM t1 } } {1 one 2 two}
- # Open a transaction and add a row using [db]. This puts [db] in
- # RESERVED state. Check that connections [db2] and [db3] can still
- # read the database content as it was before the transaction was
- # opened. [db] should see the inserted row.
- #
- do_test pager1-$tn.4 {
- sql1 {
- BEGIN;
- INSERT INTO t1 VALUES(3, 'three');
- }
- } {}
- do_test pager1-$tn.5 { sql2 { SELECT * FROM t1 } } {1 one 2 two}
- do_test pager1-$tn.7 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- # [db] still has an open write transaction. Check that this prevents
- # other connections (specifically [db2]) from writing to the database.
- #
- # Even if [db2] opens a transaction first, it may not write to the
- # database. After the attempt to write the db within a transaction,
- # [db2] is left with an open transaction, but not a read-lock on
- # the main database. So it does not prevent [db] from committing.
- #
- do_test pager1-$tn.8 {
- csql2 { UPDATE t1 SET a = a + 10 }
- } {1 {database is locked}}
- do_test pager1-$tn.9 {
- csql2 {
- BEGIN;
- UPDATE t1 SET a = a + 10;
- }
- } {1 {database is locked}}
- # Have [db] commit its transactions. Check the other connections can
- # now see the new database content.
- #
- do_test pager1-$tn.10 { sql1 { COMMIT } } {}
- do_test pager1-$tn.11 { sql1 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- do_test pager1-$tn.12 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- do_test pager1-$tn.13 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- # Check that, as noted above, [db2] really did keep an open transaction
- # after the attempt to write the database failed.
- #
- do_test pager1-$tn.14 {
- csql2 { BEGIN }
- } {1 {cannot start a transaction within a transaction}}
- do_test pager1-$tn.15 { sql2 { ROLLBACK } } {}
- # Have [db2] open a transaction and take a read-lock on the database.
- # Check that this prevents [db] from writing to the database (outside
- # of any transaction). After this fails, check that [db3] can read
- # the db (showing that [db] did not take a PENDING lock etc.)
- #
- do_test pager1-$tn.15 {
- sql2 { BEGIN; SELECT * FROM t1; }
- } {1 one 2 two 3 three}
- do_test pager1-$tn.16 {
- csql1 { UPDATE t1 SET a = a + 10 }
- } {1 {database is locked}}
- do_test pager1-$tn.17 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- # This time, have [db] open a transaction before writing the database.
- # This works - [db] gets a RESERVED lock which does not conflict with
- # the SHARED lock [db2] is holding.
- #
- do_test pager1-$tn.18 {
- sql1 {
- BEGIN;
- UPDATE t1 SET a = a + 10;
- }
- } {}
- do_test pager1-$tn-19 {
- sql1 { PRAGMA lock_status }
- } {main reserved temp closed}
- do_test pager1-$tn-20 {
- sql2 { PRAGMA lock_status }
- } {main shared temp closed}
- # Check that all connections can still read the database. Only [db] sees
- # the updated content (as the transaction has not been committed yet).
- #
- do_test pager1-$tn.21 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
- do_test pager1-$tn.22 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- do_test pager1-$tn.23 { sql3 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- # Because [db2] still has the SHARED lock, [db] is unable to commit the
- # transaction. If it tries, an error is returned and the connection
- # upgrades to a PENDING lock.
- #
- # Once this happens, [db] can read the database and see the new content,
- # [db2] (still holding SHARED) can still read the old content, but [db3]
- # (not holding any lock) is prevented by [db]'s PENDING from reading
- # the database.
- #
- do_test pager1-$tn.24 { csql1 { COMMIT } } {1 {database is locked}}
- do_test pager1-$tn-25 {
- sql1 { PRAGMA lock_status }
- } {main pending temp closed}
- do_test pager1-$tn.26 { sql1 { SELECT * FROM t1 } } {11 one 12 two 13 three}
- do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {1 one 2 two 3 three}
- do_test pager1-$tn.28 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
- # Have [db2] commit its read transaction, releasing the SHARED lock it
- # is holding. Now, neither [db2] nor [db3] may read the database (as [db]
- # is still holding a PENDING).
- #
- do_test pager1-$tn.29 { sql2 { COMMIT } } {}
- do_test pager1-$tn.30 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
- do_test pager1-$tn.31 { csql3 { SELECT * FROM t1 } } {1 {database is locked}}
- # [db] is now able to commit the transaction. Once the transaction is
- # committed, all three connections can read the new content.
- #
- do_test pager1-$tn.25 { sql1 { UPDATE t1 SET a = a+10 } } {}
- do_test pager1-$tn.26 { sql1 { COMMIT } } {}
- do_test pager1-$tn.27 { sql1 { SELECT * FROM t1 } } {21 one 22 two 23 three}
- do_test pager1-$tn.27 { sql2 { SELECT * FROM t1 } } {21 one 22 two 23 three}
- do_test pager1-$tn.28 { sql3 { SELECT * FROM t1 } } {21 one 22 two 23 three}
- # Install a busy-handler for connection [db].
- #
- set ::nbusy [list]
- proc busy {n} {
- lappend ::nbusy $n
- if {$n>5} { sql2 COMMIT }
- return 0
- }
- db busy busy
- do_test pager1-$tn.29 {
- sql1 { BEGIN ; INSERT INTO t1 VALUES('x', 'y') }
- } {}
- do_test pager1-$tn.30 {
- sql2 { BEGIN ; SELECT * FROM t1 }
- } {21 one 22 two 23 three}
- do_test pager1-$tn.31 { sql1 COMMIT } {}
- do_test pager1-$tn.32 { set ::nbusy } {0 1 2 3 4 5 6}
- }
- #-------------------------------------------------------------------------
- # Savepoint related test cases.
- #
- # pager1-3.1.2.*: Force a savepoint rollback to cause the database file
- # to grow.
- #
- # pager1-3.1.3.*: Use a journal created in synchronous=off mode as part
- # of a savepoint rollback.
- #
- do_test pager1-3.1.1 {
- faultsim_delete_and_reopen
- execsql {
- CREATE TABLE t1(a PRIMARY KEY, b);
- CREATE TABLE counter(
- i CHECK (i<5),
- u CHECK (u<10)
- );
- INSERT INTO counter VALUES(0, 0);
- CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
- UPDATE counter SET i = i+1;
- END;
- CREATE TRIGGER tr2 AFTER UPDATE ON t1 BEGIN
- UPDATE counter SET u = u+1;
- END;
- }
- execsql { SELECT * FROM counter }
- } {0 0}
- do_execsql_test pager1-3.1.2 {
- PRAGMA cache_size = 10;
- BEGIN;
- INSERT INTO t1 VALUES(1, randomblob(1500));
- INSERT INTO t1 VALUES(2, randomblob(1500));
- INSERT INTO t1 VALUES(3, randomblob(1500));
- SELECT * FROM counter;
- } {3 0}
- do_catchsql_test pager1-3.1.3 {
- INSERT INTO t1 SELECT a+3, randomblob(1500) FROM t1
- } {1 {constraint failed}}
- do_execsql_test pager1-3.4 { SELECT * FROM counter } {3 0}
- do_execsql_test pager1-3.5 { SELECT a FROM t1 } {1 2 3}
- do_execsql_test pager1-3.6 { COMMIT } {}
- foreach {tn sql tcl} {
- 7 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 0 } {
- testvfs tv -default 1
- tv devchar safe_append
- }
- 8 { PRAGMA synchronous = NORMAL ; PRAGMA temp_store = 2 } {
- testvfs tv -default 1
- tv devchar sequential
- }
- 9 { PRAGMA synchronous = FULL } { }
- 10 { PRAGMA synchronous = NORMAL } { }
- 11 { PRAGMA synchronous = OFF } { }
- 12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { }
- 13 { PRAGMA synchronous = FULL } {
- testvfs tv -default 1
- tv devchar sequential
- }
- 14 { PRAGMA locking_mode = EXCLUSIVE } {
- }
- } {
- do_test pager1-3.$tn.1 {
- eval $tcl
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql $sql
- execsql {
- PRAGMA auto_vacuum = 2;
- PRAGMA cache_size = 10;
- CREATE TABLE z(x INTEGER PRIMARY KEY, y);
- BEGIN;
- INSERT INTO z VALUES(NULL, a_string(800));
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 2
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 4
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 8
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 16
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 32
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 64
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 128
- INSERT INTO z SELECT NULL, a_string(800) FROM z; -- 256
- COMMIT;
- }
- execsql { PRAGMA auto_vacuum }
- } {2}
- do_execsql_test pager1-3.$tn.2 {
- BEGIN;
- INSERT INTO z VALUES(NULL, a_string(800));
- INSERT INTO z VALUES(NULL, a_string(800));
- SAVEPOINT one;
- UPDATE z SET y = NULL WHERE x>256;
- PRAGMA incremental_vacuum;
- SELECT count(*) FROM z WHERE x < 100;
- ROLLBACK TO one;
- COMMIT;
- } {99}
- do_execsql_test pager1-3.$tn.3 {
- BEGIN;
- SAVEPOINT one;
- UPDATE z SET y = y||x;
- ROLLBACK TO one;
- COMMIT;
- SELECT count(*) FROM z;
- } {258}
- do_execsql_test pager1-3.$tn.4 {
- SAVEPOINT one;
- UPDATE z SET y = y||x;
- ROLLBACK TO one;
- } {}
- do_execsql_test pager1-3.$tn.5 {
- SELECT count(*) FROM z;
- RELEASE one;
- PRAGMA integrity_check;
- } {258 ok}
- do_execsql_test pager1-3.$tn.6 {
- SAVEPOINT one;
- RELEASE one;
- } {}
- db close
- catch { tv delete }
- }
- #-------------------------------------------------------------------------
- # Hot journal rollback related test cases.
- #
- # pager1.4.1.*: Test that the pager module deletes very small invalid
- # journal files.
- #
- # pager1.4.2.*: Test that if the master journal pointer at the end of a
- # hot-journal file appears to be corrupt (checksum does not
- # compute) the associated journal is rolled back (and no
- # xAccess() call to check for the presence of any master
- # journal file is made).
- #
- # pager1.4.3.*: Test that the contents of a hot-journal are ignored if the
- # page-size or sector-size in the journal header appear to
- # be invalid (too large, too small or not a power of 2).
- #
- # pager1.4.4.*: Test hot-journal rollback of journal file with a master
- # journal pointer generated in various "PRAGMA synchronous"
- # modes.
- #
- # pager1.4.5.*: Test that hot-journal rollback stops if it encounters a
- # journal-record for which the checksum fails.
- #
- # pager1.4.6.*: Test that when rolling back a hot-journal that contains a
- # master journal pointer, the master journal file is deleted
- # after all the hot-journals that refer to it are deleted.
- #
- # pager1.4.7.*: Test that if a hot-journal file exists but a client can
- # open it for reading only, the database cannot be accessed and
- # SQLITE_CANTOPEN is returned.
- #
- do_test pager1.4.1.1 {
- faultsim_delete_and_reopen
- execsql {
- CREATE TABLE x(y, z);
- INSERT INTO x VALUES(1, 2);
- }
- set fd [open test.db-journal w]
- puts -nonewline $fd "helloworld"
- close $fd
- file exists test.db-journal
- } {1}
- do_test pager1.4.1.2 { execsql { SELECT * FROM x } } {1 2}
- do_test pager1.4.1.3 { file exists test.db-journal } {0}
- # Set up a [testvfs] to snapshot the file-system just before SQLite
- # deletes the master-journal to commit a multi-file transaction.
- #
- # In subsequent test cases, invoking [faultsim_restore_and_reopen] sets
- # up the file system to contain two databases, two hot-journal files and
- # a master-journal.
- #
- do_test pager1.4.2.1 {
- testvfs tstvfs -default 1
- tstvfs filter xDelete
- tstvfs script xDeleteCallback
- proc xDeleteCallback {method file args} {
- set file [file tail $file]
- if { [string match *mj* $file] } { faultsim_save }
- }
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- ATTACH 'test.db2' AS aux;
- PRAGMA journal_mode = DELETE;
- PRAGMA main.cache_size = 10;
- PRAGMA aux.cache_size = 10;
- CREATE TABLE t1(a UNIQUE, b UNIQUE);
- CREATE TABLE aux.t2(a UNIQUE, b UNIQUE);
- INSERT INTO t1 VALUES(a_string(200), a_string(300));
- INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
- INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
- INSERT INTO t2 SELECT * FROM t1;
- BEGIN;
- INSERT INTO t1 SELECT a_string(201), a_string(301) FROM t1;
- INSERT INTO t1 SELECT a_string(202), a_string(302) FROM t1;
- INSERT INTO t1 SELECT a_string(203), a_string(303) FROM t1;
- INSERT INTO t1 SELECT a_string(204), a_string(304) FROM t1;
- REPLACE INTO t2 SELECT * FROM t1;
- COMMIT;
- }
- db close
- tstvfs delete
- } {}
- if {$::tcl_platform(platform)!="windows"} {
- do_test pager1.4.2.2 {
- faultsim_restore_and_reopen
- execsql {
- SELECT count(*) FROM t1;
- PRAGMA integrity_check;
- }
- } {4 ok}
- do_test pager1.4.2.3 {
- faultsim_restore_and_reopen
- foreach f [glob test.db-mj*] { forcedelete $f }
- execsql {
- SELECT count(*) FROM t1;
- PRAGMA integrity_check;
- }
- } {64 ok}
- do_test pager1.4.2.4 {
- faultsim_restore_and_reopen
- hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
- execsql {
- SELECT count(*) FROM t1;
- PRAGMA integrity_check;
- }
- } {4 ok}
- do_test pager1.4.2.5 {
- faultsim_restore_and_reopen
- hexio_write test.db-journal [expr [file size test.db-journal]-30] 123456
- foreach f [glob test.db-mj*] { forcedelete $f }
- execsql {
- SELECT count(*) FROM t1;
- PRAGMA integrity_check;
- }
- } {4 ok}
- }
- do_test pager1.4.3.1 {
- testvfs tstvfs -default 1
- tstvfs filter xSync
- tstvfs script xSyncCallback
- proc xSyncCallback {method file args} {
- set file [file tail $file]
- if { 0==[string match *journal $file] } { faultsim_save }
- }
- faultsim_delete_and_reopen
- execsql {
- PRAGMA journal_mode = DELETE;
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES(1, 2);
- INSERT INTO t1 VALUES(3, 4);
- }
- db close
- tstvfs delete
- } {}
- foreach {tn ofst value result} {
- 2 20 31 {1 2 3 4}
- 3 20 32 {1 2 3 4}
- 4 20 33 {1 2 3 4}
- 5 20 65536 {1 2 3 4}
- 6 20 131072 {1 2 3 4}
- 7 24 511 {1 2 3 4}
- 8 24 513 {1 2 3 4}
- 9 24 131072 {1 2 3 4}
- 10 32 65536 {1 2}
- } {
- do_test pager1.4.3.$tn {
- faultsim_restore_and_reopen
- hexio_write test.db-journal $ofst [format %.8x $value]
- execsql { SELECT * FROM t1 }
- } $result
- }
- db close
- # Set up a VFS that snapshots the file-system just before a master journal
- # file is deleted to commit a multi-file transaction. Specifically, the
- # file-system is saved just before the xDelete() call to remove the
- # master journal file from the file-system.
- #
- set pwd [get_pwd]
- testvfs tv -default 1
- tv script copy_on_mj_delete
- set ::mj_filename_length 0
- proc copy_on_mj_delete {method filename args} {
- if {[string match *mj* [file tail $filename]]} {
- #
- # NOTE: Is the file name relative? If so, add the length of the current
- # directory.
- #
- if {[is_relative_file $filename]} {
- set ::mj_filename_length \
- [expr {[string length $filename] + [string length $::pwd]}]
- } else {
- set ::mj_filename_length [string length $filename]
- }
- faultsim_save
- }
- return SQLITE_OK
- }
- foreach {tn1 tcl} {
- 1 { set prefix "test.db" }
- 2 {
- # This test depends on the underlying VFS being able to open paths
- # 512 bytes in length. The idea is to create a hot-journal file that
- # contains a master-journal pointer so large that it could contain
- # a valid page record (if the file page-size is 512 bytes). So as to
- # make sure SQLite doesn't get confused by this.
- #
- set nPadding [expr 511 - $::mj_filename_length]
- if {$tcl_platform(platform)=="windows"} {
- # TBD need to figure out how to do this correctly for Windows!!!
- set nPadding [expr 255 - $::mj_filename_length]
- }
- # We cannot just create a really long database file name to open, as
- # Linux limits a single component of a path to 255 bytes by default
- # (and presumably other systems have limits too). So create a directory
- # hierarchy to work in.
- #
- set dirname "d123456789012345678901234567890/"
- set nDir [expr $nPadding / 32]
- if { $nDir } {
- set p [string repeat $dirname $nDir]
- file mkdir $p
- cd $p
- }
- set padding [string repeat x [expr $nPadding %32]]
- set prefix "test.db${padding}"
- }
- } {
- eval $tcl
- foreach {tn2 sql} {
- o {
- PRAGMA main.synchronous=OFF;
- PRAGMA aux.synchronous=OFF;
- PRAGMA journal_mode = DELETE;
- }
- o512 {
- PRAGMA main.synchronous=OFF;
- PRAGMA aux.synchronous=OFF;
- PRAGMA main.page_size = 512;
- PRAGMA aux.page_size = 512;
- PRAGMA journal_mode = DELETE;
- }
- n {
- PRAGMA main.synchronous=NORMAL;
- PRAGMA aux.synchronous=NORMAL;
- PRAGMA journal_mode = DELETE;
- }
- f {
- PRAGMA main.synchronous=FULL;
- PRAGMA aux.synchronous=FULL;
- PRAGMA journal_mode = DELETE;
- }
- } {
- set tn "${tn1}.${tn2}"
-
- # Set up a connection to have two databases, test.db (main) and
- # test.db2 (aux). Then run a multi-file transaction on them. The
- # VFS will snapshot the file-system just before the master-journal
- # file is deleted to commit the transaction.
- #
- tv filter xDelete
- do_test pager1-4.4.$tn.1 {
- faultsim_delete_and_reopen $prefix
- execsql "
- ATTACH '${prefix}2' AS aux;
- $sql
- CREATE TABLE a(x);
- CREATE TABLE aux.b(x);
- INSERT INTO a VALUES('double-you');
- INSERT INTO a VALUES('why');
- INSERT INTO a VALUES('zed');
- INSERT INTO b VALUES('won');
- INSERT INTO b VALUES('too');
- INSERT INTO b VALUES('free');
- "
- execsql {
- BEGIN;
- INSERT INTO a SELECT * FROM b WHERE rowid<=3;
- INSERT INTO b SELECT * FROM a WHERE rowid<=3;
- COMMIT;
- }
- } {}
- tv filter {}
-
- # Check that the transaction was committed successfully.
- #
- do_execsql_test pager1-4.4.$tn.2 {
- SELECT * FROM a
- } {double-you why zed won too free}
- do_execsql_test pager1-4.4.$tn.3 {
- SELECT * FROM b
- } {won too free double-you why zed}
-
- # Restore the file-system and reopen the databases. Check that it now
- # appears that the transaction was not committed (because the file-system
- # was restored to the state where it had not been).
- #
- do_test pager1-4.4.$tn.4 {
- faultsim_restore_and_reopen $prefix
- execsql "ATTACH '${prefix}2' AS aux"
- } {}
- do_execsql_test pager1-4.4.$tn.5 {SELECT * FROM a} {double-you why zed}
- do_execsql_test pager1-4.4.$tn.6 {SELECT * FROM b} {won too free}
-
- # Restore the file-system again. This time, before reopening the databases,
- # delete the master-journal file from the file-system. It now appears that
- # the transaction was committed (no master-journal file == no rollback).
- #
- do_test pager1-4.4.$tn.7 {
- faultsim_restore_and_reopen $prefix
- foreach f [glob ${prefix}-mj*] { forcedelete $f }
- execsql "ATTACH '${prefix}2' AS aux"
- } {}
- do_execsql_test pager1-4.4.$tn.8 {
- SELECT * FROM a
- } {double-you why zed won too free}
- do_execsql_test pager1-4.4.$tn.9 {
- SELECT * FROM b
- } {won too free double-you why zed}
- }
- cd $pwd
- }
- db close
- tv delete
- forcedelete $dirname
- # Set up a VFS to make a copy of the file-system just before deleting a
- # journal file to commit a transaction. The transaction modifies exactly
- # two database pages (and page 1 - the change counter).
- #
- testvfs tv -default 1
- tv sectorsize 512
- tv script copy_on_journal_delete
- tv filter xDelete
- proc copy_on_journal_delete {method filename args} {
- if {[string match *journal $filename]} faultsim_save
- return SQLITE_OK
- }
- faultsim_delete_and_reopen
- do_execsql_test pager1.4.5.1 {
- PRAGMA journal_mode = DELETE;
- PRAGMA page_size = 1024;
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(a, b);
- INSERT INTO t1 VALUES('I', 'II');
- INSERT INTO t2 VALUES('III', 'IV');
- BEGIN;
- INSERT INTO t1 VALUES(1, 2);
- INSERT INTO t2 VALUES(3, 4);
- COMMIT;
- } {delete}
- tv filter {}
- # Check the transaction was committed:
- #
- do_execsql_test pager1.4.5.2 {
- SELECT * FROM t1;
- SELECT * FROM t2;
- } {I II 1 2 III IV 3 4}
- # Now try four tests:
- #
- # pager1-4.5.3: Restore the file-system. Check that the whole transaction
- # is rolled back.
- #
- # pager1-4.5.4: Restore the file-system. Corrupt the first record in the
- # journal. Check the transaction is not rolled back.
- #
- # pager1-4.5.5: Restore the file-system. Corrupt the second record in the
- # journal. Check that the first record in the transaction is
- # played back, but not the second.
- #
- # pager1-4.5.6: Restore the file-system. Try to open the database with a
- # readonly connection. This should fail, as a read-only
- # connection cannot roll back the database file.
- #
- faultsim_restore_and_reopen
- do_execsql_test pager1.4.5.3 {
- SELECT * FROM t1;
- SELECT * FROM t2;
- } {I II III IV}
- faultsim_restore_and_reopen
- hexio_write test.db-journal [expr 512+4+1024 - 202] 0123456789ABCDEF
- do_execsql_test pager1.4.5.4 {
- SELECT * FROM t1;
- SELECT * FROM t2;
- } {I II 1 2 III IV 3 4}
- faultsim_restore_and_reopen
- hexio_write test.db-journal [expr 512+4+1024+4+4+1024 - 202] 0123456789ABCDEF
- do_execsql_test pager1.4.5.5 {
- SELECT * FROM t1;
- SELECT * FROM t2;
- } {I II III IV 3 4}
- faultsim_restore_and_reopen
- db close
- sqlite3 db test.db -readonly 1
- do_catchsql_test pager1.4.5.6 {
- SELECT * FROM t1;
- SELECT * FROM t2;
- } {1 {attempt to write a readonly database}}
- db close
- # Snapshot the file-system just before multi-file commit. Save the name
- # of the master journal file in $::mj_filename.
- #
- tv script copy_on_mj_delete
- tv filter xDelete
- proc copy_on_mj_delete {method filename args} {
- if {[string match *mj* [file tail $filename]]} {
- set ::mj_filename $filename
- faultsim_save
- }
- return SQLITE_OK
- }
- do_test pager1.4.6.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA journal_mode = DELETE;
- ATTACH 'test.db2' AS two;
- CREATE TABLE t1(a, b);
- CREATE TABLE two.t2(a, b);
- INSERT INTO t1 VALUES(1, 't1.1');
- INSERT INTO t2 VALUES(1, 't2.1');
- BEGIN;
- UPDATE t1 SET b = 't1.2';
- UPDATE t2 SET b = 't2.2';
- COMMIT;
- }
- tv filter {}
- db close
- } {}
- faultsim_restore_and_reopen
- do_execsql_test pager1.4.6.2 { SELECT * FROM t1 } {1 t1.1}
- do_test pager1.4.6.3 { file exists $::mj_filename } {1}
- do_execsql_test pager1.4.6.4 {
- ATTACH 'test.db2' AS two;
- SELECT * FROM t2;
- } {1 t2.1}
- do_test pager1.4.6.5 { file exists $::mj_filename } {0}
- faultsim_restore_and_reopen
- db close
- do_test pager1.4.6.8 {
- set ::mj_filename1 $::mj_filename
- tv filter xDelete
- sqlite3 db test.db2
- execsql {
- PRAGMA journal_mode = DELETE;
- ATTACH 'test.db3' AS three;
- CREATE TABLE three.t3(a, b);
- INSERT INTO t3 VALUES(1, 't3.1');
- BEGIN;
- UPDATE t2 SET b = 't2.3';
- UPDATE t3 SET b = 't3.3';
- COMMIT;
- }
- expr {$::mj_filename1 != $::mj_filename}
- } {1}
- faultsim_restore_and_reopen
- tv filter {}
- # The file-system now contains:
- #
- # * three databases
- # * three hot-journal files
- # * two master-journal files.
- #
- # The hot-journals associated with test.db2 and test.db3 point to
- # master journal $::mj_filename. The hot-journal file associated with
- # test.db points to master journal $::mj_filename1. So reading from
- # test.db should delete $::mj_filename1.
- #
- do_test pager1.4.6.9 {
- lsort [glob test.db*]
- } [lsort [list \
- test.db test.db2 test.db3 \
- test.db-journal test.db2-journal test.db3-journal \
- [file tail $::mj_filename] [file tail $::mj_filename1]
- ]]
- # The master-journal $::mj_filename1 contains pointers to test.db and
- # test.db2. However the hot-journal associated with test.db2 points to
- # a different master-journal. Therefore, reading from test.db only should
- # be enough to cause SQLite to delete $::mj_filename1.
- #
- do_test pager1.4.6.10 { file exists $::mj_filename } {1}
- do_test pager1.4.6.11 { file exists $::mj_filename1 } {1}
- do_execsql_test pager1.4.6.12 { SELECT * FROM t1 } {1 t1.1}
- do_test pager1.4.6.13 { file exists $::mj_filename } {1}
- do_test pager1.4.6.14 { file exists $::mj_filename1 } {0}
- do_execsql_test pager1.4.6.12 {
- ATTACH 'test.db2' AS two;
- SELECT * FROM t2;
- } {1 t2.1}
- do_test pager1.4.6.13 { file exists $::mj_filename } {1}
- do_execsql_test pager1.4.6.14 {
- ATTACH 'test.db3' AS three;
- SELECT * FROM t3;
- } {1 t3.1}
- do_test pager1.4.6.15 { file exists $::mj_filename } {0}
- db close
- tv delete
- testvfs tv -default 1
- tv sectorsize 512
- tv script copy_on_journal_delete
- tv filter xDelete
- proc copy_on_journal_delete {method filename args} {
- if {[string match *journal $filename]} faultsim_save
- return SQLITE_OK
- }
- faultsim_delete_and_reopen
- do_execsql_test pager1.4.7.1 {
- PRAGMA journal_mode = DELETE;
- CREATE TABLE t1(x PRIMARY KEY, y);
- CREATE INDEX i1 ON t1(y);
- INSERT INTO t1 VALUES('I', 'one');
- INSERT INTO t1 VALUES('II', 'four');
- INSERT INTO t1 VALUES('III', 'nine');
- BEGIN;
- INSERT INTO t1 VALUES('IV', 'sixteen');
- INSERT INTO t1 VALUES('V' , 'twentyfive');
- COMMIT;
- } {delete}
- tv filter {}
- db close
- tv delete
- catch {
- test_syscall install fchmod
- test_syscall fault 1 1
- }
- do_test pager1.4.7.2 {
- faultsim_restore_and_reopen
- catch {file attributes test.db-journal -permissions r--------}
- catch {file attributes test.db-journal -readonly 1}
- catchsql { SELECT * FROM t1 }
- } {1 {unable to open database file}}
- catch {
- test_syscall reset
- test_syscall fault 0 0
- }
- do_test pager1.4.7.3 {
- db close
- catch {file attributes test.db-journal -permissions rw-rw-rw-}
- catch {file attributes test.db-journal -readonly 0}
- delete_file test.db-journal
- file exists test.db-journal
- } {0}
- do_test pager1.4.8.1 {
- catch {file attributes test.db -permissions r--------}
- catch {file attributes test.db -readonly 1}
- sqlite3 db test.db
- db eval { SELECT * FROM t1 }
- sqlite3_db_readonly db main
- } {1}
- do_test pager1.4.8.2 {
- sqlite3_db_readonly db xyz
- } {-1}
- do_test pager1.4.8.3 {
- db close
- catch {file attributes test.db -readonly 0}
- catch {file attributes test.db -permissions rw-rw-rw-} msg
- sqlite3 db test.db
- db eval { SELECT * FROM t1 }
- sqlite3_db_readonly db main
- } {0}
- #-------------------------------------------------------------------------
- # The following tests deal with multi-file commits.
- #
- # pager1-5.1.*: The case where a multi-file cannot be committed because
- # another connection is holding a SHARED lock on one of the
- # files. After the SHARED lock is removed, the COMMIT succeeds.
- #
- # pager1-5.2.*: Multi-file commits with journal_mode=memory.
- #
- # pager1-5.3.*: Multi-file commits with journal_mode=memory.
- #
- # pager1-5.4.*: Check that with synchronous=normal, the master-journal file
- # name is added to a journal file immediately after the last
- # journal record. But with synchronous=full, extra unused space
- # is allocated between the last journal record and the
- # master-journal file name so that the master-journal file
- # name does not lie on the same sector as the last journal file
- # record.
- #
- # pager1-5.5.*: Check that in journal_mode=PERSIST mode, a journal file is
- # truncated to zero bytes when a multi-file transaction is
- # committed (instead of the first couple of bytes being zeroed).
- #
- #
- do_test pager1-5.1.1 {
- faultsim_delete_and_reopen
- execsql {
- ATTACH 'test.db2' AS aux;
- CREATE TABLE t1(a, b);
- CREATE TABLE aux.t2(a, b);
- INSERT INTO t1 VALUES(17, 'Lenin');
- INSERT INTO t1 VALUES(22, 'Stalin');
- INSERT INTO t1 VALUES(53, 'Khrushchev');
- }
- } {}
- do_test pager1-5.1.2 {
- execsql {
- BEGIN;
- INSERT INTO t1 VALUES(64, 'Brezhnev');
- INSERT INTO t2 SELECT * FROM t1;
- }
- sqlite3 db2 test.db2
- execsql {
- BEGIN;
- SELECT * FROM t2;
- } db2
- } {}
- do_test pager1-5.1.3 {
- catchsql COMMIT
- } {1 {database is locked}}
- do_test pager1-5.1.4 {
- execsql COMMIT db2
- execsql COMMIT
- execsql { SELECT * FROM t2 } db2
- } {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
- do_test pager1-5.1.5 {
- db2 close
- } {}
- do_test pager1-5.2.1 {
- execsql {
- PRAGMA journal_mode = memory;
- BEGIN;
- INSERT INTO t1 VALUES(84, 'Andropov');
- INSERT INTO t2 VALUES(84, 'Andropov');
- COMMIT;
- }
- } {memory}
- do_test pager1-5.3.1 {
- execsql {
- PRAGMA journal_mode = off;
- BEGIN;
- INSERT INTO t1 VALUES(85, 'Gorbachev');
- INSERT INTO t2 VALUES(85, 'Gorbachev');
- COMMIT;
- }
- } {off}
- do_test pager1-5.4.1 {
- db close
- testvfs tv
- sqlite3 db test.db -vfs tv
- execsql { ATTACH 'test.db2' AS aux }
- tv filter xDelete
- tv script max_journal_size
- tv sectorsize 512
- set ::max_journal 0
- proc max_journal_size {method args} {
- set sz 0
- catch { set sz [file size test.db-journal] }
- if {$sz > $::max_journal} {
- set ::max_journal $sz
- }
- return SQLITE_OK
- }
- execsql {
- PRAGMA journal_mode = DELETE;
- PRAGMA synchronous = NORMAL;
- BEGIN;
- INSERT INTO t1 VALUES(85, 'Gorbachev');
- INSERT INTO t2 VALUES(85, 'Gorbachev');
- COMMIT;
- }
- # The size of the journal file is now:
- #
- # 1) 512 byte header +
- # 2) 2 * (1024+8) byte records +
- # 3) 20+N bytes of master-journal pointer, where N is the size of
- # the master-journal name encoded as utf-8 with no nul term.
- #
- set mj_pointer [expr {
- 20 + [string length "test.db-mjXXXXXX9XX"]
- }]
- #
- # NOTE: For item 3 above, if the current SQLite VFS lacks the concept of a
- # current directory, the length of the current directory name plus 1
- # character for the directory separator character are NOT counted as
- # part of the total size; otherwise, they are.
- #
- ifcapable curdir {
- set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
- }
- expr {$::max_journal==(512+2*(1024+8)+$mj_pointer)}
- } 1
- do_test pager1-5.4.2 {
- set ::max_journal 0
- execsql {
- PRAGMA synchronous = full;
- BEGIN;
- DELETE FROM t1 WHERE b = 'Lenin';
- DELETE FROM t2 WHERE b = 'Lenin';
- COMMIT;
- }
- # In synchronous=full mode, the master-journal pointer is not written
- # directly after the last record in the journal file. Instead, it is
- # written starting at the next (in this case 512 byte) sector boundary.
- #
- set mj_pointer [expr {
- 20 + [string length "test.db-mjXXXXXX9XX"]
- }]
- #
- # NOTE: If the current SQLite VFS lacks the concept of a current directory,
- # the length of the current directory name plus 1 character for the
- # directory separator character are NOT counted as part of the total
- # size; otherwise, they are.
- #
- ifcapable curdir {
- set mj_pointer [expr {$mj_pointer + [string length [get_pwd]] + 1}]
- }
- expr {$::max_journal==(((512+2*(1024+8)+511)/512)*512 + $mj_pointer)}
- } 1
- db close
- tv delete
- do_test pager1-5.5.1 {
- sqlite3 db test.db
- execsql {
- ATTACH 'test.db2' AS aux;
- PRAGMA journal_mode = PERSIST;
- CREATE TABLE t3(a, b);
- INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
- UPDATE t3 SET b = randomblob(1500);
- }
- expr [file size test.db-journal] > 15000
- } {1}
- do_test pager1-5.5.2 {
- execsql {
- PRAGMA synchronous = full;
- BEGIN;
- DELETE FROM t1 WHERE b = 'Stalin';
- DELETE FROM t2 WHERE b = 'Stalin';
- COMMIT;
- }
- file size test.db-journal
- } {0}
- #-------------------------------------------------------------------------
- # The following tests work with "PRAGMA max_page_count"
- #
- do_test pager1-6.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA auto_vacuum = none;
- PRAGMA max_page_count = 10;
- CREATE TABLE t2(a, b);
- CREATE TABLE t3(a, b);
- CREATE TABLE t4(a, b);
- CREATE TABLE t5(a, b);
- CREATE TABLE t6(a, b);
- CREATE TABLE t7(a, b);
- CREATE TABLE t8(a, b);
- CREATE TABLE t9(a, b);
- CREATE TABLE t10(a, b);
- }
- } {10}
- do_catchsql_test pager1-6.2 {
- CREATE TABLE t11(a, b)
- } {1 {database or disk is full}}
- do_execsql_test pager1-6.4 { PRAGMA max_page_count } {10}
- do_execsql_test pager1-6.5 { PRAGMA max_page_count = 15 } {15}
- do_execsql_test pager1-6.6 { CREATE TABLE t11(a, b) } {}
- do_execsql_test pager1-6.7 {
- BEGIN;
- INSERT INTO t11 VALUES(1, 2);
- PRAGMA max_page_count = 13;
- } {13}
- do_execsql_test pager1-6.8 {
- INSERT INTO t11 VALUES(3, 4);
- PRAGMA max_page_count = 10;
- } {11}
- do_execsql_test pager1-6.9 { COMMIT } {}
- do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
- do_execsql_test pager1-6.11 { SELECT * FROM t11 } {1 2 3 4}
- do_execsql_test pager1-6.12 { PRAGMA max_page_count } {11}
- #-------------------------------------------------------------------------
- # The following tests work with "PRAGMA journal_mode=TRUNCATE" and
- # "PRAGMA locking_mode=EXCLUSIVE".
- #
- # Each test is specified with 5 variables. As follows:
- #
- # $tn: Test Number. Used as part of the [do_test] test names.
- # $sql: SQL to execute.
- # $res: Expected result of executing $sql.
- # $js: The expected size of the journal file, in bytes, after executing
- # the SQL script. Or -1 if the journal is not expected to exist.
- # $ws: The expected size of the WAL file, in bytes, after executing
- # the SQL script. Or -1 if the WAL is not expected to exist.
- #
- ifcapable wal {
- faultsim_delete_and_reopen
- foreach {tn sql res js ws} [subst {
-
- 1 {
- CREATE TABLE t1(a, b);
- PRAGMA auto_vacuum=OFF;
- PRAGMA synchronous=NORMAL;
- PRAGMA page_size=1024;
- PRAGMA locking_mode=EXCLUSIVE;
- PRAGMA journal_mode=TRUNCATE;
- INSERT INTO t1 VALUES(1, 2);
- } {exclusive truncate} 0 -1
-
- 2 {
- BEGIN IMMEDIATE;
- SELECT * FROM t1;
- COMMIT;
- } {1 2} 0 -1
-
- 3 {
- BEGIN;
- SELECT * FROM t1;
- COMMIT;
- } {1 2} 0 -1
-
- 4 { PRAGMA journal_mode = WAL } wal -1 -1
- 5 { INSERT INTO t1 VALUES(3, 4) } {} -1 [wal_file_size 1 1024]
- 6 { PRAGMA locking_mode = NORMAL } exclusive -1 [wal_file_size 1 1024]
- 7 { INSERT INTO t1 VALUES(5, 6); } {} -1 [wal_file_size 2 1024]
-
- 8 { PRAGMA journal_mode = TRUNCATE } truncate 0 -1
- 9 { INSERT INTO t1 VALUES(7, 8) } {} 0 -1
- 10 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8} 0 -1
-
- }] {
- do_execsql_test pager1-7.1.$tn.1 $sql $res
- catch { set J -1 ; set J [file size test.db-journal] }
- catch { set W -1 ; set W [file size test.db-wal] }
- do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
- }
- }
- do_test pager1-7.2.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA locking_mode = EXCLUSIVE;
- CREATE TABLE t1(a, b);
- BEGIN;
- PRAGMA journal_mode = delete;
- PRAGMA journal_mode = truncate;
- }
- } {exclusive delete truncate}
- do_test pager1-7.2.2 {
- execsql { INSERT INTO t1 VALUES(1, 2) }
- execsql { PRAGMA journal_mode = persist }
- } {truncate}
- do_test pager1-7.2.3 {
- execsql { COMMIT }
- execsql {
- PRAGMA journal_mode = persist;
- PRAGMA journal_size_limit;
- }
- } {persist -1}
- #-------------------------------------------------------------------------
- # The following tests, pager1-8.*, test that the special filenames
- # ":memory:" and "" open temporary databases.
- #
- foreach {tn filename} {
- 1 :memory:
- 2 ""
- } {
- do_test pager1-8.$tn.1 {
- faultsim_delete_and_reopen
- db close
- sqlite3 db $filename
- execsql {
- PRAGMA auto_vacuum = 1;
- CREATE TABLE x1(x);
- INSERT INTO x1 VALUES('Charles');
- INSERT INTO x1 VALUES('James');
- INSERT INTO x1 VALUES('Mary');
- SELECT * FROM x1;
- }
- } {Charles James Mary}
- do_test pager1-8.$tn.2 {
- sqlite3 db2 $filename
- catchsql { SELECT * FROM x1 } db2
- } {1 {no such table: x1}}
- do_execsql_test pager1-8.$tn.3 {
- BEGIN;
- INSERT INTO x1 VALUES('William');
- INSERT INTO x1 VALUES('Anne');
- ROLLBACK;
- } {}
- }
- #-------------------------------------------------------------------------
- # The next block of tests - pager1-9.* - deal with interactions between
- # the pager and the backup API. Test cases:
- #
- # pager1-9.1.*: Test that a backup completes successfully even if the
- # source db is written to during the backup op.
- #
- # pager1-9.2.*: Test that a backup completes successfully even if the
- # source db is written to and then rolled back during a
- # backup operation.
- #
- do_test pager1-9.0.1 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA cache_size = 10;
- BEGIN;
- CREATE TABLE ab(a, b, UNIQUE(a, b));
- INSERT INTO ab VALUES( a_string(200), a_string(300) );
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- INSERT INTO ab SELECT a_string(200), a_string(300) FROM ab;
- COMMIT;
- }
- } {}
- do_test pager1-9.0.2 {
- sqlite3 db2 test.db2
- db2 eval { PRAGMA cache_size = 10 }
- sqlite3_backup B db2 main db main
- list [B step 10000] [B finish]
- } {SQLITE_DONE SQLITE_OK}
- do_test pager1-9.0.3 {
- db one {SELECT md5sum(a, b) FROM ab}
- } [db2 one {SELECT md5sum(a, b) FROM ab}]
- do_test pager1-9.1.1 {
- execsql { UPDATE ab SET a = a_string(201) }
- sqlite3_backup B db2 main db main
- B step 30
- } {SQLITE_OK}
- do_test pager1-9.1.2 {
- execsql { UPDATE ab SET b = a_string(301) }
- list [B step 10000] [B finish]
- } {SQLITE_DONE SQLITE_OK}
- do_test pager1-9.1.3 {
- db one {SELECT md5sum(a, b) FROM ab}
- } [db2 one {SELECT md5sum(a, b) FROM ab}]
- do_test pager1-9.1.4 { execsql { SELECT count(*) FROM ab } } {128}
- do_test pager1-9.2.1 {
- execsql { UPDATE ab SET a = a_string(202) }
- sqlite3_backup B db2 main db main
- B step 30
- } {SQLITE_OK}
- do_test pager1-9.2.2 {
- execsql {
- BEGIN;
- UPDATE ab SET b = a_string(301);
- ROLLBACK;
- }
- list [B step 10000] [B finish]
- } {SQLITE_DONE SQLITE_OK}
- do_test pager1-9.2.3 {
- db one {SELECT md5sum(a, b) FROM ab}
- } [db2 one {SELECT md5sum(a, b) FROM ab}]
- do_test pager1-9.2.4 { execsql { SELECT count(*) FROM ab } } {128}
- db close
- db2 close
- do_test pager1-9.3.1 {
- testvfs tv -default 1
- tv sectorsize 4096
- faultsim_delete_and_reopen
- execsql { PRAGMA page_size = 1024 }
- for {set ii 0} {$ii < 4} {incr ii} { execsql "CREATE TABLE t${ii}(a, b)" }
- } {}
- do_test pager1-9.3.2 {
- sqlite3 db2 test.db2
- execsql {
- PRAGMA page_size = 4096;
- PRAGMA synchronous = OFF;
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(a, b);
- } db2
- sqlite3_backup B db2 main db main
- B step 30
- list [B step 10000] [B finish]
- } {SQLITE_DONE SQLITE_OK}
- do_test pager1-9.3.3 {
- db2 close
- db close
- tv delete
- file size test.db2
- } [file size test.db]
- do_test pager1-9.4.1 {
- faultsim_delete_and_reopen
- sqlite3 db2 test.db2
- execsql {
- PRAGMA page_size = 4096;
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(a, b);
- } db2
- sqlite3_backup B db2 main db main
- list [B step 10000] [B finish]
- } {SQLITE_DONE SQLITE_OK}
- do_test pager1-9.4.2 {
- list [file size test.db2] [file size test.db]
- } {1024 0}
- db2 close
- #-------------------------------------------------------------------------
- # Test that regardless of the value returned by xSectorSize(), the
- # minimum effective sector-size is 512 and the maximum 65536 bytes.
- #
- testvfs tv -default 1
- foreach sectorsize {
- 16
- 32 64 128 256 512 1024 2048
- 4096 8192 16384 32768 65536 131072 262144
- } {
- tv sectorsize $sectorsize
- tv devchar {}
- set eff $sectorsize
- if {$sectorsize < 512} { set eff 512 }
- if {$sectorsize > 65536} { set eff 65536 }
- do_test pager1-10.$sectorsize.1 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA journal_mode = PERSIST;
- PRAGMA page_size = 1024;
- BEGIN;
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(a, b);
- CREATE TABLE t3(a, b);
- COMMIT;
- }
- file size test.db-journal
- } [expr $sectorsize > 65536 ? 65536 : ($sectorsize<32 ? 512 : $sectorsize)]
- do_test pager1-10.$sectorsize.2 {
- execsql {
- INSERT INTO t3 VALUES(a_string(300), a_string(300));
- INSERT INTO t3 SELECT * FROM t3; /* 2 */
- INSERT INTO t3 SELECT * FROM t3; /* 4 */
- INSERT INTO t3 SELECT * FROM t3; /* 8 */
- INSERT INTO t3 SELECT * FROM t3; /* 16 */
- INSERT INTO t3 SELECT * FROM t3; /* 32 */
- }
- } {}
- do_test pager1-10.$sectorsize.3 {
- db close
- sqlite3 db test.db
- execsql {
- PRAGMA cache_size = 10;
- BEGIN;
- }
- recursive_select 32 t3 {db eval "INSERT INTO t2 VALUES(1, 2)"}
- execsql {
- COMMIT;
- SELECT * FROM t2;
- }
- } {1 2}
- do_test pager1-10.$sectorsize.4 {
- execsql {
- CREATE TABLE t6(a, b);
- CREATE TABLE t7(a, b);
- CREATE TABLE t5(a, b);
- DROP TABLE t6;
- DROP TABLE t7;
- }
- execsql {
- BEGIN;
- CREATE TABLE t6(a, b);
- }
- recursive_select 32 t3 {db eval "INSERT INTO t5 VALUES(1, 2)"}
- execsql {
- COMMIT;
- SELECT * FROM t5;
- }
- } {1 2}
-
- }
- db close
- tv sectorsize 4096
- do_test pager1.10.x.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA auto_vacuum = none;
- PRAGMA page_size = 1024;
- CREATE TABLE t1(x);
- }
- for {set i 0} {$i<30} {incr i} {
- execsql { INSERT INTO t1 VALUES(zeroblob(900)) }
- }
- file size test.db
- } {32768}
- do_test pager1.10.x.2 {
- execsql {
- CREATE TABLE t2(x);
- DROP TABLE t2;
- }
- file size test.db
- } {33792}
- do_test pager1.10.x.3 {
- execsql {
- BEGIN;
- CREATE TABLE t2(x);
- }
- recursive_select 30 t1
- execsql {
- CREATE TABLE t3(x);
- COMMIT;
- }
- } {}
- db close
- tv delete
- testvfs tv -default 1
- faultsim_delete_and_reopen
- db func a_string a_string
- do_execsql_test pager1-11.1 {
- PRAGMA journal_mode = DELETE;
- PRAGMA cache_size = 10;
- BEGIN;
- CREATE TABLE zz(top PRIMARY KEY);
- INSERT INTO zz VALUES(a_string(222));
- INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
- INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
- INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
- INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
- INSERT INTO zz SELECT a_string((SELECT 222+max(rowid) FROM zz)) FROM zz;
- COMMIT;
- BEGIN;
- UPDATE zz SET top = a_string(345);
- } {delete}
- proc lockout {method args} { return SQLITE_IOERR }
- tv script lockout
- tv filter {xWrite xTruncate xSync}
- do_catchsql_test pager1-11.2 { COMMIT } {1 {disk I/O error}}
- tv script {}
- do_test pager1-11.3 {
- sqlite3 db2 test.db
- execsql {
- PRAGMA journal_mode = TRUNCATE;
- PRAGMA integrity_check;
- } db2
- } {truncate ok}
- do_test pager1-11.4 {
- db2 close
- file exists test.db-journal
- } {0}
- do_execsql_test pager1-11.5 { SELECT count(*) FROM zz } {32}
- db close
- tv delete
-
- #-------------------------------------------------------------------------
- # Test "PRAGMA page_size"
- #
- testvfs tv -default 1
- tv sectorsize 1024
- foreach pagesize {
- 512 1024 2048 4096 8192 16384 32768
- } {
- faultsim_delete_and_reopen
- # The sector-size (according to the VFS) is 1024 bytes. So if the
- # page-size requested using "PRAGMA page_size" is greater than the
- # compile time value of SQLITE_MAX_PAGE_SIZE, then the effective
- # page-size remains 1024 bytes.
- #
- set eff $pagesize
- if {$eff > $::SQLITE_MAX_PAGE_SIZE} { set eff 1024 }
- do_test pager1-12.$pagesize.1 {
- sqlite3 db2 test.db
- execsql "
- PRAGMA page_size = $pagesize;
- CREATE VIEW v AS SELECT * FROM sqlite_master;
- " db2
- file size test.db
- } $eff
- do_test pager1-12.$pagesize.2 {
- sqlite3 db2 test.db
- execsql {
- SELECT count(*) FROM v;
- PRAGMA main.page_size;
- } db2
- } [list 1 $eff]
- do_test pager1-12.$pagesize.3 {
- execsql {
- SELECT count(*) FROM v;
- PRAGMA main.page_size;
- }
- } [list 1 $eff]
- db2 close
- }
- db close
- tv delete
- #-------------------------------------------------------------------------
- # Test specal "PRAGMA journal_mode=PERSIST" test cases.
- #
- # pager1-13.1.*: This tests a special case encountered in persistent
- # journal mode: If the journal associated with a transaction
- # is smaller than the journal file (because a previous
- # transaction left a very large non-hot journal file in the
- # file-system), then SQLite has to be careful that there is
- # not a journal-header left over from a previous transaction
- # immediately following the journal content just written.
- # If there is, and the process crashes so that the journal
- # becomes a hot-journal and must be rolled back by another
- # process, there is a danger that the other process may roll
- # back the aborted transaction, then continue copying data
- # from an older transaction from the remainder of the journal.
- # See the syncJournal() function for details.
- #
- # pager1-13.2.*: Same test as the previous. This time, throw an index into
- # the mix to make the integrity-check more likely to catch
- # errors.
- #
- testvfs tv -default 1
- tv script xSyncCb
- tv filter xSync
- proc xSyncCb {method filename args} {
- set t [file tail $filename]
- if {$t == "test.db"} faultsim_save
- return SQLITE_OK
- }
- faultsim_delete_and_reopen
- db func a_string a_string
- # The UPDATE statement at the end of this test case creates a really big
- # journal. Since the cache-size is only 10 pages, the journal contains
- # frequent journal headers.
- #
- do_execsql_test pager1-13.1.1 {
- PRAGMA page_size = 1024;
- PRAGMA journal_mode = PERSIST;
- PRAGMA cache_size = 10;
- BEGIN;
- CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
- INSERT INTO t1 VALUES(NULL, a_string(400));
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 2 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 4 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 8 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 16 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 32 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 64 */
- INSERT INTO t1 SELECT NULL, a_string(400) FROM t1; /* 128 */
- COMMIT;
- UPDATE t1 SET b = a_string(400);
- } {persist}
- if {$::tcl_platform(platform)!="windows"} {
- # Run transactions of increasing sizes. Eventually, one (or more than one)
- # of these will write just enough content that one of the old headers created
- # by the transaction in the block above lies immediately after the content
- # journalled by the current transaction.
- #
- for {set nUp 1} {$nUp<64} {incr nUp} {
- do_execsql_test pager1-13.1.2.$nUp.1 {
- UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
- } {}
- do_execsql_test pager1-13.1.2.$nUp.2 { PRAGMA integrity_check } {ok}
- # Try to access the snapshot of the file-system.
- #
- sqlite3 db2 sv_test.db
- do_test pager1-13.1.2.$nUp.3 {
- execsql { SELECT sum(length(b)) FROM t1 } db2
- } [expr {128*400 - ($nUp-1)}]
- do_test pager1-13.1.2.$nUp.4 {
- execsql { PRAGMA integrity_check } db2
- } {ok}
- db2 close
- }
- }
- if {$::tcl_platform(platform)!="windows"} {
- # Same test as above. But this time with an index on the table.
- #
- do_execsql_test pager1-13.2.1 {
- CREATE INDEX i1 ON t1(b);
- UPDATE t1 SET b = a_string(400);
- } {}
- for {set nUp 1} {$nUp<64} {incr nUp} {
- do_execsql_test pager1-13.2.2.$nUp.1 {
- UPDATE t1 SET b = a_string(399) WHERE a <= $nUp
- } {}
- do_execsql_test pager1-13.2.2.$nUp.2 { PRAGMA integrity_check } {ok}
- sqlite3 db2 sv_test.db
- do_test pager1-13.2.2.$nUp.3 {
- execsql { SELECT sum(length(b)) FROM t1 } db2
- } [expr {128*400 - ($nUp-1)}]
- do_test pager1-13.2.2.$nUp.4 {
- execsql { PRAGMA integrity_check } db2
- } {ok}
- db2 close
- }
- }
- db close
- tv delete
- #-------------------------------------------------------------------------
- # Test specal "PRAGMA journal_mode=OFF" test cases.
- #
- faultsim_delete_and_reopen
- do_execsql_test pager1-14.1.1 {
- PRAGMA journal_mode = OFF;
- CREATE TABLE t1(a, b);
- BEGIN;
- INSERT INTO t1 VALUES(1, 2);
- COMMIT;
- SELECT * FROM t1;
- } {off 1 2}
- do_catchsql_test pager1-14.1.2 {
- BEGIN;
- INSERT INTO t1 VALUES(3, 4);
- ROLLBACK;
- } {0 {}}
- do_execsql_test pager1-14.1.3 {
- SELECT * FROM t1;
- } {1 2}
- do_catchsql_test pager1-14.1.4 {
- BEGIN;
- INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
- INSERT INTO t1(rowid, a, b) SELECT a+3, b, b FROM t1;
- } {1 {PRIMARY KEY must be unique}}
- do_execsql_test pager1-14.1.5 {
- COMMIT;
- SELECT * FROM t1;
- } {1 2 2 2}
- #-------------------------------------------------------------------------
- # Test opening and closing the pager sub-system with different values
- # for the sqlite3_vfs.szOsFile variable.
- #
- faultsim_delete_and_reopen
- do_execsql_test pager1-15.0 {
- CREATE TABLE tx(y, z);
- INSERT INTO tx VALUES('Ayutthaya', 'Beijing');
- INSERT INTO tx VALUES('London', 'Tokyo');
- } {}
- db close
- for {set i 0} {$i<513} {incr i 3} {
- testvfs tv -default 1 -szosfile $i
- sqlite3 db test.db
- do_execsql_test pager1-15.$i.1 {
- SELECT * FROM tx;
- } {Ayutthaya Beijing London Tokyo}
- db close
- tv delete
- }
- #-------------------------------------------------------------------------
- # Check that it is not possible to open a database file if the full path
- # to the associated journal file will be longer than sqlite3_vfs.mxPathname.
- #
- testvfs tv -default 1
- tv script xOpenCb
- tv filter xOpen
- proc xOpenCb {method filename args} {
- set ::file_len [string length $filename]
- }
- sqlite3 db test.db
- db close
- tv delete
- for {set ii [expr $::file_len-5]} {$ii < [expr $::file_len+20]} {incr ii} {
- testvfs tv -default 1 -mxpathname $ii
- # The length of the full path to file "test.db-journal" is ($::file_len+8).
- # If the configured sqlite3_vfs.mxPathname value greater than or equal to
- # this, then the file can be opened. Otherwise, it cannot.
- #
- if {$ii >= [expr $::file_len+8]} {
- set res {0 {}}
- } else {
- set res {1 {unable to open database file}}
- }
- do_test pager1-16.1.$ii {
- list [catch { sqlite3 db test.db } msg] $msg
- } $res
- catch {db close}
- tv delete
- }
- #-------------------------------------------------------------------------
- # Test the pagers response to the b-tree layer requesting illegal page
- # numbers:
- #
- # + The locking page,
- # + Page 0,
- # + A page with a page number greater than (2^31-1).
- #
- # These tests will not work if SQLITE_DIRECT_OVERFLOW_READ is defined. In
- # that case IO errors are sometimes reported instead of SQLITE_CORRUPT.
- #
- ifcapable !direct_read {
- do_test pager1-18.1 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA page_size = 1024;
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES(a_string(500), a_string(200));
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- INSERT INTO t1 SELECT a_string(500), a_string(200) FROM t1;
- }
- } {}
- do_test pager1-18.2 {
- set root [db one "SELECT rootpage FROM sqlite_master"]
- set lockingpage [expr (0x10000/1024) + 1]
- execsql {
- PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage = $lockingpage;
- }
- sqlite3 db2 test.db
- catchsql { SELECT count(*) FROM t1 } db2
- } {1 {database disk image is malformed}}
- db2 close
- do_test pager1-18.3.1 {
- execsql {
- CREATE TABLE t2(x);
- INSERT INTO t2 VALUES(a_string(5000));
- }
- set pgno [expr ([file size test.db] / 1024)-2]
- hexio_write test.db [expr ($pgno-1)*1024] 00000000
- sqlite3 db2 test.db
- # even though x is malformed, because typeof() does
- # not load the content of x, the error is not noticed.
- catchsql { SELECT typeof(x) FROM t2 } db2
- } {0 text}
- do_test pager1-18.3.2 {
- # in this case, the value of x is loaded and so the error is
- # detected
- catchsql { SELECT length(x||'') FROM t2 } db2
- } {1 {database disk image is malformed}}
- db2 close
- do_test pager1-18.3.3 {
- execsql {
- DELETE FROM t2;
- INSERT INTO t2 VALUES(randomblob(5000));
- }
- set pgno [expr ([file size test.db] / 1024)-2]
- hexio_write test.db [expr ($pgno-1)*1024] 00000000
- sqlite3 db2 test.db
- # even though x is malformed, because length() and typeof() do
- # not load the content of x, the error is not noticed.
- catchsql { SELECT length(x), typeof(x) FROM t2 } db2
- } {0 {5000 blob}}
- do_test pager1-18.3.4 {
- # in this case, the value of x is loaded and so the error is
- # detected
- catchsql { SELECT length(x||'') FROM t2 } db2
- } {1 {database disk image is malformed}}
- db2 close
- do_test pager1-18.4 {
- hexio_write test.db [expr ($pgno-1)*1024] 90000000
- sqlite3 db2 test.db
- catchsql { SELECT length(x||'') FROM t2 } db2
- } {1 {database disk image is malformed}}
- db2 close
- do_test pager1-18.5 {
- sqlite3 db ""
- execsql {
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(a, b);
- PRAGMA writable_schema = 1;
- UPDATE sqlite_master SET rootpage=5 WHERE tbl_name = 't1';
- PRAGMA writable_schema = 0;
- ALTER TABLE t1 RENAME TO x1;
- }
- catchsql { SELECT * FROM x1 }
- } {1 {database disk image is malformed}}
- db close
- do_test pager1-18.6 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA page_size = 1024;
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES(a_string(800));
- INSERT INTO t1 VALUES(a_string(800));
- }
- set root [db one "SELECT rootpage FROM sqlite_master"]
- db close
- hexio_write test.db [expr ($root-1)*1024 + 8] 00000000
- sqlite3 db test.db
- catchsql { SELECT length(x) FROM t1 }
- } {1 {database disk image is malformed}}
- }
- do_test pager1-19.1 {
- sqlite3 db ""
- db func a_string a_string
- execsql {
- PRAGMA page_size = 512;
- PRAGMA auto_vacuum = 1;
- CREATE TABLE t1(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
- ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
- ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
- da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
- ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
- fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
- ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
- ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
- ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
- ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
- ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
- la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
- ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
- );
- CREATE TABLE t2(aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, an,
- ba, bb, bc, bd, be, bf, bg, bh, bi, bj, bk, bl, bm, bn,
- ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, cl, cm, cn,
- da, db, dc, dd, de, df, dg, dh, di, dj, dk, dl, dm, dn,
- ea, eb, ec, ed, ee, ef, eg, eh, ei, ej, ek, el, em, en,
- fa, fb, fc, fd, fe, ff, fg, fh, fi, fj, fk, fl, fm, fn,
- ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, gk, gl, gm, gn,
- ha, hb, hc, hd, he, hf, hg, hh, hi, hj, hk, hl, hm, hn,
- ia, ib, ic, id, ie, if, ig, ih, ii, ij, ik, il, im, ix,
- ja, jb, jc, jd, je, jf, jg, jh, ji, jj, jk, jl, jm, jn,
- ka, kb, kc, kd, ke, kf, kg, kh, ki, kj, kk, kl, km, kn,
- la, lb, lc, ld, le, lf, lg, lh, li, lj, lk, ll, lm, ln,
- ma, mb, mc, md, me, mf, mg, mh, mi, mj, mk, ml, mm, mn
- );
- INSERT INTO t1(aa) VALUES( a_string(100000) );
- INSERT INTO t2(aa) VALUES( a_string(100000) );
- VACUUM;
- }
- } {}
- #-------------------------------------------------------------------------
- # Test a couple of special cases that come up while committing
- # transactions:
- #
- # pager1-20.1.*: Committing an in-memory database transaction when the
- # database has not been modified at all.
- #
- # pager1-20.2.*: As above, but with a normal db in exclusive-locking mode.
- #
- # pager1-20.3.*: Committing a transaction in WAL mode where the database has
- # been modified, but all dirty pages have been flushed to
- # disk before the commit.
- #
- do_test pager1-20.1.1 {
- catch {db close}
- sqlite3 db :memory:
- execsql {
- CREATE TABLE one(two, three);
- INSERT INTO one VALUES('a', 'b');
- }
- } {}
- do_test pager1-20.1.2 {
- execsql {
- BEGIN EXCLUSIVE;
- COMMIT;
- }
- } {}
- do_test pager1-20.2.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA locking_mode = exclusive;
- PRAGMA journal_mode = persist;
- CREATE TABLE one(two, three);
- INSERT INTO one VALUES('a', 'b');
- }
- } {exclusive persist}
- do_test pager1-20.2.2 {
- execsql {
- BEGIN EXCLUSIVE;
- COMMIT;
- }
- } {}
- ifcapable wal {
- do_test pager1-20.3.1 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA cache_size = 10;
- PRAGMA journal_mode = wal;
- BEGIN;
- CREATE TABLE t1(x);
- CREATE TABLE t2(y);
- INSERT INTO t1 VALUES(a_string(800));
- INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */
- INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */
- INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */
- INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */
- INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */
- COMMIT;
- }
- } {wal}
- do_test pager1-20.3.2 {
- execsql {
- BEGIN;
- INSERT INTO t2 VALUES('xxxx');
- }
- recursive_select 32 t1
- execsql COMMIT
- } {}
- }
- #-------------------------------------------------------------------------
- # Test that a WAL database may not be opened if:
- #
- # pager1-21.1.*: The VFS has an iVersion less than 2, or
- # pager1-21.2.*: The VFS does not provide xShmXXX() methods.
- #
- ifcapable wal {
- do_test pager1-21.0 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA journal_mode = WAL;
- CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
- INSERT INTO ko DEFAULT VALUES;
- }
- } {wal}
- do_test pager1-21.1 {
- testvfs tv -noshm 1
- sqlite3 db2 test.db -vfs tv
- catchsql { SELECT * FROM ko } db2
- } {1 {unable to open database file}}
- db2 close
- tv delete
- do_test pager1-21.2 {
- testvfs tv -iversion 1
- sqlite3 db2 test.db -vfs tv
- catchsql { SELECT * FROM ko } db2
- } {1 {unable to open database file}}
- db2 close
- tv delete
- }
- #-------------------------------------------------------------------------
- # Test that a "PRAGMA wal_checkpoint":
- #
- # pager1-22.1.*: is a no-op on a non-WAL db, and
- # pager1-22.2.*: does not cause xSync calls with a synchronous=off db.
- #
- ifcapable wal {
- do_test pager1-22.1.1 {
- faultsim_delete_and_reopen
- execsql {
- CREATE TABLE ko(c DEFAULT 'abc', b DEFAULT 'def');
- INSERT INTO ko DEFAULT VALUES;
- }
- execsql { PRAGMA wal_checkpoint }
- } {0 -1 -1}
- do_test pager1-22.2.1 {
- testvfs tv -default 1
- tv filter xSync
- tv script xSyncCb
- proc xSyncCb {args} {incr ::synccount}
- set ::synccount 0
- sqlite3 db test.db
- execsql {
- PRAGMA synchronous = off;
- PRAGMA journal_mode = WAL;
- INSERT INTO ko DEFAULT VALUES;
- }
- execsql { PRAGMA wal_checkpoint }
- set synccount
- } {0}
- db close
- tv delete
- }
- #-------------------------------------------------------------------------
- # Tests for changing journal mode.
- #
- # pager1-23.1.*: Test that when changing from PERSIST to DELETE mode,
- # the journal file is deleted.
- #
- # pager1-23.2.*: Same test as above, but while a shared lock is held
- # on the database file.
- #
- # pager1-23.3.*: Same test as above, but while a reserved lock is held
- # on the database file.
- #
- # pager1-23.4.*: And, for fun, while holding an exclusive lock.
- #
- # pager1-23.5.*: Try to set various different journal modes with an
- # in-memory database (only MEMORY and OFF should work).
- #
- # pager1-23.6.*: Try to set locking_mode=normal on an in-memory database
- # (doesn't work - in-memory databases always use
- # locking_mode=exclusive).
- #
- do_test pager1-23.1.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA journal_mode = PERSIST;
- CREATE TABLE t1(a, b);
- }
- file exists test.db-journal
- } {1}
- do_test pager1-23.1.2 {
- execsql { PRAGMA journal_mode = DELETE }
- file exists test.db-journal
- } {0}
- do_test pager1-23.2.1 {
- execsql {
- PRAGMA journal_mode = PERSIST;
- INSERT INTO t1 VALUES('Canberra', 'ACT');
- }
- db eval { SELECT * FROM t1 } {
- db eval { PRAGMA journal_mode = DELETE }
- }
- execsql { PRAGMA journal_mode }
- } {delete}
- do_test pager1-23.2.2 {
- file exists test.db-journal
- } {0}
- do_test pager1-23.3.1 {
- execsql {
- PRAGMA journal_mode = PERSIST;
- INSERT INTO t1 VALUES('Darwin', 'NT');
- BEGIN IMMEDIATE;
- }
- db eval { PRAGMA journal_mode = DELETE }
- execsql { PRAGMA journal_mode }
- } {delete}
- do_test pager1-23.3.2 {
- file exists test.db-journal
- } {0}
- do_test pager1-23.3.3 {
- execsql COMMIT
- } {}
- do_test pager1-23.4.1 {
- execsql {
- PRAGMA journal_mode = PERSIST;
- INSERT INTO t1 VALUES('Adelaide', 'SA');
- BEGIN EXCLUSIVE;
- }
- db eval { PRAGMA journal_mode = DELETE }
- execsql { PRAGMA journal_mode }
- } {delete}
- do_test pager1-23.4.2 {
- file exists test.db-journal
- } {0}
- do_test pager1-23.4.3 {
- execsql COMMIT
- } {}
- do_test pager1-23.5.1 {
- faultsim_delete_and_reopen
- sqlite3 db :memory:
- } {}
- foreach {tn mode possible} {
- 2 off 1
- 3 memory 1
- 4 persist 0
- 5 delete 0
- 6 wal 0
- 7 truncate 0
- } {
- do_test pager1-23.5.$tn.1 {
- execsql "PRAGMA journal_mode = off"
- execsql "PRAGMA journal_mode = $mode"
- } [if $possible {list $mode} {list off}]
- do_test pager1-23.5.$tn.2 {
- execsql "PRAGMA journal_mode = memory"
- execsql "PRAGMA journal_mode = $mode"
- } [if $possible {list $mode} {list memory}]
- }
- do_test pager1-23.6.1 {
- execsql {PRAGMA locking_mode = normal}
- } {exclusive}
- do_test pager1-23.6.2 {
- execsql {PRAGMA locking_mode = exclusive}
- } {exclusive}
- do_test pager1-23.6.3 {
- execsql {PRAGMA locking_mode}
- } {exclusive}
- do_test pager1-23.6.4 {
- execsql {PRAGMA main.locking_mode}
- } {exclusive}
- #-------------------------------------------------------------------------
- #
- do_test pager1-24.1.1 {
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA cache_size = 10;
- PRAGMA auto_vacuum = FULL;
- CREATE TABLE x1(x, y, z, PRIMARY KEY(y, z));
- CREATE TABLE x2(x, y, z, PRIMARY KEY(y, z));
- INSERT INTO x2 VALUES(a_string(400), a_string(500), a_string(600));
- INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
- INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
- INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
- INSERT INTO x2 SELECT a_string(600), a_string(400), a_string(500) FROM x2;
- INSERT INTO x2 SELECT a_string(500), a_string(600), a_string(400) FROM x2;
- INSERT INTO x2 SELECT a_string(400), a_string(500), a_string(600) FROM x2;
- INSERT INTO x1 SELECT * FROM x2;
- }
- } {}
- do_test pager1-24.1.2 {
- execsql {
- BEGIN;
- DELETE FROM x1 WHERE rowid<32;
- }
- recursive_select 64 x2
- } {}
- do_test pager1-24.1.3 {
- execsql {
- UPDATE x1 SET z = a_string(300) WHERE rowid>40;
- COMMIT;
- PRAGMA integrity_check;
- SELECT count(*) FROM x1;
- }
- } {ok 33}
- do_test pager1-24.1.4 {
- execsql {
- DELETE FROM x1;
- INSERT INTO x1 SELECT * FROM x2;
- BEGIN;
- DELETE FROM x1 WHERE rowid<32;
- UPDATE x1 SET z = a_string(299) WHERE rowid>40;
- }
- recursive_select 64 x2 {db eval COMMIT}
- execsql {
- PRAGMA integrity_check;
- SELECT count(*) FROM x1;
- }
- } {ok 33}
- do_test pager1-24.1.5 {
- execsql {
- DELETE FROM x1;
- INSERT INTO x1 SELECT * FROM x2;
- }
- recursive_select 64 x2 { db eval {CREATE TABLE x3(x, y, z)} }
- execsql { SELECT * FROM x3 }
- } {}
- #-------------------------------------------------------------------------
- #
- do_test pager1-25-1 {
- faultsim_delete_and_reopen
- execsql {
- BEGIN;
- SAVEPOINT abc;
- CREATE TABLE t1(a, b);
- ROLLBACK TO abc;
- COMMIT;
- }
- db close
- } {}
- do_test pager1-25-2 {
- faultsim_delete_and_reopen
- execsql {
- SAVEPOINT abc;
- CREATE TABLE t1(a, b);
- ROLLBACK TO abc;
- COMMIT;
- }
- db close
- } {}
- #-------------------------------------------------------------------------
- # Sector-size tests.
- #
- do_test pager1-26.1 {
- testvfs tv -default 1
- tv sectorsize 4096
- faultsim_delete_and_reopen
- db func a_string a_string
- execsql {
- PRAGMA page_size = 512;
- CREATE TABLE tbl(a PRIMARY KEY, b UNIQUE);
- BEGIN;
- INSERT INTO tbl VALUES(a_string(25), a_string(600));
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- INSERT INTO tbl SELECT a_string(25), a_string(600) FROM tbl;
- COMMIT;
- }
- } {}
- do_execsql_test pager1-26.1 {
- UPDATE tbl SET b = a_string(550);
- } {}
- db close
- tv delete
- #-------------------------------------------------------------------------
- #
- do_test pager1.27.1 {
- faultsim_delete_and_reopen
- sqlite3_pager_refcounts db
- execsql {
- BEGIN;
- CREATE TABLE t1(a, b);
- }
- sqlite3_pager_refcounts db
- execsql COMMIT
- } {}
- #-------------------------------------------------------------------------
- # Test that attempting to open a write-transaction with
- # locking_mode=exclusive in WAL mode fails if there are other clients on
- # the same database.
- #
- catch { db close }
- ifcapable wal {
- do_multiclient_test tn {
- do_test pager1-28.$tn.1 {
- sql1 {
- PRAGMA journal_mode = WAL;
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES('a', 'b');
- }
- } {wal}
- do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
- do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
- do_test pager1-28.$tn.4 {
- csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
- } {1 {database is locked}}
- code2 { db2 close ; sqlite3 db2 test.db }
- do_test pager1-28.$tn.4 {
- sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
- } {}
- }
- }
- #-------------------------------------------------------------------------
- # Normally, when changing from journal_mode=PERSIST to DELETE the pager
- # attempts to delete the journal file. However, if it cannot obtain a
- # RESERVED lock on the database file, this step is skipped.
- #
- do_multiclient_test tn {
- do_test pager1-28.$tn.1 {
- sql1 {
- PRAGMA journal_mode = PERSIST;
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES('a', 'b');
- }
- } {persist}
- do_test pager1-28.$tn.2 { file exists test.db-journal } 1
- do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
- do_test pager1-28.$tn.4 { file exists test.db-journal } 0
- do_test pager1-28.$tn.5 {
- sql1 {
- PRAGMA journal_mode = PERSIST;
- INSERT INTO t1 VALUES('c', 'd');
- }
- } {persist}
- do_test pager1-28.$tn.6 { file exists test.db-journal } 1
- do_test pager1-28.$tn.7 {
- sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
- } {}
- do_test pager1-28.$tn.8 { file exists test.db-journal } 1
- do_test pager1-28.$tn.9 { sql1 { PRAGMA journal_mode = DELETE } } delete
- do_test pager1-28.$tn.10 { file exists test.db-journal } 1
- do_test pager1-28.$tn.11 { sql2 COMMIT } {}
- do_test pager1-28.$tn.12 { file exists test.db-journal } 0
- do_test pager1-28-$tn.13 {
- code1 { set channel [db incrblob -readonly t1 a 2] }
- sql1 {
- PRAGMA journal_mode = PERSIST;
- INSERT INTO t1 VALUES('g', 'h');
- }
- } {persist}
- do_test pager1-28.$tn.14 { file exists test.db-journal } 1
- do_test pager1-28.$tn.15 {
- sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
- } {}
- do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
- do_test pager1-28.$tn.17 { file exists test.db-journal } 1
- do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
- do_test pager1-28-$tn.18 { code1 { read $channel } } c
- do_test pager1-28-$tn.19 { code1 { close $channel } } {}
- do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
- }
- do_test pager1-29.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA page_size = 1024;
- PRAGMA auto_vacuum = full;
- PRAGMA locking_mode=exclusive;
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES(1, 2);
- }
- file size test.db
- } [expr 1024*3]
- do_test pager1-29.2 {
- execsql {
- PRAGMA page_size = 4096;
- VACUUM;
- }
- file size test.db
- } [expr 4096*3]
- #-------------------------------------------------------------------------
- # Test that if an empty database file (size 0 bytes) is opened in
- # exclusive-locking mode, any journal file is deleted from the file-system
- # without being rolled back. And that the RESERVED lock obtained while
- # doing this is not released.
- #
- do_test pager1-30.1 {
- db close
- delete_file test.db
- delete_file test.db-journal
- set fd [open test.db-journal w]
- seek $fd [expr 512+1032*2]
- puts -nonewline $fd x
- close $fd
- sqlite3 db test.db
- execsql {
- PRAGMA locking_mode=EXCLUSIVE;
- SELECT count(*) FROM sqlite_master;
- PRAGMA lock_status;
- }
- } {exclusive 0 main reserved temp closed}
- #-------------------------------------------------------------------------
- # Test that if the "page-size" field in a journal-header is 0, the journal
- # file can still be rolled back. This is required for backward compatibility -
- # versions of SQLite prior to 3.5.8 always set this field to zero.
- #
- if {$tcl_platform(platform)=="unix"} {
- do_test pager1-31.1 {
- faultsim_delete_and_reopen
- execsql {
- PRAGMA cache_size = 10;
- PRAGMA page_size = 1024;
- CREATE TABLE t1(x, y, UNIQUE(x, y));
- INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500));
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- INSERT INTO t1 SELECT randomblob(1500), randomblob(1500) FROM t1;
- BEGIN;
- UPDATE t1 SET y = randomblob(1499);
- }
- copy_file test.db test.db2
- copy_file test.db-journal test.db2-journal
-
- hexio_write test.db2-journal 24 00000000
- sqlite3 db2 test.db2
- execsql { PRAGMA integrity_check } db2
- } {ok}
- }
- #-------------------------------------------------------------------------
- # Test that a database file can be "pre-hinted" to a certain size and that
- # subsequent spilling of the pager cache does not result in the database
- # file being shrunk.
- #
- catch {db close}
- forcedelete test.db
- do_test pager1-32.1 {
- sqlite3 db test.db
- execsql {
- CREATE TABLE t1(x, y);
- }
- db close
- sqlite3 db test.db
- execsql {
- BEGIN;
- INSERT INTO t1 VALUES(1, randomblob(10000));
- }
- file_control_chunksize_test db main 1024
- file_control_sizehint_test db main 20971520; # 20MB
- execsql {
- PRAGMA cache_size = 10;
- INSERT INTO t1 VALUES(1, randomblob(10000));
- INSERT INTO t1 VALUES(2, randomblob(10000));
- INSERT INTO t1 SELECT x+2, randomblob(10000) from t1;
- INSERT INTO t1 SELECT x+4, randomblob(10000) from t1;
- INSERT INTO t1 SELECT x+8, randomblob(10000) from t1;
- INSERT INTO t1 SELECT x+16, randomblob(10000) from t1;
- SELECT count(*) FROM t1;
- COMMIT;
- }
- db close
- file size test.db
- } {20971520}
- # Cleanup 20MB file left by the previous test.
- forcedelete test.db
- #-------------------------------------------------------------------------
- # Test that if a transaction is committed in journal_mode=DELETE mode,
- # and the call to unlink() returns an ENOENT error, the COMMIT does not
- # succeed.
- #
- if {$::tcl_platform(platform)=="unix"} {
- do_test pager1-33.1 {
- sqlite3 db test.db
- execsql {
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES('one');
- INSERT INTO t1 VALUES('two');
- BEGIN;
- INSERT INTO t1 VALUES('three');
- INSERT INTO t1 VALUES('four');
- }
- forcedelete bak-journal
- file rename test.db-journal bak-journal
- catchsql COMMIT
- } {1 {disk I/O error}}
- do_test pager1-33.2 {
- file rename bak-journal test.db-journal
- execsql { SELECT * FROM t1 }
- } {one two}
- }
- #-------------------------------------------------------------------------
- # Test that appending pages to the database file then moving those pages
- # to the free-list before the transaction is committed does not cause
- # an error.
- #
- foreach {tn pragma strsize} {
- 1 { PRAGMA mmap_size = 0 } 2400
- 2 { } 2400
- 3 { PRAGMA mmap_size = 0 } 4400
- 4 { } 4400
- } {
- reset_db
- db func a_string a_string
- db eval $pragma
- do_execsql_test 34.$tn.1 {
- CREATE TABLE t1(a, b);
- INSERT INTO t1 VALUES(1, 2);
- }
- do_execsql_test 34.$tn.2 {
- BEGIN;
- INSERT INTO t1 VALUES(2, a_string($strsize));
- DELETE FROM t1 WHERE oid=2;
- COMMIT;
- PRAGMA integrity_check;
- } {ok}
- }
- #-------------------------------------------------------------------------
- #
- reset_db
- do_test 35 {
- sqlite3 db test.db
- execsql {
- CREATE TABLE t1(x, y);
- PRAGMA journal_mode = WAL;
- INSERT INTO t1 VALUES(1, 2);
- }
- execsql {
- BEGIN;
- CREATE TABLE t2(a, b);
- }
- hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
- catchsql ROLLBACK
- } {0 {}}
- do_multiclient_test tn {
- sql1 {
- PRAGMA auto_vacuum = 0;
- CREATE TABLE t1(x, y);
- INSERT INTO t1 VALUES(1, 2);
- }
- do_test 36.$tn.1 {
- sql2 { PRAGMA max_page_count = 2 }
- list [catch { sql2 { CREATE TABLE t2(x) } } msg] $msg
- } {1 {database or disk is full}}
- sql1 { PRAGMA checkpoint_fullfsync = 1 }
- sql1 { CREATE TABLE t2(x) }
- do_test 36.$tn.2 {
- sql2 { INSERT INTO t2 VALUES('xyz') }
- list [catch { sql2 { CREATE TABLE t3(x) } } msg] $msg
- } {1 {database or disk is full}}
- }
- forcedelete test1 test2
- foreach {tn uri} {
- 1 {file:?mode=memory&cache=shared}
- 2 {file:one?mode=memory&cache=shared}
- 3 {file:test1?cache=shared}
- 4 {file:test2?another=parameter&yet=anotherone}
- } {
- do_test 37.$tn {
- catch { db close }
- sqlite3_shutdown
- sqlite3_config_uri 1
- sqlite3 db $uri
- db eval {
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES(1);
- SELECT * FROM t1;
- }
- } {1}
- do_execsql_test 37.$tn.2 {
- VACUUM;
- SELECT * FROM t1;
- } {1}
- db close
- sqlite3_shutdown
- sqlite3_config_uri 0
- }
- do_test 38.1 {
- catch { db close }
- forcedelete test.db
- set fd [open test.db w]
- puts $fd "hello world"
- close $fd
- sqlite3 db test.db
- catchsql { CREATE TABLE t1(x) }
- } {1 {file is encrypted or is not a database}}
- do_test 38.2 {
- catch { db close }
- forcedelete test.db
- } {}
- do_test 39.1 {
- sqlite3 db test.db
- execsql {
- PRAGMA auto_vacuum = 1;
- CREATE TABLE t1(x);
- INSERT INTO t1 VALUES('xxx');
- INSERT INTO t1 VALUES('two');
- INSERT INTO t1 VALUES(randomblob(400));
- INSERT INTO t1 VALUES(randomblob(400));
- INSERT INTO t1 VALUES(randomblob(400));
- INSERT INTO t1 VALUES(randomblob(400));
- BEGIN;
- UPDATE t1 SET x = 'one' WHERE rowid=1;
- }
- set ::stmt [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
- sqlite3_step $::stmt
- sqlite3_column_text $::stmt 0
- } {one}
- do_test 39.2 {
- execsql { CREATE TABLE t2(x) }
- sqlite3_step $::stmt
- sqlite3_column_text $::stmt 0
- } {two}
- do_test 39.3 {
- sqlite3_finalize $::stmt
- execsql COMMIT
- } {}
- do_execsql_test 39.4 {
- PRAGMA auto_vacuum = 2;
- CREATE TABLE t3(x);
- CREATE TABLE t4(x);
- DROP TABLE t2;
- DROP TABLE t3;
- DROP TABLE t4;
- }
- do_test 39.5 {
- db close
- sqlite3 db test.db
- execsql {
- PRAGMA cache_size = 1;
- PRAGMA incremental_vacuum;
- PRAGMA integrity_check;
- }
- } {ok}
- do_test 40.1 {
- reset_db
- execsql {
- PRAGMA auto_vacuum = 1;
- CREATE TABLE t1(x PRIMARY KEY);
- INSERT INTO t1 VALUES(randomblob(1200));
- PRAGMA page_count;
- }
- } {6}
- do_test 40.2 {
- execsql {
- INSERT INTO t1 VALUES(randomblob(1200));
- INSERT INTO t1 VALUES(randomblob(1200));
- INSERT INTO t1 VALUES(randomblob(1200));
- }
- } {}
- do_test 40.3 {
- db close
- sqlite3 db test.db
- execsql {
- PRAGMA cache_size = 1;
- CREATE TABLE t2(x);
- PRAGMA integrity_check;
- }
- } {ok}
- do_test 41.1 {
- reset_db
- execsql {
- CREATE TABLE t1(x PRIMARY KEY);
- INSERT INTO t1 VALUES(randomblob(200));
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200) FROM t1;
- }
- } {}
- do_test 41.2 {
- testvfs tv -default 1
- tv sectorsize 16384;
- tv devchar [list]
- db close
- sqlite3 db test.db
- execsql {
- PRAGMA cache_size = 1;
- DELETE FROM t1 WHERE rowid%4;
- PRAGMA integrity_check;
- }
- } {ok}
- db close
- tv delete
- set pending_prev [sqlite3_test_control_pending_byte 0x1000000]
- do_test 42.1 {
- reset_db
- execsql {
- CREATE TABLE t1(x, y);
- INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- }
- db close
- sqlite3_test_control_pending_byte 0x0010000
- sqlite3 db test.db
- db eval { PRAGMA mmap_size = 0 }
- catchsql { SELECT sum(length(y)) FROM t1 }
- } {1 {database disk image is malformed}}
- do_test 42.2 {
- reset_db
- execsql {
- CREATE TABLE t1(x, y);
- INSERT INTO t1 VALUES(randomblob(200), randomblob(200));
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- INSERT INTO t1 SELECT randomblob(200), randomblob(200) FROM t1;
- }
- db close
- testvfs tv -default 1
- tv sectorsize 16384;
- tv devchar [list]
- sqlite3 db test.db -vfs tv
- execsql { UPDATE t1 SET x = randomblob(200) }
- } {}
- db close
- tv delete
- sqlite3_test_control_pending_byte $pending_prev
- do_test 43.1 {
- reset_db
- execsql {
- CREATE TABLE t1(x, y);
- INSERT INTO t1 VALUES(1, 2);
- CREATE TABLE t2(x, y);
- INSERT INTO t2 VALUES(1, 2);
- CREATE TABLE t3(x, y);
- INSERT INTO t3 VALUES(1, 2);
- }
- db close
- sqlite3 db test.db
- db eval { PRAGMA mmap_size = 0 }
- db eval { SELECT * FROM t1 }
- sqlite3_db_status db CACHE_MISS 0
- } {0 2 0}
- do_test 43.2 {
- db eval { SELECT * FROM t2 }
- sqlite3_db_status db CACHE_MISS 1
- } {0 3 0}
- do_test 43.3 {
- db eval { SELECT * FROM t3 }
- sqlite3_db_status db CACHE_MISS 0
- } {0 1 0}
- finish_test
|