diff --git a/Makefile.in b/Makefile.in index f3239f3d79..b0871ad940 100644 --- a/Makefile.in +++ b/Makefile.in @@ -378,7 +378,8 @@ TESTSRC = \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_vfs.c \ $(TOP)/src/test_wholenumber.c \ - $(TOP)/src/test_wsd.c + $(TOP)/src/test_wsd.c \ + $(TOP)/ext/fts3/fts3_term.c # Source code to the library files needed by the test fixture # @@ -420,6 +421,7 @@ TESTSRC2 = \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ + $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c @@ -828,12 +830,12 @@ fts3_hash.lo: $(TOP)/ext/fts3/fts3_hash.c $(HDR) $(EXTHDR) fts3_icu.lo: $(TOP)/ext/fts3/fts3_icu.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_icu.c -fts3_snippet.lo: $(TOP)/ext/fts3/fts3_snippet.c $(HDR) $(EXTHDR) - $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_snippet.c - fts3_porter.lo: $(TOP)/ext/fts3/fts3_porter.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c +fts3_snippet.lo: $(TOP)/ext/fts3/fts3_snippet.c $(HDR) $(EXTHDR) + $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_snippet.c + fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 6794e3d67e..ea430627cd 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1195,7 +1195,7 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ ** table is missing a row that is present in the full-text index. ** The data structures are corrupt. */ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; } pCsr->isEof = 1; if( pContext ){ @@ -1255,7 +1255,7 @@ static int fts3ScanInteriorNode( zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); if( zCsr>zEnd ){ - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } while( zCsrzEnd ){ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; goto finish_scan; } if( nPrefix+nSuffix>nAlloc ){ @@ -3661,7 +3661,7 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ } static const sqlite3_module fts3Module = { - /* iVersion */ 1, + /* iVersion */ 2, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index b843fe9dc6..8d1e15737d 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -381,6 +381,7 @@ int sqlite3Fts3ExprParse(sqlite3_tokenizer *, void sqlite3Fts3ExprFree(Fts3Expr *); #ifdef SQLITE_TEST int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); +int sqlite3Fts3InitTerm(sqlite3 *db); #endif /* fts3_aux.c */ diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c index 99f9dd7174..8bf9ed2d5a 100644 --- a/ext/fts3/fts3_snippet.c +++ b/ext/fts3/fts3_snippet.c @@ -960,7 +960,7 @@ static int fts3MatchinfoSelectDoctotal( a = sqlite3_column_blob(pStmt, 0); a += sqlite3Fts3GetVarint(a, &nDoc); - if( nDoc==0 ) return SQLITE_CORRUPT; + if( nDoc==0 ) return SQLITE_CORRUPT_VTAB; *pnDoc = (u32)nDoc; if( paLen ) *paLen = a; @@ -1555,7 +1555,7 @@ void sqlite3Fts3Offsets( ); rc = fts3StringAppend(&res, aBuffer, -1); }else if( rc==SQLITE_DONE ){ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; } } } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 025fb64a64..d00632a75d 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -291,7 +291,7 @@ static int fts3SelectDocsize( rc = sqlite3_step(pStmt); if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ rc = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT; + if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB; pStmt = 0; }else{ rc = SQLITE_OK; @@ -972,7 +972,7 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){ if( nPrefix<0 || nSuffix<=0 || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] ){ - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } if( nPrefix+nSuffix>pReader->nTermAlloc ){ @@ -998,7 +998,7 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){ if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] || pReader->aDoclist[pReader->nDoclist-1] ){ - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } return SQLITE_OK; } @@ -1123,7 +1123,7 @@ int sqlite3Fts3SegReaderCost( } if( nDoc==0 || nByte==0 ){ sqlite3_reset(pStmt); - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz); @@ -2762,7 +2762,7 @@ int sqlite3Fts3UpdateMethod( if( nArg>1 && rc==SQLITE_OK ){ if( bInsertDone==0 ){ rc = fts3InsertData(p, apVal, pRowid); - if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT; + if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB; } if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ rc = fts3PendingTermsDocid(p, *pRowid); diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 4529f3aabb..6e00827b46 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -517,17 +517,17 @@ nodeAcquire( if( pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; } } /* If no error has occurred so far, check if the "number of entries" ** field on the node is too large. If so, set the return code to - ** SQLITE_CORRUPT. + ** SQLITE_CORRUPT_VTAB. */ if( pNode && rc==SQLITE_OK ){ if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; } } @@ -535,7 +535,7 @@ nodeAcquire( if( pNode!=0 ){ nodeHashInsert(pRtree, pNode); }else{ - rc = SQLITE_CORRUPT; + rc = SQLITE_CORRUPT_VTAB; } *ppNode = pNode; }else{ @@ -1062,7 +1062,7 @@ static int nodeRowidIndex( return SQLITE_OK; } } - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } /* @@ -1657,7 +1657,7 @@ static int AdjustTree( int iCell; if( nodeParentIndex(pRtree, p, &iCell) ){ - return SQLITE_CORRUPT; + return SQLITE_CORRUPT_VTAB; } nodeGetCell(pRtree, pParent, iCell, &cell); @@ -2329,7 +2329,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){ } rc = sqlite3_reset(pRtree->pReadParent); if( rc==SQLITE_OK ) rc = rc2; - if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT; + if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; pChild = pChild->pParent; } return rc; diff --git a/main.mk b/main.mk index c5f9798576..840a3d01aa 100644 --- a/main.mk +++ b/main.mk @@ -55,8 +55,8 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \ fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ - fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o fts3_write.o \ - func.o global.o hash.o \ + fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \ + fts3_write.o func.o global.o hash.o \ icu.o insert.o journal.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memjournal.o \ diff --git a/manifest b/manifest index 0c02b5eafe..7c550ad27a 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C Merge\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch. -D 2011-05-05T15:46:16.843 +C Merge\sall\sthe\slatest\strunk\schanges\sinto\sthe\ssessions\sbranch,\sespecially\nthe\sdisappearing\sWAL\stransaction\sfix. +D 2011-05-19T02:48:46.609 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 +F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6 @@ -61,28 +61,28 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 73d6718dba1e4ef621ff8a4ac1c22019460c84cc +F ext/fts3/fts3.c 18c2a079ba2b9154b7485fd39d1a6d12b5872a76 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h 8c2ac39ee17362571c58ab2c4f0667324c31f738 +F ext/fts3/fts3Int.h 05d145152620e7849c452bd919f2cc3e2d75309f F ext/fts3/fts3_aux.c 9e931f55eed8498dafe7bc1160f10cbb1a652fdf F ext/fts3/fts3_expr.c 5f49e0deaf723724b08100bb3ff40aab02ad0c93 F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295 F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2 -F ext/fts3/fts3_snippet.c a4a3c7d2ab15ca9188e2d9b51a5e3927bf76580d +F ext/fts3/fts3_snippet.c 92b40397b28422c35c4127492d7ac6da34d1966a F ext/fts3/fts3_term.c f115f5a5f4298303d3b22fc6c524b8d565c7b950 F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d -F ext/fts3/fts3_write.c 7d6d904b89333448eb968fc82470a74985d0b61e +F ext/fts3/fts3_write.c b50181e5ecf484c2f56e98d651424e4b69f96c89 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 829c6901a2b065ff93a68d431f9eaba8de7128e0 +F ext/rtree/rtree.c 2445bec932f58f8f4fe9de49a63bd6bf24db82d6 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -112,7 +112,7 @@ F ext/session/sqlite3session.h 665f5591562e3c71eb3d0da26f1a1efae26f7bcf F ext/session/test_session.c 311e5b9228374d0b5780448f289847ff1cf7d388 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 -F main.mk 352002cedf9e754ec96cfe0a8d1688cdea343fea +F main.mk bc31e3b2cfa42337a34fc4509a1b550c0cd5b202 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac @@ -127,15 +127,15 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c 280f5c04b11b492703a342222b3de0a999445280 F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a -F src/attach.c 7f97ca76ef2453440170929531a9c778267c0830 +F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 6a9164af8a2ef4612ee30b253635a9bd8e5e1b1b -F src/btree.h 11753dd46597a20702bca8746cb4caa4486a82b5 +F src/btree.c 975ad691a57eb1fb60f1ec76ad0b6571eace62f9 +F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3 -F src/build.c f09c46c66a1e7668c6ee25c9a2518aaa6842044c +F src/build.c 0132bc6631fa617a1d28ef805921f6dbac18a514 F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4 @@ -145,7 +145,7 @@ F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc -F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 +F src/global.c 29bfb85611dd816b04f10fba0ca910366e128d38 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 @@ -154,8 +154,8 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/loadext.c 3ae0d52da013a6326310655be6473fd472347b85 -F src/main.c 8b97db74cb876bf34ca4fb3720b18e4ffdcf9fd5 -F src/malloc.c 74c740e8ba22b806cfb980c8c0ddea1cbd54a20e +F src/main.c 8206d7970cb858979ec84eea9a5eff2b575849a6 +F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206 F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf @@ -173,32 +173,32 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 -F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b -F src/os_win.c 4271f0bf733c0b45635ddcfb41c935573de8284c -F src/pager.c 055239dcdfe12b3f5d97f6f01f85da01e2d6d912 +F src/os_unix.c 6d4a58d81ad4b782406519f3790202f330e89bb7 +F src/os_win.c 218b899469e570d46eb8147c2383075f7c026230 +F src/pager.c 4b2358556c88660a94a4560de95dd728911e00fd F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050 F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e -F src/pragma.c 49c90ab27a4339d4b5bc0b03c08cbcf20ed8d454 +F src/pragma.c 9e778decc3ee9bcaf88904b4a3b0a4360aaf0eab F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4 F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff -F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79 -F src/sqlite.h.in 628de30f6063695288eadf34c167e49bc34c9828 +F src/shell.c decd04236a7ef26be5ef46d4ea963044bfad9a48 +F src/sqlite.h.in b851102bb0840bf6d4dde5d6690c2ad127a65ade F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 -F src/sqliteInt.h 1577ac69cb67a1dc0c07974a4e5129b1cde039a3 +F src/sqliteInt.h 2fb482cff778112e6b2797226f30f3862a627468 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c fe0da0eb0ebd8d21eec90683b779456e64351de6 -F src/test1.c e0e4af306b678da05334c2ccaf0377ae8f06e911 +F src/test1.c 4a1171af201be90c21d64a872e686b1333d9a2cf F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 -F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc +F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test5.c e1a19845625144caf038031234a12185e40d315c F src/test6.c c7256cc21d2409486d094277d5b017e8eced44ba @@ -209,7 +209,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 -F src/test_config.c 25a4128c2dc9e1dbebafcb7e8c61d45f09f7fbc3 +F src/test_config.c 2794d55f27c7faa6c8203b15e634e7103953ddcc F src/test_demovfs.c 938d0f595f8bd310076e1c06cf7885a01ce7ce01 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5 @@ -220,8 +220,8 @@ F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99 F src/test_intarray.h 489edb9068bb926583445cb02589344961054207 F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70 F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e -F src/test_malloc.c fd6188b1501c0010fb4241ddc9f0d5ac402c688d -F src/test_multiplex.c fdabd793ee7a9642c5a8a470def2347144c46d05 +F src/test_malloc.c 7ca7be34e0e09ef0ed6619544552ed95732e41f6 +F src/test_multiplex.c 8e67617b80b532315293761970589581745a52a0 F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec @@ -236,7 +236,7 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_syscall.c 162c4ec0137a549c009bb9ecab550527743cfc5d F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c 361ae0a0f1cbf5a28ad0388a258b104017a370c0 -F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86 +F src/test_vfs.c 0ac5b2e3da61bc385c1017890687c359746be2fd F src/test_vfstrace.c 2265c9895f350c8d3c39b079998fbe7481505cc1 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 @@ -244,25 +244,26 @@ F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/trigger.c 144cc18bb701f3286484aae4292a9531f09278c8 F src/update.c f66b651c15e42875f36501ec39a968e836ee5586 F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60 -F src/util.c 465fe10aabf0ca7d7826a156dab919b0b65c525a +F src/util.c 0f33bbbdfcc4a2d8cf20c3b2a16ffc3b57c58a70 F src/vacuum.c 05513dca036a1e7848fe18d5ed1265ac0b32365e -F src/vdbe.c fa5bfc0c820706a1f78042b134a0f7a388ca9a3e +F src/vdbe.c af2e9d0ffd3e111140bc51769f6995834be69e11 F src/vdbe.h 44fd57aeed86da0cd31206626c13cdde0e72cc0e F src/vdbeInt.h b95de01246c15499c700ae00cfda0de25c01358a F src/vdbeapi.c 8051038f7674c708f4515ab189fc3ea929e09a4c -F src/vdbeaux.c cc95d80b899b75829cb93d260d3f14125a5c26ad +F src/vdbeaux.c be135f46ee48b5726fb59ca41224475c1dbe8f8b F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 -F src/vtab.c 1491acb3e0a67eafe69134fb65bfa0b7b7e82342 -F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 -F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 +F src/vtab.c 48dcef8bc757c2e7b488f68b5ddebb1650da2450 +F src/wal.c de27c34c8016c00be348fc6bed588816557ceb66 +F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5 +F test/8_3_names.test b93687beebd17f6ebf812405a6833bae5d1f4199 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125 -F test/alter.test 4e47fb9ea59348b88fce4e8bb49de530128b104c +F test/alter.test a3f570072b53d7c0fe463bab3f5affa8e113c487 F test/alter2.test 75f731508f1bf27ba09a6075c66cd02216ba464b F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07 F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403 @@ -322,7 +323,7 @@ F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test bea67403a5e37a4b33230ee4723e315a2ffb31e7 F test/capi3d.test cd36571f014f34bdc4421967f6453cbb597d5d16 F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde -F test/cast.test 166951664a0b0a2e0f8fb5997a152490c6363932 +F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test db2b29d557544347d28e25b8406f5d5ecc3d1bc3 F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91 F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04 @@ -389,6 +390,7 @@ F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6 F test/e_select.test bf385ae3aa0f014c4933ae66fd3e1302138493eb F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92 F test/e_update.test 963d6876064e65f318d1c93aaed36a02b9b389bf +F test/e_uri.test 9ce11319fb9b271bf7392027f913f7830e93e7a7 F test/e_vacuum.test 6c09c2af7f2f140518f371c5342100118f779dcf F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398 @@ -400,7 +402,7 @@ F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062 F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 5e2d64b4eb5a9d08876599bdae2e1213d2d12e2a -F test/expr.test 19e8ac40313e2282a47b586d11c4892040990d3a +F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6 F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c @@ -467,7 +469,7 @@ F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c F test/fts3conf.test 8e65ea56f88ced6cdd2252bdddb1a8327ae5af7e -F test/fts3corrupt.test 7890cc202406858386ddf390a879dcf80bc10abf +F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32 F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52 @@ -598,10 +600,10 @@ F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test 29032efcd3d826fbd409e2a7af873e7939f4a4e3 F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33 -F test/multiplex.test a88f3e2c16e567e72be7296195c59fbdd6a8d3d4 +F test/multiplex.test 7a8a50c8ed72dfcf4db9ebae977f7a63184639d8 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 -F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723 +F test/nan.test dc212a22b36109fd1ae37154292444ef249c5ec2 F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310 F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a @@ -609,7 +611,7 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec F test/oserror.test 498d8337e9d15543eb7b004fef8594bf204ff43c -F test/pager1.test d8672fd0af5f4f9b99b06283d00f01547809bebe +F test/pager1.test 8baf4470b29511503abcaf1f17d16b16462e4d54 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pagerfault.test 9de4d3e0c59970b4c6cb8dac511fa242f335d8a7 @@ -700,7 +702,7 @@ F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05 -F test/tester.tcl cf301cdb35f20378b086849acd26a4574187183f +F test/tester.tcl 1949b4af9701daaca189fd5d53a6e48173c162af F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca @@ -714,6 +716,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9 F test/threadtest3.c 0ed13e09690f6204d7455fac3b0e8ece490f6eef F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660 +F test/tkt-2d1a5c67d.test 39d2368072315923021700a216379fcf23ac3a5c F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28 F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac @@ -812,13 +815,13 @@ F test/tkt3793.test 754b73f0e6a9349c70dc57e522cf3247272ecd5d F test/tkt3810.test 90fa0635dfa7da9680c8cd3513350a49b3a8ae12 F test/tkt3824.test 150aa00bb6220672e5f0eb14dc8eaa36750425f0 F test/tkt3832.test 2300d10d57562b89875b72148338ac3e14f8847d -F test/tkt3838.test f956f0719b5f805b12dd1dbf19f19d298bacebc3 +F test/tkt3838.test d8490365a1c473d214f7878007e543410cbb715f F test/tkt3841.test 4659845bc53f809a5932c61c6ce8c5bb9d6b947f F test/tkt3871.test 43ecbc8d90dc83908e2a454aef345acc9d160c6f F test/tkt3879.test 2ad5bef2c87e9991ce941e054c31abe26ef7fb90 F test/tkt3911.test 74cd324f3ba653040cc6d94cc4857b290d12d633 F test/tkt3918.test e6cdf6bfcfe9ba939d86a4238a9dc55d6eec5d42 -F test/tkt3922.test 022ace32c049e3964f68492c12eb803e8e4856d8 +F test/tkt3922.test f26be40ab4fe6c00795629bd2006d96e270d9b1a F test/tkt3929.test 75a862e45bcb39e9a7944c89b92afa531304afca F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767 F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da @@ -851,6 +854,7 @@ F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2 F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e F test/unordered.test e81169ce2a8f31b2c6b66af691887e1376ab3ced F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 +F test/uri.test 2d08a6f77bf93ca925743a65802c4aa23aaaf373 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae F test/vacuum.test 29b60e8cc9e573b39676df6c4a75fe9e02d04a09 F test/vacuum2.test 91a84c9b08adfc4472097d2e8deb0150214e0e76 @@ -882,6 +886,7 @@ F test/wal3.test 5c396cc22497244d627306f4c1d360167353f8dd F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30 F test/wal5.test 1bbfaa316dc2a1d0d1fac3f4500c38a90055a41b F test/wal6.test 07aa31ca8892d0527f2c5c5a9a2a87aa421dfaa8 +F test/wal7.test 09bc8de3d11949571d6f7a4188b308059cec27e5 F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4 F test/walbig.test e882bc1d014afffbfa2b6ba36e0f07d30a633ad0 @@ -944,7 +949,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P b91b4c31fe311b292044c9c747feba294ffce25c 930be6a1bdec8c150caafd790973f7a401fc1970 -R 13217a0634732c3fc1250bf1a2936d3d +P 6883580e6c8973010a42d1d2c5bde04c6b2f4eb7 67bf1c9a888b0d84d252d6c4c754c2c51994d208 +R f15f9213bb9ad0f88efa9254eb2387a3 U drh -Z f29377c78641e183f6acae5b288b38b3 +Z 1a1886a9d9151866e45101a5d0e49b24 diff --git a/manifest.uuid b/manifest.uuid index c83e756c42..fe55e41565 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6883580e6c8973010a42d1d2c5bde04c6b2f4eb7 \ No newline at end of file +5b1b536cf828850d0e8ac2ab08e8696082715877 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index bda1c87445..18f8823b31 100644 --- a/src/attach.c +++ b/src/attach.c @@ -70,8 +70,12 @@ static void attachFunc( sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; + char *zPath = 0; + char *zErr = 0; + unsigned int flags; Db *aNew; char *zErrDyn = 0; + sqlite3_vfs *pVfs; UNUSED_PARAMETER(NotUsed); @@ -124,8 +128,18 @@ static void attachFunc( ** it to obtain the database schema. At this point the schema may ** or may not be initialised. */ - rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0, - db->openFlags | SQLITE_OPEN_MAIN_DB); + flags = db->openFlags; + rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + sqlite3_result_error(context, zErr, -1); + sqlite3_free(zErr); + return; + } + assert( pVfs ); + flags |= SQLITE_OPEN_MAIN_DB; + rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); + sqlite3_free( zPath ); db->nDb++; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; diff --git a/src/btree.c b/src/btree.c index 103a1f3230..df75053743 100644 --- a/src/btree.c +++ b/src/btree.c @@ -788,6 +788,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } + assert( offset <= (int)pBt->usableSize-5 ); pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ @@ -827,6 +828,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); offset = PTRMAP_PTROFFSET(iPtrmap, key); + if( offset<0 ){ + sqlite3PagerUnref(pDbPage); + return SQLITE_CORRUPT_BKPT; + } + assert( offset <= (int)pBt->usableSize-5 ); assert( pEType!=0 ); *pEType = pPtrmap[offset]; if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); @@ -1688,13 +1694,13 @@ static int btreeInvokeBusyHandler(void *pArg){ ** to problems with locking. */ int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ const char *zFilename, /* Name of the file containing the BTree database */ sqlite3 *db, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ int flags, /* Options */ int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ ){ - sqlite3_vfs *pVfs; /* The VFS to use for this btree */ BtShared *pBt = 0; /* Shared part of btree structure */ Btree *p; /* Handle to return */ sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ @@ -1716,6 +1722,7 @@ int sqlite3BtreeOpen( #endif assert( db!=0 ); + assert( pVfs!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ @@ -1734,7 +1741,6 @@ int sqlite3BtreeOpen( if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; } - pVfs = db->pVfs; p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM; diff --git a/src/btree.h b/src/btree.h index c6f6aec5df..9e3a73b3b6 100644 --- a/src/btree.h +++ b/src/btree.h @@ -42,6 +42,7 @@ typedef struct BtShared BtShared; int sqlite3BtreeOpen( + sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ diff --git a/src/build.c b/src/build.c index 83a1db8400..fa2d53a14b 100644 --- a/src/build.c +++ b/src/build.c @@ -3443,7 +3443,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){ SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TEMP_DB; - rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags); + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "unable to open a temporary database " "file for storing temporary tables"); diff --git a/src/global.c b/src/global.c index 0c890684d9..f01eaa8f4a 100644 --- a/src/global.c +++ b/src/global.c @@ -129,7 +129,9 @@ const unsigned char sqlite3CtypeMap[256] = { }; #endif - +#ifndef SQLITE_USE_URI +# define SQLITE_USE_URI 0 +#endif /* ** The following singleton contains the global configuration for @@ -139,6 +141,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = { SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ 1, /* bCoreMutex */ SQLITE_THREADSAFE==1, /* bFullMutex */ + SQLITE_USE_URI, /* bOpenUri */ 0x7ffffffe, /* mxStrlen */ 100, /* szLookaside */ 500, /* nLookaside */ diff --git a/src/main.c b/src/main.c index cb2e98947a..90c9d2e9e4 100644 --- a/src/main.c +++ b/src/main.c @@ -426,6 +426,11 @@ int sqlite3_config(int op, ...){ break; } + case SQLITE_CONFIG_URI: { + sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); + break; + } + default: { rc = SQLITE_ERROR; break; @@ -1806,6 +1811,236 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ return oldLimit; /* IMP: R-53341-35419 */ } +/* +** This function is used to parse both URIs and non-URI filenames passed by the +** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database +** URIs specified as part of ATTACH statements. +** +** The first argument to this function is the name of the VFS to use (or +** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" +** query parameter. The second argument contains the URI (or non-URI filename) +** itself. When this function is called the *pFlags variable should contain +** the default flags to open the database handle with. The value stored in +** *pFlags may be updated before returning if the URI filename contains +** "cache=xxx" or "mode=xxx" query parameters. +** +** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to +** the VFS that should be used to open the database file. *pzFile is set to +** point to a buffer containing the name of the file to open. It is the +** responsibility of the caller to eventually call sqlite3_free() to release +** this buffer. +** +** If an error occurs, then an SQLite error code is returned and *pzErrMsg +** may be set to point to a buffer containing an English language error +** message. It is the responsibility of the caller to eventually release +** this buffer by calling sqlite3_free(). +*/ +int sqlite3ParseUri( + const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ + const char *zUri, /* Nul-terminated URI to parse */ + unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ + sqlite3_vfs **ppVfs, /* OUT: VFS to use */ + char **pzFile, /* OUT: Filename component of URI */ + char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ +){ + int rc = SQLITE_OK; + unsigned int flags = *pFlags; + const char *zVfs = zDefaultVfs; + char *zFile; + char c; + int nUri = sqlite3Strlen30(zUri); + + assert( *pzErrMsg==0 ); + + if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) + && nUri>=5 && memcmp(zUri, "file:", 5)==0 + ){ + char *zOpt; + int eState; /* Parser state when parsing URI */ + int iIn; /* Input character index */ + int iOut = 0; /* Output character index */ + int nByte = nUri+2; /* Bytes of space to allocate */ + + /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen + ** method that there may be extra parameters following the file-name. */ + flags |= SQLITE_OPEN_URI; + + for(iIn=0; iIn=0 && octet<256 ); + if( octet==0 ){ + /* This branch is taken when "%00" appears within the URI. In this + ** case we ignore all text in the remainder of the path, name or + ** value currently being parsed. So ignore the current character + ** and skip to the next "?", "=" or "&", as appropriate. */ + while( (c = zUri[iIn])!=0 && c!='#' + && (eState!=0 || c!='?') + && (eState!=1 || (c!='=' && c!='&')) + && (eState!=2 || c!='&') + ){ + iIn++; + } + continue; + } + c = octet; + }else if( eState==1 && (c=='&' || c=='=') ){ + if( zFile[iOut-1]==0 ){ + /* An empty option name. Ignore this option altogether. */ + while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; + continue; + } + if( c=='&' ){ + zFile[iOut++] = '\0'; + }else{ + eState = 2; + } + c = 0; + }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ + c = 0; + eState = 1; + } + zFile[iOut++] = c; + } + if( eState==1 ) zFile[iOut++] = '\0'; + zFile[iOut++] = '\0'; + zFile[iOut++] = '\0'; + + /* Check if there were any options specified that should be interpreted + ** here. Options that are interpreted here include "vfs" and those that + ** correspond to flags that may be passed to the sqlite3_open_v2() + ** method. */ + zOpt = &zFile[sqlite3Strlen30(zFile)+1]; + while( zOpt[0] ){ + int nOpt = sqlite3Strlen30(zOpt); + char *zVal = &zOpt[nOpt+1]; + int nVal = sqlite3Strlen30(zVal); + + if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ + zVfs = zVal; + }else{ + struct OpenMode { + const char *z; + int mode; + } *aMode = 0; + char *zModeType; + int mask; + int limit; + + if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ + static struct OpenMode aCacheMode[] = { + { "shared", SQLITE_OPEN_SHAREDCACHE }, + { "private", SQLITE_OPEN_PRIVATECACHE }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; + aMode = aCacheMode; + limit = mask; + zModeType = "cache"; + } + if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ + static struct OpenMode aOpenMode[] = { + { "ro", SQLITE_OPEN_READONLY }, + { "rw", SQLITE_OPEN_READWRITE }, + { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, + { 0, 0 } + }; + + mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + aMode = aOpenMode; + limit = mask & flags; + zModeType = "access"; + } + + if( aMode ){ + int i; + int mode = 0; + for(i=0; aMode[i].z; i++){ + const char *z = aMode[i].z; + if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ + mode = aMode[i].mode; + break; + } + } + if( mode==0 ){ + *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); + rc = SQLITE_ERROR; + goto parse_uri_out; + } + if( mode>limit ){ + *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", + zModeType, zVal); + rc = SQLITE_PERM; + goto parse_uri_out; + } + flags = (flags & ~mask) | mode; + } + } + + zOpt = &zVal[nVal+1]; + } + + }else{ + zFile = sqlite3_malloc(nUri+2); + if( !zFile ) return SQLITE_NOMEM; + memcpy(zFile, zUri, nUri); + zFile[nUri] = '\0'; + zFile[nUri+1] = '\0'; + } + + *ppVfs = sqlite3_vfs_find(zVfs); + if( *ppVfs==0 ){ + *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); + rc = SQLITE_ERROR; + } + parse_uri_out: + if( rc!=SQLITE_OK ){ + sqlite3_free(zFile); + zFile = 0; + } + *pFlags = flags; + *pzFile = zFile; + return rc; +} + + /* ** This routine does the work of opening a database on behalf of ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" @@ -1814,12 +2049,14 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb, /* OUT: Returned database handle */ - unsigned flags, /* Operational flags */ + unsigned int flags, /* Operational flags */ const char *zVfs /* Name of the VFS to use */ ){ - sqlite3 *db; - int rc; - int isThreadsafe; + sqlite3 *db; /* Store allocated handle here */ + int rc; /* Return code */ + int isThreadsafe; /* True for threadsafe connections */ + char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ + char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT @@ -1843,7 +2080,7 @@ static int openDatabase( testcase( (1<<(flags&7))==0x02 ); /* READONLY */ testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ - if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE; + if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT; if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; @@ -1924,13 +2161,6 @@ static int openDatabase( sqlite3HashInit(&db->aModule); #endif - db->pVfs = sqlite3_vfs_find(zVfs); - if( !db->pVfs ){ - rc = SQLITE_ERROR; - sqlite3Error(db, rc, "no such vfs: %s", zVfs); - goto opendb_out; - } - /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. @@ -1953,9 +2183,18 @@ static int openDatabase( createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0, nocaseCollatingFunc, 0); - /* Open the backend database driver */ + /* Parse the filename/URI argument. */ db->openFlags = flags; - rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0, + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); + if( rc!=SQLITE_OK ){ + if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; + sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg); + sqlite3_free(zErrMsg); + goto opendb_out; + } + + /* Open the backend database driver */ + rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, flags | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ if( rc==SQLITE_IOERR_NOMEM ){ @@ -2048,6 +2287,7 @@ static int openDatabase( sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); opendb_out: + sqlite3_free(zOpen); if( db ){ assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); @@ -2079,7 +2319,7 @@ int sqlite3_open_v2( int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ){ - return openDatabase(filename, ppDb, flags, zVfs); + return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); } #ifndef SQLITE_OMIT_UTF16 @@ -2689,3 +2929,25 @@ int sqlite3_test_control(int op, ...){ #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } + +/* +** This is a utility routine, useful to VFS implementations, that checks +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of the query parameter. +** +** The zFilename argument is the filename pointer passed into the xOpen() +** method of a VFS implementation. The zParam argument is the name of the +** query parameter we seek. This routine returns the value of the zParam +** parameter if it exists. If the parameter does not exist, this routine +** returns a NULL pointer. +*/ +const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ + zFilename += sqlite3Strlen30(zFilename) + 1; + while( zFilename[0] ){ + int x = strcmp(zFilename, zParam); + zFilename += sqlite3Strlen30(zFilename) + 1; + if( x==0 ) return zFilename; + zFilename += sqlite3Strlen30(zFilename) + 1; + } + return 0; +} diff --git a/src/malloc.c b/src/malloc.c index 3585f1245d..3e38d1df9f 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -533,7 +533,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){ nDiff = nNew - nOld; if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ - sqlite3MallocAlarm(nNew-nOld); + sqlite3MallocAlarm(nDiff); } assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); @@ -544,7 +544,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){ } if( pNew ){ nNew = sqlite3MallocSize(pNew); - sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nDiff); + sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ diff --git a/src/os_unix.c b/src/os_unix.c index a760e2c147..c768dcfa76 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3769,6 +3769,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ (u32)sStat.st_ino, (u32)sStat.st_dev); #else sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); + sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); #endif pShmNode->h = -1; pDbFd->pInode->pShmNode = pShmNode; @@ -4802,6 +4803,11 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ ** corresponding database file and sets *pMode to this value. Whenever ** possible, WAL and journal files are created using the same permissions ** as the associated database file. +** +** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the +** original filename is unavailable. But 8_3_NAMES is only used for +** FAT filesystems and permissions do not matter there, so just use +** the default permissions. */ static int findCreateFileMode( const char *zPath, /* Path of file (possibly) being created */ @@ -4809,6 +4815,7 @@ static int findCreateFileMode( mode_t *pMode /* OUT: Permissions to open file with */ ){ int rc = SQLITE_OK; /* Return Code */ + *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ @@ -4820,15 +4827,15 @@ static int findCreateFileMode( ** ** "-journal" ** "-wal" - ** "-journal-NNNN" - ** "-wal-NNNN" + ** "-journalNN" + ** "-walNN" ** - ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are + ** where NN is a 4 digit decimal number. The NN naming schemes are ** used by the test_multiplex.c module. */ nDb = sqlite3Strlen30(zPath) - 1; - while( nDb>0 && zPath[nDb]!='l' ) nDb--; - nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7); + while( nDb>0 && zPath[nDb]!='-' ) nDb--; + if( nDb==0 ) return SQLITE_OK; memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; @@ -4839,8 +4846,6 @@ static int findCreateFileMode( } }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; - }else{ - *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; } return rc; } diff --git a/src/os_win.c b/src/os_win.c index 4e91f7ab32..b3e47f8363 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1570,6 +1570,7 @@ static int winOpenSharedMemory(winFile *pDbFd){ memset(pNew, 0, sizeof(*pNew)); pNew->zFilename = (char*)&pNew[1]; sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); + sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); /* Look to see if there is an existing winShmNode that can be used. ** If no matching winShmNode currently exists, create a new one. @@ -2465,6 +2466,13 @@ static int winFullPathname( void *zConverted; char *zOut; + /* If this path name begins with "/X:", where "X" is any alphabetic + ** character, discard the initial "/" from the pathname. + */ + if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){ + zRelative++; + } + /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the diff --git a/src/pager.c b/src/pager.c index 94f647dcc9..6bddd7fd1f 100644 --- a/src/pager.c +++ b/src/pager.c @@ -4299,6 +4299,8 @@ int sqlite3PagerOpen( int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */ int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ + const char *zUri = 0; /* URI args to copy */ + int nUri = 0; /* Number of bytes of URI args at *zUri */ /* Figure out how much space is required for each journal file-handle ** (there are two of them, the main journal and the sub-journal). This @@ -4329,6 +4331,7 @@ int sqlite3PagerOpen( ** leave both nPathname and zPathname set to 0. */ if( zFilename && zFilename[0] ){ + const char *z; nPathname = pVfs->mxPathname+1; zPathname = sqlite3Malloc(nPathname*2); if( zPathname==0 ){ @@ -4337,6 +4340,12 @@ int sqlite3PagerOpen( zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); nPathname = sqlite3Strlen30(zPathname); + z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; + while( *z ){ + z += sqlite3Strlen30(z)+1; + z += sqlite3Strlen30(z)+1; + } + nUri = &z[1] - zUri; if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ /* This branch is taken when the journal path required by ** the database being opened will be more than pVfs->mxPathname @@ -4369,7 +4378,7 @@ int sqlite3PagerOpen( ROUND8(pcacheSize) + /* PCache object */ ROUND8(pVfs->szOsFile) + /* The main db file */ journalFileSize * 2 + /* The two journal files */ - nPathname + 1 + /* zFilename */ + nPathname + 1 + nUri + /* zFilename */ nPathname + 8 + 1 /* zJournal */ #ifndef SQLITE_OMIT_WAL + nPathname + 4 + 1 /* zWal */ @@ -4391,14 +4400,17 @@ int sqlite3PagerOpen( /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ if( zPathname ){ assert( nPathname>0 ); - pPager->zJournal = (char*)(pPtr += nPathname + 1); + pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); memcpy(pPager->zFilename, zPathname, nPathname); + memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); memcpy(pPager->zJournal, zPathname, nPathname); memcpy(&pPager->zJournal[nPathname], "-journal", 8); + sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); #ifndef SQLITE_OMIT_WAL pPager->zWal = &pPager->zJournal[nPathname+8+1]; memcpy(pPager->zWal, zPathname, nPathname); memcpy(&pPager->zWal[nPathname], "-wal", 4); + sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); #endif sqlite3_free(zPathname); } @@ -5735,11 +5747,21 @@ int sqlite3PagerCommitPhaseOne( }else{ if( pagerUseWal(pPager) ){ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); + PgHdr *pPageOne = 0; + if( pList==0 ){ + /* Must have at least one page for the WAL commit flag. + ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ + rc = sqlite3PagerGet(pPager, 1, &pPageOne); + pList = pPageOne; + pList->pDirty = 0; + } + assert( pList!=0 || rc!=SQLITE_OK ); if( pList ){ rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, (pPager->fullSync ? pPager->syncFlags : 0) ); } + sqlite3PagerUnref(pPageOne); if( rc==SQLITE_OK ){ sqlite3PcacheCleanAll(pPager->pPCache); } @@ -6597,6 +6619,7 @@ int sqlite3PagerOkToChangeJournalMode(Pager *pPager){ i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ if( iLimit>=-1 ){ pPager->journalSizeLimit = iLimit; + sqlite3WalLimit(pPager->pWal, iLimit); } return pPager->journalSizeLimit; } @@ -6688,7 +6711,8 @@ static int pagerOpenWal(Pager *pPager){ */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, - pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal + pPager->fd, pPager->zWal, pPager->exclusiveMode, + pPager->journalSizeLimit, &pPager->pWal ); } diff --git a/src/pragma.c b/src/pragma.c index 75ab26d441..799805c40b 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -49,7 +49,7 @@ static u8 getSafetyLevel(const char *z){ /* ** Interpret the given string as a boolean value. */ -static u8 getBoolean(const char *z){ +u8 sqlite3GetBoolean(const char *z){ return getSafetyLevel(z)&1; } @@ -219,7 +219,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){ mask &= ~(SQLITE_ForeignKeys); } - if( getBoolean(zRight) ){ + if( sqlite3GetBoolean(zRight) ){ db->flags |= mask; }else{ db->flags &= ~mask; @@ -433,7 +433,7 @@ void sqlite3Pragma( int b = -1; assert( pBt!=0 ); if( zRight ){ - b = getBoolean(zRight); + b = sqlite3GetBoolean(zRight); } if( pId2->n==0 && b>=0 ){ int ii; @@ -1033,7 +1033,7 @@ void sqlite3Pragma( #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ if( zRight ){ - if( getBoolean(zRight) ){ + if( sqlite3GetBoolean(zRight) ){ sqlite3ParserTrace(stderr, "parser: "); }else{ sqlite3ParserTrace(0, 0); @@ -1047,7 +1047,7 @@ void sqlite3Pragma( */ if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ if( zRight ){ - sqlite3RegisterLikeFunctions(db, getBoolean(zRight)); + sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight)); } }else diff --git a/src/shell.c b/src/shell.c index aab70b29db..8e9870a5a8 100644 --- a/src/shell.c +++ b/src/shell.c @@ -2649,6 +2649,7 @@ static void main_init(struct callback_data *data) { data->mode = MODE_List; memcpy(data->separator,"|", 2); data->showHeader = 0; + sqlite3_config(SQLITE_CONFIG_URI, 1); sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); @@ -2663,6 +2664,11 @@ int main(int argc, char **argv){ int i; int rc = 0; + if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ + fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", + sqlite3_sourceid(), SQLITE_SOURCE_ID); + exit(1); + } Argv0 = argv[0]; main_init(&data); stdin_is_interactive = isatty(0); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 260b240bed..ca7959a8db 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -453,14 +453,14 @@ int sqlite3_exec( #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and -** in the 4th parameter to the xOpen method of the -** [sqlite3_vfs] object. +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ @@ -468,6 +468,7 @@ int sqlite3_exec( #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ @@ -578,17 +579,18 @@ struct sqlite3_file { /* ** CAPI3REF: OS Interface File Virtual Methods Object ** -** Every file opened by the [sqlite3_vfs] xOpen method populates an +** Every file opened by the [sqlite3_vfs.xOpen] method populates an ** [sqlite3_file] object (or, more commonly, a subclass of the ** [sqlite3_file] object) with a pointer to an instance of this object. ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** -** If the xOpen method sets the sqlite3_file.pMethods element +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method -** may be invoked even if the xOpen reported that it failed. The -** only way to prevent a call to xClose following a failed xOpen -** is for the xOpen to set the sqlite3_file.pMethods element to NULL. +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element +** to NULL. ** ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). @@ -757,6 +759,7 @@ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: OS Interface Object +** KEYWORDS: VFS VFSes ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" @@ -789,6 +792,7 @@ typedef struct sqlite3_mutex sqlite3_mutex; ** The zName field holds the name of the VFS module. The name must ** be unique across all VFS modules. ** +** [[sqlite3_vfs.xOpen]] ** ^SQLite guarantees that the zFilename parameter to xOpen ** is either a NULL pointer or string obtained ** from xFullPathname() with an optional suffix added. @@ -866,6 +870,7 @@ typedef struct sqlite3_mutex sqlite3_mutex; ** element will be valid after xOpen returns regardless of the success ** or failure of the xOpen call. ** +** [[sqlite3_vfs.xAccess]] ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] @@ -1112,9 +1117,9 @@ int sqlite3_os_end(void); ** implementation of an application-defined [sqlite3_os_init()]. ** ** The first argument to sqlite3_config() is an integer -** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines +** [configuration option] that determines ** what property of SQLite is to be configured. Subsequent arguments -** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] +** vary depending on the [configuration option] ** in the first argument. ** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. @@ -1224,6 +1229,7 @@ struct sqlite3_mem_methods { /* ** CAPI3REF: Configuration Options +** KEYWORDS: {configuration option} ** ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. @@ -1236,7 +1242,7 @@ struct sqlite3_mem_methods { ** is invoked. ** **
-**
SQLITE_CONFIG_SINGLETHREAD
+** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Single-thread. In other words, it disables ** all mutexing and puts SQLite into a mode where it can only be used @@ -1247,7 +1253,7 @@ struct sqlite3_mem_methods { ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option.
** -**
SQLITE_CONFIG_MULTITHREAD
+** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Multi-thread. In other words, it disables ** mutexing on [database connection] and [prepared statement] objects. @@ -1261,7 +1267,7 @@ struct sqlite3_mem_methods { ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_MULTITHREAD configuration option.
** -**
SQLITE_CONFIG_SERIALIZED
+** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Serialized. In other words, this option enables ** all mutexes including the recursive @@ -1277,7 +1283,7 @@ struct sqlite3_mem_methods { ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.
** -**
SQLITE_CONFIG_MALLOC
+** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The argument specifies ** alternative low-level memory allocation routines to be used in place of @@ -1285,7 +1291,7 @@ struct sqlite3_mem_methods { ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
** -**
SQLITE_CONFIG_GETMALLOC
+** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ @@ -1293,7 +1299,7 @@ struct sqlite3_mem_methods { ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
** -**
SQLITE_CONFIG_MEMSTATUS
+** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
**
^This option takes single argument of type int, interpreted as a ** boolean, which enables or disables the collection of memory allocation ** statistics. ^(When memory allocation statistics are disabled, the @@ -1309,7 +1315,7 @@ struct sqlite3_mem_methods { ** allocation statistics are disabled by default. **
** -**
SQLITE_CONFIG_SCRATCH
+** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
**
^This option specifies a static memory buffer that SQLite can use for ** scratch memory. There are three arguments: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be @@ -1325,7 +1331,7 @@ struct sqlite3_mem_methods { ** scratch memory beyond what is provided by this configuration option, then ** [sqlite3_malloc()] will be used to obtain the memory needed.
** -**
SQLITE_CONFIG_PAGECACHE
+** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
**
^This option specifies a static memory buffer that SQLite can use for ** the database page cache with the default page cache implemenation. ** This configuration should not be used if an application-define page @@ -1346,7 +1352,7 @@ struct sqlite3_mem_methods { ** be aligned to an 8-byte boundary or subsequent behavior of SQLite ** will be undefined.
** -**
SQLITE_CONFIG_HEAP
+** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
**
^This option specifies a static memory buffer that SQLite will use ** for all of its dynamic memory allocation needs beyond those provided ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. @@ -1363,7 +1369,7 @@ struct sqlite3_mem_methods { ** The minimum allocation size is capped at 2^12. Reasonable values ** for the minimum allocation size are 2^5 through 2^8.
** -**
SQLITE_CONFIG_MUTEX
+** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The argument specifies ** alternative low-level mutex routines to be used in place @@ -1375,7 +1381,7 @@ struct sqlite3_mem_methods { ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will ** return [SQLITE_ERROR].
** -**
SQLITE_CONFIG_GETMUTEX
+** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] @@ -1388,7 +1394,7 @@ struct sqlite3_mem_methods { ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will ** return [SQLITE_ERROR].
** -**
SQLITE_CONFIG_LOOKASIDE
+** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
**
^(This option takes two arguments that determine the default ** memory allocation for the lookaside memory allocator on each ** [database connection]. The first argument is the @@ -1398,18 +1404,18 @@ struct sqlite3_mem_methods { ** verb to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
** -**
SQLITE_CONFIG_PCACHE
+** [[SQLITE_CONFIG_PCACHE]]
SQLITE_CONFIG_PCACHE
**
^(This option takes a single argument which is a pointer to ** an [sqlite3_pcache_methods] object. This object specifies the interface ** to a custom page cache implementation.)^ ^SQLite makes a copy of the ** object and uses it for page cache memory allocations.
** -**
SQLITE_CONFIG_GETPCACHE
+** [[SQLITE_CONFIG_GETPCACHE]]
SQLITE_CONFIG_GETPCACHE
**
^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods] object. SQLite copies of the current ** page cache implementation into that object.)^
** -**
SQLITE_CONFIG_LOG
+** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
**
^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is @@ -1427,6 +1433,18 @@ struct sqlite3_mem_methods { ** In a multi-threaded application, the application-defined logger ** function must be threadsafe.
** +** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI +**
This option takes a single argument of type int. If non-zero, then +** URI handling is globally enabled. If the parameter is zero, then URI handling +** is globally disabled. If URI handling is globally enabled, all filenames +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +** specified as part of [ATTACH] commands are interpreted as URIs, regardless +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database +** connection is opened. If it is globally disabled, filenames are +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the +** database connection is opened. By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** [SQLITE_USE_URI] symbol defined. **
*/ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ @@ -1445,6 +1463,7 @@ struct sqlite3_mem_methods { #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ /* ** CAPI3REF: Database Connection Configuration Options @@ -1530,13 +1549,17 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff); ** ** ^This routine returns the [rowid] of the most recent ** successful [INSERT] into the database from the [database connection] -** in the first argument. ^If no successful [INSERT]s +** in the first argument. ^As of SQLite version 3.7.7, this routines +** records the last insert rowid of both ordinary tables and [virtual tables]. +** ^If no successful [INSERT]s ** have ever occurred on that database connection, zero is returned. ** -** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted -** row is returned by this routine as long as the trigger is running. -** But once the trigger terminates, the value returned by this routine -** reverts to the last value inserted before the trigger fired.)^ +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] +** method, then this routine will return the [rowid] of the inserted +** row as long as the trigger or virtual table method is running. +** But once the trigger or virtual table method ends, the value returned +** by this routine reverts to what it was before the trigger or virtual +** table method began.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this @@ -2324,7 +2347,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** -** ^These routines open an SQLite database file whose name is given by the +** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually @@ -2351,7 +2374,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** sqlite3_open_v2() can take one of ** the following three values, optionally combined with the ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], -** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ ** **
** ^(
[SQLITE_OPEN_READONLY]
@@ -2370,9 +2393,8 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); **
** ** If the 3rd parameter to sqlite3_open_v2() is not one of the -** combinations shown above or one of the combinations shown above combined -** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], -** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, +** combinations shown above optionally combined with other +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. ** ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection @@ -2387,6 +2409,11 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not ** participate in [shared cache mode] even if it is enabled. ** +** ^The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system interface that +** the new database connection should use. ^If the fourth parameter is +** a NULL pointer then the default [sqlite3_vfs] object is used. +** ** ^If the filename is ":memory:", then a private, temporary in-memory database ** is created for the connection. ^This in-memory database will vanish when ** the database connection is closed. Future versions of SQLite might @@ -2399,10 +2426,111 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** on-disk database will be created. ^This private database will be ** automatically deleted as soon as the database connection is closed. ** -** ^The fourth parameter to sqlite3_open_v2() is the name of the -** [sqlite3_vfs] object that defines the operating system interface that -** the new database connection should use. ^If the fourth parameter is -** a NULL pointer then the default [sqlite3_vfs] object is used. +** [[URI filenames in sqlite3_open()]]

URI Filenames

+** +** ^If [URI filename] interpretation is enabled, and the filename argument +** begins with "file:", then the filename is interpreted as a URI. ^URI +** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is +** is set in the fourth argument to sqlite3_open_v2(), or if it has +** been enabled globally using the [SQLITE_CONFIG_URI] option with the +** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. +** As of SQLite version 3.7.7, URI filename interpretation is turned off +** by default, but future releases of SQLite might enable URI filename +** intepretation by default. See "[URI filenames]" for additional +** information. +** +** URI filenames are parsed according to RFC 3986. ^If the URI contains an +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if +** present, is ignored. +** +** ^SQLite uses the path component of the URI as the name of the disk file +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin +** with a '/' (meaning that the authority section is omitted from the URI) +** then the path is interpreted as a relative path. +** ^On windows, the first component of an absolute path +** is a drive specification (e.g. "C:"). +** +** [[core URI query parameters]] +** The query component of a URI may contain parameters that are interpreted +** either by SQLite itself, or by a [VFS | custom VFS implementation]. +** SQLite interprets the following three query parameters: +** +**
    +**
  • vfs: ^The "vfs" parameter may be used to specify the name of +** a VFS object that provides the operating system interface that should +** be used to access the database file on disk. ^If this option is set to +** an empty string the default VFS object is used. ^Specifying an unknown +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is +** present, then the VFS specified by the option takes precedence over +** the value passed as the fourth parameter to sqlite3_open_v2(). +** +**
  • mode: ^(The mode parameter may be set to either "ro", "rw" or +** "rwc". Attempting to set it to any other value is an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_prepare_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is +** used, it is an error to specify a value for the mode parameter that is +** less restrictive than that specified by the flags passed as the third +** parameter. +** +**
  • cache: ^The cache parameter may be set to either "shared" or +** "private". ^Setting it to "shared" is equivalent to setting the +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in +** a URI filename, its value overrides any behaviour requested by setting +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +**
+** +** ^Specifying an unknown parameter in the query component of a URI is not an +** error. Future versions of SQLite might understand additional query +** parameters. See "[query parameters with special meaning to SQLite]" for +** additional information. +** +** [[URI filename examples]]

URI filename examples

+** +** +**
URI filenames Results +**
file:data.db +** Open the file "data.db" in the current directory. +**
file:/home/fred/data.db
+** file:///home/fred/data.db
+** file://localhost/home/fred/data.db
+** Open the database file "/home/fred/data.db". +**
file://darkstar/home/fred/data.db +** An error. "darkstar" is not a recognized authority. +**
+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db +** Windows only: Open the file "data.db" on fred's desktop on drive +** C:. Note that the %20 escaping in this example is not strictly +** necessary - space characters can be used literally +** in URI filenames. +**
file:data.db?mode=ro&cache=private +** Open file "data.db" in the current directory for read-only access. +** Regardless of whether or not shared-cache mode is enabled by +** default, use a private cache. +**
file:/home/fred/data.db?vfs=unix-nolock +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +**
file:data.db?mode=readonly +** An error. "readonly" is not a valid option for the "mode" parameter. +**
+** +** ^URI hexadecimal escape sequences (%HH) are supported within the path and +** query components of a URI. A hexadecimal escape sequence consists of a +** percent sign - "%" - followed by exactly two hexadecimal digits +** specifying an octet value. ^Before the path or query components of a +** URI filename are interpreted, they are encoded using UTF-8 and all +** hexadecimal escape sequences replaced by a single byte containing the +** corresponding octet. If this process generates an invalid UTF-8 encoding, +** the results are undefined. ** ** Note to Windows users: The encoding used for the filename argument ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever @@ -2425,6 +2553,26 @@ int sqlite3_open_v2( const char *zVfs /* Name of VFS module to use */ ); +/* +** CAPI3REF: Obtain Values For URI Parameters +** +** This is a utility routine, useful to VFS implementations, that checks +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of the query parameter. +** +** The zFilename argument is the filename pointer passed into the xOpen() +** method of a VFS implementation. The zParam argument is the name of the +** query parameter we seek. This routine returns the value of the zParam +** parameter if it exists. If the parameter does not exist, this routine +** returns a NULL pointer. +** +** If the zFilename argument to this function is not a pointer that SQLite +** passed into the xOpen VFS method, then the behavior of this routine +** is undefined and probably undesirable. +*/ +const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); + + /* ** CAPI3REF: Error Codes And Messages ** @@ -2540,43 +2688,45 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** Additional information is available at [limits | Limits in SQLite]. ** **
-** ^(
SQLITE_LIMIT_LENGTH
+** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
**
The maximum size of any string or BLOB or table row, in bytes.
)^ ** -** ^(
SQLITE_LIMIT_SQL_LENGTH
+** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
**
The maximum length of an SQL statement, in bytes.
)^ ** -** ^(
SQLITE_LIMIT_COLUMN
+** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
**
The maximum number of columns in a table definition or in the ** result set of a [SELECT] or the maximum number of columns in an index ** or in an ORDER BY or GROUP BY clause.
)^ ** -** ^(
SQLITE_LIMIT_EXPR_DEPTH
+** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
**
The maximum depth of the parse tree on any expression.
)^ ** -** ^(
SQLITE_LIMIT_COMPOUND_SELECT
+** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
**
The maximum number of terms in a compound SELECT statement.
)^ ** -** ^(
SQLITE_LIMIT_VDBE_OP
+** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
**
The maximum number of instructions in a virtual machine program ** used to implement an SQL statement. This limit is not currently ** enforced, though that might be added in some future release of ** SQLite.
)^ ** -** ^(
SQLITE_LIMIT_FUNCTION_ARG
+** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
**
The maximum number of arguments on a function.
)^ ** -** ^(
SQLITE_LIMIT_ATTACHED
+** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
**
The maximum number of [ATTACH | attached databases].)^
** +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] ** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
**
The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.
)^ ** +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] ** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
**
The maximum index number of any [parameter] in an SQL statement.)^ ** -** ^(
SQLITE_LIMIT_TRIGGER_DEPTH
+** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
**
The maximum depth of recursion for triggers.
)^ **
*/ @@ -4611,8 +4761,8 @@ struct sqlite3_module { void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); - /* The methods above are in version 0 of the sqlite_module object. Those - ** below are for version 1 and greater. */ + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); @@ -5430,7 +5580,7 @@ int sqlite3_test_control(int op, ...); ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for ** the specific parameter to measure. ^(Recognized integer codes -** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ +** are of the form [status parameters | SQLITE_STATUS_...].)^ ** ^The current value of the parameter is returned into *pCurrent. ** ^The highest recorded value is returned in *pHighwater. ^If the ** resetFlag is true, then the highest record value is reset after @@ -5457,12 +5607,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); /* ** CAPI3REF: Status Parameters +** KEYWORDS: {status parameters} ** ** These integer constants designate various run-time status parameters ** that can be returned by [sqlite3_status()]. ** **
-** ^(
SQLITE_STATUS_MEMORY_USED
+** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
**
This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application @@ -5472,23 +5623,24 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^ ** -** ^(
SQLITE_STATUS_MALLOC_SIZE
+** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
**
This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** -** ^(
SQLITE_STATUS_MALLOC_COUNT
+** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
**
This parameter records the number of separate memory allocations ** currently checked out.
)^ ** -** ^(
SQLITE_STATUS_PAGECACHE_USED
+** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
**
This parameter returns the number of pages used out of the ** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.
)^ ** +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
**
This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] @@ -5498,13 +5650,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.
)^ ** -** ^(
SQLITE_STATUS_PAGECACHE_SIZE
+** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
**
This parameter records the largest memory allocation request ** handed to [pagecache memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** -** ^(
SQLITE_STATUS_SCRATCH_USED
+** [[SQLITE_STATUS_SCRATCH_USED]] ^(
SQLITE_STATUS_SCRATCH_USED
**
This parameter returns the number of allocations used out of the ** [scratch memory allocator] configured using ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not @@ -5512,7 +5664,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); ** outstanding at time, this parameter also reports the number of threads ** using scratch memory at the same time.
)^ ** -** ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
+** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
**
This parameter returns the number of bytes of scratch memory ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] ** buffer and where forced to overflow to [sqlite3_malloc()]. The values @@ -5522,13 +5674,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); ** slots were available. **
)^ ** -** ^(
SQLITE_STATUS_SCRATCH_SIZE
+** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
SQLITE_STATUS_SCRATCH_SIZE
**
This parameter records the largest memory allocation request ** handed to [scratch memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** -** ^(
SQLITE_STATUS_PARSER_STACK
+** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
**
This parameter records the deepest parser stack. It is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ **
@@ -5553,9 +5705,9 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that +** [SQLITE_DBSTATUS options], that ** determines the parameter to interrogate. The set of -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely +** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** ** ^The current value of the requested parameter is written into *pCur @@ -5572,6 +5724,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} ** ** These constants are the available integer "verbs" that can be passed as ** the second argument to the [sqlite3_db_status()] interface. @@ -5583,15 +5736,16 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** if a discontinued or unsupported verb is invoked. ** **
-** ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
**
This parameter returns the number of lookaside memory slots currently ** checked out.
)^ ** -** ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
+** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
**
This parameter returns the number malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of @@ -5599,6 +5753,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside @@ -5606,12 +5761,12 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** -** ^(
SQLITE_DBSTATUS_CACHE_USED
+** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
**
This parameter returns the approximate number of of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** -** ^(
SQLITE_DBSTATUS_SCHEMA_USED
+** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
**
This parameter returns the approximate number of of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ @@ -5620,7 +5775,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** -** ^(
SQLITE_DBSTATUS_STMT_USED
+** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
**
This parameter returns the approximate number of of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ @@ -5642,7 +5797,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various -** [SQLITE_STMTSTATUS_SORT | counters] that measure the number +** [SQLITE_STMTSTATUS counters] that measure the number ** of times it has performed specific operations.)^ These counters can ** be used to monitor the performance characteristics of the prepared ** statements. For example, if the number of table steps greatly exceeds @@ -5653,7 +5808,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement ** object to be interrogated. The second argument -** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] +** is an integer code for a specific [SQLITE_STMTSTATUS counter] ** to be interrogated.)^ ** ^The current value of the requested counter is returned. ** ^If the resetFlg is true, then the counter is reset to zero after this @@ -5665,24 +5820,25 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} ** ** These preprocessor macros define integer codes that name counter ** values associated with the [sqlite3_stmt_status()] interface. ** The meanings of the various counters are as follows: ** **
-**
SQLITE_STMTSTATUS_FULLSCAN_STEP
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
**
^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter ** may indicate opportunities for performance improvement through ** careful use of indices.
** -**
SQLITE_STMTSTATUS_SORT
+** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
**
^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance through careful use of indices.
** -**
SQLITE_STMTSTATUS_AUTOINDEX
+** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
**
^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to @@ -5733,6 +5889,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** the application may discard the parameter after the call to ** [sqlite3_config()] returns.)^ ** +** [[the xInit() page cache method]] ** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() @@ -5743,6 +5900,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** built-in default page cache is used instead of the application defined ** page cache.)^ ** +** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. ** It can be used to clean up ** any outstanding resources before process shutdown, if required. @@ -5757,6 +5915,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** ^SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). ** +** [[the xCreate() page cache methods]] ** ^SQLite invokes the xCreate() method to construct a new cache instance. ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The @@ -5781,6 +5940,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** +** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the ** suggested maximum cache-size (number of pages stored by) the cache ** instance passed as the first argument. This is the value configured using @@ -5788,9 +5948,11 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** parameter, the implementation is not required to do anything with this ** value; it is advisory only. ** +** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. ** +** [[the xFetch() page cache methods]] ** The xFetch() method locates a page in the cache and returns a pointer to ** the page, or a NULL pointer. ** A "page", in this context, means a buffer of szPage bytes aligned at an @@ -5819,6 +5981,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** +** [[the xUnpin() page cache method]] ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. @@ -5831,6 +5994,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** +** [[the xRekey() page cache methods]] ** The xRekey() method is used to change the key value associated with the ** page passed as the second argument. If the cache ** previously contains an entry associated with newKey, it must be @@ -5843,6 +6007,7 @@ typedef struct sqlite3_pcache sqlite3_pcache; ** of these pages are pinned, they are implicitly unpinned, meaning that ** they can be safely discarded. ** +** [[the xDestroy() page cache method]] ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). ** All resources associated with the specified cache should be freed. ^After ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] @@ -5905,7 +6070,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** -** sqlite3_backup_init() +** [[sqlite3_backup_init()]] sqlite3_backup_init() ** ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the ** [database connection] associated with the destination database @@ -5932,7 +6097,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** -** sqlite3_backup_step() +** [[sqlite3_backup_step()]] sqlite3_backup_step() ** ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. @@ -5989,7 +6154,7 @@ typedef struct sqlite3_backup sqlite3_backup; ** by the backup operation, then the backup database is automatically ** updated at the same time. ** -** sqlite3_backup_finish() +** [[sqlite3_backup_finish()]] sqlite3_backup_finish() ** ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application @@ -6012,7 +6177,8 @@ typedef struct sqlite3_backup sqlite3_backup; ** is not a permanent error and does not affect the return value of ** sqlite3_backup_finish(). ** -** sqlite3_backup_remaining(), sqlite3_backup_pagecount() +** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] +** sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** ** ^Each call to sqlite3_backup_step() sets two values inside ** the [sqlite3_backup] object: the number of pages still to be backed @@ -6393,9 +6559,6 @@ int sqlite3_wal_checkpoint_v2( ** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] ** documentation for additional information about the meaning and use of ** each of these values. -** -**
SQLITE_CONFIG_GETMUTEX
-**
^(This option takes a single argument which is a pointer to an */ #define SQLITE_CHECKPOINT_PASSIVE 0 #define SQLITE_CHECKPOINT_FULL 1 @@ -6425,37 +6588,36 @@ int sqlite3_vtab_config(sqlite3*, int op, ...); ** can use to customize and optimize their behavior. ** **
-**
SQLITE_VTAB_CONSTRAINT_SUPPORT -**
If the second argument to [sqlite3_vtab_config()] is -** SQLITE_VTAB_CONSTRAINT_SUPPORT, then SQLite expects this function to -** have been called with three arguments, the third of which being of -** type 'int'. If the third argument is zero, then the virtual table -** is indicating that it does not support constraints. In this case if -** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], the entire -** statement is rolled back as if [ON CONFLICT | OR ABORT] had been -** specified as part of the users SQL statement, regardless of the actual -** ON CONFLICT mode specified. +**
SQLITE_VTAB_CONSTRAINT_SUPPORT +**
Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, +** where X is an integer. If X is zero, then the [virtual table] whose +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not +** support constraints. In this configuration (which is the default) if +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. ** -** If the third argument passed is non-zero, then the virtual table -** implementation must guarantee that if [xUpdate] returns -** [SQLITE_CONSTRAINT], it does so before any modifications to internal -** or persistent data structures have been made. If the [ON CONFLICT] -** mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite is able to roll back -** a statement or database transaction, and abandon or continue processing -** the current SQL statement as appropriate. If the ON CONFLICT mode is -** REPLACE and the [xUpdate] method returns [SQLITE_CONSTRAINT], SQLite -** handles this as if the ON CONFLICT mode had been ABORT. +** If X is non-zero, then the virtual table implementation guarantees +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before +** any modifications to internal or persistent data structures have been made. +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** is able to roll back a statement or database transaction, and abandon +** or continue processing the current SQL statement as appropriate. +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode +** had been ABORT. ** -** Virtual table implementations that are required to handle OR REPLACE -** must do so within the xUpdate method. If a call to the -** [sqlite3_vtab_on_conflict()] function indicates that the current ON -** CONFLICT policy is REPLACE, the virtual table implementation should -** silently replace the appropriate rows within the xUpdate callback and -** return SQLITE_OK. Or, if this is not possible, it may return -** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT -** constraint handling. +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. **
-** */ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8cc19b86b2..3a8be8b8ba 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -804,7 +804,7 @@ struct sqlite3 { int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellaneous flags. See below */ - int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ + unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u8 autoCommit; /* The auto-commit flag. */ @@ -2432,6 +2432,7 @@ struct Sqlite3Config { int bMemstat; /* True to enable memory status */ int bCoreMutex; /* True to enable core mutexing */ int bFullMutex; /* True to enable full mutexing */ + int bOpenUri; /* True to interpret filenames as URIs */ int mxStrlen; /* Maximum string length */ int szLookaside; /* Default lookaside buffer size */ int nLookaside; /* Default lookaside buffer count */ @@ -2681,6 +2682,8 @@ void sqlite3AddColumnType(Parse*,Token*); void sqlite3AddDefaultValue(Parse*,ExprSpan*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3EndTable(Parse*,Token*,Token*,Select*); +int sqlite3ParseUri(const char*,const char*,unsigned int*, + sqlite3_vfs**,char**,char **); Bitvec *sqlite3BitvecCreate(u32); int sqlite3BitvecTest(Bitvec*, u32); @@ -2931,6 +2934,7 @@ char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); +u8 sqlite3HexToInt(int h); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); const char *sqlite3ErrStr(int); int sqlite3ReadSchema(Parse *pParse); @@ -2946,6 +2950,12 @@ int sqlite3AddInt64(i64*,i64); int sqlite3SubInt64(i64*,i64); int sqlite3MulInt64(i64*,i64); int sqlite3AbsInt32(int); +#ifdef SQLITE_ENABLE_8_3_NAMES +void sqlite3FileSuffix3(const char*, char*); +#else +# define sqlite3FileSuffix3(X,Y) +#endif +u8 sqlite3GetBoolean(const char *z); const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); diff --git a/src/test1.c b/src/test1.c index b79bbd0826..50575afbbc 100644 --- a/src/test1.c +++ b/src/test1.c @@ -163,6 +163,8 @@ const char *sqlite3TestErrorName(int rc){ case SQLITE_IOERR_CHECKRESERVEDLOCK: zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; + case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; + zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; default: zName = "SQLITE_Unknown"; break; } return zName; @@ -3845,6 +3847,76 @@ static int test_open( return TCL_OK; } +/* +** Usage: sqlite3_open_v2 FILENAME FLAGS VFS +*/ +static int test_open_v2( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + const char *zFilename; + const char *zVfs; + int flags = 0; + sqlite3 *db; + int rc; + char zBuf[100]; + + int nFlag; + Tcl_Obj **apFlag; + int i; + + if( objc!=4 ){ + Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS"); + return TCL_ERROR; + } + zFilename = Tcl_GetString(objv[1]); + zVfs = Tcl_GetString(objv[3]); + if( zVfs[0]==0x00 ) zVfs = 0; + + rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag); + if( rc!=TCL_OK ) return rc; + for(i=0; imxPathname characters. This function departs +** from the traditional temporary name generation in the os_win +** and os_unix VFS in several ways, but is necessary so that +** the file name is known for temporary files (like those used +** during vacuum.) +** +** N.B. This routine assumes your underlying VFS is ok with using +** "/" as a directory seperator. This is the default for UNIXs +** and is allowed (even mixed) for most versions of Windows. +*/ +static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){ + static char zChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; + int i,j; + int attempts = 0; + int exists = 0; + int rc = SQLITE_ERROR; + + /* Check that the output buffer is large enough for + ** pVfs->mxPathname characters. + */ + if( pOrigVfs->mxPathname <= nBuf ){ + char *zTmp = sqlite3_malloc(pOrigVfs->mxPathname); + if( zTmp==0 ) return SQLITE_NOMEM; + + /* sqlite3_temp_directory should always be less than + ** pVfs->mxPathname characters. + */ + sqlite3_snprintf(pOrigVfs->mxPathname, + zTmp, + "%s/", + sqlite3_temp_directory ? sqlite3_temp_directory : "."); + rc = pOrigVfs->xFullPathname(pOrigVfs, zTmp, nBuf, zBuf); + sqlite3_free(zTmp); + if( rc ) return rc; + + /* Check that the output buffer is large enough for the temporary file + ** name. + */ + j = multiplexStrlen30(zBuf); + if( (j + 8 + 1 + 3 + 1) <= nBuf ){ + /* Make 3 attempts to generate a unique name. */ + do { + attempts++; + sqlite3_randomness(8, &zBuf[j]); + for(i=0; i<8; i++){ + zBuf[j+i] = (char)zChars[ ((unsigned char)zBuf[j+i])%(sizeof(zChars)-1) ]; + } + memcpy(&zBuf[j+i], ".tmp", 5); + rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists); + } while ( (rc==SQLITE_OK) && exists && (attempts<3) ); + if( rc==SQLITE_OK && exists ){ + rc = SQLITE_ERROR; + } + } + } + + return rc; +} + /* Translate an sqlite3_file* that is really a multiplexGroup* into ** the sqlite3_file* for the underlying original VFS. */ @@ -295,12 +359,12 @@ static int multiplexOpen( int flags, /* Flags to control the opening */ int *pOutFlags /* Flags showing results of opening */ ){ - int rc; /* Result code */ + int rc = SQLITE_OK; /* Result code */ multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */ multiplexGroup *pGroup; /* Corresponding multiplexGroup object */ sqlite3_file *pSubOpen; /* Real file descriptor */ sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ - int nName = multiplexStrlen30(zName); + int nName; int i; int sz; @@ -311,23 +375,39 @@ static int multiplexOpen( */ multiplexEnter(); pMultiplexOpen = (multiplexConn*)pConn; - /* allocate space for group */ - sz = sizeof(multiplexGroup) /* multiplexGroup */ - + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */ - + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */ - + SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */ - + nName + 1; /* zName */ + + /* If the second argument to this function is NULL, generate a + ** temporary file name to use. This will be handled by the + ** original xOpen method. We just need to allocate space for + ** it. + */ + if( !zName ){ + rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName); + zName = gMultiplex.zName; + } + + if( rc==SQLITE_OK ){ + /* allocate space for group */ + nName = multiplexStrlen30(zName); + sz = sizeof(multiplexGroup) /* multiplexGroup */ + + (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */ + + (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */ + + SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */ + + nName + 1; /* zName */ #ifndef SQLITE_MULTIPLEX_EXT_OVWR - sz += SQLITE_MULTIPLEX_EXT_SZ; - assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname); + sz += SQLITE_MULTIPLEX_EXT_SZ; + assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname); #else - assert(nName >= SQLITE_MULTIPLEX_EXT_SZ); - assert(nName < pOrigVfs->mxPathname); + assert(nName >= SQLITE_MULTIPLEX_EXT_SZ); + assert(nName < pOrigVfs->mxPathname); #endif - pGroup = sqlite3_malloc( sz ); - if( pGroup==0 ){ - rc=SQLITE_NOMEM; - }else{ + pGroup = sqlite3_malloc( sz ); + if( pGroup==0 ){ + rc=SQLITE_NOMEM; + } + } + + if( rc==SQLITE_OK ){ /* assign pointers to extra space allocated */ char *p = (char *)&pGroup[1]; pMultiplexOpen->pGroup = pGroup; @@ -411,7 +491,7 @@ static int multiplexDelete( } rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName, SQLITE_ACCESS_EXISTS, &exists); - if( rc2==SQLITE_OK && exists){ + if( rc2==SQLITE_OK && exists ){ /* if it exists, delete it */ rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir); if( rc2!=SQLITE_OK ) rc = rc2; diff --git a/src/test_vfs.c b/src/test_vfs.c index 64b3cb574b..ba078a0f9b 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -114,20 +114,21 @@ struct Testvfs { ** + Simulating IO errors, and ** + Invoking the Tcl callback script. */ -#define TESTVFS_SHMOPEN_MASK 0x00000001 -#define TESTVFS_SHMLOCK_MASK 0x00000010 -#define TESTVFS_SHMMAP_MASK 0x00000020 -#define TESTVFS_SHMBARRIER_MASK 0x00000040 -#define TESTVFS_SHMCLOSE_MASK 0x00000080 +#define TESTVFS_SHMOPEN_MASK 0x00000001 +#define TESTVFS_SHMLOCK_MASK 0x00000010 +#define TESTVFS_SHMMAP_MASK 0x00000020 +#define TESTVFS_SHMBARRIER_MASK 0x00000040 +#define TESTVFS_SHMCLOSE_MASK 0x00000080 -#define TESTVFS_OPEN_MASK 0x00000100 -#define TESTVFS_SYNC_MASK 0x00000200 -#define TESTVFS_DELETE_MASK 0x00000400 -#define TESTVFS_CLOSE_MASK 0x00000800 -#define TESTVFS_WRITE_MASK 0x00001000 -#define TESTVFS_TRUNCATE_MASK 0x00002000 -#define TESTVFS_ACCESS_MASK 0x00004000 -#define TESTVFS_ALL_MASK 0x00007FFF +#define TESTVFS_OPEN_MASK 0x00000100 +#define TESTVFS_SYNC_MASK 0x00000200 +#define TESTVFS_DELETE_MASK 0x00000400 +#define TESTVFS_CLOSE_MASK 0x00000800 +#define TESTVFS_WRITE_MASK 0x00001000 +#define TESTVFS_TRUNCATE_MASK 0x00002000 +#define TESTVFS_ACCESS_MASK 0x00004000 +#define TESTVFS_FULLPATHNAME_MASK 0x00008000 +#define TESTVFS_ALL_MASK 0x0001FFFF #define TESTVFS_MAX_PAGES 1024 @@ -545,7 +546,7 @@ static int tvfsOpen( /* Evaluate the Tcl script: ** - ** SCRIPT xOpen FILENAME + ** SCRIPT xOpen FILENAME KEY-VALUE-ARGS ** ** If the script returns an SQLite error code other than SQLITE_OK, an ** error is returned to the caller. If it returns SQLITE_OK, the new @@ -554,7 +555,19 @@ static int tvfsOpen( */ Tcl_ResetResult(p->interp); if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){ - tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0); + Tcl_Obj *pArg = Tcl_NewObj(); + Tcl_IncrRefCount(pArg); + if( flags&SQLITE_OPEN_MAIN_DB ){ + const char *z = &zName[strlen(zName)+1]; + while( *z ){ + Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); + z += strlen(z) + 1; + Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); + z += strlen(z) + 1; + } + } + tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0); + Tcl_DecrRefCount(pArg); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ @@ -663,6 +676,14 @@ static int tvfsFullPathname( int nOut, char *zOut ){ + Testvfs *p = (Testvfs *)pVfs->pAppData; + if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){ + int rc; + tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0); + if( tvfsResultCode(p, &rc) ){ + if( rc!=SQLITE_OK ) return rc; + } + } return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut); } @@ -1028,18 +1049,19 @@ static int testvfs_obj_cmd( char *zName; int mask; } vfsmethod [] = { - { "xShmOpen", TESTVFS_SHMOPEN_MASK }, - { "xShmLock", TESTVFS_SHMLOCK_MASK }, - { "xShmBarrier", TESTVFS_SHMBARRIER_MASK }, - { "xShmUnmap", TESTVFS_SHMCLOSE_MASK }, - { "xShmMap", TESTVFS_SHMMAP_MASK }, - { "xSync", TESTVFS_SYNC_MASK }, - { "xDelete", TESTVFS_DELETE_MASK }, - { "xWrite", TESTVFS_WRITE_MASK }, - { "xTruncate", TESTVFS_TRUNCATE_MASK }, - { "xOpen", TESTVFS_OPEN_MASK }, - { "xClose", TESTVFS_CLOSE_MASK }, - { "xAccess", TESTVFS_ACCESS_MASK }, + { "xShmOpen", TESTVFS_SHMOPEN_MASK }, + { "xShmLock", TESTVFS_SHMLOCK_MASK }, + { "xShmBarrier", TESTVFS_SHMBARRIER_MASK }, + { "xShmUnmap", TESTVFS_SHMCLOSE_MASK }, + { "xShmMap", TESTVFS_SHMMAP_MASK }, + { "xSync", TESTVFS_SYNC_MASK }, + { "xDelete", TESTVFS_DELETE_MASK }, + { "xWrite", TESTVFS_WRITE_MASK }, + { "xTruncate", TESTVFS_TRUNCATE_MASK }, + { "xOpen", TESTVFS_OPEN_MASK }, + { "xClose", TESTVFS_CLOSE_MASK }, + { "xAccess", TESTVFS_ACCESS_MASK }, + { "xFullPathname", TESTVFS_FULLPATHNAME_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; diff --git a/src/util.c b/src/util.c index 1c9b401f89..de73577203 100644 --- a/src/util.c +++ b/src/util.c @@ -983,13 +983,12 @@ void sqlite3Put4byte(unsigned char *p, u32 v){ -#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ -static u8 hexToInt(int h){ +u8 sqlite3HexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); @@ -999,7 +998,6 @@ static u8 hexToInt(int h){ #endif return (u8)(h & 0xf); } -#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* @@ -1016,7 +1014,7 @@ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){ n--; if( zBlob ){ for(i=0; i test.nal +** test.db-wal => test.wal +** test.db-shm => test.shm +*/ +void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ + const char *zOk; + zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); + if( zOk && sqlite3GetBoolean(zOk) ){ + int i, sz; + sz = sqlite3Strlen30(z); + for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} + if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4); + } +} +#endif diff --git a/src/vdbe.c b/src/vdbe.c index 420afd41e2..59154b6aa7 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -574,6 +574,7 @@ int sqlite3VdbeExec( Mem *pOut = 0; /* Output operand */ int iCompare = 0; /* Result of last OP_Compare operation */ int *aPermute = 0; /* Permutation of columns for OP_Compare */ + i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ #ifdef VDBE_PROFILE u64 start; /* CPU clock count at start of opcode */ int origPc; /* Program counter at start of opcode */ @@ -843,6 +844,7 @@ case OP_Halt: { p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pc = sqlite3VdbeFrameRestore(pFrame); + lastRowid = db->lastRowid; if( pOp->p2==OE_Ignore ){ /* Instruction pc is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt @@ -1403,7 +1405,9 @@ case OP_Function: { assert( pOp[-1].opcode==OP_CollSeq ); ctx.pColl = pOp[-1].p4.pColl; } + db->lastRowid = lastRowid; (*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */ + lastRowid = db->lastRowid; if( db->mallocFailed ){ /* Even though a malloc() has failed, the implementation of the ** user function may have called an sqlite3_result_XXX() function @@ -3159,7 +3163,7 @@ case OP_OpenEphemeral: { pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; - rc = sqlite3BtreeOpen(0, db, &pCx->pBt, + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); @@ -3819,7 +3823,7 @@ case OP_NewRowid: { /* out2-prerelease */ assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is ** an AUTOINCREMENT table. */ /* on the first attempt, simply do one more than previous */ - v = db->lastRowid; + v = lastRowid; v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ v++; /* ensure non-zero */ cnt = 0; @@ -3948,7 +3952,7 @@ case OP_InsertInt: { #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey; + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey; if( pData->flags & MEM_Null ){ pData->z = 0; pData->n = 0; @@ -5059,7 +5063,7 @@ case OP_Program: { /* jump */ p->nFrame++; pFrame->pParent = p->pFrame; - pFrame->lastRowid = db->lastRowid; + pFrame->lastRowid = lastRowid; pFrame->nChange = p->nChange; p->nChange = 0; p->pFrame = pFrame; @@ -5866,7 +5870,7 @@ case OP_VUpdate: { importVtabErrMsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); - db->lastRowid = rowid; + db->lastRowid = lastRowid = rowid; } if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ if( pOp->p5==OE_Ignore ){ @@ -6024,6 +6028,7 @@ vdbe_error_halt: ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: + db->lastRowid = lastRowid; sqlite3VdbeLeave(p); return rc; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 51c15505a4..531d70c1e3 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1800,6 +1800,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ if( !zMaster ){ return SQLITE_NOMEM; } + sqlite3FileSuffix3(zMainFile, zMaster); rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); }while( rc==SQLITE_OK && res ); if( rc==SQLITE_OK ){ diff --git a/src/vtab.c b/src/vtab.c index cac9c96064..c64c897d07 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -874,7 +874,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int i; for(i=0; rc==SQLITE_OK && inVTrans; i++){ const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; - if( pMod->iVersion>=1 ){ + if( pMod->iVersion>=2 ){ int (*xMethod)(sqlite3_vtab *, int); switch( op ){ case SAVEPOINT_BEGIN: @@ -1001,7 +1001,7 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ */ int sqlite3_vtab_on_conflict(sqlite3 *db){ static const unsigned char aMap[] = { - SQLITE_ROLLBACK, SQLITE_IGNORE, SQLITE_ABORT, SQLITE_FAIL, SQLITE_REPLACE + SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE }; assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); assert( OE_Ignore==4 && OE_Replace==5 ); @@ -1027,7 +1027,7 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){ if( !p ){ rc = SQLITE_MISUSE_BKPT; }else{ - assert( (p->pTab->tabFlags & TF_Virtual)!=0 ); + assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); p->pVTable->bConstraint = (u8)va_arg(ap, int); } break; diff --git a/src/wal.c b/src/wal.c index 51ea18fb21..1222660985 100644 --- a/src/wal.c +++ b/src/wal.c @@ -412,6 +412,7 @@ struct Wal { sqlite3_file *pDbFd; /* File handle for the database file */ sqlite3_file *pWalFd; /* File handle for WAL file */ u32 iCallback; /* Value to pass to log callback (or 0) */ + i64 mxWalSize; /* Truncate WAL to this size upon reset */ int nWiData; /* Size of array apWiData */ volatile u32 **apWiData; /* Pointer to wal-index content in memory */ u32 szPage; /* Database page size */ @@ -1234,6 +1235,7 @@ int sqlite3WalOpen( sqlite3_file *pDbFd, /* The open database file */ const char *zWalName, /* Name of the WAL file */ int bNoShm, /* True to run in heap-memory mode */ + i64 mxWalSize, /* Truncate WAL to this size on reset */ Wal **ppWal /* OUT: Allocated Wal handle */ ){ int rc; /* Return Code */ @@ -1266,6 +1268,7 @@ int sqlite3WalOpen( pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; pRet->readLock = -1; + pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); @@ -1287,6 +1290,13 @@ int sqlite3WalOpen( return rc; } +/* +** Change the size to which the WAL file is trucated on each reset. +*/ +void sqlite3WalLimit(Wal *pWal, i64 iLimit){ + if( pWal ) pWal->mxWalSize = iLimit; +} + /* ** Find the smallest page number out of all pages held in the WAL that ** has not been returned by any prior invocation of this method on the @@ -2522,6 +2532,22 @@ static int walRestartLog(Wal *pWal){ */ int i; /* Loop counter */ u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ + + /* Limit the size of WAL file if the journal_size_limit PRAGMA is + ** set to a non-negative value. Log errors encountered + ** during the truncation attempt. */ + if( pWal->mxWalSize>=0 ){ + i64 sz; + int rx; + rx = sqlite3OsFileSize(pWal->pWalFd, &sz); + if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){ + rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize); + } + if( rx ){ + sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); + } + } + pWal->nCkpt++; pWal->hdr.mxFrame = 0; sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); diff --git a/src/wal.h b/src/wal.h index 2039c701cf..a62b23bbdc 100644 --- a/src/wal.h +++ b/src/wal.h @@ -21,6 +21,7 @@ #ifdef SQLITE_OMIT_WAL # define sqlite3WalOpen(x,y,z) 0 +# define sqlite3WalLimit(x,y) # define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalEndReadTransaction(z) @@ -46,9 +47,12 @@ typedef struct Wal Wal; /* Open and close a connection to a write-ahead log. */ -int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**); +int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); +/* Set the limiting size of a WAL file. */ +void sqlite3WalLimit(Wal*, i64); + /* Used by readers to open (lock) and close (unlock) a snapshot. A ** snapshot is like a read-transaction. It is the state of the database ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and diff --git a/test/8_3_names.test b/test/8_3_names.test new file mode 100644 index 0000000000..418685e64b --- /dev/null +++ b/test/8_3_names.test @@ -0,0 +1,197 @@ +# 2011 May 17 +# +# 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. +# +#*********************************************************************** +# +# Test cases for the SQLITE_ENABLE_8_3_NAMES feature that forces all +# filename extensions to be limited to 3 characters. Some embedded +# systems need this to work around microsoft FAT patents, but this +# feature should be disabled on most deployments. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !8_3_names { + finish_test + return +} + +db close +sqlite3_shutdown +sqlite3_config_uri 1 + +do_test 8_3_names-1.0 { + forcedelete test.db test.nal test.db-journal + sqlite3 db test.db + db eval { + PRAGMA cache_size=10; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(20000)); + BEGIN; + DELETE FROM t1; + INSERT INTO t1 VALUES(randomblob(15000)); + } + file exists test.db-journal +} 1 +do_test 8_3_names-1.1 { + file exists test.nal +} 0 +do_test 8_3_names-1.2 { + db eval { + ROLLBACK; + SELECT length(x) FROM t1 + } +} 20000 + +db close +do_test 8_3_names-2.0 { + forcedelete test.db test.nal test.db-journal + sqlite3 db file:./test.db?8_3_names=1 + db eval { + PRAGMA cache_size=10; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(20000)); + BEGIN; + DELETE FROM t1; + INSERT INTO t1 VALUES(randomblob(15000)); + } + file exists test.db-journal +} 0 +do_test 8_3_names-2.1 { + file exists test.nal +} 1 +forcedelete test2.db test2.nal test2.db-journal +file copy test.db test2.db +file copy test.nal test2.nal +do_test 8_3_names-2.2 { + db eval { + COMMIT; + SELECT length(x) FROM t1 + } +} 15000 +do_test 8_3_names-2.3 { + sqlite3 db2 file:./test2.db?8_3_names=1 + db2 eval { + PRAGMA integrity_check; + SELECT length(x) FROM t1; + } +} {ok 20000} + +db close +do_test 8_3_names-3.0 { + forcedelete test.db test.nal test.db-journal + sqlite3 db file:./test.db?8_3_names=0 + db eval { + PRAGMA cache_size=10; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(randomblob(20000)); + BEGIN; + DELETE FROM t1; + INSERT INTO t1 VALUES(randomblob(15000)); + } + file exists test.db-journal +} 1 +do_test 8_3_names-3.1 { + file exists test.nal +} 0 +forcedelete test2.db test2.nal test2.db-journal +file copy test.db test2.db +file copy test.db-journal test2.db-journal +do_test 8_3_names-3.2 { + db eval { + COMMIT; + SELECT length(x) FROM t1 + } +} 15000 +do_test 8_3_names-3.3 { + sqlite3 db2 file:./test2.db?8_3_names=0 + db2 eval { + PRAGMA integrity_check; + SELECT length(x) FROM t1; + } +} {ok 20000} + +########################################################################## +# Master journals. +# +db close +forcedelete test.db test2.db +do_test 8_3_names-4.0 { + sqlite3 db file:./test.db?8_3_names=1 + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1); + ATTACH 'file:./test2.db?8_3_names=1' AS db2; + CREATE TABLE db2.t2(y); + INSERT INTO t2 VALUES(2); + BEGIN; + INSERT INTO t1 VALUES(3); + INSERT INTO t2 VALUES(4); + COMMIT; + SELECT * FROM t1, t2 ORDER BY x, y + } +} {1 2 1 4 3 2 3 4} + + +########################################################################## +# WAL mode. +# +ifcapable !wal { + finish_test + return +} +db close +forcedelete test.db +do_test 8_3_names-5.0 { + sqlite3 db file:./test.db?8_3_names=1 + register_wholenumber_module db + db eval { + PRAGMA journal_mode=WAL; + CREATE TABLE t1(x); + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t1 SELECT value FROM nums WHERE value BETWEEN 1 AND 1000; + BEGIN; + UPDATE t1 SET x=x*2; + } + sqlite3 db2 file:./test.db?8_3_names=1 + register_wholenumber_module db2 + db2 eval { + BEGIN; + SELECT sum(x) FROM t1; + } +} {500500} + +do_test 8_3_names-5.1 { + file exists test.db-wal +} 0 +do_test 8_3_names-5.2 { + file exists test.wal +} 1 +do_test 8_3_names-5.3 { + file exists test.db-shm +} 0 +do_test 8_3_names-5.4 { + file exists test.shm +} 1 + + +do_test 8_3_names-5.5 { + db eval { + COMMIT; + SELECT sum(x) FROM t1; + } +} {1001000} +do_test 8_3_names-5.6 { + db2 eval { + SELECT sum(x) FROM t1; + } +} {500500} + + +finish_test diff --git a/test/alter.test b/test/alter.test index d4b72a6ae8..359034d5aa 100644 --- a/test/alter.test +++ b/test/alter.test @@ -650,7 +650,7 @@ do_test alter-6.7 { # Ticket #1665: Make sure ALTER TABLE ADD COLUMN works on a table # that includes a COLLATE clause. # -do_test alter-7.1 { +do_realnum_test alter-7.1 { execsql { CREATE TABLE t1(a TEXT COLLATE BINARY); ALTER TABLE t1 ADD COLUMN b INTEGER COLLATE NOCASE; diff --git a/test/cast.test b/test/cast.test index 7a239439b7..f47f4bb2bf 100644 --- a/test/cast.test +++ b/test/cast.test @@ -234,7 +234,7 @@ do_test cast-3.1 { do_test cast-3.2 { execsql {SELECT CAST(9223372036854774800 AS numeric)} } 9223372036854774800 -do_test cast-3.3 { +do_realnum_test cast-3.3 { execsql {SELECT CAST(9223372036854774800 AS real)} } 9.22337203685477e+18 do_test cast-3.4 { @@ -246,7 +246,7 @@ do_test cast-3.5 { do_test cast-3.6 { execsql {SELECT CAST(-9223372036854774800 AS numeric)} } -9223372036854774800 -do_test cast-3.7 { +do_realnum_test cast-3.7 { execsql {SELECT CAST(-9223372036854774800 AS real)} } -9.22337203685477e+18 do_test cast-3.8 { @@ -258,7 +258,7 @@ do_test cast-3.11 { do_test cast-3.12 { execsql {SELECT CAST('9223372036854774800' AS numeric)} } 9223372036854774800 -do_test cast-3.13 { +do_realnum_test cast-3.13 { execsql {SELECT CAST('9223372036854774800' AS real)} } 9.22337203685477e+18 ifcapable long_double { @@ -272,7 +272,7 @@ do_test cast-3.15 { do_test cast-3.16 { execsql {SELECT CAST('-9223372036854774800' AS numeric)} } -9223372036854774800 -do_test cast-3.17 { +do_realnum_test cast-3.17 { execsql {SELECT CAST('-9223372036854774800' AS real)} } -9.22337203685477e+18 ifcapable long_double { @@ -287,7 +287,7 @@ if {[db eval {PRAGMA encoding}]=="UTF-8"} { do_test cast-3.22 { execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS numeric)} } 9223372036854774800 - do_test cast-3.23 { + do_realnum_test cast-3.23 { execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS real)} } 9.22337203685477e+18 ifcapable long_double { diff --git a/test/e_uri.test b/test/e_uri.test new file mode 100644 index 0000000000..b0e2f876de --- /dev/null +++ b/test/e_uri.test @@ -0,0 +1,456 @@ +# 2011 May 06 +# +# 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 +set testprefix e_uri + +db close + +proc parse_uri {uri} { + testvfs tvfs2 + testvfs tvfs + tvfs filter xOpen + tvfs script parse_uri_open_cb + + set ::uri_open [list] + set DB [sqlite3_open_v2 $uri { + SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL + } tvfs] + sqlite3_close $DB + tvfs delete + tvfs2 delete + + set ::uri_open +} +proc parse_uri_open_cb {method file arglist} { + set ::uri_open [list $file $arglist] +} + +proc open_uri_error {uri} { + set flags {SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_WAL} + set DB [sqlite3_open_v2 $uri $flags ""] + set e [sqlite3_errmsg $DB] + sqlite3_close $DB + set e +} + +# EVIDENCE-OF: R-35840-33204 If URI filename interpretation is enabled, +# and the filename argument begins with "file:", then the filename is +# interpreted as a URI. +# +# EVIDENCE-OF: R-00067-59538 URI filename interpretation is enabled if +# the SQLITE_OPEN_URI flag is is set in the fourth argument to +# sqlite3_open_v2(), or if it has been enabled globally using the +# SQLITE_CONFIG_URI option with the sqlite3_config() method. +# +if {$tcl_platform(platform) == "unix"} { + set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE] + + # Tests with SQLITE_CONFIG_URI configured to false. URI intepretation is + # only enabled if the SQLITE_OPEN_URI flag is specified. + sqlite3_shutdown + sqlite3_config_uri 0 + do_test 1.1 { + forcedelete file:test.db test.db + set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""] + list [file exists file:test.db] [file exists test.db] + } {0 1} + do_test 1.2 { + forcedelete file:test.db2 test.db2 + set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] + sqlite3_step $STMT + sqlite3_finalize $STMT + list [file exists file:test.db2] [file exists test.db2] + } {0 1} + sqlite3_close $DB + do_test 1.3 { + forcedelete file:test.db test.db + set DB [sqlite3_open_v2 file:test.db [concat $flags] ""] + list [file exists file:test.db] [file exists test.db] + } {1 0} + do_test 1.4 { + forcedelete file:test.db2 test.db2 + set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] + sqlite3_step $STMT + sqlite3_finalize $STMT + list [file exists file:test.db2] [file exists test.db2] + } {1 0} + sqlite3_close $DB + + # Tests with SQLITE_CONFIG_URI configured to true. URI intepretation is + # enabled with or without SQLITE_OPEN_URI. + # + sqlite3_shutdown + sqlite3_config_uri 1 + do_test 1.5 { + forcedelete file:test.db test.db + set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""] + list [file exists file:test.db] [file exists test.db] + } {0 1} + do_test 1.6 { + forcedelete file:test.db2 test.db2 + set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] + sqlite3_step $STMT + sqlite3_finalize $STMT + list [file exists file:test.db2] [file exists test.db2] + } {0 1} + sqlite3_close $DB + do_test 1.7 { + forcedelete file:test.db test.db + set DB [sqlite3_open_v2 file:test.db [concat $flags] ""] + list [file exists file:test.db] [file exists test.db] + } {0 1} + do_test 1.8 { + forcedelete file:test.db2 test.db2 + set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] + sqlite3_step $STMT + sqlite3_finalize $STMT + list [file exists file:test.db2] [file exists test.db2] + } {0 1} + sqlite3_close $DB +} + +# EVIDENCE-OF: R-17482-00398 If the authority is not an empty string or +# "localhost", an error is returned to the caller. +# +if {$tcl_platform(platform) == "unix"} { + set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] + foreach {tn uri error} " + 1 {file://localhost[pwd]/test.db} {not an error} + 2 {file://[pwd]/test.db} {not an error} + 3 {file://x[pwd]/test.db} {invalid uri authority: x} + 4 {file://invalid[pwd]/test.db} {invalid uri authority: invalid} + " { + do_test 2.$tn { + set DB [sqlite3_open_v2 $uri $flags ""] + set e [sqlite3_errmsg $DB] + sqlite3_close $DB + set e + } $error + } +} + +# EVIDENCE-OF: R-43804-65312 The 'fragment' component of a URI, if +# present, is always ignored. +# +# It is difficult to test that something is ignore correctly. So these tests +# just show that adding a fragment does not interfere with the pathname or +# parameters passed through to the VFS xOpen() methods. +# +if {$tcl_platform(platform) == "unix"} { + foreach {tn uri parse} " + 1 {file:test.db#abc} {[pwd]/test.db {}} + 2 {file:test.db?a=b#abc} {[pwd]/test.db {a b}} + 3 {file:test.db?a=b#?c=d} {[pwd]/test.db {a b}} + " { + do_test 3.$tn { parse_uri $uri } $parse + } +} + +# EVIDENCE-OF: R-00273-20588 SQLite uses the 'path' component of the URI +# as the path to the database file to open. +# +# EVIDENCE-OF: R-28659-11035 If the path begins with a '/' character, +# then it is interpreted as an absolute path. +# +# EVIDENCE-OF: R-39349-47203 If it does not begin with a '/', it is +# interpreted as a relative path. +# +if {$tcl_platform(platform) == "unix"} { + foreach {tn uri parse} " + 1 {file:test.db} {[pwd]/test.db {}} + 2 {file:/test.db} {/test.db {}} + 3 {file:///test.db} {/test.db {}} + 4 {file://localhost/test.db} {/test.db {}} + 5 {file:/a/b/c/test.db} {/a/b/c/test.db {}} + " { + do_test 4.$tn { parse_uri $uri } $parse + } +} + +# EVIDENCE-OF: R-01612-30877 The "vfs" parameter may be used to specify +# the name of a VFS object that provides the operating system interface +# that should be used to access the database file on disk. +# +# The above is tested by cases 1.* below. +# +# EVIDENCE-OF: R-52293-58497 If this option is set to an empty string +# the default VFS object is used. +# +# The above is tested by cases 2.* below. +# +# EVIDENCE-OF: R-31855-18665 If sqlite3_open_v2() is used and the vfs +# option is present, then the VFS specified by the option takes +# precedence over the value passed as the fourth parameter to +# sqlite3_open_v2(). +# +# The above is tested by cases 3.* below. +# +proc vfs_open_cb {name args} { + set ::vfs $name +} +foreach {name default} {vfs1 0 vfs2 0 vfs3 1} { + testvfs $name -default $default + $name filter xOpen + $name script [list vfs_open_cb $name] +} +foreach {tn uri defvfs vfs} { + 1.1 "file:test.db?vfs=vfs1" "" vfs1 + 1.2 "file:test.db?vfs=vfs2" "" vfs2 + + 2.1 "file:test.db" vfs1 vfs1 + 2.2 "file:test.db?vfs=" vfs1 vfs3 + + 3.1 "file:test.db?vfs=vfs1" vfs2 vfs1 + 3.2 "file:test.db?vfs=vfs2" vfs1 vfs2 + 3.3 "file:test.db?xvfs=vfs1" vfs2 vfs2 + 3.4 "file:test.db?xvfs=vfs2" vfs1 vfs1 +} { + do_test 5.$tn { + set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] + sqlite3_close [ + sqlite3_open_v2 $uri $flags $defvfs + ] + set ::vfs + } $vfs +} +vfs1 delete +vfs2 delete +vfs3 delete + +# EVIDENCE-OF: R-48365-36308 Specifying an unknown VFS is an error. +# +set flags [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] +do_test 6.1 { + set DB [sqlite3_open_v2 file:test.db?vfs=nosuchvfs $flags ""] + set errmsg [sqlite3_errmsg $DB] + sqlite3_close $DB + set errmsg +} {no such vfs: nosuchvfs} + + +# EVIDENCE-OF: R-60479-64270 The mode parameter may be set to either +# "ro", "rw" or "rwc". Attempting to set it to any other value is an +# error +# +sqlite3 db test.db +db close +foreach {tn uri error} " + 1 {file:test.db?mode=ro} {not an error} + 2 {file:test.db?mode=rw} {not an error} + 3 {file:test.db?mode=rwc} {not an error} + 4 {file:test.db?mode=Ro} {no such access mode: Ro} + 5 {file:test.db?mode=Rw} {no such access mode: Rw} + 6 {file:test.db?mode=Rwc} {no such access mode: Rwc} +" { + do_test 7.$tn { open_uri_error $uri } $error +} + + +# EVIDENCE-OF: R-09651-31805 If "ro" is specified, then the database is +# opened for read-only access, just as if the SQLITE_OPEN_READONLY flag +# had been set in the third argument to sqlite3_prepare_v2(). +# +# EVIDENCE-OF: R-40137-26050 If the mode option is set to "rw", then the +# database is opened for read-write (but not create) access, as if +# SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had been set. +# +# EVIDENCE-OF: R-26845-32976 Value "rwc" is equivalent to setting both +# SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. +# +sqlite3_shutdown +sqlite3_config_uri 1 +foreach {tn uri read write create} { + 1 {file:test.db?mode=ro} 1 0 0 + 2 {file:test.db?mode=rw} 1 1 0 + 3 {file:test.db?mode=rwc} 1 1 1 +} { + set RES(c,0) {1 {unable to open database file}} + set RES(c,1) {0 {}} + set RES(w,0) {1 {attempt to write a readonly database}} + set RES(w,1) {0 {}} + set RES(r,0) {1 {this never happens}} + set RES(r,1) {0 {a b}} + + # Test CREATE access: + forcedelete test.db + do_test 8.$tn.c { list [catch { sqlite3 db $uri } msg] $msg } $RES(c,$create) + catch { db close } + + sqlite3 db test.db + db eval { CREATE TABLE t1(a, b) ; INSERT INTO t1 VALUES('a', 'b') ;} + db close + + # Test READ access: + do_test 8.$tn.r { + sqlite3 db $uri + catchsql { SELECT * FROM t1 } + } $RES(r,$read) + + # Test WRITE access: + do_test 8.$tn.w { + sqlite3 db $uri + catchsql { INSERT INTO t1 VALUES(1, 2) } + } $RES(w,$write) + + catch {db close} +} + +# EVIDENCE-OF: R-56032-32287 If sqlite3_open_v2() is used, it is an +# error to specify a value for the mode parameter that is less +# restrictive than that specified by the flags passed as the third +# parameter. +# +forcedelete test.db +sqlite3 db test.db +db close +foreach {tn uri flags error} { + 1 {file:test.db?mode=ro} ro {not an error} + 2 {file:test.db?mode=ro} rw {not an error} + 3 {file:test.db?mode=ro} rwc {not an error} + + 4 {file:test.db?mode=rw} ro {access mode not allowed: rw} + 5 {file:test.db?mode=rw} rw {not an error} + 6 {file:test.db?mode=rw} rwc {not an error} + + 7 {file:test.db?mode=rwc} ro {access mode not allowed: rwc} + 8 {file:test.db?mode=rwc} rw {access mode not allowed: rwc} + 9 {file:test.db?mode=rwc} rwc {not an error} +} { + set f(ro) [list SQLITE_OPEN_READONLY SQLITE_OPEN_URI] + set f(rw) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_URI] + set f(rwc) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] + + set DB [sqlite3_open_v2 $uri $f($flags) ""] + set e [sqlite3_errmsg $DB] + sqlite3_close $DB + + do_test 9.$tn { set e } $error +} + +# EVIDENCE-OF: R-23182-54295 The cache parameter may be set to either +# "shared" or "private". +sqlite3 db test.db +db close +foreach {tn uri error} " + 1 {file:test.db?cache=private} {not an error} + 2 {file:test.db?cache=shared} {not an error} + 3 {file:test.db?cache=yes} {no such cache mode: yes} + 4 {file:test.db?cache=} {no such cache mode: } +" { + do_test 10.$tn { open_uri_error $uri } $error +} + +# EVIDENCE-OF: R-23027-03515 Setting it to "shared" is equivalent to +# setting the SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed +# to sqlite3_open_v2(). +# +# EVIDENCE-OF: R-49793-28525 Setting the cache parameter to "private" is +# equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +# +# EVIDENCE-OF: R-19510-48080 If sqlite3_open_v2() is used and the +# "cache" parameter is present in a URI filename, its value overrides +# any behaviour requested by setting SQLITE_OPEN_PRIVATECACHE or +# SQLITE_OPEN_SHAREDCACHE flag. +# +set orig [sqlite3_enable_shared_cache] +foreach {tn uri flags shared_default isshared} { + 1.1 "file:test.db" "" 0 0 + 1.2 "file:test.db" "" 1 1 + 1.3 "file:test.db" private 0 0 + 1.4 "file:test.db" private 1 0 + 1.5 "file:test.db" shared 0 1 + 1.6 "file:test.db" shared 1 1 + + 2.1 "file:test.db?cache=private" "" 0 0 + 2.2 "file:test.db?cache=private" "" 1 0 + 2.3 "file:test.db?cache=private" private 0 0 + 2.4 "file:test.db?cache=private" private 1 0 + 2.5 "file:test.db?cache=private" shared 0 0 + 2.6 "file:test.db?cache=private" shared 1 0 + + 3.1 "file:test.db?cache=shared" "" 0 1 + 3.2 "file:test.db?cache=shared" "" 1 1 + 3.3 "file:test.db?cache=shared" private 0 1 + 3.4 "file:test.db?cache=shared" private 1 1 + 3.5 "file:test.db?cache=shared" shared 0 1 + 3.6 "file:test.db?cache=shared" shared 1 1 +} { + forcedelete test.db + sqlite3_enable_shared_cache 1 + sqlite3 db test.db + sqlite3_enable_shared_cache 0 + + db eval { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('ok'); + } + + unset -nocomplain f + set f() {SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI} + set f(shared) [concat $f() SQLITE_OPEN_SHAREDCACHE] + set f(private) [concat $f() SQLITE_OPEN_PRIVATECACHE] + + sqlite3_enable_shared_cache $shared_default + set DB [sqlite3_open_v2 $uri $f($flags) ""] + + set STMT [sqlite3_prepare $DB "SELECT * FROM t1" -1 dummy] + + db eval { + BEGIN; + INSERT INTO t1 VALUES('ko'); + } + + sqlite3_step $STMT + sqlite3_finalize $STMT + + set RES(0) {not an error} + set RES(1) {database table is locked: t1} + + do_test 11.$tn { sqlite3_errmsg $DB } $RES($isshared) + + sqlite3_close $DB + db close +} +sqlite3_enable_shared_cache $orig + +# EVIDENCE-OF: R-63472-46769 Specifying an unknown parameter in the +# query component of a URI is not an error. +# +do_test 12.1 { + parse_uri file://localhost/test.db?an=unknown¶meter=is&ok= +} {/test.db {an unknown parameter is ok {}}} +do_test 12.2 { + parse_uri file://localhost/test.db?an&unknown¶meter&is&ok +} {/test.db {an {} unknown {} parameter {} is {} ok {}}} + +# EVIDENCE-OF: R-27458-04043 URI hexadecimal escape sequences (%HH) are +# supported within the path and query components of a URI. +# +# EVIDENCE-OF: R-52765-50368 Before the path or query components of a +# URI filename are interpreted, they are encoded using UTF-8 and all +# hexadecimal escape sequences replaced by a single byte containing the +# corresponding octet. +# +# The second of the two statements above is tested by creating a +# multi-byte utf-8 character using a sequence of %HH escapes. +# +foreach {tn uri parse} " + 1 {file:/test.%64%62} {/test.db {}} + 2 {file:/test.db?%68%65%6c%6c%6f=%77%6f%72%6c%64} {/test.db {hello world}} + 3 {file:/%C3%BF.db} {/\xFF.db {}} +" { + do_test 13.$tn { parse_uri $uri } $parse +} + +finish_test diff --git a/test/expr.test b/test/expr.test index 5a3d167517..cc4c9c67f1 100644 --- a/test/expr.test +++ b/test/expr.test @@ -32,6 +32,11 @@ proc test_expr {name settings expr result} { execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;} } $settings $expr] $result } +proc test_realnum_expr {name settings expr result} { + do_realnum_test $name [format { + execsql {BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK;} + } $settings $expr] $result +} test_expr expr-1.1 {i1=10, i2=20} {i1+i2} 30 test_expr expr-1.2 {i1=10, i2=20} {i1-i2} -10 @@ -164,7 +169,7 @@ ifcapable floatingpoint { } if {[working_64bit_int]} { - test_expr expr-1.106 {i1=0} {-9223372036854775808/-1} 9.22337203685478e+18 + test_realnum_expr expr-1.106 {i1=0} {-9223372036854775808/-1} 9.22337203685478e+18 } test_expr expr-1.107 {i1=0} {-9223372036854775808%-1} 0 @@ -203,100 +208,100 @@ test_expr expr-1.126 {i1=8, i2=8} \ ifcapable floatingpoint {if {[working_64bit_int]} { test_expr expr-1.200\ {i1=9223372036854775806, i2=1} {i1+i2} 9223372036854775807 - test_expr expr-1.201\ + test_realnum_expr expr-1.201\ {i1=9223372036854775806, i2=2} {i1+i2} 9.22337203685478e+18 - test_expr expr-1.202\ + test_realnum_expr expr-1.202\ {i1=9223372036854775806, i2=100000} {i1+i2} 9.22337203685488e+18 - test_expr expr-1.203\ + test_realnum_expr expr-1.203\ {i1=9223372036854775807, i2=0} {i1+i2} 9223372036854775807 - test_expr expr-1.204\ + test_realnum_expr expr-1.204\ {i1=9223372036854775807, i2=1} {i1+i2} 9.22337203685478e+18 - test_expr expr-1.205\ + test_realnum_expr expr-1.205\ {i2=9223372036854775806, i1=1} {i1+i2} 9223372036854775807 - test_expr expr-1.206\ + test_realnum_expr expr-1.206\ {i2=9223372036854775806, i1=2} {i1+i2} 9.22337203685478e+18 - test_expr expr-1.207\ + test_realnum_expr expr-1.207\ {i2=9223372036854775806, i1=100000} {i1+i2} 9.22337203685488e+18 - test_expr expr-1.208\ + test_realnum_expr expr-1.208\ {i2=9223372036854775807, i1=0} {i1+i2} 9223372036854775807 - test_expr expr-1.209\ + test_realnum_expr expr-1.209\ {i2=9223372036854775807, i1=1} {i1+i2} 9.22337203685478e+18 - test_expr expr-1.210\ + test_realnum_expr expr-1.210\ {i1=-9223372036854775807, i2=-1} {i1+i2} -9223372036854775808 - test_expr expr-1.211\ + test_realnum_expr expr-1.211\ {i1=-9223372036854775807, i2=-2} {i1+i2} -9.22337203685478e+18 - test_expr expr-1.212\ + test_realnum_expr expr-1.212\ {i1=-9223372036854775807, i2=-100000} {i1+i2} -9.22337203685488e+18 - test_expr expr-1.213\ + test_realnum_expr expr-1.213\ {i1=-9223372036854775808, i2=0} {i1+i2} -9223372036854775808 - test_expr expr-1.214\ + test_realnum_expr expr-1.214\ {i1=-9223372036854775808, i2=-1} {i1+i2} -9.22337203685478e+18 - test_expr expr-1.215\ + test_realnum_expr expr-1.215\ {i2=-9223372036854775807, i1=-1} {i1+i2} -9223372036854775808 - test_expr expr-1.216\ + test_realnum_expr expr-1.216\ {i2=-9223372036854775807, i1=-2} {i1+i2} -9.22337203685478e+18 - test_expr expr-1.217\ + test_realnum_expr expr-1.217\ {i2=-9223372036854775807, i1=-100000} {i1+i2} -9.22337203685488e+18 - test_expr expr-1.218\ + test_realnum_expr expr-1.218\ {i2=-9223372036854775808, i1=0} {i1+i2} -9223372036854775808 - test_expr expr-1.219\ + test_realnum_expr expr-1.219\ {i2=-9223372036854775808, i1=-1} {i1+i2} -9.22337203685478e+18 - test_expr expr-1.220\ + test_realnum_expr expr-1.220\ {i1=9223372036854775806, i2=-1} {i1-i2} 9223372036854775807 - test_expr expr-1.221\ + test_realnum_expr expr-1.221\ {i1=9223372036854775806, i2=-2} {i1-i2} 9.22337203685478e+18 - test_expr expr-1.222\ + test_realnum_expr expr-1.222\ {i1=9223372036854775806, i2=-100000} {i1-i2} 9.22337203685488e+18 - test_expr expr-1.223\ + test_realnum_expr expr-1.223\ {i1=9223372036854775807, i2=0} {i1-i2} 9223372036854775807 - test_expr expr-1.224\ + test_realnum_expr expr-1.224\ {i1=9223372036854775807, i2=-1} {i1-i2} 9.22337203685478e+18 - test_expr expr-1.225\ + test_realnum_expr expr-1.225\ {i2=-9223372036854775806, i1=1} {i1-i2} 9223372036854775807 - test_expr expr-1.226\ + test_realnum_expr expr-1.226\ {i2=-9223372036854775806, i1=2} {i1-i2} 9.22337203685478e+18 - test_expr expr-1.227\ + test_realnum_expr expr-1.227\ {i2=-9223372036854775806, i1=100000} {i1-i2} 9.22337203685488e+18 - test_expr expr-1.228\ + test_realnum_expr expr-1.228\ {i2=-9223372036854775807, i1=0} {i1-i2} 9223372036854775807 - test_expr expr-1.229\ + test_realnum_expr expr-1.229\ {i2=-9223372036854775807, i1=1} {i1-i2} 9.22337203685478e+18 - test_expr expr-1.230\ + test_realnum_expr expr-1.230\ {i1=-9223372036854775807, i2=1} {i1-i2} -9223372036854775808 - test_expr expr-1.231\ + test_realnum_expr expr-1.231\ {i1=-9223372036854775807, i2=2} {i1-i2} -9.22337203685478e+18 - test_expr expr-1.232\ + test_realnum_expr expr-1.232\ {i1=-9223372036854775807, i2=100000} {i1-i2} -9.22337203685488e+18 - test_expr expr-1.233\ + test_realnum_expr expr-1.233\ {i1=-9223372036854775808, i2=0} {i1-i2} -9223372036854775808 - test_expr expr-1.234\ + test_realnum_expr expr-1.234\ {i1=-9223372036854775808, i2=1} {i1-i2} -9.22337203685478e+18 - test_expr expr-1.235\ + test_realnum_expr expr-1.235\ {i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808 - test_expr expr-1.236\ + test_realnum_expr expr-1.236\ {i2=9223372036854775807, i1=-2} {i1-i2} -9.22337203685478e+18 - test_expr expr-1.237\ + test_realnum_expr expr-1.237\ {i2=9223372036854775807, i1=-100000} {i1-i2} -9.22337203685488e+18 - test_expr expr-1.238\ + test_realnum_expr expr-1.238\ {i2=9223372036854775807, i1=0} {i1-i2} -9223372036854775807 - test_expr expr-1.239\ + test_realnum_expr expr-1.239\ {i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808 - test_expr expr-1.250\ + test_realnum_expr expr-1.250\ {i1=4294967296, i2=2147483648} {i1*i2} 9.22337203685478e+18 - test_expr expr-1.251\ + test_realnum_expr expr-1.251\ {i1=4294967296, i2=2147483647} {i1*i2} 9223372032559808512 - test_expr expr-1.252\ + test_realnum_expr expr-1.252\ {i1=-4294967296, i2=2147483648} {i1*i2} -9223372036854775808 - test_expr expr-1.253\ + test_realnum_expr expr-1.253\ {i1=-4294967296, i2=2147483647} {i1*i2} -9223372032559808512 - test_expr expr-1.254\ + test_realnum_expr expr-1.254\ {i1=4294967296, i2=-2147483648} {i1*i2} -9223372036854775808 - test_expr expr-1.255\ + test_realnum_expr expr-1.255\ {i1=4294967296, i2=-2147483647} {i1*i2} -9223372032559808512 - test_expr expr-1.256\ + test_realnum_expr expr-1.256\ {i1=-4294967296, i2=-2147483648} {i1*i2} 9.22337203685478e+18 - test_expr expr-1.257\ + test_realnum_expr expr-1.257\ {i1=-4294967296, i2=-2147483647} {i1*i2} 9223372032559808512 }} @@ -883,7 +888,7 @@ do_test expr-12.2 { } {1 {near ")": syntax error}} ifcapable floatingpoint { - do_test expr-13.1 { + do_realnum_test expr-13.1 { execsql { SELECT 12345678901234567890; } @@ -908,12 +913,12 @@ if {[working_64bit_int]} { # If the value is too large, use String->Float conversion. # ifcapable floatingpoint { - do_test expr-13.4 { + do_realnum_test expr-13.4 { execsql { SELECT 0+'9223372036854775808' } } {9.22337203685478e+18} - do_test expr-13.5 { + do_realnum_test expr-13.5 { execsql { SELECT '9223372036854775808'+0 } @@ -923,12 +928,12 @@ ifcapable floatingpoint { # Use String->float conversion if the value is explicitly a floating # point value. # -do_test expr-13.6 { +do_realnum_test expr-13.6 { execsql { SELECT 0+'9223372036854775807.0' } } {9.22337203685478e+18} -do_test expr-13.7 { +do_realnum_test expr-13.7 { execsql { SELECT '9223372036854775807.0'+0 } diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test index b8b45c3951..ea4c9a9d3b 100644 --- a/test/fts3corrupt.test +++ b/test/fts3corrupt.test @@ -40,6 +40,7 @@ do_test fts3corrupt-1.2 { do_catchsql_test 1.3 { INSERT INTO t1 VALUES('world'); } {1 {database disk image is malformed}} +do_test 1.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_execsql_test 1.4 { DROP TABLE t1; } @@ -69,6 +70,7 @@ do_test fts3corrupt-2.1 { do_catchsql_test 2.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'hello' } {1 {database disk image is malformed}} +do_test 2.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_execsql_test 3.0 { DROP TABLE t1; @@ -86,6 +88,7 @@ do_test fts3corrupt-3.1 { do_catchsql_test 3.2 { SELECT rowid FROM t1 WHERE t1 MATCH 'world' } {1 {database disk image is malformed}} +do_test 3.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_execsql_test 4.0 { @@ -111,6 +114,7 @@ do_catchsql_test 4.2 { UPDATE t1_segdir SET root = X'FFFFFFFFFFFFFFFF'; SELECT rowid FROM t1 WHERE t1 MATCH 'world'; } {1 {database disk image is malformed}} +do_test 4.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB set blob [binary format cca*cca*cca*cca*cca*cca*cca*cca*cca*cca*a* \ 22 120 [string repeat a 120] \ @@ -130,6 +134,7 @@ do_catchsql_test 4.3 { UPDATE t1_segdir SET root = $blob; SELECT rowid FROM t1 WHERE t1 MATCH 'world'; } {1 {database disk image is malformed}} +do_test 4.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB # Test a special kind of corruption, where the %_stat table contains # an invalid entry. At one point this could lead to a division-by-zero @@ -152,10 +157,12 @@ do_catchsql_test 5.2 { UPDATE t1_stat SET value = X'0000'; SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*'; } {1 {database disk image is malformed}} +do_test 5.2.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB do_catchsql_test 5.3 { UPDATE t1_stat SET value = NULL; SELECT matchinfo(t1, 'nxa') FROM t1 WHERE t1 MATCH 't*'; } {1 {database disk image is malformed}} +do_test 5.3.1 { sqlite3_extended_errcode db } SQLITE_CORRUPT_VTAB finish_test diff --git a/test/multiplex.test b/test/multiplex.test index 518cbe37a0..ae60d639e5 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -567,5 +567,45 @@ if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} { } } +#------------------------------------------------------------------------- +# Test that you can vacuum a multiplex'ed DB. + +ifcapable vacuum { + +do_test multiplex-6.0.0 { + multiplex_delete test.db + sqlite3_multiplex_initialize "" 1 + sqlite3 db test.db + multiplex_set db main 4096 16 +} {SQLITE_OK} + +do_test multiplex-6.1.0 { + execsql { + PRAGMA page_size=1024; + PRAGMA journal_mode=DELETE; + PRAGMA auto_vacuum=OFF; + } + execsql { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, randomblob($g_chunk_size)); + INSERT INTO t1 VALUES(2, randomblob($g_chunk_size)); + } +} {} +do_test multiplex-6.2.1 { file size [multiplex_name test.db 0] } [list $g_chunk_size] +do_test multiplex-6.2.2 { file size [multiplex_name test.db 1] } [list $g_chunk_size] + +do_test multiplex-6.3.0 { + execsql { VACUUM } +} {} + +do_test multiplex-6.99 { + db close + multiplex_delete test.db + sqlite3_multiplex_shutdown +} {SQLITE_OK} + +} + + catch { sqlite3_multiplex_shutdown } finish_test diff --git a/test/nan.test b/test/nan.test index 0e9462fcb5..3257a439e4 100644 --- a/test/nan.test +++ b/test/nan.test @@ -42,31 +42,31 @@ do_test nan-1.1.1 { db eval {SELECT x, typeof(x) FROM t1} } {{} null} if {$tcl_platform(platform) != "symbian"} { - do_test nan-1.1.2 { + do_realnum_test nan-1.1.2 { sqlite3_bind_double $::STMT 1 +Inf sqlite3_step $::STMT sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real} - do_test nan-1.1.3 { + do_realnum_test nan-1.1.3 { sqlite3_bind_double $::STMT 1 -Inf sqlite3_step $::STMT sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real -inf real} - do_test nan-1.1.4 { + do_realnum_test nan-1.1.4 { sqlite3_bind_double $::STMT 1 -NaN sqlite3_step $::STMT sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real -inf real {} null} - do_test nan-1.1.5 { + do_realnum_test nan-1.1.5 { sqlite3_bind_double $::STMT 1 NaN0 sqlite3_step $::STMT sqlite3_reset $::STMT db eval {SELECT x, typeof(x) FROM t1} } {{} null inf real -inf real {} null {} null} - do_test nan-1.1.6 { + do_realnum_test nan-1.1.6 { sqlite3_bind_double $::STMT 1 -NaN0 sqlite3_step $::STMT sqlite3_reset $::STMT @@ -231,12 +231,12 @@ if {$tcl_platform(platform) != "symbian"} { # Do not run these tests on Symbian, as the Tcl port doesn't like to # convert from floating point value "-inf" to a string. # - do_test nan-4.7 { + do_realnum_test nan-4.7 { db eval {DELETE FROM t1} db eval "INSERT INTO t1 VALUES([string repeat 9 309].0)" db eval {SELECT x, typeof(x) FROM t1} } {inf real} - do_test nan-4.8 { + do_realnum_test nan-4.8 { db eval {DELETE FROM t1} db eval "INSERT INTO t1 VALUES(-[string repeat 9 309].0)" db eval {SELECT x, typeof(x) FROM t1} @@ -313,7 +313,7 @@ do_test nan-4.18 { db eval {SELECT CAST(x AS text), typeof(x) FROM t1} } {-9.88131291682493e-324 real} -do_test nan-4.20 { +do_realnum_test nan-4.20 { db eval {DELETE FROM t1} set big [string repeat 9 10000].0e-9000 db eval "INSERT INTO t1 VALUES($big)" diff --git a/test/pager1.test b/test/pager1.test index 8c31e1539c..fbdd4b20b9 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -1653,7 +1653,7 @@ for {set i 0} {$i<513} {incr i 3} { testvfs tv -default 1 tv script xOpenCb tv filter xOpen -proc xOpenCb {method filename} { +proc xOpenCb {method filename args} { set ::file_len [string length $filename] } sqlite3 db test.db @@ -2381,6 +2381,7 @@ do_test pager1-30.1 { # 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 { @@ -2408,7 +2409,7 @@ do_test pager1-31.1 { sqlite3 db2 test.db2 execsql { PRAGMA integrity_check } db2 } {ok} - +} finish_test diff --git a/test/tester.tcl b/test/tester.tcl index 8e54084f20..be21334f1d 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -354,6 +354,15 @@ proc do_test {name cmd expected} { flush stdout } +proc realnum_normalize {r} { + string map {1.#INF inf} [regsub -all {(e[+-])0+} $r {\1}] +} +proc do_realnum_test {name cmd expected} { + uplevel [list do_test $name [ + subst -nocommands { realnum_normalize [ $cmd ] } + ] [realnum_normalize $expected]] +} + proc fix_testname {varname} { upvar $varname testname if {[info exists ::testprefix] diff --git a/test/tkt-2d1a5c67d.test b/test/tkt-2d1a5c67d.test new file mode 100644 index 0000000000..676e60b057 --- /dev/null +++ b/test/tkt-2d1a5c67d.test @@ -0,0 +1,73 @@ +# 2011 May 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. Specifically, +# it tests that ticket [2d1a5c67dfc2363e44f29d9bbd57f7331851390a] has +# been resolved. +# +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !wal {finish_test; return} + +for {set ii 1} {$ii<=10} {incr ii} { + do_test tkt-2d1a5c67d.1.$ii { + db close + forcedelete test.db test.db-wal + sqlite3 db test.db + db eval "PRAGMA cache_size=$::ii" + db eval { + PRAGMA journal_mode=WAL; + CREATE TABLE t1(a,b); + CREATE INDEX t1b ON t1(b); + CREATE TABLE t2(x,y UNIQUE); + INSERT INTO t2 VALUES(3,4); + BEGIN; + INSERT INTO t1(a,b) VALUES(1,2); + SELECT 'A', * FROM t2 WHERE y=4; + SELECT 'B', * FROM t1; + COMMIT; + SELECT 'C', * FROM t1; + } + } {wal A 3 4 B 1 2 C 1 2} +} + +db close +forcedelete test.db test.db-wal +sqlite3 db test.db +register_wholenumber_module db +db eval { + PRAGMA journal_mode=WAL; + CREATE TABLE t1(a,b); + CREATE INDEX t1b ON t1(b); + CREATE TABLE t2(x,y); + CREATE VIRTUAL TABLE nums USING wholenumber; + INSERT INTO t2 SELECT value, randomblob(1000) FROM nums + WHERE value BETWEEN 1 AND 1000; +} + +for {set ii 1} {$ii<=10} {incr ii} { + do_test tkt-2d1a5c67d.2.$ii { + db eval "PRAGMA cache_size=$::ii" + db eval { + DELETE FROM t1; + BEGIN; + INSERT INTO t1(a,b) VALUES(1,2); + SELECT sum(length(y)) FROM t2; + COMMIT; + SELECT * FROM t1; + } + } {1000000 1 2} +} + +finish_test diff --git a/test/tkt3838.test b/test/tkt3838.test index 4fb5c55a8a..5dfc2b8afc 100644 --- a/test/tkt3838.test +++ b/test/tkt3838.test @@ -25,7 +25,7 @@ ifcapable !altertable { return } -do_test tkt3838-1.1 { +do_realnum_test tkt3838-1.1 { db eval { PRAGMA encoding=UTF16; CREATE TABLE t1(x); diff --git a/test/tkt3922.test b/test/tkt3922.test index 6506dcedb7..86bf5feceb 100644 --- a/test/tkt3922.test +++ b/test/tkt3922.test @@ -36,21 +36,21 @@ if {[working_64bit_int]} { } } {-1 integer} } -do_test tkt3922.2 { +do_realnum_test tkt3922.2 { execsql { DELETE FROM t1; INSERT INTO t1 VALUES('-9223372036854775809'); SELECT a, typeof(a) FROM t1; } } {-9.22337203685478e+18 real} -do_test tkt3922.3 { +do_realnum_test tkt3922.3 { execsql { DELETE FROM t1; INSERT INTO t1 VALUES('-9223372036854776832'); SELECT a, typeof(a) FROM t1; } } {-9.22337203685478e+18 real} -do_test tkt3922.4 { +do_realnum_test tkt3922.4 { execsql { DELETE FROM t1; INSERT INTO t1 VALUES('-9223372036854776833'); @@ -78,7 +78,7 @@ if {[working_64bit_int]} { } } {1 integer} } -do_test tkt3922.6 { +do_realnum_test tkt3922.6 { execsql { DELETE FROM t1; INSERT INTO t1 VALUES('9223372036854775808'); diff --git a/test/uri.test b/test/uri.test new file mode 100644 index 0000000000..42cbc66d77 --- /dev/null +++ b/test/uri.test @@ -0,0 +1,309 @@ +# 2011 April 22 +# +# 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 + +# Test organization: +# +# 1.*: That file names are correctly extracted from URIs. +# 2.*: That URI options (query parameters) are correctly extracted from URIs. +# 3.*: That specifying an unknown VFS causes an error. +# 4.*: Tests for specifying other options (other than "vfs"). +# 5.*: Test using a different VFS with an attached database. +# 6.*: Test that authorities other than "" and localhost cause errors. +# 7.*: Test that a read-write db can be attached to a read-only connection. +# + +set testprefix uri +db close +sqlite3_shutdown +sqlite3_config_uri 1 + +#------------------------------------------------------------------------- +# Test that file names are correctly extracted from URIs. +# +foreach {tn uri file} { + 1 test.db test.db + 2 file:test.db test.db + 3 file://PWD/test.db test.db + 4 file:PWD/test.db test.db + 5 file:test.db?mork=1 test.db + 6 file:test.db?mork=1&tonglor=2 test.db + 7 file:test.db?mork=1#boris test.db + 8 file:test.db#boris test.db + 9 test.db#boris test.db#boris + 10 file:test%2Edb test.db + 11 file file + 12 http:test.db http:test.db + 13 file:test.db%00extra test.db + 14 file:test%00.db%00extra test + + 15 test.db?mork=1#boris test.db?mork=1#boris + 16 file://localhostPWD/test.db%3Fhello test.db?hello +} { + + if {$tcl_platform(platform)=="windows"} { + if {$tn>14} break + set uri [string map [list PWD /[pwd]] $uri] + } else { + set uri [string map [list PWD [pwd]] $uri] + } + + forcedelete $file + do_test 1.$tn.1 { file exists $file } 0 + set DB [sqlite3_open $uri] + do_test 1.$tn.2 { file exists $file } 1 + sqlite3_close $DB + forcedelete $file + + do_test 1.$tn.3 { file exists $file } 0 + sqlite3 db xxx.db + catchsql { ATTACH $uri AS aux } + do_test 1.$tn.4 { file exists $file } 1 + db close +} + +#------------------------------------------------------------------------- +# Test that URI query parameters are passed through to the VFS layer +# correctly. +# +testvfs tvfs2 +testvfs tvfs -default 1 +tvfs filter xOpen +tvfs script open_method +proc open_method {method file arglist} { + set ::arglist $arglist +} +foreach {tn uri kvlist} { + 1 file:test.db?hello=world {hello world} + 2 file:test.db?hello&world {hello {} world {}} + 3 file:test.db?hello=1&world=2&vfs=tvfs {hello 1 world 2 vfs tvfs} + 4 file:test.db?hello=1&world=2&vfs=tvfs2 {} + 5 file:test.db?%68%65%6C%6C%6F=%77%6F%72%6C%64 {hello world} + 6 file:test%00.db?hello%00extra=world%00ex {hello world} + 7 file:test%00.db?hello%00=world%00 {hello world} + 8 file:test%00.db?=world&xyz=abc {xyz abc} + 9 file:test.db?%00hello=world&xyz=abc {xyz abc} + 10 file:test.db?hello=%00world&xyz= {hello {} xyz {}} + 11 file:test.db?=#ravada {} + 12 file:test.db?&&&&&&&&hello=world&&&&&&& {hello world} + + 13 test.db?&&&&&&&&hello=world&&&&&&& {} + 14 http:test.db?hello&world {} +} { + + if {$tcl_platform(platform) == "windows" && $tn>12} { + continue + } + + set ::arglist "" + set DB [sqlite3_open $uri] + do_test 2.$tn.1 { set ::arglist } $kvlist + sqlite3_close $DB + + sqlite3 db xxx.db + set ::arglist "" + execsql { ATTACH $uri AS aux } + do_test 2.$tn.2 { set ::arglist } $kvlist + db close +} +tvfs delete +tvfs2 delete + +#------------------------------------------------------------------------- +# Test that specifying a non-existent VFS raises an error. +# +do_test 3.1 { + list [catch { sqlite3 db "file:test.db?vfs=nosuchvfs" } msg] $msg +} {1 {no such vfs: nosuchvfs}} + +#------------------------------------------------------------------------- +# Test some of the other options (other than "vfs"). +# +foreach {tn mode create_ok write_ok readonly_ok} { + 1 ro 0 0 1 + 2 rw 0 1 0 + 3 rwc 1 1 0 +} { + catch { db close } + forcedelete test.db + + set A(1) {0 {}} + set A(0) {1 {unable to open database file}} + do_test 4.1.$tn.1 { + list [catch {sqlite3 db "file:test.db?mode=$mode"} msg] $msg + } $A($create_ok) + + catch { db close } + forcedelete test.db + sqlite3 db test.db + db eval { CREATE TABLE t1(a, b) } + db close + + set A(1) {0 {}} + set A(0) {1 {attempt to write a readonly database}} + do_test 4.1.$tn.2 { + sqlite3 db "file:test.db?mode=$mode" + catchsql { INSERT INTO t1 VALUES(1, 2) } + } $A($write_ok) + + set A(1) {0 {}} + set A(0) [list 1 "access mode not allowed: $mode"] + do_test 4.1.$tn.3 { + list [catch {sqlite3 db "file:test.db?mode=$mode" -readonly 1} msg] $msg + } $A($readonly_ok) +} + +set orig [sqlite3_enable_shared_cache] +foreach {tn options sc_default is_shared} { + 1 "" 1 1 + 2 "cache=private" 1 0 + 3 "cache=shared" 1 1 + 4 "" 0 0 + 5 "cache=private" 0 0 + 6 "cache=shared" 0 1 +} { + catch { db close } + forcedelete test.db + + sqlite3_enable_shared_cache 1 + sqlite3 db2 test.db + db2 eval {CREATE TABLE t1(a, b)} + + sqlite3_enable_shared_cache $sc_default + sqlite3 db "file:test.db?$options" + db eval {SELECT * FROM t1} + + set A(1) {1 {database table is locked: t1}} + set A(0) {0 {}} + do_test 4.2.$tn { + db2 eval {BEGIN; INSERT INTO t1 VALUES(1, 2);} + catchsql { SELECT * FROM t1 } + } $A($is_shared) + + db2 close +} + +do_test 4.3.1 { + list [catch {sqlite3 db "file:test.db?mode=rc"} msg] $msg +} {1 {no such access mode: rc}} +do_test 4.3.2 { + list [catch {sqlite3 db "file:test.db?cache=public"} msg] $msg +} {1 {no such cache mode: public}} + +#------------------------------------------------------------------------- +# Test that things work if an ATTACHed database uses a different VFS than +# the main database. The important point is that for all operations +# involving the ATTACHed database, the correct versions of the following +# VFS are used for all operations involving the attached database. +# +# xOpen +# xDelete +# xAccess +# xFullPathname +# + +# This block of code creates two VFS - "tvfs1" and "tvfs2". Each time one +# of the above methods is called using "tvfs1", global variable ::T1(X) is +# set, where X is the file-name the method is called on. Calls to the above +# methods using "tvfs2" set entries in the global T2 array. +# +testvfs tvfs1 +tvfs1 filter {xOpen xDelete xAccess xFullPathname} +tvfs1 script tvfs1_callback +proc tvfs1_callback {method filename args} { + set ::T1([file tail $filename]) 1 +} +testvfs tvfs2 +tvfs2 filter {xOpen xDelete xAccess xFullPathname} +tvfs2 script tvfs2_callback +proc tvfs2_callback {method filename args} { + set ::T2([file tail $filename]) 1 +} + +catch {db close} +eval forcedelete [glob test.db*] +do_test 5.1.1 { + sqlite3 db file:test.db1?vfs=tvfs1 + execsql { + ATTACH 'file:test.db2?vfs=tvfs2' AS aux; + PRAGMA main.journal_mode = PERSIST; + PRAGMA aux.journal_mode = PERSIST; + CREATE TABLE t1(a, b); + CREATE TABLE aux.t2(a, b); + PRAGMA main.journal_mode = WAL; + PRAGMA aux.journal_mode = WAL; + INSERT INTO t1 VALUES('x', 'y'); + INSERT INTO t2 VALUES('x', 'y'); + } + lsort [array names ::T1] +} {test.db1 test.db1-journal test.db1-wal} + +do_test 5.1.2 { + lsort [array names ::T2] +} {test.db2 test.db2-journal test.db2-wal} + +db close +tvfs1 delete +tvfs2 delete + +#------------------------------------------------------------------------- +# Check that only "" and "localhost" are acceptable as authorities. +# +catch {db close} +foreach {tn uri res} { + 1 "file://localhost/PWD/test.db" {not an error} + 2 "file:///PWD/test.db" {not an error} + 3 "file:/PWD/test.db" {not an error} + 4 "file://l%6Fcalhost/PWD/test.db" {invalid uri authority: l%6Fcalhost} + 5 "file://lbcalhost/PWD/test.db" {invalid uri authority: lbcalhost} + 6 "file://x/PWD/test.db" {invalid uri authority: x} +} { + + if {$tcl_platform(platform)=="windows"} { + set uri [string map [list PWD [string range [pwd] 3 end]] $uri] + } else { + set uri [string map [list PWD [string range [pwd] 1 end]] $uri] + } + + do_test 6.$tn { + set DB [sqlite3_open $uri] + sqlite3_errmsg $DB + } $res + catch { sqlite3_close $DB } +} + +forcedelete test.db test.db2 +do_test 7.1 { + sqlite3 db test.db + execsql { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + ATTACH 'test.db2' AS aux; + CREATE TABLE aux.t2(a, b); + INSERT INTO t1 VALUES('a', 'b'); + } + db close +} {} +do_test 7.2 { + sqlite3 db file:test.db?mode=ro + execsql { ATTACH 'file:test.db2?mode=rw' AS aux } +} {} +do_execsql_test 7.3 { + INSERT INTO t2 VALUES('c', 'd') +} {} +do_catchsql_test 7.4 { + INSERT INTO t1 VALUES(3, 4) +} {1 {attempt to write a readonly database}} + +finish_test diff --git a/test/wal7.test b/test/wal7.test new file mode 100644 index 0000000000..cfe2d7b8b0 --- /dev/null +++ b/test/wal7.test @@ -0,0 +1,118 @@ +# 2011 May 16 +# +# 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. The +# focus of this file is testing the PRAGMA journal_size_limit when +# in WAL mode. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +ifcapable !wal {finish_test ; return } + +# Case 1: No size limit. Journal can get large. +# +do_test wal7-1.0 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA journal_mode=WAL; + PRAGMA wal_autocheckpoint=50; -- 50 pages + CREATE TABLE t1(x, y UNIQUE); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(zeroblob(200000),4); + CREATE TABLE t2(z); + DELETE FROM t1; + INSERT INTO t2 SELECT x FROM t1; + } + expr {[file size test.db-wal]>50*1100} +} 1 +do_test wal7-1.1 { + db eval {PRAGMA wal_checkpoint} + expr {[file size test.db-wal]>50*1100} +} 1 +do_test wal7-1.2 { + db eval {INSERT INTO t2 VALUES('hi');} + expr {[file size test.db-wal]>50*1100} +} 1 + +# Case 2: Size limit at half the autocheckpoint size. +# +do_test wal7-2.0 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA journal_mode=WAL; + PRAGMA wal_autocheckpoint=50; -- 50 pages + PRAGMA journal_size_limit=25000; + CREATE TABLE t1(x, y UNIQUE); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(zeroblob(200000),4); + CREATE TABLE t2(z); + DELETE FROM t1; + INSERT INTO t2 SELECT x FROM t1; + } + file size test.db-wal +} 25000 + + +# Case 3: Size limit of zero. +# +do_test wal7-3.0 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA journal_mode=WAL; + PRAGMA wal_autocheckpoint=50; -- 50 pages + PRAGMA journal_size_limit=0; + CREATE TABLE t1(x, y UNIQUE); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(zeroblob(200000),4); + CREATE TABLE t2(z); + DELETE FROM t1; + INSERT INTO t2 SELECT x FROM t1; + } + set sz [file size test.db-wal] + expr {$sz>0 && $sz<10000} +} 1 + + +# Case 4: Size limit set before going WAL +# +do_test wal7-4.0 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA journal_size_limit=25000; + PRAGMA journal_mode=WAL; + PRAGMA wal_autocheckpoint=50; -- 50 pages + CREATE TABLE t1(x, y UNIQUE); + INSERT INTO t1 VALUES(1,2); + INSERT INTO t1 VALUES(zeroblob(200000),4); + CREATE TABLE t2(z); + DELETE FROM t1; + INSERT INTO t2 SELECT x FROM t1; + } + set sz [file size test.db-wal] +} 25000 + + + + + +finish_test