From e8d1777a2de65611519adffa20997b2b19ece6b7 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 16 Dec 2014 12:46:38 +0000 Subject: [PATCH 1/7] Fix the e_walauto.test script so that it works on windows. FossilOrigin-Name: 7d092ebb6724c3c0fdc05dc94ca767d158933fb5 --- manifest | 13 ++++++------- manifest.uuid | 2 +- test/e_walauto.test | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 012153429f..269b2e6b45 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhanced\s"stress2"\stesting\sin\sthe\sthreadtest3.c\stest\sprogram. -D 2014-12-16T00:20:07.236 +C Fix\sthe\se_walauto.test\sscript\sso\sthat\sit\sworks\son\swindows. +D 2014-12-16T12:46:38.635 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -478,7 +478,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test 0967f0b8f1dfda871dc7b9b5574198f1f4f7d69a -F test/e_walauto.test a1fa9d36c160cc4001a934d1e009aae597b440b7 +F test/e_walauto.test eab3bedddbc3fd19795d51e618da41a48e19a3e3 F test/e_walckpt.test 3116a98fa0dd9b2c9e493de7c59730adfe436746 F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea @@ -1232,8 +1232,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5b1b697040116048e464b3ebab8395fe088e389a 5648af96d8e2521c5b0cca19f1358374d032394d -R 64bec50dd05bb00af986c569d5edb044 -T +closed 5648af96d8e2521c5b0cca19f1358374d032394d +P ae43539e62e76676a3daf561b629a1b9b4e2d2c9 +R 6cb5309eecfa4835aff26790e68b0f80 U drh -Z 1075019e3631a6f364d3a72648c7dd6d +Z 6fc407d3934d070a5bb755e43a0ba0ad diff --git a/manifest.uuid b/manifest.uuid index 209ef7a57a..fd507f2f23 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ae43539e62e76676a3daf561b629a1b9b4e2d2c9 \ No newline at end of file +7d092ebb6724c3c0fdc05dc94ca767d158933fb5 \ No newline at end of file diff --git a/test/e_walauto.test b/test/e_walauto.test index fc394e9053..79a2702d04 100644 --- a/test/e_walauto.test +++ b/test/e_walauto.test @@ -68,7 +68,7 @@ foreach {tn code} { reset_db do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal} do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) } - set shmfd [open "test.db-shm"] + set shmfd [open "test.db-shm" rb] # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to # having the auto-checkpoint enabled with a threshold of 1000 or From 0466883300819e9b95cd07212136e1ee2bb8aee9 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 16 Dec 2014 20:13:30 +0000 Subject: [PATCH 2/7] Experimental opimizations to speed up FK constraint CASCADE and SET NULL action processing. FossilOrigin-Name: 35a20a5f22245c70faa51965951e8cc011defa93 --- manifest | 21 ++++++------ manifest.uuid | 2 +- src/fkey.c | 63 +++++++++++++++++++++++++----------- src/vdbeaux.c | 11 ++++--- test/fkey8.test | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 32 deletions(-) create mode 100644 test/fkey8.test diff --git a/manifest b/manifest index 012153429f..d7fc48ce45 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhanced\s"stress2"\stesting\sin\sthe\sthreadtest3.c\stest\sprogram. -D 2014-12-16T00:20:07.236 +C Experimental\sopimizations\sto\sspeed\sup\sFK\sconstraint\sCASCADE\sand\sSET\sNULL\saction\sprocessing. +D 2014-12-16T20:13:30.440 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -184,7 +184,7 @@ F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744 F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 F src/expr.c 00da3072f362b06f39ce4052baa1d4ce2bb36d1c F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7 +F src/fkey.c eab56799b0339b04c258233b0f462b6e9317f90f F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430 F src/global.c 6ded36dda9466fc1c9a3c5492ded81d79bf3977d F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 @@ -295,7 +295,7 @@ F src/vdbe.c 1a9e671c9cfc259e4d2affc71f7df4a4c00a842c F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78 F src/vdbeapi.c 4bc511a46b9839392ae0e90844a71dc96d9dbd71 -F src/vdbeaux.c 6f7f39c3fcf0f5923758df8561bb5d843908a553 +F src/vdbeaux.c 07ef87c6d4b5abdf13ff33babb10205702fdab0a F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778 F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c c150803a3e98fbc68bd07772cbbd4328a0a7212d @@ -504,6 +504,7 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 +F test/fkey8.test 2d58cfb990cdd56b2fbac9f4ae54ee53968b3e06 F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c @@ -1232,8 +1233,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5b1b697040116048e464b3ebab8395fe088e389a 5648af96d8e2521c5b0cca19f1358374d032394d -R 64bec50dd05bb00af986c569d5edb044 -T +closed 5648af96d8e2521c5b0cca19f1358374d032394d -U drh -Z 1075019e3631a6f364d3a72648c7dd6d +P ae43539e62e76676a3daf561b629a1b9b4e2d2c9 +R ea6275c5fe67bcf602365c1ede77fced +T *branch * experimental-fk-actions +T *sym-experimental-fk-actions * +T -sym-trunk * +U dan +Z b6352d484674a0d7b3ae6d8d076cd106 diff --git a/manifest.uuid b/manifest.uuid index 209ef7a57a..859f607ae0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ae43539e62e76676a3daf561b629a1b9b4e2d2c9 \ No newline at end of file +35a20a5f22245c70faa51965951e8cc011defa93 \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index e816bd95da..7ea48f5058 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -437,7 +437,7 @@ static void fkLookupParent( OE_Abort, 0, P4_STATIC, P5_ConstraintFK); }else{ if( nIncr>0 && pFKey->isDeferred==0 ){ - sqlite3ParseToplevel(pParse)->mayAbort = 1; + sqlite3MayAbort(pParse); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); } @@ -509,6 +509,10 @@ static Expr *exprTableColumn( ** code for an SQL UPDATE operation, this function may be called twice - ** once to "delete" the old row and once to "insert" the new row. ** +** Parameter nIncr is passed -1 when inserting a row (as this may decrease +** the number of FK violations in the db) or +1 when deleting one (as this +** may increase the number of FK constraint problems). +** ** The code generated by this function scans through the rows in the child ** table that correspond to the parent table row being deleted or inserted. ** For each child row found, one of the following actions is taken: @@ -629,9 +633,6 @@ static void fkScanChildren( ** each row found. Otherwise, for deferred constraints, increment the ** deferred constraint counter by nIncr for each row selected. */ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); - if( nIncr>0 && pFKey->isDeferred==0 ){ - sqlite3ParseToplevel(pParse)->mayAbort = 1; - } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); if( pWInfo ){ sqlite3WhereEnd(pWInfo); @@ -810,6 +811,24 @@ static int fkParentIsModified( return 0; } +/* +** Return true if the parser passed as the first argument is being +** used to code a trigger that is really a "SET NULL" action belonging +** to trigger pFKey. +*/ +static int isSetNullAction(Parse *pParse, FKey *pFKey){ + Parse *pTop = sqlite3ParseToplevel(pParse); + if( pTop->pTriggerPrg ){ + Trigger *p = pTop->pTriggerPrg->pTrigger; + if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull) + || (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull) + ){ + return 1; + } + } + return 0; +} + /* ** This function is called when inserting, deleting or updating a row of ** table pTab to generate VDBE code to perform foreign key constraint @@ -862,7 +881,7 @@ void sqlite3FkCheck( int *aiCol; int iCol; int i; - int isIgnore = 0; + int bIgnore = 0; if( aChange && sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0 @@ -921,7 +940,7 @@ void sqlite3FkCheck( int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); - isIgnore = (rcauth==SQLITE_IGNORE); + bIgnore = (rcauth==SQLITE_IGNORE); } #endif } @@ -936,12 +955,18 @@ void sqlite3FkCheck( /* A row is being removed from the child table. Search for the parent. ** If the parent does not exist, removing the child row resolves an ** outstanding foreign key constraint violation. */ - fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore); + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore); } - if( regNew!=0 ){ + if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){ /* A row is being added to the child table. If a parent row cannot - ** be found, adding the child row has violated the FK constraint. */ - fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore); + ** be found, adding the child row has violated the FK constraint. + ** + ** If this operation is being performed as part of a trigger program + ** that is actually a "SET NULL" action belonging to this very + ** foreign key, then omit this scan altogether. As the child keys + ** values are guaranteed to be NULL, it is not possible for adding + ** this row to cause an FK violation. */ + fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore); } sqlite3DbFree(db, aiFree); @@ -962,8 +987,8 @@ void sqlite3FkCheck( && !pParse->pToplevel && !pParse->isMultiWrite ){ assert( regOld==0 && regNew!=0 ); - /* Inserting a single row into a parent table cannot cause an immediate - ** foreign key violation. So do nothing in this case. */ + /* Inserting a single row into a parent table cannot cause (or fix) + ** an immediate foreign key violation. So do nothing in this case. */ continue; } @@ -987,13 +1012,15 @@ void sqlite3FkCheck( fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); } if( regOld!=0 ){ - /* If there is a RESTRICT action configured for the current operation - ** on the parent table of this FK, then throw an exception - ** immediately if the FK constraint is violated, even if this is a - ** deferred trigger. That's what RESTRICT means. To defer checking - ** the constraint, the FK should specify NO ACTION (represented - ** using OE_None). NO ACTION is the default. */ + int eAction = pFKey->aAction[aChange!=0]; fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); + /* If this is a deferred FK constraint, or a CASCADE or SET NULL + ** action applies, do not set the may-abort flag on this statement. + ** The flag may be set on this statement for some other reason, but + ** not as a result of this FK constraint. */ + if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ + sqlite3MayAbort(pParse); + } } pItem->zName = 0; sqlite3SrcListDelete(db, pSrc); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7900bd52ac..03c229c994 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -396,6 +396,7 @@ static Op *opIterNext(VdbeOpIter *p){ */ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; + int hasFkCounter = 0; Op *pOp; VdbeOpIter sIter; memset(&sIter, 0, sizeof(sIter)); @@ -404,15 +405,17 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ while( (pOp = opIterNext(&sIter))!=0 ){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename -#ifndef SQLITE_OMIT_FOREIGN_KEY - || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1) -#endif || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } +#ifndef SQLITE_OMIT_FOREIGN_KEY + if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ + hasFkCounter = 1; + } +#endif } sqlite3DbFree(v->db, sIter.apSub); @@ -421,7 +424,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** through all opcodes and hasAbort may be set incorrectly. Return ** true for this case to prevent the assert() in the callers frame ** from failing. */ - return ( v->db->mallocFailed || hasAbort==mayAbort ); + return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ diff --git a/test/fkey8.test b/test/fkey8.test new file mode 100644 index 0000000000..e9f3093930 --- /dev/null +++ b/test/fkey8.test @@ -0,0 +1,85 @@ +# 2001 September 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for foreign keys. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix fkey8 + +ifcapable {!foreignkey} { + finish_test + return +} +do_execsql_test 1.0 { PRAGMA foreign_keys = 1; } + + +foreach {tn use_stmt sql schema} { + 1 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1); + } + + 2.1 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE); + } + 2.2 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE SET NULL); + } + 2.3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE SET DEFAULT); + } + + 3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE); + CREATE TRIGGER ct1 AFTER DELETE ON c1 BEGIN + INSERT INTO p1 VALUES('x'); + END; + } + + 4 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1); + } + + 5.1 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE CASCADE); + } + 5.2 0 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE SET NULL); + } + +} { + drop_all_tables + do_test 1.$tn { + execsql $schema + set stmt [sqlite3_prepare_v2 db $sql -1 dummy] + set ret [uses_stmt_journal $stmt] + sqlite3_finalize $stmt + set ret + } $use_stmt +} + + + + +finish_test From d457271130985a26c10b2b2d2c853fb27cfcdcb7 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 17 Dec 2014 14:38:45 +0000 Subject: [PATCH 3/7] Fix some comments in fkey.c. Add tests to fkey8.test. FossilOrigin-Name: 210cb2a6aaf780365064a26c0c99926bd6346e19 --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/fkey.c | 28 ++++++++++++++++++++-------- test/fkey8.test | 25 +++++++++++++++++++++++-- 4 files changed, 51 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index d7fc48ce45..ec31cc9e8a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Experimental\sopimizations\sto\sspeed\sup\sFK\sconstraint\sCASCADE\sand\sSET\sNULL\saction\sprocessing. -D 2014-12-16T20:13:30.440 +C Fix\ssome\scomments\sin\sfkey.c.\sAdd\stests\sto\sfkey8.test. +D 2014-12-17T14:38:45.643 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -184,7 +184,7 @@ F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744 F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417 F src/expr.c 00da3072f362b06f39ce4052baa1d4ce2bb36d1c F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c eab56799b0339b04c258233b0f462b6e9317f90f +F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12 F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430 F src/global.c 6ded36dda9466fc1c9a3c5492ded81d79bf3977d F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 @@ -504,7 +504,7 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 -F test/fkey8.test 2d58cfb990cdd56b2fbac9f4ae54ee53968b3e06 +F test/fkey8.test 8f08203458321e6c19a263829de4cfc936274ab0 F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c @@ -1233,10 +1233,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ae43539e62e76676a3daf561b629a1b9b4e2d2c9 -R ea6275c5fe67bcf602365c1ede77fced -T *branch * experimental-fk-actions -T *sym-experimental-fk-actions * -T -sym-trunk * +P 35a20a5f22245c70faa51965951e8cc011defa93 +R c39a2128ba39a16276f2dc7a158fbe28 U dan -Z b6352d484674a0d7b3ae6d8d076cd106 +Z 96b8a9e537739194255aed7e579f65ad diff --git a/manifest.uuid b/manifest.uuid index 859f607ae0..367ac4e6aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -35a20a5f22245c70faa51965951e8cc011defa93 \ No newline at end of file +210cb2a6aaf780365064a26c0c99926bd6346e19 \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index 7ea48f5058..fa148ba6a3 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -629,9 +629,8 @@ static void fkScanChildren( sqlite3ResolveExprNames(&sNameContext, pWhere); /* Create VDBE to loop through the entries in pSrc that match the WHERE - ** clause. If the constraint is not deferred, throw an exception for - ** each row found. Otherwise, for deferred constraints, increment the - ** deferred constraint counter by nIncr for each row selected. */ + ** clause. For each row found, increment either the deferred or immediate + ** foreign key constraint counter. */ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); if( pWInfo ){ @@ -963,9 +962,9 @@ void sqlite3FkCheck( ** ** If this operation is being performed as part of a trigger program ** that is actually a "SET NULL" action belonging to this very - ** foreign key, then omit this scan altogether. As the child keys + ** foreign key, then omit this scan altogether. As all child key ** values are guaranteed to be NULL, it is not possible for adding - ** this row to cause an FK violation. */ + ** this row to cause an FK violation. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1, bIgnore); } @@ -1015,9 +1014,22 @@ void sqlite3FkCheck( int eAction = pFKey->aAction[aChange!=0]; fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); /* If this is a deferred FK constraint, or a CASCADE or SET NULL - ** action applies, do not set the may-abort flag on this statement. - ** The flag may be set on this statement for some other reason, but - ** not as a result of this FK constraint. */ + ** action applies, then any foreign key violations caused by + ** removing the parent key will be rectified by the action trigger. + ** So do not set the "may-abort" flag in this case. + ** + ** Note 1: If the FK is declared "ON UPDATE CASCADE", then the + ** may-abort flag will eventually be set on this statement anyway + ** (when this function is called as part of processing the UPDATE + ** within the action trigger). + ** + ** Note 2: At first glance it may seem like SQLite could simply omit + ** all OP_FkCounter related scans when either CASCADE or SET NULL + ** applies. The trouble starts if the CASCADE or SET NULL action + ** trigger causes other triggers or action rules attached to the + ** child table to fire. In these cases the fk constraint counters + ** might be set incorrectly if any OP_FkCounter related scans are + ** omitted. */ if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){ sqlite3MayAbort(pParse); } diff --git a/test/fkey8.test b/test/fkey8.test index e9f3093930..60bb8e4640 100644 --- a/test/fkey8.test +++ b/test/fkey8.test @@ -67,6 +67,28 @@ foreach {tn use_stmt sql schema} { CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); CREATE TABLE cc1(d REFERENCES c1 ON DELETE SET NULL); } + 5.3 1 "DELETE FROM p1" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON DELETE CASCADE, c PRIMARY KEY); + CREATE TABLE cc1(d REFERENCES c1 ON DELETE SET DEFAULT); + } + + 6.1 1 "UPDATE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE SET NULL, c); + } + 6.2 0 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE SET NULL, c); + } + 6.3 1 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b REFERENCES p1 ON UPDATE CASCADE, c); + } + 6.4 1 "UPDATE OR IGNORE p1 SET a = ?" { + CREATE TABLE p1(a PRIMARY KEY); + CREATE TABLE c1(b NOT NULL REFERENCES p1 ON UPDATE SET NULL, c); + } } { drop_all_tables @@ -80,6 +102,5 @@ foreach {tn use_stmt sql schema} { } - - finish_test + From 8e755e7e19613a71feb59775cfd456cad3b5a2e4 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 19 Dec 2014 18:49:55 +0000 Subject: [PATCH 4/7] Simplify the implementation of the "header-value" pragmas (schema_version, user_version, freelist_count, and application_id) by making them more table-driven. FossilOrigin-Name: da27a09d1d991583b59997f6cc67efa28ffd9d6a --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/pragma.c | 30 ++++++++---------------------- tool/mkpragmatab.tcl | 5 +++++ 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 1752ddd915..940c131970 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Experimental\sopimizations\sto\sspeed\sup\sFK\sconstraint\sCASCADE\sand\sSET\sNULL\saction\sprocessing. -D 2014-12-17T15:03:50.611 +C Simplify\sthe\simplementation\sof\sthe\s"header-value"\spragmas\s(schema_version,\nuser_version,\sfreelist_count,\sand\sapplication_id)\sby\smaking\sthem\smore\ntable-driven. +D 2014-12-19T18:49:55.326 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -222,7 +222,7 @@ F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 -F src/pragma.c c93be505649183b2d80082c2eef1a56879dabfe6 +F src/pragma.c 7337e5d9f14664e987be3e6ed4d73fad16e48ad1 F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 @@ -1197,7 +1197,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh 5dc5010e2e748a9e1bba67baca5956a2c2deda7b F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl cce51d8f60c7f145d8fccabe6b5dfdedf31c5f5c +F tool/mkpragmatab.tcl f7facbe8988ce61946f8069d34827ffc6af92521 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 88a1e3b0c769773fb7a9ebb363ffc603a4ac21d8 F tool/mksqlite3c.tcl e72c0c97fe1a105fa9616483e652949be2199fe6 @@ -1233,7 +1233,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7d092ebb6724c3c0fdc05dc94ca767d158933fb5 210cb2a6aaf780365064a26c0c99926bd6346e19 -R 2edc2fe620223f33e078e9395972a943 -U dan -Z c2959ecd9d3a1afd4baaa55723226ea7 +P 8c5dd6cc259e0cdaaddaa52ccfa96fee6b166906 +R 8ba8633e296b4b7fe64ae8b30f249024 +U drh +Z d788c0d876adfa7410350841952e3917 diff --git a/manifest.uuid b/manifest.uuid index ee9030a0e4..e0e3164dca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8c5dd6cc259e0cdaaddaa52ccfa96fee6b166906 \ No newline at end of file +da27a09d1d991583b59997f6cc67efa28ffd9d6a \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 837a15102d..cbeb81eee6 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -71,6 +71,7 @@ #define PragTyp_LOCK_STATUS 40 #define PragTyp_PARSER_TRACE 41 #define PragFlag_NeedSchema 0x01 +#define PragFlag_ReadOnly 0x02 static const struct sPragmaNames { const char *const zName; /* Name of pragma */ u8 ePragTyp; /* PragTyp_XXX value */ @@ -87,7 +88,7 @@ static const struct sPragmaNames { { /* zName: */ "application_id", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_APPLICATION_ID }, #endif #if !defined(SQLITE_OMIT_AUTOVACUUM) { /* zName: */ "auto_vacuum", @@ -208,8 +209,8 @@ static const struct sPragmaNames { #if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) { /* zName: */ "freelist_count", /* ePragTyp: */ PragTyp_HEADER_VALUE, - /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_FREE_PAGE_COUNT }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "full_column_names", @@ -361,7 +362,7 @@ static const struct sPragmaNames { { /* zName: */ "schema_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_SCHEMA_VERSION }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) { /* zName: */ "secure_delete", @@ -427,7 +428,7 @@ static const struct sPragmaNames { { /* zName: */ "user_version", /* ePragTyp: */ PragTyp_HEADER_VALUE, /* ePragFlag: */ 0, - /* iArg: */ 0 }, + /* iArg: */ BTREE_USER_VERSION }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if defined(SQLITE_DEBUG) @@ -2126,24 +2127,9 @@ void sqlite3Pragma( ** applications for any purpose. */ case PragTyp_HEADER_VALUE: { - int iCookie; /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */ + int iCookie = aPragmaNames[mid].iArg; /* Which cookie to read or write */ sqlite3VdbeUsesBtree(v, iDb); - switch( zLeft[0] ){ - case 'a': case 'A': - iCookie = BTREE_APPLICATION_ID; - break; - case 'f': case 'F': - iCookie = BTREE_FREE_PAGE_COUNT; - break; - case 's': case 'S': - iCookie = BTREE_SCHEMA_VERSION; - break; - default: - iCookie = BTREE_USER_VERSION; - break; - } - - if( zRight && iCookie!=BTREE_FREE_PAGE_COUNT ){ + if( zRight && (aPragmaNames[mid].mPragFlag & PragFlag_ReadOnly)==0 ){ /* Write the specified cookie value */ static const VdbeOpList setCookie[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index aa7c8078c5..2c9b84b735 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -246,18 +246,23 @@ set pragma_def { NAME: schema_version TYPE: HEADER_VALUE + ARG: BTREE_SCHEMA_VERSION IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: user_version TYPE: HEADER_VALUE + ARG: BTREE_USER_VERSION IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: freelist_count TYPE: HEADER_VALUE + ARG: BTREE_FREE_PAGE_COUNT + FLAG: ReadOnly IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: application_id TYPE: HEADER_VALUE + ARG: BTREE_APPLICATION_ID IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) NAME: compile_options From 91618564955d2da0e70c795076f214b5cb974b40 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 19 Dec 2014 19:28:02 +0000 Subject: [PATCH 5/7] Experimental "PRAGMA data_version" command for detecting when another process has changed the database file. FossilOrigin-Name: 43db1f44bce5a0ee50197b95ab0d844540b69d86 --- manifest | 25 ++++++++++++++----------- manifest.uuid | 2 +- src/btree.c | 13 ++++++++++++- src/btree.h | 8 +++++++- src/pager.c | 12 +++++++++++- src/pager.h | 1 + src/pragma.c | 8 +++++++- tool/mkpragmatab.tcl | 6 ++++++ 8 files changed, 59 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 940c131970..f22a0f1b43 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplify\sthe\simplementation\sof\sthe\s"header-value"\spragmas\s(schema_version,\nuser_version,\sfreelist_count,\sand\sapplication_id)\sby\smaking\sthem\smore\ntable-driven. -D 2014-12-19T18:49:55.326 +C Experimental\s"PRAGMA\sdata_version"\scommand\sfor\sdetecting\swhen\sanother\sprocess\nhas\schanged\sthe\sdatabase\sfile. +D 2014-12-19T19:28:02.465 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -173,8 +173,8 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5 -F src/btree.c 92f745ccd18099973beb28e25fce80148545429e -F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e +F src/btree.c b2b2bd0aa02430fe86bc891295db919fcafb0d64 +F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474 F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21 F src/build.c 162d84e4833b03f9d07192ef06057b0226f6e543 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -216,13 +216,13 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 F src/os_win.c ecb04a0dad2fa6fa659931a9d8f0f3aca33f908a F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c 7a5c5bc0e29b9b16834f5558a9d5d22bbae59a08 -F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b +F src/pager.c abe022cd72e112a05db5fd1d6d46f5ed93284247 +F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77 F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8 F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98 -F src/pragma.c 7337e5d9f14664e987be3e6ed4d73fad16e48ad1 +F src/pragma.c bd33aa24456f043bb6f6d32a918bbeed41d8c591 F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9 F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 @@ -1197,7 +1197,7 @@ F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh 5dc5010e2e748a9e1bba67baca5956a2c2deda7b F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl f7facbe8988ce61946f8069d34827ffc6af92521 +F tool/mkpragmatab.tcl 07a5124cf2dbafa1b375eefcf8ac4227028b0f8b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 88a1e3b0c769773fb7a9ebb363ffc603a4ac21d8 F tool/mksqlite3c.tcl e72c0c97fe1a105fa9616483e652949be2199fe6 @@ -1233,7 +1233,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 8c5dd6cc259e0cdaaddaa52ccfa96fee6b166906 -R 8ba8633e296b4b7fe64ae8b30f249024 +P da27a09d1d991583b59997f6cc67efa28ffd9d6a +R df4854633d0919cb180185852b6a45b5 +T *branch * data_version_pragma +T *sym-data_version_pragma * +T -sym-trunk * U drh -Z d788c0d876adfa7410350841952e3917 +Z 81defb06f28b03737e8cb7607139b4d9 diff --git a/manifest.uuid b/manifest.uuid index e0e3164dca..92b0ead781 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -da27a09d1d991583b59997f6cc67efa28ffd9d6a \ No newline at end of file +43db1f44bce5a0ee50197b95ab0d844540b69d86 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index d24f6a876a..1223f78e48 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8177,6 +8177,13 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. +** +** This routine treats Meta[BTREE_DATA_VERSION] as a special case. Instead +** of reading the value out of the header, it instead loads the "DataVersion" +** from the pager. The BTREE_DATA_VERSION value is not actually stored in the +** database file. It is a number computed by the pager. But its access +** pattern is the same as header meta values, and so it is convenient to +** read it from this routine. */ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; @@ -8187,7 +8194,11 @@ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); - *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); + if( idx==BTREE_DATA_VERSION ){ + *pMeta = sqlite3PagerDataVersion(pBt->pPager); + }else{ + *pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]); + } /* If auto-vacuum is disabled in this build and this is an auto-vacuum ** database, mark the database as read-only. */ diff --git a/src/btree.h b/src/btree.h index 281e57dafd..b57d500c77 100644 --- a/src/btree.h +++ b/src/btree.h @@ -19,7 +19,7 @@ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ -#define SQLITE_N_BTREE_META 10 +#define SQLITE_N_BTREE_META 16 /* ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise @@ -134,6 +134,11 @@ int sqlite3BtreeNewDb(Btree *p); ** For example, the free-page-count field is located at byte offset 36 of ** the database file header. The incr-vacuum-flag field is located at ** byte offset 64 (== 36+4*7). +** +** The BTREE_DATA_VERSION value is not really a value stored in the header. +** It is a read-only number computed by the pager. But we merge it with +** the header value access routines since its access pattern is the same. +** Call it a "virtual meta value". */ #define BTREE_FREE_PAGE_COUNT 0 #define BTREE_SCHEMA_VERSION 1 @@ -144,6 +149,7 @@ int sqlite3BtreeNewDb(Btree *p); #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 #define BTREE_APPLICATION_ID 8 +#define BTREE_DATA_VERSION 15 /* A virtual meta-value */ /* ** Values that may be OR'd together to form the second argument of an diff --git a/src/pager.c b/src/pager.c index a2ae9cc410..97dd78e35b 100644 --- a/src/pager.c +++ b/src/pager.c @@ -646,6 +646,7 @@ struct Pager { u8 setMaster; /* True if a m-j name has been written to jrnl */ u8 doNotSpill; /* Do not spill the cache when non-zero */ u8 subjInMemory; /* True to use in-memory sub-journals */ + u8 bUseFetch; /* True to use xFetch() */ Pgno dbSize; /* Number of pages in the database */ Pgno dbOrigSize; /* dbSize before the current transaction */ Pgno dbFileSize; /* Number of pages in the database file */ @@ -663,9 +664,9 @@ struct Pager { sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ + u32 nReset; /* Number of calls to pager_reset() */ char dbFileVers[16]; /* Changes whenever database file changes */ - u8 bUseFetch; /* True to use xFetch() */ int nMmapOut; /* Number of mmap pages currently outstanding */ sqlite3_int64 szMmap; /* Desired maximum mmap size */ PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */ @@ -1681,10 +1682,19 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ ** Discard the entire contents of the in-memory page-cache. */ static void pager_reset(Pager *pPager){ + pPager->nReset++; sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); } +/* +** Return the pPager->nReset value +*/ +u32 sqlite3PagerDataVersion(Pager *pPager){ + assert( pPager->eState>PAGER_OPEN ); + return pPager->nReset; +} + /* ** Free all structures in the Pager.aSavepoint[] array and set both ** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal diff --git a/src/pager.h b/src/pager.h index 764c7bd197..e07fa88fc5 100644 --- a/src/pager.h +++ b/src/pager.h @@ -172,6 +172,7 @@ int sqlite3PagerSharedLock(Pager *pPager); /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); +u32 sqlite3PagerDataVersion(Pager*); int sqlite3PagerRefcount(Pager*); int sqlite3PagerMemUsed(Pager*); const char *sqlite3PagerFilename(Pager*, int); diff --git a/src/pragma.c b/src/pragma.c index cbeb81eee6..1312beef04 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -154,6 +154,12 @@ static const struct sPragmaNames { /* ePragFlag: */ 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + { /* zName: */ "data_version", + /* ePragTyp: */ PragTyp_HEADER_VALUE, + /* ePragFlag: */ PragFlag_ReadOnly, + /* iArg: */ BTREE_DATA_VERSION }, +#endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) { /* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, @@ -471,7 +477,7 @@ static const struct sPragmaNames { /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode }, #endif }; -/* Number of pragmas: 57 on by default, 70 total. */ +/* Number of pragmas: 58 on by default, 71 total. */ /* End of the automatically generated pragma table. ***************************************************************************/ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 2c9b84b735..21503d16ee 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -254,6 +254,12 @@ set pragma_def { ARG: BTREE_USER_VERSION IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + NAME: data_version + TYPE: HEADER_VALUE + ARG: BTREE_DATA_VERSION + FLAG: ReadOnly + IF: !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS) + NAME: freelist_count TYPE: HEADER_VALUE ARG: BTREE_FREE_PAGE_COUNT From 0d339e44a0fa01a8f99ca2bda5971aecbd860922 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 19 Dec 2014 20:27:02 +0000 Subject: [PATCH 6/7] Adding test cases for the "PRAGMA data_version" command. FossilOrigin-Name: c5fb7d6a106d46f10e71abe3a6d4243b21ed02a5 --- manifest | 14 ++++------ manifest.uuid | 2 +- test/pragma3.test | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 test/pragma3.test diff --git a/manifest b/manifest index f22a0f1b43..221ed91de4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Experimental\s"PRAGMA\sdata_version"\scommand\sfor\sdetecting\swhen\sanother\sprocess\nhas\schanged\sthe\sdatabase\sfile. -D 2014-12-19T19:28:02.465 +C Adding\stest\scases\sfor\sthe\s"PRAGMA\sdata_version"\scommand. +D 2014-12-19T20:27:02.112 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -785,6 +785,7 @@ F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 4e12d43f4639ea8a0e366d9c64e0009afe2eb544 F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 +F test/pragma3.test 117ef9768f6c8d11823de7bbe3231b35c426b013 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d @@ -1233,10 +1234,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P da27a09d1d991583b59997f6cc67efa28ffd9d6a -R df4854633d0919cb180185852b6a45b5 -T *branch * data_version_pragma -T *sym-data_version_pragma * -T -sym-trunk * +P 43db1f44bce5a0ee50197b95ab0d844540b69d86 +R 2feb9c2cda6af5a5f57185acec7e4041 U drh -Z 81defb06f28b03737e8cb7607139b4d9 +Z 8c3ff0ee7ae569dc5dbcf90ed4307270 diff --git a/manifest.uuid b/manifest.uuid index 92b0ead781..bcdaad2219 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -43db1f44bce5a0ee50197b95ab0d844540b69d86 \ No newline at end of file +c5fb7d6a106d46f10e71abe3a6d4243b21ed02a5 \ No newline at end of file diff --git a/test/pragma3.test b/test/pragma3.test new file mode 100644 index 0000000000..f3229ee528 --- /dev/null +++ b/test/pragma3.test @@ -0,0 +1,70 @@ +# 2014-12-19 +# +# 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. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. +# +# This file implements tests for PRAGMA data_version command. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test pragma3-100 { + PRAGMA data_version; +} {1} +do_execsql_test pragma3-101 { + PRAGMA temp.data_version; +} {1} + +# Writing is a no-op +do_execsql_test pragma3-102 { + PRAGMA main.data_version=1234; + PRAGMA main.data_version; +} {1 1} + +do_execsql_test pragma3-110 { + CREATE TABLE t1(a); + INSERT INTO t1 VALUES(100),(200),(300); + SELECT * FROM t1; + PRAGMA data_version; +} {100 200 300 1} + +sqlite3 db2 test.db +do_test pragma3-120 { + db2 eval { + SELECT * FROM t1; + PRAGMA data_version; + } +} {100 200 300 1} + +do_execsql_test pragma3-130 { + INSERT INTO t1 VALUES(400),(500); + SELECT * FROM t1; + PRAGMA data_version; +} {100 200 300 400 500 1} + +do_test pragma3-140 { + db2 eval { + SELECT * FROM t1; + PRAGMA data_version; + UPDATE t1 SET a=a+1; + SELECT * FROM t1; + PRAGMA data_version; + } +} {100 200 300 400 500 2 101 201 301 401 501 2} + +do_execsql_test pragma3-150 { + SELECT * FROM t1; + PRAGMA data_version; +} {101 201 301 401 501 2} + + +db2 close +finish_test From d7107b3852793d77c7e5e4ac679ec99300a42507 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 20 Dec 2014 14:34:02 +0000 Subject: [PATCH 7/7] Update the PRAGMA data_version command so that it reponse to changes made by a shared-cache database connection, and also to changes made by the same database connection. Add test cases to verify the new behavior. FossilOrigin-Name: 44ee538374940c50198949f2cbb9213ba2375b6a --- manifest | 14 +++---- manifest.uuid | 2 +- src/pager.c | 9 ++-- test/pragma3.test | 102 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 108 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 221ed91de4..affc6751c4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adding\stest\scases\sfor\sthe\s"PRAGMA\sdata_version"\scommand. -D 2014-12-19T20:27:02.112 +C Update\sthe\sPRAGMA\sdata_version\scommand\sso\sthat\sit\sreponse\sto\schanges\smade\nby\sa\sshared-cache\sdatabase\sconnection,\sand\salso\sto\schanges\smade\sby\sthe\ssame\ndatabase\sconnection.\s\sAdd\stest\scases\sto\sverify\sthe\snew\sbehavior. +D 2014-12-20T14:34:02.508 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -216,7 +216,7 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7 F src/os_win.c ecb04a0dad2fa6fa659931a9d8f0f3aca33f908a F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21 -F src/pager.c abe022cd72e112a05db5fd1d6d46f5ed93284247 +F src/pager.c 2cbaf886a6157c53a8061ea7e677f81620ff46eb F src/pager.h c3476e7c89cdf1c6914e50a11f3714e30b4e0a77 F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45 F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4 @@ -785,7 +785,7 @@ F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 4e12d43f4639ea8a0e366d9c64e0009afe2eb544 F test/pragma.test aa16dedfe01c02c8895169012f7dfde9c163f0d5 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 -F test/pragma3.test 117ef9768f6c8d11823de7bbe3231b35c426b013 +F test/pragma3.test af097524ab7fdac11d3a37a5bab4f947f2d5d16c F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d @@ -1234,7 +1234,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 43db1f44bce5a0ee50197b95ab0d844540b69d86 -R 2feb9c2cda6af5a5f57185acec7e4041 +P c5fb7d6a106d46f10e71abe3a6d4243b21ed02a5 +R 4d00079d15bfd5a1a2ef4485d7808f56 U drh -Z 8c3ff0ee7ae569dc5dbcf90ed4307270 +Z 7090cd431f3e847d9d9c987c1e3b054c diff --git a/manifest.uuid b/manifest.uuid index bcdaad2219..5bbac1f6ef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c5fb7d6a106d46f10e71abe3a6d4243b21ed02a5 \ No newline at end of file +44ee538374940c50198949f2cbb9213ba2375b6a \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 97dd78e35b..67b95f7186 100644 --- a/src/pager.c +++ b/src/pager.c @@ -664,7 +664,7 @@ struct Pager { sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ - u32 nReset; /* Number of calls to pager_reset() */ + u32 iDataVersion; /* Changes whenever database content changes */ char dbFileVers[16]; /* Changes whenever database file changes */ int nMmapOut; /* Number of mmap pages currently outstanding */ @@ -1682,17 +1682,17 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){ ** Discard the entire contents of the in-memory page-cache. */ static void pager_reset(Pager *pPager){ - pPager->nReset++; + pPager->iDataVersion++; sqlite3BackupRestart(pPager->pBackup); sqlite3PcacheClear(pPager->pPCache); } /* -** Return the pPager->nReset value +** Return the pPager->iDataVersion value */ u32 sqlite3PagerDataVersion(Pager *pPager){ assert( pPager->eState>PAGER_OPEN ); - return pPager->nReset; + return pPager->iDataVersion; } /* @@ -6317,6 +6317,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); + pPager->iDataVersion++; rc = pager_end_transaction(pPager, pPager->setMaster, 1); return pager_error(pPager, rc); } diff --git a/test/pragma3.test b/test/pragma3.test index f3229ee528..a070c9b42c 100644 --- a/test/pragma3.test +++ b/test/pragma3.test @@ -23,18 +23,34 @@ do_execsql_test pragma3-101 { PRAGMA temp.data_version; } {1} -# Writing is a no-op +# Writing to the pragma is a no-op do_execsql_test pragma3-102 { PRAGMA main.data_version=1234; PRAGMA main.data_version; } {1 1} +# EVIDENCE-OF: R-27726-60934 The "PRAGMA data_version" command provides +# an indication that the database file has been modified. +# +# EVIDENCE-OF: R-30058-27547 The integer values returned by two +# invocations of "PRAGMA data_version" will be different if changes +# where committed to that database in between the two invocations. +# +# EVIDENCE-OF: R-10201-09349 The "PRAGMA data_version" command responses +# to changes committed by the same database connection, by database +# connections sharing a cache in shared cache mode, and by completely +# independent database connections including connections in separate +# threads and processes. +# +# In this test, it response to two separate changes on the same database +# connection. +# do_execsql_test pragma3-110 { CREATE TABLE t1(a); INSERT INTO t1 VALUES(100),(200),(300); SELECT * FROM t1; PRAGMA data_version; -} {100 200 300 1} +} {100 200 300 3} sqlite3 db2 test.db do_test pragma3-120 { @@ -48,8 +64,17 @@ do_execsql_test pragma3-130 { INSERT INTO t1 VALUES(400),(500); SELECT * FROM t1; PRAGMA data_version; -} {100 200 300 400 500 1} +} {100 200 300 400 500 4} +# EVIDENCE-OF: R-10201-09349 The "PRAGMA data_version" command responses +# to changes committed by the same database connection, by database +# connections sharing a cache in shared cache mode, and by completely +# independent database connections including connections in separate +# threads and processes. +# +# In these test, it response to changes in a different database connection +# part of the same process. +# do_test pragma3-140 { db2 eval { SELECT * FROM t1; @@ -58,13 +83,76 @@ do_test pragma3-140 { SELECT * FROM t1; PRAGMA data_version; } -} {100 200 300 400 500 2 101 201 301 401 501 2} - +} {100 200 300 400 500 2 101 201 301 401 501 3} do_execsql_test pragma3-150 { SELECT * FROM t1; PRAGMA data_version; -} {101 201 301 401 501 2} - +} {101 201 301 401 501 5} +# EVIDENCE-OF: R-10201-09349 The "PRAGMA data_version" command responses +# to changes committed by the same database connection, by database +# connections sharing a cache in shared cache mode, and by completely +# independent database connections including connections in separate +# threads and processes. +# +# This test verifies behavior when a separate process changes the database +# file. +# +do_test pragma3-200 { + set fd [open pragma3.txt wb] + puts $fd { + sqlite3 db test.db; + db eval {DELETE FROM t1 WHERE a>300}; + db close; + exit; + } + close $fd + exec [info nameofexec] pragma3.txt + forcedelete pragma3.txt + db eval { + PRAGMA data_version; + SELECT * FROM t1; + } +} {6 101 201} db2 close +db close + +# EVIDENCE-OF: R-10201-09349 The "PRAGMA data_version" command responses +# to changes committed by the same database connection, by database +# connections sharing a cache in shared cache mode, and by completely +# independent database connections including connections in separate +# threads and processes. +# +# The next series of tests verifies the behavior for shared-cache +# database connections. +# +ifcapable shared_cache { + set ::enable_shared_cache [sqlite3_enable_shared_cache 1] + sqlite3 db test.db + sqlite3 db2 test.db + do_test pragma3-300 { + db eval { + PRAGMA data_version; + CREATE TABLE t3(a,b,c); + PRAGMA data_version; + } + } {1 2} + do_test pragma3-310 { + db2 eval { + PRAGMA data_version; + INSERT INTO t3(a,b,c) VALUES('abc','def','ghi'); + SELECT * FROM t3; + PRAGMA data_version; + } + } {2 abc def ghi 3} + do_test pragma3-320 { + db eval { + PRAGMA data_version; + SELECT * FROM t3; + } + } {3 abc def ghi} + db2 close + sqlite3_enable_shared_cache $::enable_shared_cache +} + finish_test