Compare commits
57 Commits
winSyscall
...
nx-devkit
| Author | SHA1 | Date | |
|---|---|---|---|
| 76ea46c045 | |||
| 8e33b23089 | |||
| 1bfbdcbe6d | |||
| 03c8582307 | |||
| e7cad43368 | |||
| 09a982e4ce | |||
| 4a7eb4b545 | |||
| 34cf60ec74 | |||
| 8c24a369a5 | |||
| 0699966798 | |||
| e7d9f13d99 | |||
| 38deeb9763 | |||
| 5c531a4aab | |||
| f580860f51 | |||
| e712b5823e | |||
| 78c0eafb35 | |||
| 31b21295b0 | |||
| 2be25bffca | |||
| 0f2ab8db33 | |||
| de60fc2d87 | |||
| 43a6d4bd44 | |||
| 27e69643cf | |||
| c7f946297a | |||
| add995cc25 | |||
| 658dd586ed | |||
| 5b1626aa47 | |||
| e5077c1211 | |||
| 43795e3b0b | |||
| 9797706c04 | |||
| 73795becfe | |||
| 21495ba8a3 | |||
| 070ad6b6fe | |||
| 283829cb20 | |||
| f20fb8c6f3 | |||
| 09419b4bae | |||
| 870c0178f7 | |||
| 8f10acdb5b | |||
| 6f13323118 | |||
| 0c733f67d8 | |||
| bf567db91d | |||
| 3f5b98df17 | |||
| e09b84c558 | |||
| 81ef0f97ef | |||
| f923f82118 | |||
| d515660523 | |||
| cc682cc875 | |||
| 4cb5f436cb | |||
| c90747313e | |||
| 3def2357e6 | |||
| 61a4bd5c6c | |||
| 8225d66be6 | |||
| 32121199be | |||
| e73c91496f | |||
| 3b42abb35b | |||
| 6a8ab6d9cb | |||
| e5c40b18e3 | |||
| 22e21ff4fc |
@@ -49,6 +49,9 @@ BCC = cl.exe
|
||||
#
|
||||
TCC = cl.exe -W3 -DSQLITE_OS_WIN=1 -I. -I$(TOP)\src -fp:precise
|
||||
|
||||
# We always have the _msize function available when using MSVC.
|
||||
TCC = $(TCC) -DHAVE_MALLOC_USABLE_SIZE -Dmalloc_usable_size=_msize
|
||||
|
||||
# The mksqlite3c.tcl and mksqlite3h.tcl scripts will pull in
|
||||
# any extension header files by default. For non-amalgamation
|
||||
# builds, we need to make sure the compiler can find these.
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
/* Define to 1 if you have the `localtime_s' function. */
|
||||
#undef HAVE_LOCALTIME_S
|
||||
|
||||
/* Define to 1 if you have the `malloc_usable_size' function. */
|
||||
#undef HAVE_MALLOC_USABLE_SIZE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ AC_CHECK_HEADERS([sys/types.h stdlib.h stdint.h inttypes.h])
|
||||
#########
|
||||
# Figure out whether or not we have these functions
|
||||
#
|
||||
AC_CHECK_FUNCS([usleep fdatasync localtime_r gmtime_r localtime_s utime])
|
||||
AC_CHECK_FUNCS([usleep fdatasync localtime_r gmtime_r localtime_s utime malloc_usable_size])
|
||||
|
||||
#########
|
||||
# By default, we use the amalgamation (this may be changed below...)
|
||||
|
||||
+3
-1
@@ -2600,7 +2600,9 @@ static int fts3SegReaderCursor(
|
||||
}
|
||||
|
||||
rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
|
||||
iStartBlock, iLeavesEndBlock, iEndBlock, zRoot, nRoot, &pSeg
|
||||
(isPrefix==0 && isScan==0),
|
||||
iStartBlock, iLeavesEndBlock,
|
||||
iEndBlock, zRoot, nRoot, &pSeg
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
|
||||
|
||||
+1
-1
@@ -401,7 +401,7 @@ int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
|
||||
int sqlite3Fts3PendingTermsFlush(Fts3Table *);
|
||||
void sqlite3Fts3PendingTermsClear(Fts3Table *);
|
||||
int sqlite3Fts3Optimize(Fts3Table *);
|
||||
int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
|
||||
int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64,
|
||||
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
|
||||
int sqlite3Fts3SegReaderPending(
|
||||
Fts3Table*,int,const char*,int,int,Fts3SegReader**);
|
||||
|
||||
+28
-8
@@ -110,6 +110,7 @@ struct Fts3DeferredToken {
|
||||
*/
|
||||
struct Fts3SegReader {
|
||||
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
|
||||
int bLookup; /* True for a lookup only */
|
||||
|
||||
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
|
||||
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
|
||||
@@ -1088,6 +1089,18 @@ static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set an Fts3SegReader cursor to point at EOF.
|
||||
*/
|
||||
static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
|
||||
if( !fts3SegReaderIsRootOnly(pSeg) ){
|
||||
sqlite3_free(pSeg->aNode);
|
||||
sqlite3_blob_close(pSeg->pBlob);
|
||||
pSeg->pBlob = 0;
|
||||
}
|
||||
pSeg->aNode = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the iterator passed as the first argument to the next term in the
|
||||
** segment. If successful, SQLITE_OK is returned. If there is no next term,
|
||||
@@ -1127,12 +1140,7 @@ static int fts3SegReaderNext(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( !fts3SegReaderIsRootOnly(pReader) ){
|
||||
sqlite3_free(pReader->aNode);
|
||||
sqlite3_blob_close(pReader->pBlob);
|
||||
pReader->pBlob = 0;
|
||||
}
|
||||
pReader->aNode = 0;
|
||||
fts3SegReaderSetEof(pReader);
|
||||
|
||||
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
||||
** blocks have already been traversed. */
|
||||
@@ -1379,6 +1387,7 @@ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
|
||||
*/
|
||||
int sqlite3Fts3SegReaderNew(
|
||||
int iAge, /* Segment "age". */
|
||||
int bLookup, /* True for a lookup only */
|
||||
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
|
||||
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
|
||||
sqlite3_int64 iEndBlock, /* Final block of segment */
|
||||
@@ -1401,6 +1410,7 @@ int sqlite3Fts3SegReaderNew(
|
||||
}
|
||||
memset(pReader, 0, sizeof(Fts3SegReader));
|
||||
pReader->iIdx = iAge;
|
||||
pReader->bLookup = bLookup;
|
||||
pReader->iStartBlock = iStartLeaf;
|
||||
pReader->iLeafEndBlock = iEndLeaf;
|
||||
pReader->iEndBlock = iEndBlock;
|
||||
@@ -2403,11 +2413,16 @@ static int fts3SegReaderStart(
|
||||
** b-tree leaf nodes contain more than one term.
|
||||
*/
|
||||
for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
|
||||
int res;
|
||||
Fts3SegReader *pSeg = pCsr->apSegment[i];
|
||||
do {
|
||||
int rc = fts3SegReaderNext(p, pSeg, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
|
||||
}while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 );
|
||||
|
||||
if( pSeg->bLookup && res!=0 ){
|
||||
fts3SegReaderSetEof(pSeg);
|
||||
}
|
||||
}
|
||||
fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp);
|
||||
|
||||
@@ -2528,7 +2543,12 @@ int sqlite3Fts3SegReaderStep(
|
||||
** forward. Then sort the list in order of current term again.
|
||||
*/
|
||||
for(i=0; i<pCsr->nAdvance; i++){
|
||||
rc = fts3SegReaderNext(p, apSegment[i], 0);
|
||||
Fts3SegReader *pSeg = apSegment[i];
|
||||
if( pSeg->bLookup ){
|
||||
fts3SegReaderSetEof(pSeg);
|
||||
}else{
|
||||
rc = fts3SegReaderNext(p, pSeg, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
C Make\ssure\sto\sflag\sbenign\smalloc\sfailures\sin\sthe\sWindows\sVFS\sas\ssuch.\s\sExpand\suse\sof\sthe\sDO_OS_MALLOC_TEST\sto\scover\sthe\sVFS\sfunctions\sthat\scan\snow\sreturn\san\sout\sof\smemory\serror.\s\sSupport\san\sexperimental\s--match\soption\sto\sthe\stest\ssuite\sthat\swill\srun\sonly\sthose\stests\smatching\sthe\sspecified\spattern.
|
||||
D 2011-11-12T03:17:40.954
|
||||
C Fix\sthe\smultiplexor\slogging\sso\sthat\sit\sworks\swith\sSQLITE_ENABLE_8_3_NAMES.
|
||||
D 2012-04-04T13:51:22.547
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc dcad80fa69f17d46fe6778ba873fc108ca16298d
|
||||
F Makefile.msc 3bd3641a345d488a9601c0cc7f9d35aeede5d12b
|
||||
F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION bb37c274b503bbe73f00ea4f374eb817cba4b171
|
||||
@@ -21,10 +21,10 @@ F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 405a958bdb3af382a809dccb08a44694923ddd61
|
||||
F config.h.in 31cc8c4943f56e60c4aa4fba929c9d4c70e418b4
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 806c06aef5895860da49600ce098dbe4d5a8435c x
|
||||
F configure.ac 298a759c086e72c013da459c2aec02a104f4224f
|
||||
F configure 194ed7797c67c24ebbeb001fcfc557116fe5eba9 x
|
||||
F configure.ac 75323bdac56fb0e69f6a3fc5b23f24359550b9d9
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 3091574143dd3415669b6745843ff8d011d33549
|
||||
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
|
||||
@@ -63,9 +63,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c bd570b99f1f65b17d587361a421d7f2f28082aa0
|
||||
F ext/fts3/fts3.c 4cf7b8e5bbb6667f5d7818fa0bf064fbbb72b086
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h def7a900f98c5ab5fa4772e922bfa219d5097f05
|
||||
F ext/fts3/fts3Int.h ce958a6fa92a95462853aa3acc0b69bcda39102f
|
||||
F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691
|
||||
F ext/fts3/fts3_expr.c f5df26bddf46a5916b2a5f80c4027996e92b7b15
|
||||
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
@@ -78,7 +78,7 @@ F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894
|
||||
F ext/fts3/fts3_tokenizer.c 9ff7ec66ae3c5c0340fa081958e64f395c71a106
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68
|
||||
F ext/fts3/fts3_write.c c097228bff4d33c6b8a270c9717b9f8339068776
|
||||
F ext/fts3/fts3_write.c cfb96f850c7bc86d901d143d0f8f8a642c910b10
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
@@ -125,10 +125,10 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 4368158da74d4711888e03264105c5c527d76caf
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 60e0151ccc9d1d09a3fd2d0e609689ab8544e93f
|
||||
F src/btree.c 2fdde7d16c80bd4e8a0913038e766c4297818f6f
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
|
||||
F src/build.c 8af67a08a852ff4c63701963cb1ab7166f577814
|
||||
F src/btreeInt.h ea863a819224d3e6845ad1e39954d41558b8cd8b
|
||||
F src/build.c 8915bb6d72ead998f94c2756ea8d143c77709b70
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
|
||||
@@ -138,19 +138,19 @@ F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
|
||||
F src/global.c e230227de13601714b29f9363028514aada5ae2f
|
||||
F src/global.c 107ccaacb4b30895cf3a3a39decf417c804acfa1
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 9794a963911da8157ad0dc39726c9c695b1c4692
|
||||
F src/insert.c 8f283d6734dd837ed7531b26d7622fda70874390
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
F src/loadext.c d0d2022a5a07274d408820b978b9e549189d314f
|
||||
F src/main.c df06f5229b8046f85dde253dfd7fe35ae9e4902e
|
||||
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
|
||||
F src/main.c e7e6985365795ef6c500d05d766222222efbb0ac
|
||||
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
F src/mem1.c 7456e2ca0524609ebc06a9befeda5289d4575ad4
|
||||
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
|
||||
@@ -163,33 +163,33 @@ F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
|
||||
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 28bbdab2170dfce84d86c45456a18eab1d0f99a9
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os.h 3ee45fed34d174eabdafe27c659428a8a1ff973d
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 4fbb91726165e105c1679a2660f49a3f4c376e4f
|
||||
F src/os_win.c a22b88d2c088c09a678a471abafa8d60dbf56803
|
||||
F src/pager.c db33d4bf1e3e019c34c220971cc6c3aa07c30f54
|
||||
F src/pager.h 9f81b08efb06db4ba8be69446e10b005c351373d
|
||||
F src/os_unix.c baad28b27adc563579170b6d765af0b0cc1d98c8
|
||||
F src/os_win.c f954207e8ce20b2b587c44404334aa92ae905961
|
||||
F src/pager.c afadbdf1563265756c3d09f2f77f541d6a1cfa73
|
||||
F src/pager.h 5cd760857707529b403837d813d86b68938d6183
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 24f5e85a78514584b46190260ba7ab0a66312197
|
||||
F src/pragma.c da8ef96b3eec351e81e0061c39810e548bcc96d7
|
||||
F src/prepare.c e64261559a3187698a3e7e6c8b001a4f4f98dab4
|
||||
F src/pcache.c 1fdd77978c1525d1ca4b9ef48eb80abca710cb4c
|
||||
F src/pcache.h b1d8775a9bddf44e65edb0d20bfc57a4982f840f
|
||||
F src/pcache1.c 9d735349ac87ef08076c6b1230f04cd83b15c6da
|
||||
F src/pragma.c dd66f21fafe7be40e1a48ad4195764cc191cf583
|
||||
F src/prepare.c ec4989f7f480544bdc4192fe663470d2a2d7d61e
|
||||
F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6
|
||||
F src/shell.c 6d2ad7f80adc9c8c3195412879af36eb3196c1b6
|
||||
F src/sqlite.h.in b7a4e8d428e467d820cbb4c1d275fdda88b4d7ab
|
||||
F src/shell.c 92e96bf5e465d63c55c5fe7fca38228c67ce7682
|
||||
F src/sqlite.h.in 84cd7be33f5bf39329e018f93eb34b4a345c9c23
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h b0b6df8f7fe739e3cd718debb60f58853666d13e
|
||||
F src/sqliteInt.h f412e020e1009163c74be56eaac1bf7f6c0a4515
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c de581e2e71f5e7f98366156afad83b4742ac6fe0
|
||||
F src/test1.c 0f41b7c67719207a5de24b009e172c4dcf189827
|
||||
F src/test1.c d019682c4480d612e4eca73412011a120e1468db
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
|
||||
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
@@ -202,57 +202,57 @@ 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 bc8826296a7b3a86eeaba1ac2af5551d1c20c35b
|
||||
F src/test_config.c a036a69b550ebc477ab9ca2b37269201f888436e
|
||||
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
|
||||
F src/test_fuzzer.c f884f6f32e8513d34248d6e1ac8a32047fead254
|
||||
F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a
|
||||
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
|
||||
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
F src/test_journal.c 03313c693cca72959dcaaf79f8d76f21c01e19ff
|
||||
F src/test_journal.c 2c06e4be6584d51b935dc8b353980a9388de62ef
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 8d416f29ad8573f32601f6056c9d2b17472e9ad5
|
||||
F src/test_multiplex.c 3fc368022c46fe44ec22c5e1ed727223a54a6a1d
|
||||
F src/test_multiplex.c 42967feac8203afd180e2faa6fd1efd4191f85e2
|
||||
F src/test_multiplex.h e99c571bc4968b7a9363b661481f3934bfead61d
|
||||
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||
F src/test_osinst.c 62b0b8ef21ce754cc94e17bb42377ed8795dba32
|
||||
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
|
||||
F src/test_quota.c a391c866217e92986c6f523f05b08aa6956c8419
|
||||
F src/test_osinst.c 6abf0a37ce831120c4ef1b913afdd813e7ac1a73
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c ec7d1056936f69be953c343bcb480305ce8928f3
|
||||
F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
|
||||
F src/test_stat.c 69de4361c7a69fc1136d31ab7144408cd00805c7
|
||||
F src/test_stat.c 80271ad7d776a79babe0e025bb3a1bfcd3a3cfb1
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 35022393dd54d147b998b6b7f7e945b01114d666
|
||||
F src/test_vfs.c 27b7d9de40630f603b9e2cf9ef2a7c81d31c4515
|
||||
F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d
|
||||
F src/test_vfstrace.c 065c7270a614254b2c68fbc7ba8d1fb1d5cbc823
|
||||
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
|
||||
F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
|
||||
F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 01238e2b0f24a14779181dbf991fe02620a80e31
|
||||
F src/util.c 343508d359df65685b62e63964a40e7af4cfbe05
|
||||
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
|
||||
F src/vdbe.c 326994a64a9a08853122200dc9f62cb96b8f0831
|
||||
F src/vdbe.c a7ab9993ec5a4d9479dc99671faec061fbf9b889
|
||||
F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
|
||||
F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176
|
||||
F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546
|
||||
F src/vdbeaux.c a950e34449a508d48d90475acc287943a4094f3a
|
||||
F src/vdbeaux.c 52ebf2a62d6b66ded536d0a2745f2236771097c7
|
||||
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
|
||||
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
|
||||
F src/wal.c 9658df8d404b82e6b2d40fd05944463214e2d935
|
||||
F src/wal.c 5fe1ba55b8fab9d3936bc9093af61ab9f1c580a1
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 7c85f4c93058e27100d404f0777aaeb0d1b296ae
|
||||
F src/where.c f73752ca85c0ed221753fda98aeaf6b9d4616e0e
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@@ -274,7 +274,7 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test 0dd8701bd588bf6e70c2557a22ae3f22b2567b4c
|
||||
F test/attach.test 0e6f8de2589f11a5f474ef57fe5af2877e61c0e8
|
||||
F test/attach.test 0d112b7713611fdf0340260192749737135fda5f
|
||||
F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
|
||||
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
@@ -296,6 +296,7 @@ F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
|
||||
F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103
|
||||
F test/bigfile2.test f8e83eca9abef60692a34255a2ebcb96aff897fc
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
@@ -361,7 +362,7 @@ F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/date.test a18a2ce81add84b17b06559e82ad7bb91bc6ddff
|
||||
F test/dbstatus.test 9eb484ba837c6f3f9bbcaecc29e6060a8c3ba6d2
|
||||
F test/dbstatus.test 179575499759241bf92ca2fb86bd3ccc8a562aac
|
||||
F test/dbstatus2.test dc57b0d9610851c0ff58a8e1b5b191678398b72a
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
|
||||
@@ -462,7 +463,7 @@ F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
|
||||
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
|
||||
F test/fts3ao.test e7b80272efcced57d1d087a9da5c690dd7c21fd9
|
||||
F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3
|
||||
F test/fts3auto.test c1a30b37002b7c764a96937fbc71065b73d69494
|
||||
F test/fts3auto.test 868a2afea308d7d8b45ef29fcf022644a9e6d662
|
||||
F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
|
||||
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
||||
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
||||
@@ -485,6 +486,7 @@ F test/fts3malloc.test b86ea33db9e8c58c0c2f8027a9fcadaf6a1568be
|
||||
F test/fts3matchinfo.test 6507fe1c342e542300d65ea637d4110eccf894e6
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1
|
||||
F test/fts3prefix2.test 477ca96e67f60745b7ac931cfa6e9b080c562da5
|
||||
F test/fts3query.test ef79d31fdb355d094baec1c1b24b60439a1fb8a2
|
||||
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
|
||||
F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2
|
||||
@@ -592,7 +594,7 @@ F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 16ce163ac1ace3d71bf0eaa6a821ed153addd91f
|
||||
F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f
|
||||
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
|
||||
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
|
||||
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
|
||||
@@ -605,7 +607,9 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test eafaa41b9133d7a2ded4641bbe5f340731d35a52
|
||||
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
|
||||
F test/multiplex.test 9df8bf738b3b97c718fceb3fadb30900ba494418
|
||||
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
|
||||
F test/multiplex2.test 896ff138d27688b68c894b8166606454ce915793
|
||||
F test/multiplex3.test e17b73e904dbd789de37192b6b94424e6f847bc3
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
@@ -627,13 +631,13 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/permutations.test 522823b47238cb1754198f80817fe9f9158ede55
|
||||
F test/pragma.test 1ea0c85be853135bb7468e6eed48ee12b04794d4
|
||||
F test/pragma.test 7fa35e53085812dac94c2bfcbb02c2a4ad35df5e
|
||||
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota.test 1c59a396e8f7b5d8466fa74b59f2aeb778d74f7a
|
||||
F test/quota.test e09a01ec974e04a2c4f1c7615005722725b5e131
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
|
||||
@@ -678,6 +682,7 @@ F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
|
||||
F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/shrink.test 28165922bfea5c003c51a2d02bce69c4141ef013
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53
|
||||
@@ -893,7 +898,7 @@ F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test e11da8d5ea8a38a247339455098357e9adf63d76
|
||||
F test/wal.test c743be787e60c1242fa6cdf73b410e64b2977e25
|
||||
F test/wal2.test ad6412596815f553cd30f271d291ab003092bc7e
|
||||
F test/wal3.test 18da4e65c30c43c646ad40e145e9a074e4062fc9
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
@@ -927,6 +932,7 @@ F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test bed66dcfc69a54a99661c0c9906189cb5e58f4e2
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
@@ -974,7 +980,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P 8966ec1797be63d1305628d459bdad5be08cf3ca
|
||||
R b05037fbfa7e2180ed81bf446e380e48
|
||||
U mistachkin
|
||||
Z 1660438f613633eeb0e91d69e2a176bd
|
||||
P e6806f0dc6a06796700d805952f95e2cc18f0ea3
|
||||
R 36de029057c30e17d2fa1fff1aac580d
|
||||
U drh
|
||||
Z 7a6d88ce3643ba76bc132c1e4c6b20fc
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
76dec8aa9dbbc39e0a7c3b358b58ce7f7a477a2b
|
||||
627eff32a23ec676f7e87f6904981b3804e0e1f0
|
||||
+17
-7
@@ -859,7 +859,7 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||
** This routine works only for pages that do not contain overflow cells.
|
||||
*/
|
||||
#define findCell(P,I) \
|
||||
((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
|
||||
((P)->aData + ((P)->maskPage & get2byte(&(P)->aCellIdx[2*(I)])))
|
||||
#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
|
||||
|
||||
|
||||
@@ -1409,6 +1409,8 @@ static int btreeInitPage(MemPage *pPage){
|
||||
pPage->nOverflow = 0;
|
||||
usableSize = pBt->usableSize;
|
||||
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
|
||||
pPage->aDataEnd = &data[usableSize];
|
||||
pPage->aCellIdx = &data[cellOffset];
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
@@ -1512,6 +1514,8 @@ static void zeroPage(MemPage *pPage, int flags){
|
||||
decodeFlags(pPage, flags);
|
||||
pPage->hdrOffset = hdr;
|
||||
pPage->cellOffset = first;
|
||||
pPage->aDataEnd = &data[pBt->usableSize];
|
||||
pPage->aCellIdx = &data[first];
|
||||
pPage->nOverflow = 0;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
@@ -1773,7 +1777,7 @@ int sqlite3BtreeOpen(
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc ){
|
||||
sqlite3_free(zFullPathname);
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
@@ -3975,7 +3979,7 @@ static int accessPayload(
|
||||
u8 aSave[4];
|
||||
u8 *aWrite = &pBuf[-4];
|
||||
memcpy(aSave, aWrite, 4);
|
||||
rc = sqlite3OsRead(fd, aWrite, a+4, pBt->pageSize * (nextPage-1));
|
||||
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
|
||||
nextPage = get4byte(aWrite);
|
||||
memcpy(aWrite, aSave, 4);
|
||||
}else
|
||||
@@ -4555,16 +4559,22 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** 2 bytes of the cell.
|
||||
*/
|
||||
int nCell = pCell[0];
|
||||
if( !(nCell & 0x80) && nCell<=pPage->maxLocal ){
|
||||
if( !(nCell & 0x80)
|
||||
&& nCell<=pPage->maxLocal
|
||||
&& (pCell+nCell+1)<=pPage->aDataEnd
|
||||
){
|
||||
/* This branch runs if the record-size field of the cell is a
|
||||
** single byte varint and the record fits entirely on the main
|
||||
** b-tree page. */
|
||||
testcase( pCell+nCell+1==pPage->aDataEnd );
|
||||
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
||||
}else if( !(pCell[1] & 0x80)
|
||||
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
||||
&& (pCell+nCell+2)<=pPage->aDataEnd
|
||||
){
|
||||
/* The record-size field is a 2 byte varint and the record
|
||||
** fits entirely on the main b-tree page. */
|
||||
testcase( pCell+nCell+2==pPage->aDataEnd );
|
||||
c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
||||
}else{
|
||||
/* The record flows over onto one or more overflow pages. In
|
||||
@@ -5459,7 +5469,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
data = pPage->aData;
|
||||
ptr = &data[pPage->cellOffset + 2*idx];
|
||||
ptr = &pPage->aCellIdx[2*idx];
|
||||
pc = get2byte(ptr);
|
||||
hdr = pPage->hdrOffset;
|
||||
testcase( pc==get2byte(&data[hdr+5]) );
|
||||
@@ -5473,7 +5483,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
*pRC = rc;
|
||||
return;
|
||||
}
|
||||
endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2];
|
||||
endPtr = &pPage->aCellIdx[2*pPage->nCell - 2];
|
||||
assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
|
||||
while( ptr<endPtr ){
|
||||
*(u16*)ptr = *(u16*)&ptr[2];
|
||||
@@ -5615,7 +5625,7 @@ static void assemblePage(
|
||||
assert( pPage->nCell==0 );
|
||||
assert( get2byteNotZero(&data[hdr+5])==nUsable );
|
||||
|
||||
pCellptr = &data[pPage->cellOffset + nCell*2];
|
||||
pCellptr = &pPage->aCellIdx[nCell*2];
|
||||
cellbody = nUsable;
|
||||
for(i=nCell-1; i>=0; i--){
|
||||
u16 sz = aSize[i];
|
||||
|
||||
@@ -289,6 +289,8 @@ struct MemPage {
|
||||
} aOvfl[5];
|
||||
BtShared *pBt; /* Pointer to BtShared that this page is part of */
|
||||
u8 *aData; /* Pointer to disk image of the page data */
|
||||
u8 *aDataEnd; /* One byte past the end of usable data */
|
||||
u8 *aCellIdx; /* The cell index area */
|
||||
DbPage *pDbPage; /* Pager page handle */
|
||||
Pgno pgno; /* Page number for this page */
|
||||
};
|
||||
|
||||
+11
-8
@@ -2661,19 +2661,22 @@ Index *sqlite3CreateIndex(
|
||||
nName = sqlite3Strlen30(zName);
|
||||
nCol = pList->nExpr;
|
||||
pIndex = sqlite3DbMallocZero(db,
|
||||
sizeof(Index) + /* Index structure */
|
||||
sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */
|
||||
sizeof(int)*nCol + /* Index.aiColumn */
|
||||
sizeof(char *)*nCol + /* Index.azColl */
|
||||
sizeof(u8)*nCol + /* Index.aSortOrder */
|
||||
nName + 1 + /* Index.zName */
|
||||
nExtra /* Collation sequence names */
|
||||
sizeof(Index) + /* Index structure */
|
||||
ROUND8(sizeof(tRowcnt)*(nCol+1)) + /* Index.aiRowEst */
|
||||
sizeof(char *)*nCol + /* Index.azColl */
|
||||
sizeof(int)*nCol + /* Index.aiColumn */
|
||||
sizeof(u8)*nCol + /* Index.aSortOrder */
|
||||
nName + 1 + /* Index.zName */
|
||||
nExtra /* Collation sequence names */
|
||||
);
|
||||
if( db->mallocFailed ){
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->aiRowEst = (tRowcnt*)(&pIndex[1]);
|
||||
pIndex->azColl = (char**)(&pIndex->aiRowEst[nCol+1]);
|
||||
pIndex->azColl = (char**)
|
||||
((char*)pIndex->aiRowEst + ROUND8(sizeof(tRowcnt)*nCol+1));
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
|
||||
pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
|
||||
pIndex->aSortOrder = (u8 *)(&pIndex->aiColumn[nCol]);
|
||||
pIndex->zName = (char *)(&pIndex->aSortOrder[nCol]);
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
500, /* nLookaside */
|
||||
{0,0,0,0,0,0,0,0}, /* m */
|
||||
{0,0,0,0,0,0,0,0,0}, /* mutex */
|
||||
{0,0,0,0,0,0,0,0,0,0,0}, /* pcache */
|
||||
{0,0,0,0,0,0,0,0,0,0,0}, /* pcache2 */
|
||||
(void*)0, /* pHeap */
|
||||
0, /* nHeap */
|
||||
0, 0, /* mnHeap, mxHeap */
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ void sqlite3OpenTable(
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
**
|
||||
** An extra 'b' is appended to the end of the string to cover the
|
||||
** An extra 'd' is appended to the end of the string to cover the
|
||||
** rowid that appears as the last column in every index.
|
||||
**
|
||||
** Memory for the buffer containing the column index affinity string
|
||||
@@ -75,7 +75,7 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
for(n=0; n<pIdx->nColumn; n++){
|
||||
pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
|
||||
}
|
||||
pIdx->zColAff[n++] = SQLITE_AFF_NONE;
|
||||
pIdx->zColAff[n++] = SQLITE_AFF_INTEGER;
|
||||
pIdx->zColAff[n] = 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -625,6 +625,7 @@ void sqlite3_reset_auto_extension(void){
|
||||
void sqlite3AutoLoadExtensions(sqlite3 *db){
|
||||
int i;
|
||||
int go = 1;
|
||||
int rc;
|
||||
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
|
||||
wsdAutoextInit;
|
||||
@@ -647,8 +648,8 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
zErrmsg = 0;
|
||||
if( xInit && xInit(db, &zErrmsg, &sqlite3Apis) ){
|
||||
sqlite3Error(db, SQLITE_ERROR,
|
||||
if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
|
||||
sqlite3Error(db, rc,
|
||||
"automatic extension loading failed: %s", zErrmsg);
|
||||
go = 0;
|
||||
}
|
||||
|
||||
+62
-23
@@ -239,8 +239,8 @@ int sqlite3_initialize(void){
|
||||
*/
|
||||
#ifdef SQLITE_EXTRA_INIT
|
||||
if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){
|
||||
int SQLITE_EXTRA_INIT(void);
|
||||
rc = SQLITE_EXTRA_INIT();
|
||||
int SQLITE_EXTRA_INIT(const char*);
|
||||
rc = SQLITE_EXTRA_INIT(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -257,6 +257,10 @@ int sqlite3_initialize(void){
|
||||
*/
|
||||
int sqlite3_shutdown(void){
|
||||
if( sqlite3GlobalConfig.isInit ){
|
||||
#ifdef SQLITE_EXTRA_SHUTDOWN
|
||||
void SQLITE_EXTRA_SHUTDOWN(void);
|
||||
SQLITE_EXTRA_SHUTDOWN();
|
||||
#endif
|
||||
sqlite3_os_end();
|
||||
sqlite3_reset_auto_extension();
|
||||
sqlite3GlobalConfig.isInit = 0;
|
||||
@@ -365,16 +369,25 @@ int sqlite3_config(int op, ...){
|
||||
}
|
||||
|
||||
case SQLITE_CONFIG_PCACHE: {
|
||||
/* Specify an alternative page cache implementation */
|
||||
sqlite3GlobalConfig.pcache = *va_arg(ap, sqlite3_pcache_methods*);
|
||||
/* no-op */
|
||||
break;
|
||||
}
|
||||
case SQLITE_CONFIG_GETPCACHE: {
|
||||
/* now an error */
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_CONFIG_GETPCACHE: {
|
||||
if( sqlite3GlobalConfig.pcache.xInit==0 ){
|
||||
case SQLITE_CONFIG_PCACHE2: {
|
||||
/* Specify an alternative page cache implementation */
|
||||
sqlite3GlobalConfig.pcache2 = *va_arg(ap, sqlite3_pcache_methods2*);
|
||||
break;
|
||||
}
|
||||
case SQLITE_CONFIG_GETPCACHE2: {
|
||||
if( sqlite3GlobalConfig.pcache2.xInit==0 ){
|
||||
sqlite3PCacheSetDefault();
|
||||
}
|
||||
*va_arg(ap, sqlite3_pcache_methods*) = sqlite3GlobalConfig.pcache;
|
||||
*va_arg(ap, sqlite3_pcache_methods2*) = sqlite3GlobalConfig.pcache2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -473,21 +486,21 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
||||
if( db->lookaside.bMalloced ){
|
||||
sqlite3_free(db->lookaside.pStart);
|
||||
}
|
||||
/* The size of a lookaside slot needs to be larger than a pointer
|
||||
** to be useful.
|
||||
/* The size of a lookaside slot after ROUNDDOWN8 needs to be larger
|
||||
** than a pointer to be useful.
|
||||
*/
|
||||
sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
|
||||
if( sz<=(int)sizeof(LookasideSlot*) ) sz = 0;
|
||||
if( cnt<0 ) cnt = 0;
|
||||
if( sz==0 || cnt==0 ){
|
||||
sz = 0;
|
||||
pStart = 0;
|
||||
}else if( pBuf==0 ){
|
||||
sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
|
||||
sqlite3BeginBenignMalloc();
|
||||
pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */
|
||||
sqlite3EndBenignMalloc();
|
||||
if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
|
||||
}else{
|
||||
sz = ROUNDDOWN8(sz); /* IMP: R-33038-09382 */
|
||||
pStart = pBuf;
|
||||
}
|
||||
db->lookaside.pStart = pStart;
|
||||
@@ -521,6 +534,24 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
|
||||
return db->mutex;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free up as much memory as we can from the given database
|
||||
** connection.
|
||||
*/
|
||||
int sqlite3_db_release_memory(sqlite3 *db){
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
Pager *pPager = sqlite3BtreePager(pBt);
|
||||
sqlite3PagerShrink(pPager);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Configuration settings for an individual database connection
|
||||
*/
|
||||
@@ -2219,10 +2250,13 @@ static int openDatabase(
|
||||
/* Load automatic extensions - extensions that have been registered
|
||||
** using the sqlite3_automatic_extension() API.
|
||||
*/
|
||||
sqlite3AutoLoadExtensions(db);
|
||||
rc = sqlite3_errcode(db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto opendb_out;
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3AutoLoadExtensions(db);
|
||||
rc = sqlite3_errcode(db);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto opendb_out;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_FTS1
|
||||
@@ -2889,15 +2923,6 @@ int sqlite3_test_control(int op, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_PGHDRSZ)
|
||||
**
|
||||
** Return the size of a pcache header in bytes.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_PGHDRSZ: {
|
||||
rc = sizeof(PgHdr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
|
||||
**
|
||||
** Pass pFree into sqlite3ScratchFree().
|
||||
@@ -2952,3 +2977,17 @@ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the filename of the database associated with a database
|
||||
** connection.
|
||||
*/
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt && sqlite3StrICmp(zDbName, db->aDb[i].zName)==0 ){
|
||||
return sqlite3BtreeGetFilename(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+32
@@ -26,6 +26,10 @@
|
||||
*/
|
||||
#ifdef SQLITE_SYSTEM_MALLOC
|
||||
|
||||
#ifdef HAVE_MALLOC_USABLE_SIZE
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Like malloc(), but remember the size of the allocation
|
||||
** so that we can find it later using sqlite3MemSize().
|
||||
@@ -35,6 +39,14 @@
|
||||
** routines.
|
||||
*/
|
||||
static void *sqlite3MemMalloc(int nByte){
|
||||
#ifdef HAVE_MALLOC_USABLE_SIZE
|
||||
void *p = malloc( nByte );
|
||||
if( p==0 ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
|
||||
}
|
||||
return p;
|
||||
#else
|
||||
sqlite3_int64 *p;
|
||||
assert( nByte>0 );
|
||||
nByte = ROUND8(nByte);
|
||||
@@ -47,6 +59,7 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
|
||||
}
|
||||
return (void *)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -58,10 +71,14 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
** by higher-level routines.
|
||||
*/
|
||||
static void sqlite3MemFree(void *pPrior){
|
||||
#if HAVE_MALLOC_USABLE_SIZE
|
||||
free(pPrior);
|
||||
#else
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
|
||||
assert( pPrior!=0 );
|
||||
p--;
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -69,11 +86,15 @@ static void sqlite3MemFree(void *pPrior){
|
||||
** or xRealloc().
|
||||
*/
|
||||
static int sqlite3MemSize(void *pPrior){
|
||||
#if HAVE_MALLOC_USABLE_SIZE
|
||||
return pPrior ? (int)malloc_usable_size(pPrior) : 0;
|
||||
#else
|
||||
sqlite3_int64 *p;
|
||||
if( pPrior==0 ) return 0;
|
||||
p = (sqlite3_int64*)pPrior;
|
||||
p--;
|
||||
return (int)p[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -87,6 +108,16 @@ static int sqlite3MemSize(void *pPrior){
|
||||
** routines and redirected to xFree.
|
||||
*/
|
||||
static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
#if HAVE_MALLOC_USABLE_SIZE
|
||||
void *p = realloc(pPrior, nByte);
|
||||
if( p==0 ){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
sqlite3_log(SQLITE_NOMEM,
|
||||
"failed memory resize %u to %u bytes",
|
||||
malloc_usable_size(pPrior), nByte);
|
||||
}
|
||||
return p;
|
||||
#else
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
|
||||
assert( pPrior!=0 && nByte>0 );
|
||||
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
|
||||
@@ -102,6 +133,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
sqlite3MemSize(pPrior), nByte);
|
||||
}
|
||||
return (void*)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -100,6 +100,37 @@
|
||||
# define SQLITE_TEMPNAME_SIZE 200
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with Windows NT.
|
||||
**
|
||||
** We ought to be able to determine if we are compiling for win98 or winNT
|
||||
** using the _WIN32_WINNT macro as follows:
|
||||
**
|
||||
** #if defined(_WIN32_WINNT)
|
||||
** # define SQLITE_OS_WINNT 1
|
||||
** #else
|
||||
** # define SQLITE_OS_WINNT 0
|
||||
** #endif
|
||||
**
|
||||
** However, vs2005 does not set _WIN32_WINNT by default, as it ought to,
|
||||
** so the above test does not work. We'll just assume that everything is
|
||||
** winNT unless the programmer explicitly says otherwise by setting
|
||||
** SQLITE_OS_WINNT to 0.
|
||||
*/
|
||||
#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
|
||||
# define SQLITE_OS_WINNT 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Determine if we are dealing with WindowsCE - which has a much
|
||||
** reduced API.
|
||||
*/
|
||||
#if defined(_WIN32_WCE)
|
||||
# define SQLITE_OS_WINCE 1
|
||||
#else
|
||||
# define SQLITE_OS_WINCE 0
|
||||
#endif
|
||||
|
||||
/* If the SET_FULLSYNC macro is not defined above, then make it
|
||||
** a no-op
|
||||
*/
|
||||
|
||||
+7
-1
@@ -206,6 +206,7 @@ struct UnixUnusedFd {
|
||||
typedef struct unixFile unixFile;
|
||||
struct unixFile {
|
||||
sqlite3_io_methods const *pMethod; /* Always the first entry */
|
||||
sqlite3_vfs *pVfs; /* The VFS that created this unixFile */
|
||||
unixInodeInfo *pInode; /* Info about locks on this inode */
|
||||
int h; /* The file descriptor */
|
||||
unsigned char eFileLock; /* The type of lock held on this fd */
|
||||
@@ -3533,6 +3534,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_VFSNAME: {
|
||||
*(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@@ -4560,6 +4565,7 @@ static int fillInUnixFile(
|
||||
|
||||
OSTRACE(("OPEN %-3d %s\n", h, zFilename));
|
||||
pNew->h = h;
|
||||
pNew->pVfs = pVfs;
|
||||
pNew->zPath = zFilename;
|
||||
if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
|
||||
pNew->ctrlFlags = UNIXFILE_EXCL;
|
||||
@@ -4899,7 +4905,7 @@ static int findCreateFileMode(
|
||||
*/
|
||||
nDb = sqlite3Strlen30(zPath) - 1;
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
while( nDb>0 && !sqlite3Isalnum(zPath[nDb]) ) nDb--;
|
||||
while( nDb>0 && sqlite3Isalnum(zPath[nDb]) ) nDb--;
|
||||
if( nDb==0 || zPath[nDb]!='-' ) return SQLITE_OK;
|
||||
#else
|
||||
while( zPath[nDb]!='-' ){
|
||||
|
||||
+5
-1
@@ -181,7 +181,7 @@ static int sqlite3_os_type = 0;
|
||||
# define SQLITE_WIN32_HAS_ANSI
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_WINCE || defined(_WIN32_WINNT)
|
||||
#if SQLITE_OS_WINCE || SQLITE_OS_WINNT
|
||||
# define SQLITE_WIN32_HAS_WIDE
|
||||
#endif
|
||||
|
||||
@@ -2145,6 +2145,10 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_VFSNAME: {
|
||||
*(char**)pArg = sqlite3_mprintf("win32");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: {
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+13
-6
@@ -2485,7 +2485,7 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
|
||||
if( rc==SQLITE_OK && currentSize!=newSize ){
|
||||
if( currentSize>newSize ){
|
||||
rc = sqlite3OsTruncate(pPager->fd, newSize);
|
||||
}else{
|
||||
}else if( (currentSize+szPage)<=newSize ){
|
||||
char *pTmp = pPager->pTmpSpace;
|
||||
memset(pTmp, 0, szPage);
|
||||
testcase( (newSize-szPage) < currentSize );
|
||||
@@ -3074,7 +3074,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
nPage = (Pgno)(n / pPager->pageSize);
|
||||
nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
|
||||
if( nPage==0 && n>0 ){
|
||||
nPage = 1;
|
||||
}
|
||||
@@ -3267,13 +3267,13 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
|
||||
*/
|
||||
if( pSavepoint ){
|
||||
u32 ii; /* Loop counter */
|
||||
i64 offset = pSavepoint->iSubRec*(4+pPager->pageSize);
|
||||
i64 offset = (i64)pSavepoint->iSubRec*(4+pPager->pageSize);
|
||||
|
||||
if( pagerUseWal(pPager) ){
|
||||
rc = sqlite3WalSavepointUndo(pPager->pWal, pSavepoint->aWalData);
|
||||
}
|
||||
for(ii=pSavepoint->iSubRec; rc==SQLITE_OK && ii<pPager->nSubRec; ii++){
|
||||
assert( offset==ii*(4+pPager->pageSize) );
|
||||
assert( offset==(i64)ii*(4+pPager->pageSize) );
|
||||
rc = pager_playback_one_page(pPager, &offset, pDone, 0, 1);
|
||||
}
|
||||
assert( rc!=SQLITE_DONE );
|
||||
@@ -3294,6 +3294,13 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
|
||||
sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free as much memory as possible from the pager.
|
||||
*/
|
||||
void sqlite3PagerShrink(Pager *pPager){
|
||||
sqlite3PcacheShrink(pPager->pPCache);
|
||||
}
|
||||
|
||||
/*
|
||||
** Adjust the robustness of the database to damage due to OS crashes
|
||||
** or power failures by changing the number of syncs()s when writing
|
||||
@@ -3497,7 +3504,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pager_reset(pPager);
|
||||
pPager->dbSize = (Pgno)(nByte/pageSize);
|
||||
pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
|
||||
pPager->pageSize = pageSize;
|
||||
sqlite3PageFree(pPager->pTmpSpace);
|
||||
pPager->pTmpSpace = pNew;
|
||||
@@ -4114,7 +4121,7 @@ static int subjournalPage(PgHdr *pPg){
|
||||
** write the journal record into the file. */
|
||||
if( rc==SQLITE_OK ){
|
||||
void *pData = pPg->pData;
|
||||
i64 offset = pPager->nSubRec*(4+pPager->pageSize);
|
||||
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
|
||||
char *pData2;
|
||||
|
||||
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
|
||||
|
||||
@@ -103,6 +103,7 @@ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
|
||||
int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
||||
int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
void sqlite3PagerShrink(Pager*);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
|
||||
int sqlite3PagerLockingMode(Pager *, int);
|
||||
int sqlite3PagerSetJournalMode(Pager *, int);
|
||||
|
||||
+66
-41
@@ -20,7 +20,7 @@ struct PCache {
|
||||
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
|
||||
PgHdr *pSynced; /* Last synced page in dirty page list */
|
||||
int nRef; /* Number of referenced pages */
|
||||
int nMax; /* Configured cache size */
|
||||
int szCache; /* Configured cache size */
|
||||
int szPage; /* Size of every page in this cache */
|
||||
int szExtra; /* Size of extra space for each page */
|
||||
int bPurgeable; /* True if pages are on backing store */
|
||||
@@ -131,7 +131,7 @@ static void pcacheUnpin(PgHdr *p){
|
||||
if( p->pgno==1 ){
|
||||
pCache->pPage1 = 0;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 0);
|
||||
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,18 +141,18 @@ static void pcacheUnpin(PgHdr *p){
|
||||
** functions are threadsafe.
|
||||
*/
|
||||
int sqlite3PcacheInitialize(void){
|
||||
if( sqlite3GlobalConfig.pcache.xInit==0 ){
|
||||
if( sqlite3GlobalConfig.pcache2.xInit==0 ){
|
||||
/* IMPLEMENTATION-OF: R-26801-64137 If the xInit() method is NULL, then the
|
||||
** built-in default page cache is used instead of the application defined
|
||||
** page cache. */
|
||||
sqlite3PCacheSetDefault();
|
||||
}
|
||||
return sqlite3GlobalConfig.pcache.xInit(sqlite3GlobalConfig.pcache.pArg);
|
||||
return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
|
||||
}
|
||||
void sqlite3PcacheShutdown(void){
|
||||
if( sqlite3GlobalConfig.pcache.xShutdown ){
|
||||
if( sqlite3GlobalConfig.pcache2.xShutdown ){
|
||||
/* IMPLEMENTATION-OF: R-26000-56589 The xShutdown() method may be NULL. */
|
||||
sqlite3GlobalConfig.pcache.xShutdown(sqlite3GlobalConfig.pcache.pArg);
|
||||
sqlite3GlobalConfig.pcache2.xShutdown(sqlite3GlobalConfig.pcache2.pArg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ void sqlite3PcacheOpen(
|
||||
p->bPurgeable = bPurgeable;
|
||||
p->xStress = xStress;
|
||||
p->pStress = pStress;
|
||||
p->nMax = 100;
|
||||
p->szCache = 100;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,13 +191,24 @@ void sqlite3PcacheOpen(
|
||||
void sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
|
||||
assert( pCache->nRef==0 && pCache->pDirty==0 );
|
||||
if( pCache->pCache ){
|
||||
sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
|
||||
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
|
||||
pCache->pCache = 0;
|
||||
pCache->pPage1 = 0;
|
||||
}
|
||||
pCache->szPage = szPage;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the number of pages of cache requested.
|
||||
*/
|
||||
static int numberOfCachePages(PCache *p){
|
||||
if( p->szCache>=0 ){
|
||||
return p->szCache;
|
||||
}else{
|
||||
return (-1024*p->szCache)/(p->szPage+p->szExtra);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to obtain a page from the cache.
|
||||
*/
|
||||
@@ -207,7 +218,8 @@ int sqlite3PcacheFetch(
|
||||
int createFlag, /* If true, create page if it does not exist already */
|
||||
PgHdr **ppPage /* Write the page here */
|
||||
){
|
||||
PgHdr *pPage = 0;
|
||||
sqlite3_pcache_page *pPage = 0;
|
||||
PgHdr *pPgHdr = 0;
|
||||
int eCreate;
|
||||
|
||||
assert( pCache!=0 );
|
||||
@@ -219,19 +231,19 @@ int sqlite3PcacheFetch(
|
||||
*/
|
||||
if( !pCache->pCache && createFlag ){
|
||||
sqlite3_pcache *p;
|
||||
int nByte;
|
||||
nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr);
|
||||
p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable);
|
||||
p = sqlite3GlobalConfig.pcache2.xCreate(
|
||||
pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
||||
);
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax);
|
||||
sqlite3GlobalConfig.pcache2.xCachesize(p, numberOfCachePages(pCache));
|
||||
pCache->pCache = p;
|
||||
}
|
||||
|
||||
eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
|
||||
if( pCache->pCache ){
|
||||
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate);
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
}
|
||||
|
||||
if( !pPage && eCreate==1 ){
|
||||
@@ -258,7 +270,7 @@ int sqlite3PcacheFetch(
|
||||
"spill page %d making room for %d - cache used: %d/%d",
|
||||
pPg->pgno, pgno,
|
||||
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
|
||||
pCache->nMax);
|
||||
numberOfCachePages(pCache));
|
||||
#endif
|
||||
rc = pCache->xStress(pCache->pStress, pPg);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
||||
@@ -266,33 +278,36 @@ int sqlite3PcacheFetch(
|
||||
}
|
||||
}
|
||||
|
||||
pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, 2);
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
|
||||
}
|
||||
|
||||
if( pPage ){
|
||||
if( !pPage->pData ){
|
||||
memset(pPage, 0, sizeof(PgHdr));
|
||||
pPage->pData = (void *)&pPage[1];
|
||||
pPage->pExtra = (void*)&((char *)pPage->pData)[pCache->szPage];
|
||||
memset(pPage->pExtra, 0, pCache->szExtra);
|
||||
pPage->pCache = pCache;
|
||||
pPage->pgno = pgno;
|
||||
}
|
||||
assert( pPage->pCache==pCache );
|
||||
assert( pPage->pgno==pgno );
|
||||
assert( pPage->pData==(void *)&pPage[1] );
|
||||
assert( pPage->pExtra==(void *)&((char *)&pPage[1])[pCache->szPage] );
|
||||
pPgHdr = (PgHdr *)pPage->pExtra;
|
||||
|
||||
if( 0==pPage->nRef ){
|
||||
if( !pPgHdr->pPage ){
|
||||
memset(pPgHdr, 0, sizeof(PgHdr));
|
||||
pPgHdr->pPage = pPage;
|
||||
pPgHdr->pData = pPage->pBuf;
|
||||
pPgHdr->pExtra = (void *)&pPgHdr[1];
|
||||
memset(pPgHdr->pExtra, 0, pCache->szExtra);
|
||||
pPgHdr->pCache = pCache;
|
||||
pPgHdr->pgno = pgno;
|
||||
}
|
||||
assert( pPgHdr->pCache==pCache );
|
||||
assert( pPgHdr->pgno==pgno );
|
||||
assert( pPgHdr->pData==pPage->pBuf );
|
||||
assert( pPgHdr->pExtra==(void *)&pPgHdr[1] );
|
||||
|
||||
if( 0==pPgHdr->nRef ){
|
||||
pCache->nRef++;
|
||||
}
|
||||
pPage->nRef++;
|
||||
pPgHdr->nRef++;
|
||||
if( pgno==1 ){
|
||||
pCache->pPage1 = pPage;
|
||||
pCache->pPage1 = pPgHdr;
|
||||
}
|
||||
}
|
||||
*ppPage = pPage;
|
||||
return (pPage==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
|
||||
*ppPage = pPgHdr;
|
||||
return (pPgHdr==0 && eCreate) ? SQLITE_NOMEM : SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -339,7 +354,7 @@ void sqlite3PcacheDrop(PgHdr *p){
|
||||
if( p->pgno==1 ){
|
||||
pCache->pPage1 = 0;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xUnpin(pCache->pCache, p, 1);
|
||||
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, p->pPage, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -397,7 +412,7 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
|
||||
PCache *pCache = p->pCache;
|
||||
assert( p->nRef>0 );
|
||||
assert( newPgno>0 );
|
||||
sqlite3GlobalConfig.pcache.xRekey(pCache->pCache, p, p->pgno, newPgno);
|
||||
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
|
||||
p->pgno = newPgno;
|
||||
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
|
||||
pcacheRemoveFromDirtyList(p);
|
||||
@@ -434,7 +449,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
||||
memset(pCache->pPage1->pData, 0, pCache->szPage);
|
||||
pgno = 1;
|
||||
}
|
||||
sqlite3GlobalConfig.pcache.xTruncate(pCache->pCache, pgno+1);
|
||||
sqlite3GlobalConfig.pcache2.xTruncate(pCache->pCache, pgno+1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +458,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
|
||||
*/
|
||||
void sqlite3PcacheClose(PCache *pCache){
|
||||
if( pCache->pCache ){
|
||||
sqlite3GlobalConfig.pcache.xDestroy(pCache->pCache);
|
||||
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +570,7 @@ int sqlite3PcachePageRefcount(PgHdr *p){
|
||||
int sqlite3PcachePagecount(PCache *pCache){
|
||||
int nPage = 0;
|
||||
if( pCache->pCache ){
|
||||
nPage = sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache);
|
||||
nPage = sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache);
|
||||
}
|
||||
return nPage;
|
||||
}
|
||||
@@ -565,7 +580,7 @@ int sqlite3PcachePagecount(PCache *pCache){
|
||||
** Get the suggested cache-size value.
|
||||
*/
|
||||
int sqlite3PcacheGetCachesize(PCache *pCache){
|
||||
return pCache->nMax;
|
||||
return numberOfCachePages(pCache);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -573,9 +588,19 @@ int sqlite3PcacheGetCachesize(PCache *pCache){
|
||||
** Set the suggested cache-size value.
|
||||
*/
|
||||
void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){
|
||||
pCache->nMax = mxPage;
|
||||
pCache->szCache = mxPage;
|
||||
if( pCache->pCache ){
|
||||
sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage);
|
||||
sqlite3GlobalConfig.pcache2.xCachesize(pCache->pCache,
|
||||
numberOfCachePages(pCache));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free up as much memory as possible from the page cache.
|
||||
*/
|
||||
void sqlite3PcacheShrink(PCache *pCache){
|
||||
if( pCache->pCache ){
|
||||
sqlite3GlobalConfig.pcache2.xShrink(pCache->pCache);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -23,7 +23,8 @@ typedef struct PCache PCache;
|
||||
** structure.
|
||||
*/
|
||||
struct PgHdr {
|
||||
void *pData; /* Content of this page */
|
||||
sqlite3_pcache_page *pPage; /* Pcache object page handle */
|
||||
void *pData; /* Page data */
|
||||
void *pExtra; /* Extra content */
|
||||
PgHdr *pDirty; /* Transient list of dirty pages */
|
||||
Pgno pgno; /* Page number for this page */
|
||||
@@ -141,6 +142,9 @@ void sqlite3PcacheSetCachesize(PCache *, int);
|
||||
int sqlite3PcacheGetCachesize(PCache *);
|
||||
#endif
|
||||
|
||||
/* Free up as much memory as possible from the page cache */
|
||||
void sqlite3PcacheShrink(PCache*);
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
/* Try to return memory used by the pcache module to the main memory heap */
|
||||
int sqlite3PcacheReleaseMemory(int);
|
||||
|
||||
+92
-47
@@ -24,7 +24,6 @@ typedef struct PgHdr1 PgHdr1;
|
||||
typedef struct PgFreeslot PgFreeslot;
|
||||
typedef struct PGroup PGroup;
|
||||
|
||||
|
||||
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
||||
** of one or more PCaches that are able to recycle each others unpinned
|
||||
** pages when they are under memory pressure. A PGroup is an instance of
|
||||
@@ -72,6 +71,7 @@ struct PCache1 {
|
||||
*/
|
||||
PGroup *pGroup; /* PGroup this cache belongs to */
|
||||
int szPage; /* Size of allocated pages in bytes */
|
||||
int szExtra; /* Size of extra space in bytes */
|
||||
int bPurgeable; /* True if cache is purgeable */
|
||||
unsigned int nMin; /* Minimum number of pages reserved */
|
||||
unsigned int nMax; /* Configured "cache_size" value */
|
||||
@@ -90,11 +90,12 @@ struct PCache1 {
|
||||
|
||||
/*
|
||||
** Each cache entry is represented by an instance of the following
|
||||
** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
|
||||
** directly before this structure in memory (see the PGHDR1_TO_PAGE()
|
||||
** macro below).
|
||||
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
|
||||
** PgHdr1.pCache->szPage bytes is allocated directly before this structure
|
||||
** in memory.
|
||||
*/
|
||||
struct PgHdr1 {
|
||||
sqlite3_pcache_page page;
|
||||
unsigned int iKey; /* Key value (page number) */
|
||||
PgHdr1 *pNext; /* Next in hash table chain */
|
||||
PCache1 *pCache; /* Cache that currently owns this page */
|
||||
@@ -144,21 +145,6 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
*/
|
||||
#define pcache1 (GLOBAL(struct PCacheGlobal, pcache1_g))
|
||||
|
||||
/*
|
||||
** When a PgHdr1 structure is allocated, the associated PCache1.szPage
|
||||
** bytes of data are located directly before it in memory (i.e. the total
|
||||
** size of the allocation is sizeof(PgHdr1)+PCache1.szPage byte). The
|
||||
** PGHDR1_TO_PAGE() macro takes a pointer to a PgHdr1 structure as
|
||||
** an argument and returns a pointer to the associated block of szPage
|
||||
** bytes. The PAGE_TO_PGHDR1() macro does the opposite: its argument is
|
||||
** a pointer to a block of szPage bytes of data and the return value is
|
||||
** a pointer to the associated PgHdr1 structure.
|
||||
**
|
||||
** assert( PGHDR1_TO_PAGE(PAGE_TO_PGHDR1(pCache, X))==X );
|
||||
*/
|
||||
#define PGHDR1_TO_PAGE(p) (void*)(((char*)p) - p->pCache->szPage)
|
||||
#define PAGE_TO_PGHDR1(c, p) (PgHdr1*)(((char*)p) + c->szPage)
|
||||
|
||||
/*
|
||||
** Macros to enter and leave the PCache LRU mutex.
|
||||
*/
|
||||
@@ -241,8 +227,9 @@ static void *pcache1Alloc(int nByte){
|
||||
/*
|
||||
** Free an allocated buffer obtained from pcache1Alloc().
|
||||
*/
|
||||
static void pcache1Free(void *p){
|
||||
if( p==0 ) return;
|
||||
static int pcache1Free(void *p){
|
||||
int nFreed = 0;
|
||||
if( p==0 ) return 0;
|
||||
if( p>=pcache1.pStart && p<pcache1.pEnd ){
|
||||
PgFreeslot *pSlot;
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
@@ -255,15 +242,15 @@ static void pcache1Free(void *p){
|
||||
assert( pcache1.nFreeSlot<=pcache1.nSlot );
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
}else{
|
||||
int iSize;
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
iSize = sqlite3MallocSize(p);
|
||||
nFreed = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -nFreed);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return nFreed;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
@@ -288,7 +275,6 @@ static int pcache1MemSize(void *p){
|
||||
** Allocate a new page object initially associated with cache pCache.
|
||||
*/
|
||||
static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
|
||||
int nByte = sizeof(PgHdr1) + pCache->szPage;
|
||||
PgHdr1 *p = 0;
|
||||
void *pPg;
|
||||
|
||||
@@ -297,16 +283,29 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
|
||||
** this mutex is not held. */
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
pPg = pcache1Alloc(nByte);
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
pPg = pcache1Alloc(pCache->szPage);
|
||||
p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
|
||||
if( !pPg || !p ){
|
||||
pcache1Free(pPg);
|
||||
sqlite3_free(p);
|
||||
pPg = 0;
|
||||
}
|
||||
#else
|
||||
pPg = pcache1Alloc(sizeof(PgHdr1) + pCache->szPage + pCache->szExtra);
|
||||
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
|
||||
#endif
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
|
||||
if( pPg ){
|
||||
p = PAGE_TO_PGHDR1(pCache, pPg);
|
||||
p->page.pBuf = pPg;
|
||||
p->page.pExtra = &p[1];
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
return p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -320,7 +319,10 @@ static void pcache1FreePage(PgHdr1 *p){
|
||||
if( ALWAYS(p) ){
|
||||
PCache1 *pCache = p->pCache;
|
||||
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
|
||||
pcache1Free(PGHDR1_TO_PAGE(p));
|
||||
pcache1Free(p->page.pBuf);
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
sqlite3_free(p);
|
||||
#endif
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage--;
|
||||
}
|
||||
@@ -361,7 +363,7 @@ void sqlite3PageFree(void *p){
|
||||
** the heap even further.
|
||||
*/
|
||||
static int pcache1UnderMemoryPressure(PCache1 *pCache){
|
||||
if( pcache1.nSlot && pCache->szPage<=pcache1.szSlot ){
|
||||
if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
|
||||
return pcache1.bUnderPressure;
|
||||
}else{
|
||||
return sqlite3HeapNearlyFull();
|
||||
@@ -552,7 +554,7 @@ static void pcache1Shutdown(void *NotUsed){
|
||||
**
|
||||
** Allocate a new cache.
|
||||
*/
|
||||
static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
||||
PCache1 *pCache; /* The newly created page cache */
|
||||
PGroup *pGroup; /* The group the new page cache will belong to */
|
||||
int sz; /* Bytes of memory required to allocate the new cache */
|
||||
@@ -575,6 +577,9 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
|
||||
#endif
|
||||
|
||||
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
|
||||
assert( szExtra < 300 );
|
||||
|
||||
sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
|
||||
pCache = (PCache1 *)sqlite3_malloc(sz);
|
||||
if( pCache ){
|
||||
@@ -587,6 +592,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
}
|
||||
pCache->pGroup = pGroup;
|
||||
pCache->szPage = szPage;
|
||||
pCache->szExtra = szExtra;
|
||||
pCache->bPurgeable = (bPurgeable ? 1 : 0);
|
||||
if( bPurgeable ){
|
||||
pCache->nMin = 10;
|
||||
@@ -618,6 +624,25 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite3_pcache.xShrink method.
|
||||
**
|
||||
** Free up as much memory as possible.
|
||||
*/
|
||||
static void pcache1Shrink(sqlite3_pcache *p){
|
||||
PCache1 *pCache = (PCache1*)p;
|
||||
if( pCache->bPurgeable ){
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
int savedMaxPage;
|
||||
pcache1EnterMutex(pGroup);
|
||||
savedMaxPage = pGroup->nMaxPage;
|
||||
pGroup->nMaxPage = 0;
|
||||
pcache1EnforceMaxPage(pGroup);
|
||||
pGroup->nMaxPage = savedMaxPage;
|
||||
pcache1LeaveMutex(pGroup);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite3_pcache.xPagecount method.
|
||||
*/
|
||||
@@ -684,7 +709,11 @@ static int pcache1Pagecount(sqlite3_pcache *p){
|
||||
**
|
||||
** 5. Otherwise, allocate and return a new page buffer.
|
||||
*/
|
||||
static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
static sqlite3_pcache_page *pcache1Fetch(
|
||||
sqlite3_pcache *p,
|
||||
unsigned int iKey,
|
||||
int createFlag
|
||||
){
|
||||
int nPinned;
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PGroup *pGroup;
|
||||
@@ -719,7 +748,6 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
pGroup = pCache->pGroup;
|
||||
#endif
|
||||
|
||||
|
||||
/* Step 3: Abort if createFlag is 1 but the cache is nearly full */
|
||||
nPinned = pCache->nPage - pCache->nRecyclable;
|
||||
assert( nPinned>=0 );
|
||||
@@ -743,16 +771,24 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
PCache1 *pOtherCache;
|
||||
PCache1 *pOther;
|
||||
pPage = pGroup->pLruTail;
|
||||
pcache1RemoveFromHash(pPage);
|
||||
pcache1PinPage(pPage);
|
||||
if( (pOtherCache = pPage->pCache)->szPage!=pCache->szPage ){
|
||||
pOther = pPage->pCache;
|
||||
|
||||
/* We want to verify that szPage and szExtra are the same for pOther
|
||||
** and pCache. Assert that we can verify this by comparing sums. */
|
||||
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
|
||||
assert( pCache->szExtra<512 );
|
||||
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
|
||||
assert( pOther->szExtra<512 );
|
||||
|
||||
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
|
||||
pcache1FreePage(pPage);
|
||||
pPage = 0;
|
||||
}else{
|
||||
pGroup->nCurrentPage -=
|
||||
(pOtherCache->bPurgeable - pCache->bPurgeable);
|
||||
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,7 +809,7 @@ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){
|
||||
pPage->pCache = pCache;
|
||||
pPage->pLruPrev = 0;
|
||||
pPage->pLruNext = 0;
|
||||
*(void **)(PGHDR1_TO_PAGE(pPage)) = 0;
|
||||
*(void **)pPage->page.pExtra = 0;
|
||||
pCache->apHash[h] = pPage;
|
||||
}
|
||||
|
||||
@@ -782,7 +818,7 @@ fetch_out:
|
||||
pCache->iMaxKey = iKey;
|
||||
}
|
||||
pcache1LeaveMutex(pGroup);
|
||||
return (pPage ? PGHDR1_TO_PAGE(pPage) : 0);
|
||||
return &pPage->page;
|
||||
}
|
||||
|
||||
|
||||
@@ -791,9 +827,13 @@ fetch_out:
|
||||
**
|
||||
** Mark a page as unpinned (eligible for asynchronous recycling).
|
||||
*/
|
||||
static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
|
||||
static void pcache1Unpin(
|
||||
sqlite3_pcache *p,
|
||||
sqlite3_pcache_page *pPg,
|
||||
int reuseUnlikely
|
||||
){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
|
||||
PgHdr1 *pPage = (PgHdr1 *)pPg;
|
||||
PGroup *pGroup = pCache->pGroup;
|
||||
|
||||
assert( pPage->pCache==pCache );
|
||||
@@ -829,12 +869,12 @@ static void pcache1Unpin(sqlite3_pcache *p, void *pPg, int reuseUnlikely){
|
||||
*/
|
||||
static void pcache1Rekey(
|
||||
sqlite3_pcache *p,
|
||||
void *pPg,
|
||||
sqlite3_pcache_page *pPg,
|
||||
unsigned int iOld,
|
||||
unsigned int iNew
|
||||
){
|
||||
PCache1 *pCache = (PCache1 *)p;
|
||||
PgHdr1 *pPage = PAGE_TO_PGHDR1(pCache, pPg);
|
||||
PgHdr1 *pPage = (PgHdr1 *)pPg;
|
||||
PgHdr1 **pp;
|
||||
unsigned int h;
|
||||
assert( pPage->iKey==iOld );
|
||||
@@ -903,7 +943,8 @@ static void pcache1Destroy(sqlite3_pcache *p){
|
||||
** already provided an alternative.
|
||||
*/
|
||||
void sqlite3PCacheSetDefault(void){
|
||||
static const sqlite3_pcache_methods defaultMethods = {
|
||||
static const sqlite3_pcache_methods2 defaultMethods = {
|
||||
1, /* iVersion */
|
||||
0, /* pArg */
|
||||
pcache1Init, /* xInit */
|
||||
pcache1Shutdown, /* xShutdown */
|
||||
@@ -914,9 +955,10 @@ void sqlite3PCacheSetDefault(void){
|
||||
pcache1Unpin, /* xUnpin */
|
||||
pcache1Rekey, /* xRekey */
|
||||
pcache1Truncate, /* xTruncate */
|
||||
pcache1Destroy /* xDestroy */
|
||||
pcache1Destroy, /* xDestroy */
|
||||
pcache1Shrink /* xShrink */
|
||||
};
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultMethods);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultMethods);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
@@ -937,7 +979,10 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex(&pcache1.grp);
|
||||
while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
|
||||
nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
|
||||
nFree += pcache1MemSize(p->page.pBuf);
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
nFree += sqlite3MemSize(p);
|
||||
#endif
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p);
|
||||
pcache1FreePage(p);
|
||||
|
||||
+26
-12
@@ -346,7 +346,7 @@ void sqlite3Pragma(
|
||||
goto pragma_out;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
||||
/*
|
||||
** PRAGMA [database.]default_cache_size
|
||||
** PRAGMA [database.]default_cache_size=N
|
||||
@@ -395,7 +395,9 @@ void sqlite3Pragma(
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
}else
|
||||
#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */
|
||||
|
||||
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
||||
/*
|
||||
** PRAGMA [database.]page_size
|
||||
** PRAGMA [database.]page_size=N
|
||||
@@ -416,7 +418,7 @@ void sqlite3Pragma(
|
||||
** buffer that the pager module resizes using sqlite3_realloc().
|
||||
*/
|
||||
db->nextPagesize = sqlite3Atoi(zRight);
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
||||
if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
@@ -456,6 +458,10 @@ void sqlite3Pragma(
|
||||
** second form attempts to change this setting. Both
|
||||
** forms return the current setting.
|
||||
**
|
||||
** The absolute value of N is used. This is undocumented and might
|
||||
** change. The only purpose is to provide an easy way to test
|
||||
** the sqlite3AbsInt32() function.
|
||||
**
|
||||
** PRAGMA [database.]page_count
|
||||
**
|
||||
** Return the number of pages in the specified database.
|
||||
@@ -470,7 +476,8 @@ void sqlite3Pragma(
|
||||
if( sqlite3Tolower(zLeft[0])=='p' ){
|
||||
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
|
||||
}else{
|
||||
sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
|
||||
sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
|
||||
sqlite3AbsInt32(sqlite3Atoi(zRight)));
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
@@ -684,14 +691,11 @@ void sqlite3Pragma(
|
||||
** PRAGMA [database.]cache_size=N
|
||||
**
|
||||
** The first form reports the current local setting for the
|
||||
** page cache size. The local setting can be different from
|
||||
** the persistent cache size value that is stored in the database
|
||||
** file itself. The value returned is the maximum number of
|
||||
** pages in the page cache. The second form sets the local
|
||||
** page cache size value. It does not change the persistent
|
||||
** cache size stored on the disk so the cache size will revert
|
||||
** to its default value when the database is closed and reopened.
|
||||
** N should be a positive integer.
|
||||
** page cache size. The second form sets the local
|
||||
** page cache size value. If N is positive then that is the
|
||||
** number of pages in the cache. If N is negative, then the
|
||||
** number of pages is adjusted so that the cache uses -N kibibytes
|
||||
** of memory.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
@@ -699,7 +703,7 @@ void sqlite3Pragma(
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
|
||||
}else{
|
||||
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
|
||||
int size = sqlite3Atoi(zRight);
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
@@ -1434,6 +1438,16 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif
|
||||
|
||||
/*
|
||||
** PRAGMA shrink_memory
|
||||
**
|
||||
** This pragma attempts to free as much memory as possible from the
|
||||
** current database connection.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "shrink_memory")==0 ){
|
||||
sqlite3_db_release_memory(db);
|
||||
}else
|
||||
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/*
|
||||
** Report the current state of file logs for all databases
|
||||
|
||||
@@ -278,9 +278,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
pDb->pSchema->enc = ENC(db);
|
||||
|
||||
if( pDb->pSchema->cache_size==0 ){
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
|
||||
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
|
||||
pDb->pSchema->cache_size = size;
|
||||
#else
|
||||
pDb->pSchema->cache_size = SQLITE_DEFAULT_CACHE_SIZE;
|
||||
#endif
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
|
||||
|
||||
+59
-24
@@ -1396,6 +1396,7 @@ static char zHelp[] =
|
||||
" If TABLE specified, only list tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
".timeout MS Try opening locked tables for MS milliseconds\n"
|
||||
".vfsname ?AUX? Print the name of the VFS stack\n"
|
||||
".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
|
||||
;
|
||||
|
||||
@@ -2220,7 +2221,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "pghdrsz", SQLITE_TESTCTRL_PGHDRSZ },
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
};
|
||||
int testctrl = -1;
|
||||
@@ -2265,7 +2265,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
case SQLITE_TESTCTRL_PRNG_SAVE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESTORE:
|
||||
case SQLITE_TESTCTRL_PRNG_RESET:
|
||||
case SQLITE_TESTCTRL_PGHDRSZ:
|
||||
if( nArg==2 ){
|
||||
rc = sqlite3_test_control(testctrl);
|
||||
printf("%d (0x%08x)\n", rc, rc);
|
||||
@@ -2337,10 +2336,22 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}else
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
|
||||
printf("SQLite %s %s\n",
|
||||
printf("SQLite %s %s\n" /*extra-version-info*/,
|
||||
sqlite3_libversion(), sqlite3_sourceid());
|
||||
}else
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
|
||||
const char *zDbName = nArg==2 ? azArg[1] : "main";
|
||||
char *zVfsName = 0;
|
||||
if( p->db ){
|
||||
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
|
||||
if( zVfsName ){
|
||||
printf("%s\n", zVfsName);
|
||||
sqlite3_free(zVfsName);
|
||||
}
|
||||
}
|
||||
}else
|
||||
|
||||
if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
|
||||
int j;
|
||||
assert( nArg<=ArraySize(azArg) );
|
||||
@@ -2646,29 +2657,30 @@ static int process_sqliterc(
|
||||
** Show available command line options
|
||||
*/
|
||||
static const char zOptions[] =
|
||||
" -help show this message\n"
|
||||
" -init filename read/process named file\n"
|
||||
" -echo print commands before execution\n"
|
||||
" -[no]header turn headers on or off\n"
|
||||
" -bail stop after hitting an error\n"
|
||||
" -interactive force interactive I/O\n"
|
||||
" -batch force batch I/O\n"
|
||||
" -column set output mode to 'column'\n"
|
||||
" -cmd command run \"command\" before reading stdin\n"
|
||||
" -csv set output mode to 'csv'\n"
|
||||
" -echo print commands before execution\n"
|
||||
" -init filename read/process named file\n"
|
||||
" -[no]header turn headers on or off\n"
|
||||
" -help show this message\n"
|
||||
" -html set output mode to HTML\n"
|
||||
" -interactive force interactive I/O\n"
|
||||
" -line set output mode to 'line'\n"
|
||||
" -list set output mode to 'list'\n"
|
||||
#ifdef SQLITE_ENABLE_MULTIPLEX
|
||||
" -multiplex enable the multiplexor VFS\n"
|
||||
#endif
|
||||
" -nullvalue 'text' set text string for NULL values\n"
|
||||
" -separator 'x' set output field separator (|)\n"
|
||||
" -stats print memory stats before each finalize\n"
|
||||
" -nullvalue 'text' set text string for NULL values\n"
|
||||
" -version show SQLite version\n"
|
||||
" -vfs NAME use NAME as the default VFS\n"
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
" -vfstrace enable tracing of all VFS calls\n"
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MULTIPLEX
|
||||
" -multiplex enable the multiplexor VFS\n"
|
||||
#endif
|
||||
;
|
||||
static void usage(int showDetail){
|
||||
fprintf(stderr,
|
||||
@@ -2731,19 +2743,22 @@ int main(int argc, char **argv){
|
||||
char *z;
|
||||
if( argv[i][0]!='-' ) break;
|
||||
z = argv[i];
|
||||
if( z[0]=='-' && z[1]=='-' ) z++;
|
||||
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-separator")==0
|
||||
|| strcmp(z,"-nullvalue")==0
|
||||
|| strcmp(z,"-cmd")==0
|
||||
){
|
||||
i++;
|
||||
}else if( strcmp(argv[i],"-init")==0 ){
|
||||
}else if( strcmp(z,"-init")==0 ){
|
||||
i++;
|
||||
zInitFile = argv[i];
|
||||
/* Need to check for batch mode here to so we can avoid printing
|
||||
** informational messages (like from process_sqliterc) before
|
||||
** we do the actual processing of arguments later in a second pass.
|
||||
*/
|
||||
}else if( strcmp(argv[i],"-batch")==0 ){
|
||||
}else if( strcmp(z,"-batch")==0 ){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(argv[i],"-heap")==0 ){
|
||||
}else if( strcmp(z,"-heap")==0 ){
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
int j, c;
|
||||
const char *zSize;
|
||||
@@ -2760,7 +2775,7 @@ int main(int argc, char **argv){
|
||||
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
}else if( strcmp(argv[i],"-vfstrace")==0 ){
|
||||
}else if( strcmp(z,"-vfstrace")==0 ){
|
||||
extern int vfstrace_register(
|
||||
const char *zTraceName,
|
||||
const char *zOldVfsName,
|
||||
@@ -2771,11 +2786,11 @@ int main(int argc, char **argv){
|
||||
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MULTIPLEX
|
||||
}else if( strcmp(argv[i],"-multiplex")==0 ){
|
||||
}else if( strcmp(z,"-multiplex")==0 ){
|
||||
extern int sqlite3_multiple_initialize(const char*,int);
|
||||
sqlite3_multiplex_initialize(0, 1);
|
||||
#endif
|
||||
}else if( strcmp(argv[i],"-vfs")==0 ){
|
||||
}else if( strcmp(z,"-vfs")==0 ){
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
|
||||
if( pVfs ){
|
||||
sqlite3_vfs_register(pVfs, 1);
|
||||
@@ -2857,7 +2872,8 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-separator")==0 ){
|
||||
i++;
|
||||
if(i>=argc){
|
||||
fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
|
||||
fprintf(stderr,"%s: Error: missing argument for option: %s\n",
|
||||
Argv0, z);
|
||||
fprintf(stderr,"Use -help for a list of options.\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -2866,7 +2882,8 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-nullvalue")==0 ){
|
||||
i++;
|
||||
if(i>=argc){
|
||||
fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
|
||||
fprintf(stderr,"%s: Error: missing argument for option: %s\n",
|
||||
Argv0, z);
|
||||
fprintf(stderr,"Use -help for a list of options.\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -2901,8 +2918,26 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-multiplex")==0 ){
|
||||
i++;
|
||||
#endif
|
||||
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
|
||||
}else if( strcmp(z,"-help")==0 ){
|
||||
usage(1);
|
||||
}else if( strcmp(z,"-cmd")==0 ){
|
||||
if( i==argc-1 ) break;
|
||||
i++;
|
||||
z = argv[i];
|
||||
if( z[0]=='.' ){
|
||||
rc = do_meta_command(z, &data);
|
||||
if( rc && bail_on_error ) return rc;
|
||||
}else{
|
||||
open_db(&data);
|
||||
rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
|
||||
if( zErrMsg!=0 ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
if( bail_on_error ) return rc!=0 ? rc : 1;
|
||||
}else if( rc!=0 ){
|
||||
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
|
||||
if( bail_on_error ) return rc;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
|
||||
fprintf(stderr,"Use -help for a list of options.\n");
|
||||
@@ -2934,7 +2969,7 @@ int main(int argc, char **argv){
|
||||
char *zHistory = 0;
|
||||
int nHistory;
|
||||
printf(
|
||||
"SQLite version %s %.19s\n"
|
||||
"SQLite version %s %.19s\n" /*extra-version-info*/
|
||||
"Enter \".help\" for instructions\n"
|
||||
"Enter SQL statements terminated with a \";\"\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid()
|
||||
|
||||
+130
-32
@@ -771,6 +771,17 @@ struct sqlite3_io_methods {
|
||||
** a write transaction to indicate that, unless it is rolled back for some
|
||||
** reason, the entire database file will be overwritten by the current
|
||||
** transaction. This is used by VACUUM operations.
|
||||
**
|
||||
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
|
||||
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
|
||||
** final bottom-level VFS are written into memory obtained from
|
||||
** [sqlite3_malloc()] and the result is stored in the char* variable
|
||||
** that the fourth parameter of [sqlite3_file_control()] points to.
|
||||
** The caller is responsible for freeing the memory when done. As with
|
||||
** all file-control actions, there is no guarantee that this will actually
|
||||
** do anything. Callers should initialize the char* variable to a NULL
|
||||
** pointer in case this file-control is not implemented. This file-control
|
||||
** is intended for diagnostic use only.
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
@@ -783,6 +794,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_WIN32_AV_RETRY 9
|
||||
#define SQLITE_FCNTL_PERSIST_WAL 10
|
||||
#define SQLITE_FCNTL_OVERWRITE 11
|
||||
#define SQLITE_FCNTL_VFSNAME 12
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -1368,7 +1380,7 @@ struct sqlite3_mem_methods {
|
||||
** <dd> ^This option specifies a static memory buffer that SQLite can use for
|
||||
** the database page cache with the default page cache implementation.
|
||||
** This configuration should not be used if an application-define page
|
||||
** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
|
||||
** cache implementation is loaded using the SQLITE_CONFIG_PCACHE2 option.
|
||||
** There are three arguments to this option: A pointer to 8-byte aligned
|
||||
** memory, the size of each page buffer (sz), and the number of pages (N).
|
||||
** The sz argument should be the size of the largest database page
|
||||
@@ -1437,15 +1449,15 @@ struct sqlite3_mem_methods {
|
||||
** verb to [sqlite3_db_config()] can be used to change the lookaside
|
||||
** configuration on individual connections.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
|
||||
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to
|
||||
** an [sqlite3_pcache_methods] object. This object specifies the interface
|
||||
** an [sqlite3_pcache_methods2] 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.</dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
|
||||
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** [sqlite3_pcache_methods] object. SQLite copies of the current
|
||||
** [sqlite3_pcache_methods2] object. SQLite copies of the current
|
||||
** page cache implementation into that object.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
|
||||
@@ -1478,6 +1490,11 @@ struct sqlite3_mem_methods {
|
||||
** 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.
|
||||
**
|
||||
** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]]
|
||||
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFNIG_GETPCACHE
|
||||
** <dd> These options are obsolete and should not be used by new code.
|
||||
** They are retained for backwards compatibility but are now no-ops.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
@@ -1493,10 +1510,12 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
|
||||
/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
|
||||
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
|
||||
#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
|
||||
#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
|
||||
#define SQLITE_CONFIG_PCACHE 14 /* no-op */
|
||||
#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
|
||||
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
|
||||
#define SQLITE_CONFIG_URI 17 /* int */
|
||||
#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
|
||||
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
@@ -4366,6 +4385,22 @@ int sqlite3_get_autocommit(sqlite3*);
|
||||
*/
|
||||
sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return The Filename For A Database Connection
|
||||
**
|
||||
** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
|
||||
** associated with database N of connection D. ^The main database file
|
||||
** has the name "main". If there is no attached database N on the database
|
||||
** connection D, or if database N is a temporary or in-memory database, then
|
||||
** a NULL pointer is returned.
|
||||
**
|
||||
** ^The filename returned by this function is the output of the
|
||||
** xFullPathname method of the [VFS]. ^In other words, the filename
|
||||
** will be an absolute pathname, even if the filename used
|
||||
** to open the database originally was a URI or relative pathname.
|
||||
*/
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Find the next prepared statement
|
||||
**
|
||||
@@ -4522,9 +4557,24 @@ int sqlite3_enable_shared_cache(int);
|
||||
** which might be more or less than the amount requested.
|
||||
** ^The sqlite3_release_memory() routine is a no-op returning zero
|
||||
** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT].
|
||||
**
|
||||
** See also: [sqlite3_db_release_memory()]
|
||||
*/
|
||||
int sqlite3_release_memory(int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Free Memory Used By A Database Connection
|
||||
**
|
||||
** ^The sqlite3_db_shrink(D) interface attempts to free as much heap
|
||||
** memory as possible from database connection D. Unlike the
|
||||
** [sqlite3_release_memory()] interface, this interface is effect even
|
||||
** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
|
||||
** omitted.
|
||||
**
|
||||
** See also: [sqlite3_release_memory()]
|
||||
*/
|
||||
int sqlite3_db_release_memory(sqlite3*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Impose A Limit On Heap Size
|
||||
**
|
||||
@@ -4555,7 +4605,7 @@ int sqlite3_release_memory(int);
|
||||
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
|
||||
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
|
||||
** <li> An alternative page cache implementation is specified using
|
||||
** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...).
|
||||
** [sqlite3_config]([SQLITE_CONFIG_PCACHE2],...).
|
||||
** <li> The page cache allocates from its own memory pool supplied
|
||||
** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than
|
||||
** from the heap.
|
||||
@@ -5623,10 +5673,9 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_RESERVE 14
|
||||
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
||||
#define SQLITE_TESTCTRL_PGHDRSZ 17
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19
|
||||
#define SQLITE_TESTCTRL_LAST 19
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||
#define SQLITE_TESTCTRL_LAST 18
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
@@ -5928,17 +5977,33 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
** sqlite3_pcache object except by holding and passing pointers
|
||||
** to the object.
|
||||
**
|
||||
** See [sqlite3_pcache_methods] for additional information.
|
||||
** See [sqlite3_pcache_methods2] for additional information.
|
||||
*/
|
||||
typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
|
||||
/*
|
||||
** CAPI3REF: Custom Page Cache Object
|
||||
**
|
||||
** The sqlite3_pcache_page object represents a single page in the
|
||||
** page cache. The page cache will allocate instances of this
|
||||
** object. Various methods of the page cache use pointers to instances
|
||||
** of this object as parameters or as their return value.
|
||||
**
|
||||
** See [sqlite3_pcache_methods2] for additional information.
|
||||
*/
|
||||
typedef struct sqlite3_pcache_page sqlite3_pcache_page;
|
||||
struct sqlite3_pcache_page {
|
||||
void *pBuf; /* The content of the page */
|
||||
void *pExtra; /* Extra information associated with the page */
|
||||
};
|
||||
|
||||
/*
|
||||
** CAPI3REF: Application Defined Page Cache.
|
||||
** KEYWORDS: {page cache}
|
||||
**
|
||||
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
|
||||
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
|
||||
** register an alternative page cache implementation by passing in an
|
||||
** instance of the sqlite3_pcache_methods structure.)^
|
||||
** instance of the sqlite3_pcache_methods2 structure.)^
|
||||
** In many applications, most of the heap memory allocated by
|
||||
** SQLite is used for the page cache.
|
||||
** By implementing a
|
||||
@@ -5952,7 +6017,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** extreme measure that is only needed by the most demanding applications.
|
||||
** The built-in page cache is recommended for most uses.
|
||||
**
|
||||
** ^(The contents of the sqlite3_pcache_methods structure are copied to an
|
||||
** ^(The contents of the sqlite3_pcache_methods2 structure are copied to an
|
||||
** internal buffer by SQLite within the call to [sqlite3_config]. Hence
|
||||
** the application may discard the parameter after the call to
|
||||
** [sqlite3_config()] returns.)^
|
||||
@@ -5987,18 +6052,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** ^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
|
||||
** first parameter, szPage, is the size in bytes of the pages that must
|
||||
** be allocated by the cache. ^szPage will not be a power of two. ^szPage
|
||||
** will the page size of the database file that is to be cached plus an
|
||||
** increment (here called "R") of less than 250. SQLite will use the
|
||||
** extra R bytes on each page to store metadata about the underlying
|
||||
** database page on disk. The value of R depends
|
||||
** parameter parameter, szPage, is the size in bytes of the pages that must
|
||||
** be allocated by the cache. ^szPage will always a power of two. ^The
|
||||
** second parameter szExtra is a number of bytes of extra storage
|
||||
** associated with each page cache entry. ^The szExtra parameter will
|
||||
** a number less than 250. SQLite will use the
|
||||
** extra szExtra bytes on each page to store metadata about the underlying
|
||||
** database page on disk. The value passed into szExtra depends
|
||||
** on the SQLite version, the target platform, and how SQLite was compiled.
|
||||
** ^(R is constant for a particular build of SQLite. Except, there are two
|
||||
** distinct values of R when SQLite is compiled with the proprietary
|
||||
** ZIPVFS extension.)^ ^The second argument to
|
||||
** xCreate(), bPurgeable, is true if the cache being created will
|
||||
** be used to cache database pages of a file stored on disk, or
|
||||
** ^The third argument to xCreate(), bPurgeable, is true if the cache being
|
||||
** created will be used to cache database pages of a file stored on disk, or
|
||||
** false if it is used for an in-memory database. The cache implementation
|
||||
** does not have to do anything special based with the value of bPurgeable;
|
||||
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
||||
@@ -6022,11 +6085,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
**
|
||||
** [[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
|
||||
** 8-byte boundary. The page to be fetched is determined by the key. ^The
|
||||
** minimum key value is 1. After it has been retrieved using xFetch, the page
|
||||
** is considered to be "pinned".
|
||||
** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
|
||||
** The pBuf element of the returned sqlite3_pcache_page object will be a
|
||||
** pointer to a buffer of szPage bytes used to store the content of a
|
||||
** single database page. The pExtra element of sqlite3_pcache_page will be
|
||||
** a pointer to the szExtra bytes of extra storage that SQLite has requested
|
||||
** for each entry in the page cache.
|
||||
**
|
||||
** The page to be fetched is determined by the key. ^The minimum key value
|
||||
** is 1. After it has been retrieved using xFetch, the page is considered
|
||||
** to be "pinned".
|
||||
**
|
||||
** If the requested page is already in the page cache, then the page cache
|
||||
** implementation must return a pointer to the page buffer with its content
|
||||
@@ -6081,6 +6149,35 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
|
||||
** handle invalid, and will not use it with any other sqlite3_pcache_methods
|
||||
** functions.
|
||||
**
|
||||
** [[the xShrink() page cache method]]
|
||||
** ^SQLite invokes the xShrink() method when it wants the page cache to
|
||||
** free up as much of heap memory as possible. The page cache implementation
|
||||
** is not obligated to free any memory, but well-behaved implementions should
|
||||
** do their best.
|
||||
*/
|
||||
typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
|
||||
struct sqlite3_pcache_methods2 {
|
||||
int iVersion;
|
||||
void *pArg;
|
||||
int (*xInit)(void*);
|
||||
void (*xShutdown)(void*);
|
||||
sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable);
|
||||
void (*xCachesize)(sqlite3_pcache*, int nCachesize);
|
||||
int (*xPagecount)(sqlite3_pcache*);
|
||||
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
|
||||
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
|
||||
void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
|
||||
unsigned oldKey, unsigned newKey);
|
||||
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
|
||||
void (*xDestroy)(sqlite3_pcache*);
|
||||
void (*xShrink)(sqlite3_pcache*);
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the obsolete pcache_methods object that has now been replaced
|
||||
** by sqlite3_pcache_methods2. This object is not used by SQLite. It is
|
||||
** retained in the header file for backwards compatibility only.
|
||||
*/
|
||||
typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
|
||||
struct sqlite3_pcache_methods {
|
||||
@@ -6097,6 +6194,7 @@ struct sqlite3_pcache_methods {
|
||||
void (*xDestroy)(sqlite3_pcache*);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Online Backup Object
|
||||
**
|
||||
|
||||
+1
-2
@@ -1453,7 +1453,6 @@ struct UnpackedRecord {
|
||||
*/
|
||||
#define UNPACKED_NEED_FREE 0x0001 /* Memory is from sqlite3Malloc() */
|
||||
#define UNPACKED_NEED_DESTROY 0x0002 /* apMem[]s should all be destroyed */
|
||||
#define UNPACKED_IGNORE_ROWID 0x0004 /* Ignore trailing rowid on key1 */
|
||||
#define UNPACKED_INCRKEY 0x0008 /* Make this key an epsilon larger */
|
||||
#define UNPACKED_PREFIX_MATCH 0x0010 /* A prefix match is considered OK */
|
||||
#define UNPACKED_PREFIX_SEARCH 0x0020 /* A prefix match is considered OK */
|
||||
@@ -2459,7 +2458,7 @@ struct Sqlite3Config {
|
||||
int nLookaside; /* Default lookaside buffer count */
|
||||
sqlite3_mem_methods m; /* Low-level memory allocation interface */
|
||||
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
|
||||
sqlite3_pcache_methods pcache; /* Low-level page-cache interface */
|
||||
sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */
|
||||
void *pHeap; /* Heap storage space */
|
||||
int nHeap; /* Size of pHeap[] */
|
||||
int mnReq, mxReq; /* Min and max heap requests sizes */
|
||||
|
||||
+84
@@ -4593,6 +4593,54 @@ static int test_release_memory(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_db_release_memory DB
|
||||
**
|
||||
** Attempt to release memory currently held by database DB. Return the
|
||||
** result code (which in the current implementation is always zero).
|
||||
*/
|
||||
static int test_db_release_memory(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_db_release_memory(db);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_db_filename DB DBNAME
|
||||
**
|
||||
** Return the name of a file associated with a database.
|
||||
*/
|
||||
static int test_db_filename(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zDbName;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zDbName = Tcl_GetString(objv[2]);
|
||||
Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_soft_heap_limit ?N?
|
||||
**
|
||||
@@ -5161,6 +5209,39 @@ static int file_control_persist_wal(
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_vfsname DB ?AUXDB?
|
||||
**
|
||||
** Return a string that describes the stack of VFSes.
|
||||
*/
|
||||
static int file_control_vfsname(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zDbName = "main";
|
||||
char *zVfsName = 0;
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==3 ){
|
||||
zDbName = Tcl_GetString(objv[2]);
|
||||
}
|
||||
sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName);
|
||||
Tcl_AppendResult(interp, zVfsName, (char*)0);
|
||||
sqlite3_free(zVfsName);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_vfs_list
|
||||
**
|
||||
@@ -5915,6 +5996,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "uses_stmt_journal", uses_stmt_journal ,0 },
|
||||
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
{ "sqlite3_db_release_memory", test_db_release_memory, 0},
|
||||
{ "sqlite3_db_filename", test_db_filename, 0},
|
||||
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
|
||||
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
|
||||
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0},
|
||||
@@ -5982,6 +6065,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
|
||||
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
|
||||
{ "file_control_persist_wal", file_control_persist_wal, 0 },
|
||||
{ "file_control_vfsname", file_control_vfsname, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
|
||||
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
** procedures use this to determine when tests should be omitted.
|
||||
*/
|
||||
static void set_options(Tcl_Interp *interp){
|
||||
#ifdef HAVE_MALLOC_USABLE_SIZE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "malloc_usable_size", "1",
|
||||
TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "malloc_usable_size", "0",
|
||||
TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_32BIT_ROWID
|
||||
Tcl_SetVar2(interp, "sqlite_options", "rowid32", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
+18
-13
@@ -30,9 +30,9 @@
|
||||
#include <tcl.h>
|
||||
|
||||
static struct Wrapped {
|
||||
sqlite3_pcache_methods pcache;
|
||||
sqlite3_mem_methods mem;
|
||||
sqlite3_mutex_methods mutex;
|
||||
sqlite3_pcache_methods2 pcache;
|
||||
sqlite3_mem_methods mem;
|
||||
sqlite3_mutex_methods mutex;
|
||||
|
||||
int mem_init; /* True if mem subsystem is initalized */
|
||||
int mem_fail; /* True to fail mem subsystem inialization */
|
||||
@@ -123,8 +123,8 @@ static void wrPCacheShutdown(void *pArg){
|
||||
wrapped.pcache_init = 0;
|
||||
}
|
||||
|
||||
static sqlite3_pcache *wrPCacheCreate(int a, int b){
|
||||
return wrapped.pcache.xCreate(a, b);
|
||||
static sqlite3_pcache *wrPCacheCreate(int a, int b, int c){
|
||||
return wrapped.pcache.xCreate(a, b, c);
|
||||
}
|
||||
static void wrPCacheCachesize(sqlite3_pcache *p, int n){
|
||||
wrapped.pcache.xCachesize(p, n);
|
||||
@@ -132,13 +132,18 @@ static void wrPCacheCachesize(sqlite3_pcache *p, int n){
|
||||
static int wrPCachePagecount(sqlite3_pcache *p){
|
||||
return wrapped.pcache.xPagecount(p);
|
||||
}
|
||||
static void *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){
|
||||
static sqlite3_pcache_page *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){
|
||||
return wrapped.pcache.xFetch(p, a, b);
|
||||
}
|
||||
static void wrPCacheUnpin(sqlite3_pcache *p, void *a, int b){
|
||||
static void wrPCacheUnpin(sqlite3_pcache *p, sqlite3_pcache_page *a, int b){
|
||||
wrapped.pcache.xUnpin(p, a, b);
|
||||
}
|
||||
static void wrPCacheRekey(sqlite3_pcache *p, void *a, unsigned b, unsigned c){
|
||||
static void wrPCacheRekey(
|
||||
sqlite3_pcache *p,
|
||||
sqlite3_pcache_page *a,
|
||||
unsigned b,
|
||||
unsigned c
|
||||
){
|
||||
wrapped.pcache.xRekey(p, a, b, c);
|
||||
}
|
||||
static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){
|
||||
@@ -154,8 +159,8 @@ static void installInitWrappers(void){
|
||||
wrMutexFree, wrMutexEnter, wrMutexTry,
|
||||
wrMutexLeave, wrMutexHeld, wrMutexNotheld
|
||||
};
|
||||
sqlite3_pcache_methods pcachemethods = {
|
||||
0,
|
||||
sqlite3_pcache_methods2 pcachemethods = {
|
||||
1, 0,
|
||||
wrPCacheInit, wrPCacheShutdown, wrPCacheCreate,
|
||||
wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch,
|
||||
wrPCacheUnpin, wrPCacheRekey, wrPCacheTruncate,
|
||||
@@ -173,10 +178,10 @@ static void installInitWrappers(void){
|
||||
sqlite3_shutdown();
|
||||
sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex);
|
||||
sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem);
|
||||
sqlite3_config(SQLITE_CONFIG_GETPCACHE, &wrapped.pcache);
|
||||
sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &wrapped.pcache);
|
||||
sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods);
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &pcachemethods);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods);
|
||||
}
|
||||
|
||||
static int init_wrapper_install(
|
||||
@@ -218,7 +223,7 @@ static int init_wrapper_uninstall(
|
||||
sqlite3_shutdown();
|
||||
sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex);
|
||||
sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &wrapped.pcache);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE2, &wrapped.pcache);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -391,7 +391,7 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
|
||||
while( rc==SQLITE_OK && iTrunk>0 ){
|
||||
u32 nLeaf;
|
||||
u32 iLeaf;
|
||||
sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize;
|
||||
sqlite3_int64 iOff = (i64)(iTrunk-1)*pMain->nPagesize;
|
||||
rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff);
|
||||
nLeaf = decodeUint32(&aData[4]);
|
||||
for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){
|
||||
|
||||
+264
-217
@@ -81,6 +81,9 @@
|
||||
#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
||||
#endif /* SQLITE_THREADSAFE==0 */
|
||||
|
||||
/* First chunk for rollback journal files */
|
||||
#define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400
|
||||
|
||||
|
||||
/************************ Shim Definitions ******************************/
|
||||
|
||||
@@ -96,26 +99,16 @@
|
||||
# define SQLITE_MULTIPLEX_CHUNK_SIZE 2147418112
|
||||
#endif
|
||||
|
||||
/* Default limit on number of chunks. Care should be taken
|
||||
** so that values for chunks numbers fit in the SQLITE_MULTIPLEX_EXT_FMT
|
||||
** format specifier. It may be changed by calling
|
||||
** the xFileControl() interface.
|
||||
/* This used to be the default limit on number of chunks, but
|
||||
** it is no longer enforced. There is currently no limit to the
|
||||
** number of chunks.
|
||||
**
|
||||
** May be changed by calling the xFileControl() interface.
|
||||
*/
|
||||
#ifndef SQLITE_MULTIPLEX_MAX_CHUNKS
|
||||
# define SQLITE_MULTIPLEX_MAX_CHUNKS 32
|
||||
# define SQLITE_MULTIPLEX_MAX_CHUNKS 12
|
||||
#endif
|
||||
|
||||
/* If SQLITE_MULTIPLEX_EXT_OVWR is defined, the
|
||||
** last SQLITE_MULTIPLEX_EXT_SZ characters of the
|
||||
** filename will be overwritten, otherwise, the
|
||||
** multiplex extension is simply appended to the filename.
|
||||
** Ex. (undefined) test.db -> test.db01
|
||||
** (defined) test.db -> test.01
|
||||
** Chunk 0 does not have a modified extension.
|
||||
*/
|
||||
#define SQLITE_MULTIPLEX_EXT_FMT "%02d"
|
||||
#define SQLITE_MULTIPLEX_EXT_SZ 2
|
||||
|
||||
/************************ Object Definitions ******************************/
|
||||
|
||||
/* Forward declaration of all object types */
|
||||
@@ -140,7 +133,8 @@ struct multiplexGroup {
|
||||
int nName; /* Length of base filename */
|
||||
int flags; /* Flags used for original opening */
|
||||
unsigned int szChunk; /* Chunk size used for this group */
|
||||
int bEnabled; /* TRUE to use Multiplex VFS for this file */
|
||||
unsigned char bEnabled; /* TRUE to use Multiplex VFS for this file */
|
||||
unsigned char bTruncate; /* TRUE to enable truncation of databases */
|
||||
multiplexGroup *pNext, *pPrev; /* Doubly linked list of all group objects */
|
||||
};
|
||||
|
||||
@@ -224,68 +218,36 @@ static int multiplexStrlen30(const char *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at pOrigVfs->mxPathname 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.
|
||||
** Generate the file-name for chunk iChunk of the group with base name
|
||||
** zBase. The file-name is written to buffer zOut before returning. Buffer
|
||||
** zOut must be allocated by the caller so that it is at least (nBase+4)
|
||||
** bytes in size, where nBase is the length of zBase, not including the
|
||||
** nul-terminator.
|
||||
*/
|
||||
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++){
|
||||
unsigned char uc = (unsigned char)zBuf[j+i];
|
||||
zBuf[j+i] = (char)zChars[uc%(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;
|
||||
}
|
||||
static void multiplexFilename(
|
||||
const char *zBase, /* Filename for chunk 0 */
|
||||
int nBase, /* Size of zBase in bytes (without \0) */
|
||||
int flags, /* Flags used to open file */
|
||||
int iChunk, /* Chunk to generate filename for */
|
||||
char *zOut /* Buffer to write generated name to */
|
||||
){
|
||||
memcpy(zOut, zBase, nBase+1);
|
||||
if( iChunk!=0 && iChunk!=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
|
||||
int n = nBase;
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
int i;
|
||||
for(i=n-1; i>0 && i>=n-4 && zOut[i]!='.'; i--){}
|
||||
if( i>=n-4 ) n = i+1;
|
||||
if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
|
||||
/* The extensions on overflow files for main databases are 001, 002,
|
||||
** 003 and so forth. To avoid name collisions, add 400 to the
|
||||
** extensions of journal files so that they are 401, 402, 403, ....
|
||||
*/
|
||||
iChunk += SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET;
|
||||
}
|
||||
#endif
|
||||
sqlite3_snprintf(4,&zOut[n],"%03d",iChunk);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Compute the filename for the iChunk-th chunk
|
||||
@@ -301,50 +263,80 @@ static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
|
||||
pGroup->aReal = p;
|
||||
pGroup->nReal = iChunk+1;
|
||||
}
|
||||
if( pGroup->aReal[iChunk].z==0 ){
|
||||
if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
|
||||
char *z;
|
||||
int n = pGroup->nName;
|
||||
pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+3 );
|
||||
pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 );
|
||||
if( z==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memcpy(z, pGroup->zName, n+1);
|
||||
if( iChunk>0 ){
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
if( n>3 && z[n-3]=='.' ){
|
||||
n--;
|
||||
}else if( n>4 && z[n-4]=='.' ){
|
||||
n -= 2;
|
||||
}
|
||||
#endif
|
||||
sqlite3_snprintf(3,&z[n],"%02d",iChunk);
|
||||
}
|
||||
multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Translate an sqlite3_file* that is really a multiplexGroup* into
|
||||
** the sqlite3_file* for the underlying original VFS.
|
||||
**
|
||||
** For chunk 0, the pGroup->flags determines whether or not a new file
|
||||
** is created if it does not already exist. For chunks 1 and higher, the
|
||||
** file is created only if createFlag is 1.
|
||||
*/
|
||||
static sqlite3_file *multiplexSubOpen(
|
||||
multiplexGroup *pGroup,
|
||||
int iChunk,
|
||||
int *rc,
|
||||
int *pOutFlags
|
||||
multiplexGroup *pGroup, /* The multiplexor group */
|
||||
int iChunk, /* Which chunk to open. 0==original file */
|
||||
int *rc, /* Result code in and out */
|
||||
int *pOutFlags, /* Output flags */
|
||||
int createFlag /* True to create if iChunk>0 */
|
||||
){
|
||||
sqlite3_file *pSubOpen = 0;
|
||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
/* If JOURNAL_8_3_OFFSET is set to (say) 400, then any overflow files are
|
||||
** part of a database journal are named db.401, db.402, and so on. A
|
||||
** database may therefore not grow to larger than 400 chunks. Attempting
|
||||
** to open chunk 401 indicates the database is full. */
|
||||
if( iChunk>=SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET ){
|
||||
sqlite3_log(SQLITE_FULL, "multiplexed chunk overflow: %s", pGroup->zName);
|
||||
*rc = SQLITE_FULL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
*rc = multiplexSubFilename(pGroup, iChunk);
|
||||
if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
|
||||
int flags, bExists;
|
||||
flags = pGroup->flags;
|
||||
if( createFlag ){
|
||||
flags |= SQLITE_OPEN_CREATE;
|
||||
}else if( iChunk==0 ){
|
||||
/* Fall through */
|
||||
}else if( pGroup->aReal[iChunk].z==0 ){
|
||||
return 0;
|
||||
}else{
|
||||
*rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
|
||||
SQLITE_ACCESS_EXISTS, &bExists);
|
||||
if( *rc || !bExists ){
|
||||
if( *rc ){
|
||||
sqlite3_log(*rc, "multiplexor.xAccess failure on %s",
|
||||
pGroup->aReal[iChunk].z);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
flags &= ~SQLITE_OPEN_CREATE;
|
||||
}
|
||||
pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile );
|
||||
if( pSubOpen==0 ){
|
||||
*rc = SQLITE_NOMEM;
|
||||
*rc = SQLITE_IOERR_NOMEM;
|
||||
return 0;
|
||||
}
|
||||
pGroup->aReal[iChunk].p = pSubOpen;
|
||||
*rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
|
||||
pGroup->flags, pOutFlags);
|
||||
if( *rc!=SQLITE_OK ){
|
||||
flags, pOutFlags);
|
||||
if( (*rc)!=SQLITE_OK ){
|
||||
sqlite3_log(*rc, "multiplexor.xOpen failure on %s",
|
||||
pGroup->aReal[iChunk].z);
|
||||
sqlite3_free(pSubOpen);
|
||||
pGroup->aReal[iChunk].p = 0;
|
||||
return 0;
|
||||
@@ -353,6 +345,25 @@ static sqlite3_file *multiplexSubOpen(
|
||||
return pSubOpen;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the size, in bytes, of chunk number iChunk. If that chunk
|
||||
** does not exist, then return 0. This function does not distingish between
|
||||
** non-existant files and zero-length files.
|
||||
*/
|
||||
static sqlite3_int64 multiplexSubSize(
|
||||
multiplexGroup *pGroup, /* The multiplexor group */
|
||||
int iChunk, /* Which chunk to open. 0==original file */
|
||||
int *rc /* Result code in and out */
|
||||
){
|
||||
sqlite3_file *pSub;
|
||||
sqlite3_int64 sz = 0;
|
||||
|
||||
pSub = multiplexSubOpen(pGroup, iChunk, rc, NULL, 0);
|
||||
if( pSub==0 ) return 0;
|
||||
*rc = pSub->pMethods->xFileSize(pSub, &sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the implementation of the multiplex_control() SQL function.
|
||||
*/
|
||||
@@ -420,7 +431,9 @@ static void multiplexSubClose(
|
||||
sqlite3_file *pSubOpen = pGroup->aReal[iChunk].p;
|
||||
if( pSubOpen ){
|
||||
pSubOpen->pMethods->xClose(pSubOpen);
|
||||
if( pOrigVfs ) pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
|
||||
if( pOrigVfs && pGroup->aReal[iChunk].z ){
|
||||
pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
|
||||
}
|
||||
sqlite3_free(pGroup->aReal[iChunk].p);
|
||||
}
|
||||
sqlite3_free(pGroup->aReal[iChunk].z);
|
||||
@@ -466,6 +479,7 @@ static int multiplexOpen(
|
||||
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
memset(pConn, 0, pVfs->szOsFile);
|
||||
assert( zName || (flags & SQLITE_OPEN_DELETEONCLOSE) );
|
||||
|
||||
/* We need to create a group structure and manage
|
||||
** access to this group of files.
|
||||
@@ -473,23 +487,9 @@ static int multiplexOpen(
|
||||
multiplexEnter();
|
||||
pMultiplexOpen = (multiplexConn*)pConn;
|
||||
|
||||
/* 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 ){
|
||||
zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 );
|
||||
if( zName==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* allocate space for group */
|
||||
nName = multiplexStrlen30(zName);
|
||||
nName = zName ? multiplexStrlen30(zName) : 0;
|
||||
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
||||
+ nName + 1; /* zName */
|
||||
pGroup = sqlite3_malloc( sz );
|
||||
@@ -500,62 +500,100 @@ static int multiplexOpen(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* assign pointers to extra space allocated */
|
||||
char *p = (char *)&pGroup[1];
|
||||
pMultiplexOpen->pGroup = pGroup;
|
||||
memset(pGroup, 0, sz);
|
||||
pMultiplexOpen->pGroup = pGroup;
|
||||
pGroup->bEnabled = -1;
|
||||
pGroup->bTruncate = (flags & SQLITE_OPEN_MAIN_DB)==0;
|
||||
pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE;
|
||||
if( flags & SQLITE_OPEN_URI ){
|
||||
const char *zChunkSize;
|
||||
zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
|
||||
if( zChunkSize ){
|
||||
unsigned int n = 0;
|
||||
int i;
|
||||
for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){
|
||||
n = n*10 + zChunkSize[i] - '0';
|
||||
}
|
||||
if( n>0 ){
|
||||
pGroup->szChunk = (n+0xffff)&~0xffff;
|
||||
}else{
|
||||
/* A zero or negative chunksize disabled the multiplexor */
|
||||
pGroup->bEnabled = 0;
|
||||
|
||||
if( zName ){
|
||||
char *p = (char *)&pGroup[1];
|
||||
if( flags & SQLITE_OPEN_URI ){
|
||||
const char *zChunkSize;
|
||||
zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
|
||||
if( zChunkSize ){
|
||||
unsigned int n = 0;
|
||||
int i;
|
||||
for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){
|
||||
n = n*10 + zChunkSize[i] - '0';
|
||||
}
|
||||
if( n>0 ){
|
||||
pGroup->szChunk = (n+0xffff)&~0xffff;
|
||||
}else{
|
||||
/* A zero or negative chunksize disabled the multiplexor */
|
||||
pGroup->bEnabled = 0;
|
||||
}
|
||||
}
|
||||
if( sqlite3_uri_parameter(zName, "truncate") ) pGroup->bTruncate = 1;
|
||||
}
|
||||
pGroup->zName = p;
|
||||
memcpy(pGroup->zName, zName, nName+1);
|
||||
pGroup->nName = nName;
|
||||
}
|
||||
if( pGroup->bEnabled ){
|
||||
/* Make sure that the chunksize is not such that the pending byte
|
||||
** falls at the end of a chunk. A region of up to 64K following
|
||||
** the pending byte is never written, so if the pending byte occurs
|
||||
** near the end of a chunk, that chunk will be too small. */
|
||||
extern int sqlite3PendingByte;
|
||||
while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){
|
||||
pGroup->szChunk += 65536;
|
||||
}
|
||||
}
|
||||
pGroup->zName = p;
|
||||
/* save off base filename, name length, and original open flags */
|
||||
memcpy(pGroup->zName, zName, nName+1);
|
||||
pGroup->nName = nName;
|
||||
pGroup->flags = flags;
|
||||
rc = multiplexSubFilename(pGroup, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
|
||||
pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0);
|
||||
if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN;
|
||||
}
|
||||
if( pSubOpen ){
|
||||
int exists, rc2, rc3;
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_int64 sz;
|
||||
|
||||
rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
|
||||
if( rc2==SQLITE_OK ){
|
||||
/* If the first overflow file exists and if the size of the main file
|
||||
** is different from the chunk size, that means the chunk size is set
|
||||
** set incorrectly. So fix it.
|
||||
**
|
||||
** Or, if the first overflow file does not exist and the main file is
|
||||
** larger than the chunk size, that means the chunk size is too small.
|
||||
** But we have no way of determining the intended chunk size, so
|
||||
** just disable the multiplexor all togethre.
|
||||
*/
|
||||
rc3 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
|
||||
SQLITE_ACCESS_EXISTS, &exists);
|
||||
if( rc3==SQLITE_OK && exists && sz==(sz&0xffff0000) && sz>0
|
||||
&& sz!=pGroup->szChunk ){
|
||||
pGroup->szChunk = sz;
|
||||
}else if( rc3==SQLITE_OK && !exists && sz>pGroup->szChunk ){
|
||||
pGroup->bEnabled = 0;
|
||||
rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
|
||||
if( rc==SQLITE_OK && zName ){
|
||||
int bExists;
|
||||
if( sz==0 ){
|
||||
if( flags & SQLITE_OPEN_MAIN_JOURNAL ){
|
||||
/* If opening a main journal file and the first chunk is zero
|
||||
** bytes in size, delete any subsequent chunks from the
|
||||
** file-system. */
|
||||
int iChunk = 1;
|
||||
do {
|
||||
rc = pOrigVfs->xAccess(pOrigVfs,
|
||||
pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists
|
||||
);
|
||||
if( rc==SQLITE_OK && bExists ){
|
||||
rc = pOrigVfs->xDelete(pOrigVfs, pGroup->aReal[iChunk].z, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = multiplexSubFilename(pGroup, ++iChunk);
|
||||
}
|
||||
}
|
||||
}while( rc==SQLITE_OK && bExists );
|
||||
}
|
||||
}else{
|
||||
/* If the first overflow file exists and if the size of the main file
|
||||
** is different from the chunk size, that means the chunk size is set
|
||||
** set incorrectly. So fix it.
|
||||
**
|
||||
** Or, if the first overflow file does not exist and the main file is
|
||||
** larger than the chunk size, that means the chunk size is too small.
|
||||
** But we have no way of determining the intended chunk size, so
|
||||
** just disable the multiplexor all togethre.
|
||||
*/
|
||||
rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z,
|
||||
SQLITE_ACCESS_EXISTS, &bExists);
|
||||
bExists = multiplexSubSize(pGroup, 1, &rc)>0;
|
||||
if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0
|
||||
&& sz!=pGroup->szChunk ){
|
||||
pGroup->szChunk = sz;
|
||||
}else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){
|
||||
pGroup->bEnabled = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pSubOpen->pMethods->iVersion==1 ){
|
||||
pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1;
|
||||
}else{
|
||||
@@ -584,8 +622,33 @@ static int multiplexDelete(
|
||||
const char *zName, /* Name of file to delete */
|
||||
int syncDir
|
||||
){
|
||||
int rc;
|
||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||
return pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
|
||||
rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir);
|
||||
if( rc==SQLITE_OK ){
|
||||
/* If the main chunk was deleted successfully, also delete any subsequent
|
||||
** chunks - starting with the last (highest numbered).
|
||||
*/
|
||||
int nName = strlen(zName);
|
||||
char *z;
|
||||
z = sqlite3_malloc(nName + 4);
|
||||
if( z==0 ){
|
||||
rc = SQLITE_IOERR_NOMEM;
|
||||
}else{
|
||||
int iChunk = 0;
|
||||
int bExists;
|
||||
do{
|
||||
multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z);
|
||||
rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists);
|
||||
}while( rc==SQLITE_OK && bExists );
|
||||
while( rc==SQLITE_OK && iChunk>1 ){
|
||||
multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, --iChunk, z);
|
||||
rc = pOrigVfs->xDelete(pOrigVfs, z, syncDir);
|
||||
}
|
||||
}
|
||||
sqlite3_free(z);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int multiplexAccess(sqlite3_vfs *a, const char *b, int c, int *d){
|
||||
@@ -662,7 +725,7 @@ static int multiplexRead(
|
||||
int rc = SQLITE_OK;
|
||||
multiplexEnter();
|
||||
if( !pGroup->bEnabled ){
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen==0 ){
|
||||
rc = SQLITE_IOERR_READ;
|
||||
}else{
|
||||
@@ -671,7 +734,7 @@ static int multiplexRead(
|
||||
}else{
|
||||
while( iAmt > 0 ){
|
||||
int i = (int)(iOfst / pGroup->szChunk);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
|
||||
if( pSubOpen ){
|
||||
int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk;
|
||||
if( extra<0 ) extra = 0;
|
||||
@@ -707,16 +770,16 @@ static int multiplexWrite(
|
||||
int rc = SQLITE_OK;
|
||||
multiplexEnter();
|
||||
if( !pGroup->bEnabled ){
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen==0 ){
|
||||
rc = SQLITE_IOERR_WRITE;
|
||||
}else{
|
||||
rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst);
|
||||
}
|
||||
}else{
|
||||
while( iAmt > 0 ){
|
||||
while( rc==SQLITE_OK && iAmt>0 ){
|
||||
int i = (int)(iOfst / pGroup->szChunk);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1);
|
||||
if( pSubOpen ){
|
||||
int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) -
|
||||
pGroup->szChunk;
|
||||
@@ -724,13 +787,9 @@ static int multiplexWrite(
|
||||
iAmt -= extra;
|
||||
rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt,
|
||||
iOfst % pGroup->szChunk);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
pBuf = (char *)pBuf + iAmt;
|
||||
iOfst += iAmt;
|
||||
iAmt = extra;
|
||||
}else{
|
||||
rc = SQLITE_IOERR_WRITE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -748,28 +807,35 @@ static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){
|
||||
int rc = SQLITE_OK;
|
||||
multiplexEnter();
|
||||
if( !pGroup->bEnabled ){
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen==0 ){
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
}else{
|
||||
rc = pSubOpen->pMethods->xTruncate(pSubOpen, size);
|
||||
}
|
||||
}else{
|
||||
int rc2;
|
||||
int i;
|
||||
int iBaseGroup = (int)(size / pGroup->szChunk);
|
||||
sqlite3_file *pSubOpen;
|
||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||
/* delete the chunks above the truncate limit */
|
||||
for(i=(int)(size / pGroup->szChunk)+1; i<pGroup->nReal; i++){
|
||||
multiplexSubClose(pGroup, i, pOrigVfs);
|
||||
for(i = pGroup->nReal-1; i>iBaseGroup && rc==SQLITE_OK; i--){
|
||||
if( pGroup->bTruncate ){
|
||||
multiplexSubClose(pGroup, i, pOrigVfs);
|
||||
}else{
|
||||
pSubOpen = multiplexSubOpen(pGroup, i, &rc, 0, 0);
|
||||
if( pSubOpen ){
|
||||
rc = pSubOpen->pMethods->xTruncate(pSubOpen, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
pSubOpen = multiplexSubOpen(pGroup, (int)(size/pGroup->szChunk), &rc2,0);
|
||||
if( pSubOpen ){
|
||||
rc2 = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
|
||||
if( rc2!=SQLITE_OK ) rc = rc2;
|
||||
}else{
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
if( rc==SQLITE_OK ){
|
||||
pSubOpen = multiplexSubOpen(pGroup, iBaseGroup, &rc, 0, 0);
|
||||
if( pSubOpen ){
|
||||
rc = pSubOpen->pMethods->xTruncate(pSubOpen, size % pGroup->szChunk);
|
||||
}
|
||||
}
|
||||
if( rc ) rc = SQLITE_IOERR_TRUNCATE;
|
||||
}
|
||||
multiplexLeave();
|
||||
return rc;
|
||||
@@ -801,47 +867,21 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
multiplexGroup *pGroup = p->pGroup;
|
||||
int rc = SQLITE_OK;
|
||||
int rc2;
|
||||
int i;
|
||||
multiplexEnter();
|
||||
if( !pGroup->bEnabled ){
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen==0 ){
|
||||
rc = SQLITE_IOERR_FSTAT;
|
||||
}else{
|
||||
rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
|
||||
}
|
||||
}else{
|
||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
|
||||
*pSize = 0;
|
||||
for(i=0; 1; i++){
|
||||
sqlite3_file *pSubOpen = 0;
|
||||
int exists = 0;
|
||||
rc = multiplexSubFilename(pGroup, i);
|
||||
if( rc ) break;
|
||||
rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z,
|
||||
SQLITE_ACCESS_EXISTS, &exists);
|
||||
if( rc2==SQLITE_OK && exists){
|
||||
/* if it exists, open it */
|
||||
pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
|
||||
}else{
|
||||
/* stop at first "gap" */
|
||||
break;
|
||||
}
|
||||
if( pSubOpen ){
|
||||
sqlite3_int64 sz;
|
||||
rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
|
||||
if( rc2!=SQLITE_OK ){
|
||||
rc = rc2;
|
||||
}else{
|
||||
if( sz>pGroup->szChunk ){
|
||||
rc = SQLITE_IOERR_FSTAT;
|
||||
}
|
||||
*pSize += sz;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
for(i=0; rc==SQLITE_OK; i++){
|
||||
sqlite3_int64 sz = multiplexSubSize(pGroup, i, &rc);
|
||||
if( sz==0 ) break;
|
||||
*pSize = i*(sqlite3_int64)pGroup->szChunk + sz;
|
||||
}
|
||||
}
|
||||
multiplexLeave();
|
||||
@@ -853,7 +893,7 @@ static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
|
||||
static int multiplexLock(sqlite3_file *pConn, int lock){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xLock(pSubOpen, lock);
|
||||
}
|
||||
@@ -865,7 +905,7 @@ static int multiplexLock(sqlite3_file *pConn, int lock){
|
||||
static int multiplexUnlock(sqlite3_file *pConn, int lock){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xUnlock(pSubOpen, lock);
|
||||
}
|
||||
@@ -877,7 +917,7 @@ static int multiplexUnlock(sqlite3_file *pConn, int lock){
|
||||
static int multiplexCheckReservedLock(sqlite3_file *pConn, int *pResOut){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xCheckReservedLock(pSubOpen, pResOut);
|
||||
}
|
||||
@@ -925,9 +965,12 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
rc = SQLITE_OK;
|
||||
break;
|
||||
default:
|
||||
pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
|
||||
pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
|
||||
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
||||
*(char**)pArg = sqlite3_mprintf("multiplex/%z", *(char**)pArg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -939,8 +982,8 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
static int multiplexSectorSize(sqlite3_file *pConn){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
if( pSubOpen ){
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen && pSubOpen->pMethods->xSectorSize ){
|
||||
return pSubOpen->pMethods->xSectorSize(pSubOpen);
|
||||
}
|
||||
return DEFAULT_SECTOR_SIZE;
|
||||
@@ -951,7 +994,7 @@ static int multiplexSectorSize(sqlite3_file *pConn){
|
||||
static int multiplexDeviceCharacteristics(sqlite3_file *pConn){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xDeviceCharacteristics(pSubOpen);
|
||||
}
|
||||
@@ -969,7 +1012,7 @@ static int multiplexShmMap(
|
||||
){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xShmMap(pSubOpen, iRegion, szRegion, bExtend,pp);
|
||||
}
|
||||
@@ -986,7 +1029,7 @@ static int multiplexShmLock(
|
||||
){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xShmLock(pSubOpen, ofst, n, flags);
|
||||
}
|
||||
@@ -998,7 +1041,7 @@ static int multiplexShmLock(
|
||||
static void multiplexShmBarrier(sqlite3_file *pConn){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
pSubOpen->pMethods->xShmBarrier(pSubOpen);
|
||||
}
|
||||
@@ -1009,7 +1052,7 @@ static void multiplexShmBarrier(sqlite3_file *pConn){
|
||||
static int multiplexShmUnmap(sqlite3_file *pConn, int deleteFlag){
|
||||
multiplexConn *p = (multiplexConn*)pConn;
|
||||
int rc;
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL);
|
||||
sqlite3_file *pSubOpen = multiplexSubOpen(p->pGroup, 0, &rc, NULL, 0);
|
||||
if( pSubOpen ){
|
||||
return pSubOpen->pMethods->xShmUnmap(pSubOpen, deleteFlag);
|
||||
}
|
||||
@@ -1191,9 +1234,13 @@ static int test_multiplex_dump(
|
||||
for(pGroup=gMultiplex.pGroups; pGroup; pGroup=pGroup->pNext){
|
||||
pGroupTerm = Tcl_NewObj();
|
||||
|
||||
pGroup->zName[pGroup->nName] = '\0';
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||
if( pGroup->zName ){
|
||||
pGroup->zName[pGroup->nName] = '\0';
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||
Tcl_NewStringObj(pGroup->zName, -1));
|
||||
}else{
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_NewObj());
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||
Tcl_NewIntObj(pGroup->nName));
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||
|
||||
+5
-1
@@ -389,7 +389,11 @@ static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
*/
|
||||
static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
VfslogFile *p = (VfslogFile *)pFile;
|
||||
return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
||||
int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
||||
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
||||
*(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+30
-21
@@ -100,15 +100,16 @@ static void testpcacheShutdown(void *pArg){
|
||||
typedef struct testpcache testpcache;
|
||||
struct testpcache {
|
||||
int szPage; /* Size of each page. Multiple of 8. */
|
||||
int szExtra; /* Size of extra data that accompanies each page */
|
||||
int bPurgeable; /* True if the page cache is purgeable */
|
||||
int nFree; /* Number of unused slots in a[] */
|
||||
int nPinned; /* Number of pinned slots in a[] */
|
||||
unsigned iRand; /* State of the PRNG */
|
||||
unsigned iMagic; /* Magic number for sanity checking */
|
||||
struct testpcachePage {
|
||||
sqlite3_pcache_page page; /* Base class */
|
||||
unsigned key; /* The key for this page. 0 means unallocated */
|
||||
int isPinned; /* True if the page is pinned */
|
||||
void *pData; /* Data for this page */
|
||||
} a[TESTPCACHE_NPAGE]; /* All pages in the cache */
|
||||
};
|
||||
|
||||
@@ -129,27 +130,33 @@ static unsigned testpcacheRandom(testpcache *p){
|
||||
/*
|
||||
** Allocate a new page cache instance.
|
||||
*/
|
||||
static sqlite3_pcache *testpcacheCreate(int szPage, int bPurgeable){
|
||||
static sqlite3_pcache *testpcacheCreate(
|
||||
int szPage,
|
||||
int szExtra,
|
||||
int bPurgeable
|
||||
){
|
||||
int nMem;
|
||||
char *x;
|
||||
testpcache *p;
|
||||
int i;
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
szPage = (szPage+7)&~7;
|
||||
nMem = sizeof(testpcache) + TESTPCACHE_NPAGE*szPage;
|
||||
nMem = sizeof(testpcache) + TESTPCACHE_NPAGE*(szPage+szExtra);
|
||||
p = sqlite3_malloc( nMem );
|
||||
if( p==0 ) return 0;
|
||||
x = (char*)&p[1];
|
||||
p->szPage = szPage;
|
||||
p->szExtra = szExtra;
|
||||
p->nFree = TESTPCACHE_NPAGE;
|
||||
p->nPinned = 0;
|
||||
p->iRand = testpcacheGlobal.prngSeed;
|
||||
p->bPurgeable = bPurgeable;
|
||||
p->iMagic = TESTPCACHE_VALID;
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++, x += szPage){
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++, x += (szPage+szExtra)){
|
||||
p->a[i].key = 0;
|
||||
p->a[i].isPinned = 0;
|
||||
p->a[i].pData = (void*)x;
|
||||
p->a[i].page.pBuf = (void*)x;
|
||||
p->a[i].page.pExtra = (void*)&x[szPage];
|
||||
}
|
||||
testpcacheGlobal.nInstance++;
|
||||
return (sqlite3_pcache*)p;
|
||||
@@ -161,7 +168,6 @@ static sqlite3_pcache *testpcacheCreate(int szPage, int bPurgeable){
|
||||
static void testpcacheCachesize(sqlite3_pcache *pCache, int newSize){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
assert( p->iMagic==TESTPCACHE_VALID );
|
||||
assert( newSize>=1 );
|
||||
assert( testpcacheGlobal.pDummy!=0 );
|
||||
assert( testpcacheGlobal.nInstance>0 );
|
||||
}
|
||||
@@ -181,7 +187,7 @@ static int testpcachePagecount(sqlite3_pcache *pCache){
|
||||
/*
|
||||
** Fetch a page.
|
||||
*/
|
||||
static void *testpcacheFetch(
|
||||
static sqlite3_pcache_page *testpcacheFetch(
|
||||
sqlite3_pcache *pCache,
|
||||
unsigned key,
|
||||
int createFlag
|
||||
@@ -200,7 +206,7 @@ static void *testpcacheFetch(
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
p->a[i].isPinned = 1;
|
||||
}
|
||||
return p->a[i].pData;
|
||||
return &p->a[i].page;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,11 +243,12 @@ static void *testpcacheFetch(
|
||||
if( p->a[j].key==0 ){
|
||||
p->a[j].key = key;
|
||||
p->a[j].isPinned = 1;
|
||||
memset(p->a[j].pData, 0, p->szPage);
|
||||
memset(p->a[j].page.pBuf, 0, p->szPage);
|
||||
memset(p->a[j].page.pExtra, 0, p->szExtra);
|
||||
p->nPinned++;
|
||||
p->nFree--;
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
return p->a[j].pData;
|
||||
return &p->a[j].page;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,10 +270,11 @@ static void *testpcacheFetch(
|
||||
if( p->a[j].key>0 && p->a[j].isPinned==0 ){
|
||||
p->a[j].key = key;
|
||||
p->a[j].isPinned = 1;
|
||||
memset(p->a[j].pData, 0, p->szPage);
|
||||
memset(p->a[j].page.pBuf, 0, p->szPage);
|
||||
memset(p->a[j].page.pExtra, 0, p->szExtra);
|
||||
p->nPinned++;
|
||||
assert( p->nPinned <= TESTPCACHE_NPAGE - p->nFree );
|
||||
return p->a[j].pData;
|
||||
return &p->a[j].page;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +288,7 @@ static void *testpcacheFetch(
|
||||
*/
|
||||
static void testpcacheUnpin(
|
||||
sqlite3_pcache *pCache,
|
||||
void *pOldPage,
|
||||
sqlite3_pcache_page *pOldPage,
|
||||
int discard
|
||||
){
|
||||
testpcache *p = (testpcache*)pCache;
|
||||
@@ -300,7 +308,7 @@ static void testpcacheUnpin(
|
||||
}
|
||||
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].pData==pOldPage ){
|
||||
if( &p->a[i].page==pOldPage ){
|
||||
/* The pOldPage pointer always points to a pinned page */
|
||||
assert( p->a[i].isPinned );
|
||||
p->a[i].isPinned = 0;
|
||||
@@ -325,7 +333,7 @@ static void testpcacheUnpin(
|
||||
*/
|
||||
static void testpcacheRekey(
|
||||
sqlite3_pcache *pCache,
|
||||
void *pOldPage,
|
||||
sqlite3_pcache_page *pOldPage,
|
||||
unsigned oldKey,
|
||||
unsigned newKey
|
||||
){
|
||||
@@ -354,7 +362,7 @@ static void testpcacheRekey(
|
||||
for(i=0; i<TESTPCACHE_NPAGE; i++){
|
||||
if( p->a[i].key==oldKey ){
|
||||
/* The oldKey and pOldPage parameters match */
|
||||
assert( p->a[i].pData==pOldPage );
|
||||
assert( &p->a[i].page==pOldPage );
|
||||
/* Page to be rekeyed must be pinned */
|
||||
assert( p->a[i].isPinned );
|
||||
p->a[i].key = newKey;
|
||||
@@ -422,7 +430,8 @@ void installTestPCache(
|
||||
unsigned prngSeed, /* Seed for the PRNG */
|
||||
unsigned highStress /* Call xStress agressively */
|
||||
){
|
||||
static const sqlite3_pcache_methods testPcache = {
|
||||
static const sqlite3_pcache_methods2 testPcache = {
|
||||
1,
|
||||
(void*)&testpcacheGlobal,
|
||||
testpcacheInit,
|
||||
testpcacheShutdown,
|
||||
@@ -435,7 +444,7 @@ void installTestPCache(
|
||||
testpcacheTruncate,
|
||||
testpcacheDestroy,
|
||||
};
|
||||
static sqlite3_pcache_methods defaultPcache;
|
||||
static sqlite3_pcache_methods2 defaultPcache;
|
||||
static int isInstalled = 0;
|
||||
|
||||
assert( testpcacheGlobal.nInstance==0 );
|
||||
@@ -446,12 +455,12 @@ void installTestPCache(
|
||||
testpcacheGlobal.highStress = highStress;
|
||||
if( installFlag!=isInstalled ){
|
||||
if( installFlag ){
|
||||
sqlite3_config(SQLITE_CONFIG_GETPCACHE, &defaultPcache);
|
||||
sqlite3_config(SQLITE_CONFIG_GETPCACHE2, &defaultPcache);
|
||||
assert( defaultPcache.xCreate!=testpcacheCreate );
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &testPcache);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE2, &testPcache);
|
||||
}else{
|
||||
assert( defaultPcache.xCreate!=0 );
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE, &defaultPcache);
|
||||
sqlite3_config(SQLITE_CONFIG_PCACHE2, &defaultPcache);
|
||||
}
|
||||
isInstalled = installFlag;
|
||||
}
|
||||
|
||||
+5
-1
@@ -589,7 +589,11 @@ static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){
|
||||
*/
|
||||
static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
sqlite3_file *pSubOpen = quotaSubOpen(pConn);
|
||||
return pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
|
||||
int rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
|
||||
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
||||
*(char**)pArg = sqlite3_mprintf("quota/%z", *(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Pass xSectorSize requests through to the original VFS unchanged.
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
||||
|
||||
/* The default page size and offset */
|
||||
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
|
||||
pCsr->iOffset = pCsr->szPage * (pCsr->iPageno - 1);
|
||||
pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
|
||||
|
||||
/* If connected to a ZIPVFS backend, override the page size and
|
||||
** offset with actual values obtained from ZIPVFS.
|
||||
|
||||
@@ -471,6 +471,10 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
}
|
||||
case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: zOp = "SYNC_OMITTED"; break;
|
||||
case SQLITE_FCNTL_WIN32_AV_RETRY: zOp = "WIN32_AV_RETRY"; break;
|
||||
case SQLITE_FCNTL_PERSIST_WAL: zOp = "PERSIST_WAL"; break;
|
||||
case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
|
||||
case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
|
||||
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
|
||||
default: {
|
||||
sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
|
||||
@@ -482,6 +486,10 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
pInfo->zVfsName, p->zFName, zOp);
|
||||
rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
||||
*(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
|
||||
pInfo->zVfsName, *(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,6 +1169,7 @@ int sqlite3AbsInt32(int x){
|
||||
** test.db-journal => test.nal
|
||||
** test.db-wal => test.wal
|
||||
** test.db-shm => test.shm
|
||||
** test.db-mj7f3319fa => test.9fa
|
||||
*/
|
||||
void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
|
||||
#if SQLITE_ENABLE_8_3_NAMES<2
|
||||
|
||||
+2
-2
@@ -4616,9 +4616,9 @@ case OP_IdxGE: { /* jump */
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
if( pOp->p5 ){
|
||||
r.flags = UNPACKED_INCRKEY | UNPACKED_IGNORE_ROWID;
|
||||
r.flags = UNPACKED_INCRKEY | UNPACKED_PREFIX_MATCH;
|
||||
}else{
|
||||
r.flags = UNPACKED_IGNORE_ROWID;
|
||||
r.flags = UNPACKED_PREFIX_MATCH;
|
||||
}
|
||||
r.aMem = &aMem[pOp->p3];
|
||||
#ifdef SQLITE_DEBUG
|
||||
|
||||
+16
-18
@@ -1824,16 +1824,26 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
sqlite3_file *pMaster = 0;
|
||||
i64 offset = 0;
|
||||
int res;
|
||||
int retryCount = 0;
|
||||
int nMainFile;
|
||||
|
||||
/* Select a master journal file name */
|
||||
nMainFile = sqlite3Strlen30(zMainFile);
|
||||
zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XX", zMainFile);
|
||||
if( zMaster==0 ) return SQLITE_NOMEM;
|
||||
do {
|
||||
u32 iRandom;
|
||||
sqlite3DbFree(db, zMaster);
|
||||
sqlite3_randomness(sizeof(iRandom), &iRandom);
|
||||
zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff);
|
||||
if( !zMaster ){
|
||||
return SQLITE_NOMEM;
|
||||
if( retryCount++>100 ){
|
||||
sqlite3_log(SQLITE_FULL, "cannot find unique master-journal");
|
||||
sqlite3OsDelete(pVfs, zMaster, 0);
|
||||
break;
|
||||
}
|
||||
sqlite3_randomness(sizeof(iRandom), &iRandom);
|
||||
sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
|
||||
(iRandom>>8)&0xffffff, iRandom&0xff);
|
||||
/* The antipenultimate character of the master journal name must
|
||||
** be "9" to avoid name collisions when using 8+3 filenames. */
|
||||
assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
|
||||
sqlite3FileSuffix3(zMainFile, zMaster);
|
||||
rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
|
||||
}while( rc==SQLITE_OK && res );
|
||||
@@ -2943,15 +2953,6 @@ void sqlite3VdbeRecordUnpack(
|
||||
** Or if the UNPACKED_MATCH_PREFIX flag is set and the prefixes are
|
||||
** equal, then the keys are considered to be equal and
|
||||
** the parts beyond the common prefix are ignored.
|
||||
**
|
||||
** If the UNPACKED_IGNORE_ROWID flag is set, then the last byte of
|
||||
** the header of pKey1 is ignored. It is assumed that pKey1 is
|
||||
** an index key, and thus ends with a rowid value. The last byte
|
||||
** of the header will therefore be the serial type of the rowid:
|
||||
** one of 1, 2, 3, 4, 5, 6, 8, or 9 - the integer serial types.
|
||||
** The serial type of the final rowid will always be a single byte.
|
||||
** By ignoring this last byte of the header, we force the comparison
|
||||
** to ignore the rowid at the end of key1.
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
@@ -2984,9 +2985,6 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
if( pPKey2->flags & UNPACKED_IGNORE_ROWID ){
|
||||
szHdr1--;
|
||||
}
|
||||
nField = pKeyInfo->nField;
|
||||
while( idx1<szHdr1 && i<pPKey2->nField ){
|
||||
u32 serial_type1;
|
||||
@@ -3166,7 +3164,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID );
|
||||
assert( pUnpacked->flags & UNPACKED_PREFIX_MATCH );
|
||||
*res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -2310,7 +2310,7 @@ int sqlite3WalRead(
|
||||
for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
|
||||
u32 iFrame = aHash[iKey] + iZero;
|
||||
if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
|
||||
assert( iFrame>iRead );
|
||||
/* assert( iFrame>iRead ); -- not true if there is corruption */
|
||||
iRead = iFrame;
|
||||
}
|
||||
if( (nCollide--)==0 ){
|
||||
|
||||
+27
-15
@@ -604,7 +604,7 @@ static WhereTerm *findTerm(
|
||||
&& pTerm->u.leftColumn==iColumn
|
||||
&& (pTerm->eOperator & op)!=0
|
||||
){
|
||||
if( pIdx && pTerm->eOperator!=WO_ISNULL ){
|
||||
if( iColumn>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
|
||||
Expr *pX = pTerm->pExpr;
|
||||
CollSeq *pColl;
|
||||
char idxaff;
|
||||
@@ -3052,10 +3052,24 @@ static void bestBtreeIndex(
|
||||
#endif
|
||||
used |= pTerm->prereqRight;
|
||||
}
|
||||
|
||||
/* Determine the value of rangeDiv */
|
||||
if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){
|
||||
int j = pProbe->aiColumn[nEq];
|
||||
|
||||
/* If the index being considered is UNIQUE, and there is an equality
|
||||
** constraint for all columns in the index, then this search will find
|
||||
** at most a single row. In this case set the WHERE_UNIQUE flag to
|
||||
** indicate this to the caller.
|
||||
**
|
||||
** Otherwise, if the search may find more than one row, test to see if
|
||||
** there is a range constraint on indexed column (nEq+1) that can be
|
||||
** optimized using the index.
|
||||
*/
|
||||
if( nEq==pProbe->nColumn && pProbe->onError!=OE_None ){
|
||||
testcase( wsFlags & WHERE_COLUMN_IN );
|
||||
testcase( wsFlags & WHERE_COLUMN_NULL );
|
||||
if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
|
||||
wsFlags |= WHERE_UNIQUE;
|
||||
}
|
||||
}else if( pProbe->bUnordered==0 ){
|
||||
int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
|
||||
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
|
||||
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
|
||||
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
|
||||
@@ -3074,12 +3088,6 @@ static void bestBtreeIndex(
|
||||
}
|
||||
wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
|
||||
}
|
||||
}else if( pProbe->onError!=OE_None ){
|
||||
testcase( wsFlags & WHERE_COLUMN_IN );
|
||||
testcase( wsFlags & WHERE_COLUMN_NULL );
|
||||
if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){
|
||||
wsFlags |= WHERE_UNIQUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause and the index being considered will
|
||||
@@ -3690,10 +3698,12 @@ static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
|
||||
|
||||
j = i;
|
||||
if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
|
||||
explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
|
||||
char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
|
||||
explainAppendTerm(&txt, i++, z, ">");
|
||||
}
|
||||
if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
|
||||
explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
|
||||
char *z = (j==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[j]].zName;
|
||||
explainAppendTerm(&txt, i, z, "<");
|
||||
}
|
||||
sqlite3StrAccumAppend(&txt, ")", 1);
|
||||
return sqlite3StrAccumFinish(&txt);
|
||||
@@ -4051,7 +4061,7 @@ static Bitmask codeOneLoopStart(
|
||||
|
||||
pIdx = pLevel->plan.u.pIdx;
|
||||
iIdxCur = pLevel->iIdxCur;
|
||||
k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */
|
||||
k = (nEq==pIdx->nColumn ? -1 : pIdx->aiColumn[nEq]);
|
||||
|
||||
/* If this loop satisfies a sort order (pOrderBy) request that
|
||||
** was passed to this function to implement a "SELECT min(x) ..."
|
||||
@@ -4097,7 +4107,9 @@ static Bitmask codeOneLoopStart(
|
||||
** a forward order scan on a descending index, interchange the
|
||||
** start and end terms (pRangeStart and pRangeEnd).
|
||||
*/
|
||||
if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
|
||||
if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
|
||||
|| (bRev && pIdx->nColumn==nEq)
|
||||
){
|
||||
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,25 @@ do_test attach-1.3 {
|
||||
SELECT * FROM two.t2;
|
||||
}
|
||||
} {1 x 2 y}
|
||||
|
||||
# Tests for the sqlite3_db_filename interface
|
||||
#
|
||||
do_test attach-1.3.1 {
|
||||
file tail [sqlite3_db_filename db main]
|
||||
} {test.db}
|
||||
do_test attach-1.3.2 {
|
||||
file tail [sqlite3_db_filename db MAIN]
|
||||
} {test.db}
|
||||
do_test attach-1.3.3 {
|
||||
file tail [sqlite3_db_filename db temp]
|
||||
} {}
|
||||
do_test attach-1.3.4 {
|
||||
file tail [sqlite3_db_filename db two]
|
||||
} {test2.db}
|
||||
do_test attach-1.3.5 {
|
||||
file tail [sqlite3_db_filename db three]
|
||||
} {}
|
||||
|
||||
do_test attach-1.4 {
|
||||
execsql {
|
||||
SELECT * FROM t2;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# 2011 December 20
|
||||
#
|
||||
# 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 script testing the ability of SQLite to handle database
|
||||
# files larger than 4GB.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bigfile2
|
||||
|
||||
# Create a small database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
|
||||
# Pad the file out to 4GB in size. Then clear the file-size field in the
|
||||
# db header. This will cause SQLite to assume that the first 4GB of pages
|
||||
# are actually in use and new pages will be appended to the file.
|
||||
#
|
||||
db close
|
||||
if {[catch {fake_big_file 4096 [pwd]/test.db} msg]} {
|
||||
puts "**** Unable to create a file larger than 4096 MB. *****"
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
hexio_write test.db 28 00000000
|
||||
|
||||
do_test 1.2 {
|
||||
file size test.db
|
||||
} [expr 14 + 4096 * (1<<20)]
|
||||
|
||||
# Now insert a large row. The overflow pages will be located past the 4GB
|
||||
# boundary. Then, after opening and closing the database, test that the row
|
||||
# can be read back in.
|
||||
#
|
||||
set str [string repeat k 30000]
|
||||
do_test 1.3 {
|
||||
sqlite3 db test.db
|
||||
execsql { INSERT INTO t1 VALUES(3, $str) }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
db one { SELECT b FROM t1 WHERE a = 3 }
|
||||
} $str
|
||||
|
||||
db close
|
||||
file delete test.db
|
||||
|
||||
finish_test
|
||||
@@ -62,6 +62,11 @@ ifcapable stat3 {
|
||||
set STAT3 0
|
||||
}
|
||||
|
||||
ifcapable malloc_usable_size {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Run the dbstatus-2 and dbstatus-3 tests with several of different
|
||||
# lookaside buffer sizes.
|
||||
|
||||
+4
-4
@@ -573,10 +573,10 @@ set chunkconfig [fts3_configure_incr_load 1 1]
|
||||
foreach {tn create pending} {
|
||||
1 "fts4(a, b)" 1
|
||||
2 "fts4(a, b, order=ASC, prefix=1)" 1
|
||||
3 "fts4(a, b, order=ASC, prefix=1,3)" 0
|
||||
4 "fts4(a, b, order=DESC, prefix=2,4)" 0
|
||||
5 "fts4(a, b, order=DESC, prefix=1)" 0
|
||||
6 "fts4(a, b, order=ASC, prefix=1,3)" 0
|
||||
3 "fts4(a, b, order=ASC, prefix=\"1,3\")" 0
|
||||
4 "fts4(a, b, order=DESC, prefix=\"2,4\")" 0
|
||||
5 "fts4(a, b, order=DESC, prefix=\"1\")" 0
|
||||
6 "fts4(a, b, order=ASC, prefix=\"1,3\")" 0
|
||||
} {
|
||||
|
||||
execsql [subst {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# 2012 January 25
|
||||
#
|
||||
# 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 script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3prefix2
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 { PRAGMA page_size = 512 }
|
||||
do_execsql_test 1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(x, prefix="2,3");
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('T TX T TX T TX T TX T TX');
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 512
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 1024
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2048
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
DELETE FROM t1 WHERE docid > 5;
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'T*';
|
||||
} {
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -68,7 +68,7 @@ proc reset_highwater_marks {} {
|
||||
sqlite3_status SQLITE_STATUS_PARSER_STACK 1
|
||||
}
|
||||
|
||||
set xtra_size 256
|
||||
set xtra_size 290
|
||||
|
||||
# Test 1: Both PAGECACHE and SCRATCH are shut down.
|
||||
#
|
||||
@@ -97,9 +97,11 @@ reset_highwater_marks
|
||||
build_test_db memsubsys1-2 {PRAGMA page_size=1024}
|
||||
#show_memstats
|
||||
set MEMORY_MANAGEMENT $sqlite_options(memorymanage)
|
||||
do_test memsubsys1-2.3 {
|
||||
set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
|
||||
} [expr ($TEMP_STORE>1 || $MEMORY_MANAGEMENT==0)*1024]
|
||||
ifcapable !malloc_usable_size {
|
||||
do_test memsubsys1-2.3 {
|
||||
set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
|
||||
} [expr ($TEMP_STORE>1 || $MEMORY_MANAGEMENT==0)*1024]
|
||||
}
|
||||
do_test memsubsys1-2.4 {
|
||||
set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
|
||||
} 20
|
||||
|
||||
+21
-3
@@ -14,6 +14,16 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
# The tests in this file assume that SQLite is compiled without
|
||||
# ENABLE_8_3_NAMES.
|
||||
#
|
||||
ifcapable 8_3_names {
|
||||
puts -nonewline "SQLite compiled with SQLITE_ENABLE_8_3_NAMES. "
|
||||
puts "Skipping tests multiplex-*."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
|
||||
set g_max_chunks 32
|
||||
|
||||
@@ -24,7 +34,7 @@ set g_max_chunks 32
|
||||
# file name with the chunk number.
|
||||
proc multiplex_name {name chunk} {
|
||||
if {$chunk==0} { return $name }
|
||||
set num [format "%02d" $chunk]
|
||||
set num [format "%03d" $chunk]
|
||||
ifcapable {multiplex_ext_overwrite} {
|
||||
set name [string range $name 0 [expr [string length $name]-2-1]]
|
||||
}
|
||||
@@ -146,6 +156,9 @@ sqlite3_multiplex_initialize "" 1
|
||||
multiplex_set db main 32768 16
|
||||
|
||||
forcedelete test.x
|
||||
foreach f [glob -nocomplain {test.x*[0-9][0-9][0-9]}] {
|
||||
forcedelete $f
|
||||
}
|
||||
do_test multiplex-2.1.2 {
|
||||
sqlite3 db test.x
|
||||
execsql {
|
||||
@@ -182,12 +195,17 @@ do_test multiplex-2.4.2 {
|
||||
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
|
||||
} {}
|
||||
do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
|
||||
do_test multiplex-2.4.99 {
|
||||
do_test multiplex-2.4.5 {
|
||||
db close
|
||||
sqlite3 db test.x
|
||||
db eval vacuum
|
||||
db close
|
||||
glob test.x*
|
||||
} {test.x}
|
||||
do_test multiplex-2.4.99 {
|
||||
sqlite3_multiplex_shutdown
|
||||
} {SQLITE_OK}
|
||||
|
||||
|
||||
do_test multiplex-2.5.1 {
|
||||
multiplex_delete test.x
|
||||
sqlite3_multiplex_initialize "" 1
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# 2010 October 29
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
set testprefix multiplex2
|
||||
db close
|
||||
|
||||
do_multiclient_test tn {
|
||||
foreach f [glob -nocomplain test.*] { forcedelete $f }
|
||||
|
||||
code1 { catch { sqlite3_multiplex_initialize "" 0 } }
|
||||
code2 { catch { sqlite3_multiplex_initialize "" 0 } }
|
||||
|
||||
code1 { db close }
|
||||
code2 { db2 close }
|
||||
|
||||
code1 { sqlite3 db test.db -vfs multiplex }
|
||||
code2 { sqlite3 db2 test.db -vfs multiplex }
|
||||
|
||||
code1 { sqlite3_multiplex_control db main chunk_size [expr 1024*1024] }
|
||||
code2 { sqlite3_multiplex_control db2 main chunk_size [expr 1024*1024] }
|
||||
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(4000)); -- 1
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 512
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
|
||||
do_test 1.$tn.1 { sql1 { SELECT count(*) FROM t1 } } 512
|
||||
do_test 1.$tn.2 { sql2 { SELECT count(*) FROM t1 } } 512
|
||||
sql2 { DELETE FROM t1 ; VACUUM }
|
||||
do_test 1.$tn.3 { sql1 { SELECT count(*) FROM t1 } } 0
|
||||
|
||||
sql1 {
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(4000)); -- 1
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 512
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
|
||||
do_test 1.$tn.4 { sql2 { SELECT count(*) FROM t1 } } 512
|
||||
}
|
||||
|
||||
catch {db close}
|
||||
foreach f [glob -nocomplain test.*] { forcedelete $f }
|
||||
|
||||
ifcapable 8_3_names {
|
||||
sqlite3 db test.db -vfs multiplex
|
||||
sqlite3_multiplex_control db main chunk_size [expr 256*1024]
|
||||
|
||||
# Insert 512 * 256K (128MB) of data. If each row is around 4K, this means
|
||||
# we need 32768 rows.
|
||||
do_catchsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(4000)); -- 1
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 512
|
||||
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 1K
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 2K
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 4K
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 8K
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 16K
|
||||
INSERT INTO t1 SELECT randomblob(10), randomblob(4000) FROM t1; -- 32K
|
||||
|
||||
} {1 {database or disk is full}}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
UPDATE t1 SET a=randomblob(9), b=randomblob(3900);
|
||||
PRAGMA integrity_check;
|
||||
} ok
|
||||
|
||||
db close
|
||||
sqlite3 db test.db -vfs multiplex
|
||||
sqlite3_multiplex_control db main chunk_size [expr 256*1024]
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
PRAGMA integrity_check;
|
||||
} ok
|
||||
}
|
||||
|
||||
catch { db close }
|
||||
catch { sqlite3_multiplex_shutdown }
|
||||
finish_test
|
||||
@@ -0,0 +1,133 @@
|
||||
|
||||
# 2011 December 13
|
||||
#
|
||||
# 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 contains tests for error (IO, OOM etc.) handling when using
|
||||
# the multiplexor extension with 8.3 filenames.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set ::testprefix multiplex3
|
||||
|
||||
ifcapable !8_3_names {
|
||||
puts -nonewline "SQLite compiled without SQLITE_ENABLE_8_3_NAMES. "
|
||||
puts "Skipping tests zipvfsD-*."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_uri 1
|
||||
autoinstall_test_functions
|
||||
|
||||
sqlite3_multiplex_initialize "" 1
|
||||
|
||||
proc destroy_vfs_stack {} {
|
||||
generic_unregister stack
|
||||
sqlite3_multiplex_shutdown
|
||||
}
|
||||
|
||||
proc multiplex_delete_db {} {
|
||||
forcedelete test.db
|
||||
for {set i 1} {$i <= 1000} {incr i} {
|
||||
forcedelete test.[format %03d $i]
|
||||
}
|
||||
}
|
||||
|
||||
# Procs to save and restore the current muliplexed database.
|
||||
#
|
||||
proc multiplex_save_db {} {
|
||||
foreach f [glob -nocomplain sv_test.*] { forcedelete $f }
|
||||
foreach f [glob -nocomplain test.*] { forcecopy $f "sv_$f" }
|
||||
}
|
||||
proc multiplex_restore_db {} {
|
||||
foreach f [glob -nocomplain test.*] {forcedelete $f}
|
||||
foreach f [glob -nocomplain sv_test.*] {forcecopy $f [string range $f 3 end]} }
|
||||
|
||||
proc setup_and_save_db {} {
|
||||
multiplex_delete_db
|
||||
sqlite3 db file:test.db?8_3_names=1
|
||||
sqlite3_multiplex_control db main chunk_size [expr 256*1024]
|
||||
execsql {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
INSERT INTO t1 VALUES(randomblob(15), randomblob(2000));
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1; -- 512
|
||||
}
|
||||
set ::cksum1 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
|
||||
db close
|
||||
multiplex_save_db
|
||||
}
|
||||
|
||||
do_test 1.0 { setup_and_save_db } {}
|
||||
do_faultsim_test 1 -prep {
|
||||
multiplex_restore_db
|
||||
sqlite3 db file:test.db?8_3_names=1
|
||||
sqlite3_multiplex_control db main chunk_size [expr 256*1024]
|
||||
} -body {
|
||||
execsql {
|
||||
UPDATE t1 SET a=randomblob(12), b=randomblob(1500) WHERE (rowid%32)=0
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
if {$testrc!=0} {
|
||||
set cksum2 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
|
||||
if {$cksum2 != $::cksum1} { error "data mismatch" }
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests verify that hot-journal rollback works. As follows:
|
||||
#
|
||||
# 1. Create a large database.
|
||||
# 2. Set the pager cache to be very small.
|
||||
# 3. Open a transaction.
|
||||
# 4. Run the following 100 times:
|
||||
# a. Update a row.
|
||||
# b. Copy all files on disk to a new db location, including the journal.
|
||||
# c. Verify that the new db can be opened and that the content matches
|
||||
# the database created in step 1 (proving the journal was rolled
|
||||
# back).
|
||||
|
||||
do_test 2.0 {
|
||||
setup_and_save_db
|
||||
multiplex_restore_db
|
||||
sqlite3 db file:test.db?8_3_names=1
|
||||
execsql { PRAGMA cache_size = 10 }
|
||||
execsql { BEGIN }
|
||||
} {}
|
||||
|
||||
for {set iTest 1} {$iTest<=100} {incr iTest} {
|
||||
do_test 2.$iTest {
|
||||
execsql {
|
||||
UPDATE t1 SET a=randomblob(12), b=randomblob(1400) WHERE rowid=5*$iTest
|
||||
}
|
||||
foreach f [glob -nocomplain test.*] {forcecopy $f "xx_$f"}
|
||||
sqlite3 db2 file:xx_test.db?8_3_names=1
|
||||
execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a} db2
|
||||
} $::cksum1
|
||||
|
||||
db2 close
|
||||
}
|
||||
|
||||
catch { db close }
|
||||
sqlite3_multiplex_shutdown
|
||||
finish_test
|
||||
+2
-2
@@ -99,7 +99,7 @@ do_test pragma-1.5 {
|
||||
PRAGMA default_cache_size;
|
||||
PRAGMA synchronous;
|
||||
}
|
||||
} [list 4321 $DFLT_CACHE_SZ 0]
|
||||
} [list -4321 $DFLT_CACHE_SZ 0]
|
||||
do_test pragma-1.6 {
|
||||
execsql {
|
||||
PRAGMA synchronous=ON;
|
||||
@@ -107,7 +107,7 @@ do_test pragma-1.6 {
|
||||
PRAGMA default_cache_size;
|
||||
PRAGMA synchronous;
|
||||
}
|
||||
} [list 4321 $DFLT_CACHE_SZ 1]
|
||||
} [list -4321 $DFLT_CACHE_SZ 1]
|
||||
do_test pragma-1.7 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
@@ -14,6 +14,8 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
unset -nocomplain defaultVfs
|
||||
set defaultVfs [file_control_vfsname db]
|
||||
db close
|
||||
|
||||
do_test quota-1.1 { sqlite3_quota_initialize nosuchvfs 1 } {SQLITE_ERROR}
|
||||
@@ -73,6 +75,9 @@ do_test quota-2.1.2 {
|
||||
}
|
||||
set ::quota
|
||||
} {}
|
||||
do_test quota-2.1.2.1 {
|
||||
file_control_vfsname db
|
||||
} quota/$defaultVfs
|
||||
do_test quota-2.1.3 { file size test.db } {4096}
|
||||
do_test quota-2.1.4 {
|
||||
catchsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# 2011 November 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 contains test cases for sqlite3_db_release_memory and
|
||||
# the PRAGMA shrink_memory statement.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
unset -nocomplain baseline
|
||||
do_test shrink-1.1 {
|
||||
db eval {
|
||||
CREATE TABLE t1(x,y);
|
||||
INSERT INTO t1 VALUES(randomblob(1000000),1);
|
||||
}
|
||||
set ::baseline sqlite3_memory_used
|
||||
sqlite3_db_release_memory db
|
||||
expr {$::baseline > [sqlite3_memory_used]+500000}
|
||||
} {1}
|
||||
do_test shrink-1.2 {
|
||||
set baseline [sqlite3_memory_used]
|
||||
db eval {
|
||||
UPDATE t1 SET y=y+1;
|
||||
}
|
||||
expr {$::baseline+500000 < [sqlite3_memory_used]}
|
||||
} {1}
|
||||
do_test shrink-1.3 {
|
||||
set baseline [sqlite3_memory_used]
|
||||
db eval {PRAGMA shrink_memory}
|
||||
expr {$::baseline > [sqlite3_memory_used]+500000}
|
||||
} {1}
|
||||
|
||||
finish_test
|
||||
@@ -416,6 +416,7 @@ do_test wal-8.3 {
|
||||
do_test wal-9.1 {
|
||||
reopen_db
|
||||
execsql {
|
||||
PRAGMA cache_size=2000;
|
||||
CREATE TABLE t1(x PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES(blob(900));
|
||||
INSERT INTO t1 VALUES(blob(900));
|
||||
@@ -1124,6 +1125,7 @@ foreach {tn sectorsize logsize} "
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA page_size = 512;
|
||||
PRAGMA cache_size = -2000;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = FULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# 2011 November 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix whereC
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b INTEGER);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 1, 1);
|
||||
INSERT INTO t1 VALUES(2, 1, 1);
|
||||
INSERT INTO t1 VALUES(3, 1, 2);
|
||||
INSERT INTO t1 VALUES(4, 1, 2);
|
||||
INSERT INTO t1 VALUES(5, 1, 2);
|
||||
INSERT INTO t1 VALUES(6, 1, 3);
|
||||
INSERT INTO t1 VALUES(7, 1, 3);
|
||||
|
||||
INSERT INTO t1 VALUES(8, 2, 1);
|
||||
INSERT INTO t1 VALUES(9, 2, 1);
|
||||
INSERT INTO t1 VALUES(10, 2, 2);
|
||||
INSERT INTO t1 VALUES(11, 2, 2);
|
||||
INSERT INTO t1 VALUES(12, 2, 2);
|
||||
INSERT INTO t1 VALUES(13, 2, 3);
|
||||
INSERT INTO t1 VALUES(14, 2, 3);
|
||||
|
||||
INSERT INTO t1 VALUES(15, 2, 1);
|
||||
INSERT INTO t1 VALUES(16, 2, 1);
|
||||
INSERT INTO t1 VALUES(17, 2, 2);
|
||||
INSERT INTO t1 VALUES(18, 2, 2);
|
||||
INSERT INTO t1 VALUES(19, 2, 2);
|
||||
INSERT INTO t1 VALUES(20, 2, 3);
|
||||
INSERT INTO t1 VALUES(21, 2, 3);
|
||||
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
|
||||
foreach {tn sql res} {
|
||||
1 "SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3" {4 5}
|
||||
2 "SELECT i FROM t1 WHERE rowid='12'" {12}
|
||||
3 "SELECT i FROM t1 WHERE a=1 AND b='2'" {3 4 5}
|
||||
4 "SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'" {4 5}
|
||||
5 "SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5" {3 4}
|
||||
6 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12" {10 11}
|
||||
7 "SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11" {3 4 5 10}
|
||||
8 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12" {10 11 12}
|
||||
9 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 11 AND 12" {11 12}
|
||||
10 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 11" {10 11}
|
||||
11 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10" {}
|
||||
12 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL" {}
|
||||
13 "SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL" {}
|
||||
14 "SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5" {3 4}
|
||||
} {
|
||||
do_execsql_test 1.$tn.1 $sql $res
|
||||
do_execsql_test 1.$tn.2 "$sql ORDER BY i ASC" [lsort -integer -inc $res]
|
||||
do_execsql_test 1.$tn.3 "$sql ORDER BY i DESC" [lsort -integer -dec $res]
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user