Compare commits

...

57 Commits

Author SHA1 Message Date
drh 76ea46c045 Fix the multiplexor logging so that it works with SQLITE_ENABLE_8_3_NAMES.
FossilOrigin-Name: 627eff32a23ec676f7e87f6904981b3804e0e1f0
2012-04-04 13:51:22 +00:00
drh 8e33b23089 In the multiplexor extension, improve the error logging when a chunk fails
to open.

FossilOrigin-Name: e6806f0dc6a06796700d805952f95e2cc18f0ea3
2012-04-04 13:47:35 +00:00
drh 1bfbdcbe6d Port the command-line shell enhancements including the new --cmd option
to the nx-devkit branch.

FossilOrigin-Name: 81ce52afb1bdb55d4585f01e7fb3ab86f81b7512
2012-02-07 14:22:18 +00:00
drh 03c8582307 Do not rely on the _WIN32_WINNT macro as vs2005 does not define it by default.
Instead, always assume winNT unless the makefile explicitly sets
SQLITE_OS_WINNT=0.

FossilOrigin-Name: 4f0997c7fab79cb7f12cf30f5ea5c87ce96bc266
2012-01-30 16:13:51 +00:00
drh e7cad43368 Cherrypick the FTS fix in [c05c3fd0d] into the nx-devkit branch.
Ticket [edb497982c].

FossilOrigin-Name: 2a7170f03c746473aca38ddc4b4a4091fe8331eb
2012-01-25 22:08:39 +00:00
drh 09a982e4ce Cherrypick the fix from [629108c8e5376f989] into the nx-devkit branch.
FossilOrigin-Name: d7374568cbce156523f5a6930e473ba2653c758b
2012-01-20 15:05:05 +00:00
drh 4a7eb4b545 Cherry-pick the fix to surplus overflow files in the multiplexor,
check-in [1238619756c0c] in the trunk.

FossilOrigin-Name: 2f8c62c3378a702fa623a2880a989d958eece0df
2012-01-09 14:57:38 +00:00
drh 34cf60ec74 Cherry-pick the SQLITE_DIRECT_OVERFLOW_READ fix for ticket
[ac0ff496b7e3] of changes [c5256b59ad] and [c723e3e18a] 
into the nx-devkit branch.

FossilOrigin-Name: 42f31f190a0ac971fa0ee361fe4c175f479c75e3
2011-12-21 23:38:21 +00:00
drh 8c24a369a5 Tweaks to the way multiplexSubOpen() works, for backwards compatibility.
FossilOrigin-Name: bb40338887c912be70cb6fe3b760d87c14bb88a5
2011-12-16 05:50:39 +00:00
drh 0699966798 Fix a potential infinite loop (inserted by the previous check-in)
on the multiplexWrite() method of the multiplexor.

FossilOrigin-Name: 022bf427c2edfe494ec7c222f436953ff56574a6
2011-12-16 05:09:46 +00:00
drh e7d9f13d99 The xTruncate method for the multiplexor now changes surplus overflow
files to zero-length by default.  Or if the "truncate" query parameter 
is used, it actually deletes the surplus overflow files.  This allows
VACUUM to shrink the database again.

FossilOrigin-Name: 5aefef04d6cc3b734c3f05e036b3869a52248f4d
2011-12-16 04:57:32 +00:00
drh 38deeb9763 Call sqlite3_log() with an appropriate message if unable to find a unique
master-journal filename.

FossilOrigin-Name: e9177f7d4ec19f0841d0613990d2fb5725700ba1
2011-12-16 01:30:15 +00:00
drh 5c531a4aab A better solution to being unable to find a unique master-journal filename:
just delete an existing master-journal and reuse it.

FossilOrigin-Name: 2685c2b949061f18bf6a4940eac8c8148873abb6
2011-12-16 01:21:31 +00:00
drh f580860f51 Make sure the antipenultimate character of master-journal filenames is a "9"
in order to avoid collisions with other files in 8+3 filename mode.  Also,
limit the number of attempts at finding a unique master-journal filename.

FossilOrigin-Name: 34a0483605d36e6cf03065ed0df33fb1f7c8a272
2011-12-16 00:33:04 +00:00
dan e712b5823e When deleting a file with the multiplexor VFS, also delete any overflow files that exist.
FossilOrigin-Name: 3af1feaa35d3fb2e7be550cd32a727001b874938
2011-12-15 17:00:10 +00:00
drh 78c0eafb35 Make sure the chunksize in test_multiplex does not cause the pending byte
to fall near the end of a chunk.  Adjust the chunksize upward as necessary
to prevent this.

FossilOrigin-Name: e05f8a2998f4f4cbdb65702baa65893c538b3d38
2011-12-15 13:29:12 +00:00
dan 31b21295b0 Fix some problems with dropped error codes in multiplexOpen().
FossilOrigin-Name: 2d50f78188e3297e8cefdf73cff51fa0a3b36e65
2011-12-15 11:45:19 +00:00
drh 2be25bffca In the multiplexor, do not try to delete overflow files that do not exist.
And assume all but the last overflow file is the size of the chunk size.

FossilOrigin-Name: a822a80d3cfe42b2fca6f8c9ff11762993114a27
2011-12-15 02:22:16 +00:00
drh 0f2ab8db33 Merge the VFSNAME file-control addition into the nx-devkit branch.
FossilOrigin-Name: 08c1dc517c1340737a55ad9012b7b06f72899c6f
2011-12-14 18:28:18 +00:00
drh de60fc2d87 Add a file-control that will discover the name of the bottom-level VFS and
all the shims in between.

FossilOrigin-Name: cdbfb553af02d10767a905489d9dfc57fc6be54e
2011-12-14 17:53:36 +00:00
drh 43a6d4bd44 Improvements to comments. No code changes.
FossilOrigin-Name: 08bbbd8e38697908ab8ae0f6b512d01c32f7e4da
2011-12-14 01:38:12 +00:00
dan 27e69643cf Add a hard limit to the number of chunks a multiplexed database may consist of if ENABLE_8_3_NAMES is defined.
FossilOrigin-Name: 43a1264088c57bf598787b7a9f5d7a2536603d67
2011-12-13 19:03:34 +00:00
drh c7f946297a Change the SQLITE_EXTRA_INIT routine to take a single argument which is a
pointer to a string.  Call SQLITE_EXTRA_INIT with a NULL argument.
Fixes to multiplexor to treat the VFS properly in corner cases.  Fix the
initialization of multiplex3.test.

FossilOrigin-Name: 8e65b9132530e46c62bd1352bfc2e9c29f57af5f
2011-12-13 18:22:38 +00:00
dan add995cc25 Add extra tests for the multiplexor VFS. No changes to code.
FossilOrigin-Name: c7de6f683d0fec62bc138b4a53b5cccc80c736c3
2011-12-13 16:40:33 +00:00
drh 658dd586ed Update the multiplex.test script to conform to that found in the "experimental"
branch off of trunk.

FossilOrigin-Name: 2eb79efbff9cdab843b172e9fa9fb400c542fab1
2011-12-13 15:25:06 +00:00
drh 5b1626aa47 Move the multiplexor changes in the experimental branch
(check-ins [255d21499b] and [199f52bced]) into the nx-devkit branch.

FossilOrigin-Name: eb95d2f72c625bcfd0f8e9db1db2cb8799854b57
2011-12-13 15:02:54 +00:00
drh e5077c1211 When an sqlite3_auto_extension() function fails, report back its actual
error code, not the generic SQLITE_ERROR.

FossilOrigin-Name: ce55f250f56fa3a1ca864f81e9e86f911b981490
2011-12-13 04:08:36 +00:00
drh 43795e3b0b When the multiplexor FileSize procedure fails to open the file, assume that
the file is zero bytes in size.

FossilOrigin-Name: dc8118cd89da71f2035c6ee07c0edb772bba2186
2011-12-13 02:41:13 +00:00
drh 9797706c04 Add a compile-time shutdown procedure to be called by sqlite3_shutdown()
to undo the effects of the compile-time initialization procedure.

FossilOrigin-Name: c2ed86f5945662a4ddcdc7b303df3f64fb3bf17d
2011-12-13 01:34:21 +00:00
drh 73795becfe Backport a minimal set of changes needed to get 8+3 filenames and the
multiplexor shim playing well together.

FossilOrigin-Name: c4e2ce486217c96373836bfe641f46abf891799a
2011-12-12 20:01:12 +00:00
drh 21495ba8a3 Improvements to the documentation of the sqlite3_db_filename() interface.
FossilOrigin-Name: 1c45b2a0c055f6fc5da9d00ae2e9171099d904d4
2011-11-17 11:49:58 +00:00
drh 070ad6b6fe Restore the test for sqlite3OsFullPathname() failure that was mistakenly
removed when [ceee03c79a] was backed out by [69ec53fc1c].

FossilOrigin-Name: 4d3cf9e1d8ac356db5a708913f614e42a6a56b94
2011-11-17 11:43:19 +00:00
drh 283829cb20 Add the sqlite3_db_filename() interface.
FossilOrigin-Name: 93a947989b57959aacc37007a143fdf3921793ab
2011-11-17 00:56:20 +00:00
drh f20fb8c6f3 Back out the [ceee03c79a] change.
FossilOrigin-Name: 69ec53fc1c60b07bf4aaa983dcd5bf3164fb1ea5
2011-11-16 23:29:37 +00:00
drh 09419b4bae Add the sqlite3_db_release_memory() interface and the shrink_memory pragma.
FossilOrigin-Name: 3f58e7c8895d1252eff56282c08b1a6f1194452c
2011-11-16 19:29:17 +00:00
drh 870c0178f7 Merge the PCACHE2 changes into trunk.
FossilOrigin-Name: 457513f21f2438c61b1a214716e338a4e3eeaafa
2011-11-16 18:08:07 +00:00
drh 8f10acdb5b Remove code made obsolete by the changes to index processing that allow
range search on the rowid.

FossilOrigin-Name: a5418c7fc216a30abf7b2fa8c579aee586393a91
2011-11-16 16:23:15 +00:00
dan 6f13323118 Fix an invalid assert() statement added by [3b58f5f066].
FossilOrigin-Name: 888b09dd8fc0a31b69852a2c10eebb5f31fe35de
2011-11-16 15:41:29 +00:00
dan 0c733f67d8 Where possible, take advantage of the rowid at the end of index records to optimize range constraints (<, >, <=, >=) on the rowid column.
FossilOrigin-Name: 3b58f5f06648205a47e5cace0201269c406e476a
2011-11-16 15:27:09 +00:00
dan bf567db91d Update memsubsys1.test to account for the recently increased size of the MemPage structure in btreeInt.h.
FossilOrigin-Name: 4fb3ca756a3a7c66baa4745a9b2c1e246a67c699
2011-11-16 08:18:20 +00:00
drh 3f5b98df17 Forward port the 8-byte alignment fix from branch-3.7.9.
FossilOrigin-Name: ebf6eb6ed756c0a3158b4cb5fb4b460c79d93c29
2011-11-14 03:00:28 +00:00
drh e09b84c558 Fix a 8-byte alignment problem that causes a SIGBUS on Sparc.
FossilOrigin-Name: 54cc11981127b52145e39f551d958580b1d45169
2011-11-14 02:53:54 +00:00
drh 81ef0f97ef Add a version number to the sqlite3_pcache_methods2 object. Other PCACHE2
documentation improvements.

FossilOrigin-Name: 9f839ac05a9f3cfe587d2ccdccd50dac41baedbe
2011-11-13 21:44:03 +00:00
drh f923f82118 Attempt to modify btree.c so that it assumes that calls to sqlite3PagerWrite()
will reallocate the page buffer.  As there is not good way to test this
assumption yet, probably a few spots were missed.

FossilOrigin-Name: ceee03c79a55ea39866758aa76b78b10e5f4246d
2011-11-12 23:10:13 +00:00
drh d515660523 Remove a couple of incorrect assert statements so that the test suite will
run with -DSQLITE_DEFAULT_CACHE_SIZE=0.

FossilOrigin-Name: 87614b62ace530761e0e1170ec5840b212735ec6
2011-11-12 16:46:55 +00:00
drh cc682cc875 Merge the windows xSyscall enhancements into trunk.
FossilOrigin-Name: c1fab9aca1fe1dda2b4c7e4fdc0a406998847bdb
2011-11-12 15:41:52 +00:00
drh 4cb5f436cb Catch and report errors from sqlite3OsFullPathname().
FossilOrigin-Name: 77119785c84ac7f416ed72c38c532399b6093d7a
2011-11-11 23:51:15 +00:00
drh c90747313e Pull over all the latest changes from trunk.
FossilOrigin-Name: 1bbbf8574a820c5f787a937f02a8e2a91264ace0
2011-11-11 14:12:36 +00:00
drh 3def2357e6 Make sure a corrupt index does not cause a buffer overread in
sqlite3VdbeRecordCompare().

FossilOrigin-Name: 471cf0d8e7857110e525e029c2d535cb518dba6a
2011-11-11 00:27:15 +00:00
drh 61a4bd5c6c Follow-on to the previous check-in to prevent a division by zero if the
lookahead slot size is something goofy like 6 on a 32-bit machine.

FossilOrigin-Name: 6bda711f93e753dd0be8d896a007b3f7b5064787
2011-11-10 02:39:28 +00:00
drh 8225d66be6 Use sqlite3MallocSize() to get the actual size of the memory allocation
used for lookaside cache and increase the size of the cache to use the
full allocation.

FossilOrigin-Name: 0e53ecad9468d0a13d155a4462551d4c234a7d5c
2011-11-10 02:24:11 +00:00
mistachkin 32121199be When compiling with MSVC, use the _msize function.
FossilOrigin-Name: 797a147934743a565c6f1f9dd4d41574690b4c2b
2011-11-09 17:01:40 +00:00
drh e73c91496f Minor changes needed to restore full branch test coverage.
FossilOrigin-Name: bc10a753579b65ba4604867204b7b3d8383f3ac7
2011-11-09 16:12:24 +00:00
drh 3b42abb35b A negative value N for the cache_size pragma adjusts the number of cache
pages to use approximately N kibibytes of memory.

FossilOrigin-Name: b3faa680aedc94ed8aa2819228c0d304b181cc51
2011-11-09 14:23:04 +00:00
drh 6a8ab6d9cb For the mem1.c system malloc implementation, use the malloc_usable_size()
function if the HAVE_MALLOC_USABLE_SIZE macro is defined.  Update autoconf
to look for that function when configuring.

FossilOrigin-Name: 2e8ab3cedfebc33a831837792b523d1aa7cdc6b7
2011-11-09 01:53:25 +00:00
drh e5c40b18e3 Update the API documentation for the new pcache2 interface. Change the
order of parameters on the xCreate method of pcache2.

FossilOrigin-Name: 4da7095683ec821414e255419d63a24dbd9d726d
2011-11-09 00:06:05 +00:00
dan 22e21ff4fc Experimental change to the pcache interface to allow page buffers to be allocated separately from their associated container structures.
FossilOrigin-Name: c275c9d323cb1dccb031b199d413ac3a0b244fea
2011-11-08 20:08:44 +00:00
59 changed files with 1898 additions and 765 deletions
+3
View File
@@ -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.
+3
View File
@@ -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
Vendored
+205 -182
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+63 -57
View File
@@ -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
View File
@@ -1 +1 @@
76dec8aa9dbbc39e0a7c3b358b58ce7f7a477a2b
627eff32a23ec676f7e87f6904981b3804e0e1f0
+17 -7
View File
@@ -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];
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
/*
+31
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 },
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+8
View File
@@ -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;
}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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);
}
+19
View File
@@ -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;
+59
View File
@@ -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
+5
View File
@@ -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
View File
@@ -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 {
+62
View File
@@ -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
+6 -4
View File
@@ -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
View File
@@ -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
+119
View File
@@ -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
+133
View File
@@ -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
View File
@@ -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
+5
View File
@@ -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)) }
+42
View File
@@ -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
+2
View File
@@ -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;
}
+70
View File
@@ -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