Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 76ea46c045 | |||
| 8e33b23089 | |||
| 1bfbdcbe6d | |||
| 03c8582307 | |||
| e7cad43368 | |||
| 09a982e4ce | |||
| 4a7eb4b545 | |||
| 34cf60ec74 |
@@ -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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.68 for sqlite 3.7.10.
|
||||
# Generated by GNU Autoconf 2.68 for sqlite 3.7.9.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -706,8 +706,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.7.10'
|
||||
PACKAGE_STRING='sqlite 3.7.10'
|
||||
PACKAGE_VERSION='3.7.9'
|
||||
PACKAGE_STRING='sqlite 3.7.9'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -1440,7 +1440,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.7.10 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.7.9 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1505,7 +1505,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.10:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.9:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1622,7 +1622,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.7.10
|
||||
sqlite configure 3.7.9
|
||||
generated by GNU Autoconf 2.68
|
||||
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
@@ -2041,7 +2041,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.7.10, which was
|
||||
It was created by sqlite $as_me 3.7.9, which was
|
||||
generated by GNU Autoconf 2.68. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -11868,7 +11868,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.7.10, which was
|
||||
This file was extended by sqlite $as_me 3.7.9, which was
|
||||
generated by GNU Autoconf 2.68. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -11934,7 +11934,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.7.10
|
||||
sqlite config.status 3.7.9
|
||||
configured by $0, generated by GNU Autoconf 2.68,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+3
-1
@@ -2600,7 +2600,9 @@ static int fts3SegReaderCursor(
|
||||
}
|
||||
|
||||
rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
|
||||
iStartBlock, iLeavesEndBlock, iEndBlock, zRoot, nRoot, &pSeg
|
||||
(isPrefix==0 && isScan==0),
|
||||
iStartBlock, iLeavesEndBlock,
|
||||
iEndBlock, zRoot, nRoot, &pSeg
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
rc = fts3SegReaderCursorAppend(pCsr, pSeg);
|
||||
|
||||
+1
-1
@@ -401,7 +401,7 @@ int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
|
||||
int sqlite3Fts3PendingTermsFlush(Fts3Table *);
|
||||
void sqlite3Fts3PendingTermsClear(Fts3Table *);
|
||||
int sqlite3Fts3Optimize(Fts3Table *);
|
||||
int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
|
||||
int sqlite3Fts3SegReaderNew(int, int, sqlite3_int64,
|
||||
sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
|
||||
int sqlite3Fts3SegReaderPending(
|
||||
Fts3Table*,int,const char*,int,int,Fts3SegReader**);
|
||||
|
||||
+28
-8
@@ -110,6 +110,7 @@ struct Fts3DeferredToken {
|
||||
*/
|
||||
struct Fts3SegReader {
|
||||
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
|
||||
int bLookup; /* True for a lookup only */
|
||||
|
||||
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
|
||||
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
|
||||
@@ -1088,6 +1089,18 @@ static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set an Fts3SegReader cursor to point at EOF.
|
||||
*/
|
||||
static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
|
||||
if( !fts3SegReaderIsRootOnly(pSeg) ){
|
||||
sqlite3_free(pSeg->aNode);
|
||||
sqlite3_blob_close(pSeg->pBlob);
|
||||
pSeg->pBlob = 0;
|
||||
}
|
||||
pSeg->aNode = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the iterator passed as the first argument to the next term in the
|
||||
** segment. If successful, SQLITE_OK is returned. If there is no next term,
|
||||
@@ -1127,12 +1140,7 @@ static int fts3SegReaderNext(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( !fts3SegReaderIsRootOnly(pReader) ){
|
||||
sqlite3_free(pReader->aNode);
|
||||
sqlite3_blob_close(pReader->pBlob);
|
||||
pReader->pBlob = 0;
|
||||
}
|
||||
pReader->aNode = 0;
|
||||
fts3SegReaderSetEof(pReader);
|
||||
|
||||
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
||||
** blocks have already been traversed. */
|
||||
@@ -1379,6 +1387,7 @@ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
|
||||
*/
|
||||
int sqlite3Fts3SegReaderNew(
|
||||
int iAge, /* Segment "age". */
|
||||
int bLookup, /* True for a lookup only */
|
||||
sqlite3_int64 iStartLeaf, /* First leaf to traverse */
|
||||
sqlite3_int64 iEndLeaf, /* Final leaf to traverse */
|
||||
sqlite3_int64 iEndBlock, /* Final block of segment */
|
||||
@@ -1401,6 +1410,7 @@ int sqlite3Fts3SegReaderNew(
|
||||
}
|
||||
memset(pReader, 0, sizeof(Fts3SegReader));
|
||||
pReader->iIdx = iAge;
|
||||
pReader->bLookup = bLookup;
|
||||
pReader->iStartBlock = iStartLeaf;
|
||||
pReader->iLeafEndBlock = iEndLeaf;
|
||||
pReader->iEndBlock = iEndBlock;
|
||||
@@ -2403,11 +2413,16 @@ static int fts3SegReaderStart(
|
||||
** b-tree leaf nodes contain more than one term.
|
||||
*/
|
||||
for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
|
||||
int res;
|
||||
Fts3SegReader *pSeg = pCsr->apSegment[i];
|
||||
do {
|
||||
int rc = fts3SegReaderNext(p, pSeg, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
|
||||
}while( zTerm && (res = fts3SegReaderTermCmp(pSeg, zTerm, nTerm))<0 );
|
||||
|
||||
if( pSeg->bLookup && res!=0 ){
|
||||
fts3SegReaderSetEof(pSeg);
|
||||
}
|
||||
}
|
||||
fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp);
|
||||
|
||||
@@ -2528,7 +2543,12 @@ int sqlite3Fts3SegReaderStep(
|
||||
** forward. Then sort the list in order of current term again.
|
||||
*/
|
||||
for(i=0; i<pCsr->nAdvance; i++){
|
||||
rc = fts3SegReaderNext(p, apSegment[i], 0);
|
||||
Fts3SegReader *pSeg = apSegment[i];
|
||||
if( pSeg->bLookup ){
|
||||
fts3SegReaderSetEof(pSeg);
|
||||
}else{
|
||||
rc = fts3SegReaderNext(p, pSeg, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Enhance\sthe\sWAL\sheader\ssync\sso\sthat\sit\shonors\sthe\svarious\ssynchronous\npragmas,\ssettings,\sand\sdevice\scharacteristics.
|
||||
D 2011-12-16T21:26:26.087
|
||||
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 af03cd6400f9d71d38bdb7a9d66a1aefdc2f3e0d
|
||||
F VERSION bb37c274b503bbe73f00ea4f374eb817cba4b171
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@@ -23,7 +23,7 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 31cc8c4943f56e60c4aa4fba929c9d4c70e418b4
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure cdfb8a907ded1f8e75b6967e3e3bd35718884aff x
|
||||
F configure 194ed7797c67c24ebbeb001fcfc557116fe5eba9 x
|
||||
F configure.ac 75323bdac56fb0e69f6a3fc5b23f24359550b9d9
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 3091574143dd3415669b6745843ff8d011d33549
|
||||
@@ -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
|
||||
@@ -119,13 +119,13 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
|
||||
F src/analyze.c f32ff304da413851eefa562b04e61ff6cb88248b
|
||||
F src/analyze.c 5a1db16a651ce6310c8b046b2cbb736e030e14b9
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 4368158da74d4711888e03264105c5c527d76caf
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 80ea65224512884bb72976c93810d2dcaecc1353
|
||||
F src/btree.c 2fdde7d16c80bd4e8a0913038e766c4297818f6f
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btreeInt.h ea863a819224d3e6845ad1e39954d41558b8cd8b
|
||||
F src/build.c 8915bb6d72ead998f94c2756ea8d143c77709b70
|
||||
@@ -133,24 +133,24 @@ F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 51d32f0a9c880663e54ce309f52e40c325d5e112
|
||||
F src/expr.c 537591e95eac74af783e4eb033954fb218cf398e
|
||||
F src/delete.c ff68e5ef23aee08c0ff528f699a19397ed8bbed8
|
||||
F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
|
||||
F src/global.c 4cfdca5cb0edd33c4d021baec4ede958cb2c793b
|
||||
F src/global.c 107ccaacb4b30895cf3a3a39decf417c804acfa1
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c ea820fe9af748075b3b6827fb6f23f25079bf1f7
|
||||
F src/insert.c 8f283d6734dd837ed7531b26d7622fda70874390
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
|
||||
F src/main.c c837e24182e8ec7121c61e44f547b59cbe413e7f
|
||||
F src/main.c e7e6985365795ef6c500d05d766222222efbb0ac
|
||||
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 7998e7003a3047e323c849a26dda004debc04d03
|
||||
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 549b1a2e5e0ed1e1499f252dac126c4973e7379c
|
||||
F src/os.h 3ee45fed34d174eabdafe27c659428a8a1ff973d
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 7dc7df10331942b139032328449a3723e051979e
|
||||
F src/os_win.c 197d23ce8a0dff748e766e034bf95ff756dd3884
|
||||
F src/pager.c c7c32a1c279e0bbbde3578172985c41d4c5efc35
|
||||
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 fabb2e7047417d840e6fdb3ef0988a86849a08ba
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
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 7ffb4ebb8b341f67e049695ba031da717b3d2699
|
||||
F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40
|
||||
F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c a1d075db66a0ea42807353501b62997969e5be79
|
||||
F src/shell.c aa4183d4a5243d8110b1d3d77faa4aea7e9c9c2d
|
||||
F src/sqlite.h.in e3e45b5c69ab3236c7ec4591a5858221863cecd4
|
||||
F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6
|
||||
F src/shell.c 92e96bf5e465d63c55c5fe7fca38228c67ce7682
|
||||
F src/sqlite.h.in 84cd7be33f5bf39329e018f93eb34b4a345c9c23
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h 165409fa8adc8701148830804febeded3f2e4448
|
||||
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 33b9c49f728cf28937eea7b246c28e89e3cf5e9e
|
||||
F src/test1.c d019682c4480d612e4eca73412011a120e1468db
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
|
||||
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
@@ -211,21 +211,20 @@ F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a
|
||||
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 6e07b94e2fe430f7f4f0d7d67b5e58f504dea655
|
||||
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 6abf0a37ce831120c4ef1b913afdd813e7ac1a73
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 1a5874e3ee9074426f43b37e8d7404948065b585
|
||||
F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358
|
||||
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
|
||||
@@ -235,25 +234,25 @@ 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 ee7e178fb9188f44b532cebd449a7c1df90fb684
|
||||
F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
|
||||
F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
|
||||
F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c 343508d359df65685b62e63964a40e7af4cfbe05
|
||||
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
|
||||
F src/vdbe.c 029add0c5197a61db588824a58570547330b9d8f
|
||||
F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
|
||||
F src/vdbeInt.h 48c158b2fceca9682d1577e61c62da3c58cf0748
|
||||
F src/vdbeapi.c 86189ebba2c49791d75eaa12929f3ce6527596bd
|
||||
F src/vdbeaux.c 3015179b27672cb773d014495023eaa4a8cd8f9c
|
||||
F src/vdbe.c a7ab9993ec5a4d9479dc99671faec061fbf9b889
|
||||
F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
|
||||
F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176
|
||||
F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546
|
||||
F src/vdbeaux.c 52ebf2a62d6b66ded536d0a2745f2236771097c7
|
||||
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
|
||||
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
|
||||
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
|
||||
F src/wal.c 20022b733ce06f77cc1d7f154da32987b57532ae
|
||||
F src/wal.h 42f8313f7aaf8913e2d1fdf7b47025c23491ea1d
|
||||
F src/wal.c 5fe1ba55b8fab9d3936bc9093af61ab9f1c580a1
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c af623942514571895818b9b7ae11db95ae3b3d88
|
||||
F src/where.c f73752ca85c0ed221753fda98aeaf6b9d4616e0e
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@@ -297,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
|
||||
@@ -316,7 +316,7 @@ F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi3.test 7200dff6acb17b9a4b6f9918f554eaae04968ddd
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test ccf0acf045dbacd09f6229aa4efed670aaba76a9
|
||||
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
F test/capi3d.test cd36571f014f34bdc4421967f6453cbb597d5d16
|
||||
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test db2b29d557544347d28e25b8406f5d5ecc3d1bc3
|
||||
@@ -463,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
|
||||
@@ -486,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
|
||||
@@ -606,9 +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 8bc3c71f73fe833bc8a659d454d320044a33b5da
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test 15903c343f1eaa4b00998b7ceacfc4987e4ccfe9
|
||||
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
|
||||
@@ -636,9 +637,7 @@ F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota-glob.test 32901e9eed6705d68ca3faee2a06b73b57cb3c26
|
||||
F test/quota.test af47d25c166aa7b33ef25f21bb7f2afb29d82c77
|
||||
F test/quota2.test 1b8df088e604f2df573f96e726b5e518cb0cddaa
|
||||
F test/quota.test e09a01ec974e04a2c4f1c7615005722725b5e131
|
||||
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
|
||||
@@ -671,7 +670,7 @@ F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectB.test 0d072c5846071b569766e6cd7f923f646a8b2bfa
|
||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
|
||||
F test/shared.test 34945a516532b11182c3eb26e31247eee3c9ae48
|
||||
@@ -733,7 +732,6 @@ F test/tkt-31338dca7e.test 1f714c14b6682c5db715e0bda347926a3456f7a9
|
||||
F test/tkt-313723c356.test c47f8a9330523e6f35698bf4489bcb29609b53ac
|
||||
F test/tkt-38cb5df375.test 9e9b19857dba0896a8efdaf334d405ba423492f2
|
||||
F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
|
||||
F test/tkt-3a77c9714e.test 1675c22a5be71d7fa026e5db5daeeb4dd64f7824
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
|
||||
@@ -742,7 +740,6 @@ F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f
|
||||
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
|
||||
F test/tkt-78e04e52ea.test ab52f0c1e2de6e46c910f4cc16b086bba05952b7
|
||||
F test/tkt-7bbfb7d442.test 8e7658f77d1ccea9d88dc9e255d3ed7fb68f8bdf
|
||||
F test/tkt-80ba201079.test a09684db1a0bd55b8838f606adccee456a51ddbf
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
|
||||
@@ -902,8 +899,8 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test c743be787e60c1242fa6cdf73b410e64b2977e25
|
||||
F test/wal2.test 29e2cbe840582fc6efd0487b4f6337caed4b3e80
|
||||
F test/wal3.test 29a6e8843e5f5fd13f33cb0407d2923107020d32
|
||||
F test/wal2.test ad6412596815f553cd30f271d291ab003092bc7e
|
||||
F test/wal3.test 18da4e65c30c43c646ad40e145e9a074e4062fc9
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 1bbfaa316dc2a1d0d1fac3f4500c38a90055a41b
|
||||
F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
|
||||
@@ -914,12 +911,11 @@ F test/walbig.test 0ab8a430ef420a3114f7092e0f30fc9585ffa155
|
||||
F test/walcksum.test f5447800a157c9e2234fbb8e80243f0813941bde
|
||||
F test/walcrash.test 4fcb661faf71db91214156d52d43ee327f52bde1
|
||||
F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
|
||||
F test/walcrash3.test 26d251a6dfaa1daae983268ccc6da0521d61e2e7
|
||||
F test/walfault.test efb0d5724893133e71b8d9d90abdb781845a6bb0
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
|
||||
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
|
||||
F test/walpersist.test 4d308b7f16470e85cb389636e59c455fe6b3a61a
|
||||
F test/walpersist.test fd40d33765b2693f721c90c66d97f99757559006
|
||||
F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63
|
||||
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
@@ -984,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 91d0437c0702904d27f0ef7b1b52d0797efe1826
|
||||
R 5f78dbf89e78a567743daf43caa5df96
|
||||
P e6806f0dc6a06796700d805952f95e2cc18f0ea3
|
||||
R 36de029057c30e17d2fa1fff1aac580d
|
||||
U drh
|
||||
Z da5e946383fd5dfe4d9a2957cf126f26
|
||||
Z 7a6d88ce3643ba76bc132c1e4c6b20fc
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
9799241f7de952c4d1ea8bf6508b577d2b57a370
|
||||
627eff32a23ec676f7e87f6904981b3804e0e1f0
|
||||
@@ -529,7 +529,6 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumEq);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regNumLt);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regNumDLt);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regSample, regAccum);
|
||||
sqlite3VdbeAddOp4(v, OP_Function, 1, regCount, regAccum,
|
||||
(char*)&stat3InitFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2);
|
||||
|
||||
+1
-1
@@ -3979,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
|
||||
|
||||
@@ -148,6 +148,7 @@ Expr *sqlite3LimitWhere(
|
||||
*/
|
||||
if( pOrderBy && (pLimit == 0) ) {
|
||||
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
||||
pParse->parseError = 1;
|
||||
goto limit_where_cleanup_2;
|
||||
}
|
||||
|
||||
|
||||
+11
-287
@@ -870,7 +870,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
|
||||
pItem->sortOrder = pOldItem->sortOrder;
|
||||
pItem->done = 0;
|
||||
pItem->iOrderByCol = pOldItem->iOrderByCol;
|
||||
pItem->iCol = pOldItem->iCol;
|
||||
pItem->iAlias = pOldItem->iAlias;
|
||||
}
|
||||
return pNew;
|
||||
@@ -940,7 +940,7 @@ IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
||||
return pNew;
|
||||
}
|
||||
Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
Select *pNew, *pPrior;
|
||||
Select *pNew;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(*p) );
|
||||
if( pNew==0 ) return 0;
|
||||
@@ -951,9 +951,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
|
||||
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
|
||||
pNew->op = p->op;
|
||||
pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = 0;
|
||||
pNew->pPrior = sqlite3SelectDup(db, p->pPrior, flags);
|
||||
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
|
||||
pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
|
||||
pNew->iLimit = 0;
|
||||
@@ -1375,15 +1373,6 @@ static int isCandidateForInOpt(Select *p){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** Code an OP_Once instruction and allocate space for its flag. Return the
|
||||
** address of the new instruction.
|
||||
*/
|
||||
int sqlite3CodeOnce(Parse *pParse){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used by the implementation of the IN (...) operator.
|
||||
** It's job is to find or create a b-tree structure that may be used
|
||||
@@ -1444,7 +1433,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
||||
int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
|
||||
@@ -1455,6 +1443,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
int iCol; /* Index of column <column> */
|
||||
@@ -1479,9 +1468,10 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*/
|
||||
assert(v);
|
||||
if( iCol<0 ){
|
||||
int iMem = ++pParse->nMem;
|
||||
int iAddr;
|
||||
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
|
||||
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
eType = IN_INDEX_ROWID;
|
||||
@@ -1507,11 +1497,12 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
|
||||
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
|
||||
){
|
||||
int iMem = ++pParse->nMem;
|
||||
int iAddr;
|
||||
char *pKey;
|
||||
|
||||
pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
|
||||
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
|
||||
pKey,P4_KEYINFO_HANDOFF);
|
||||
@@ -1521,7 +1512,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
if( prNotFound && !pTab->aCol[iCol].notNull ){
|
||||
*prNotFound = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1537,7 +1527,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
eType = IN_INDEX_EPH;
|
||||
if( prNotFound ){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>(double)1 );
|
||||
pParse->nQueryLoop = (double)1;
|
||||
@@ -1610,8 +1599,9 @@ int sqlite3CodeSubselect(
|
||||
** If all of the above are false, then we can run this code just once
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse);
|
||||
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
|
||||
int mem = ++pParse->nMem;
|
||||
testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
@@ -2949,264 +2939,6 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
return inReg;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression tree.
|
||||
*/
|
||||
void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
|
||||
int op; /* The opcode being coded */
|
||||
const char *zBinOp = 0; /* Binary operator */
|
||||
const char *zUniOp = 0; /* Unary operator */
|
||||
if( pExpr==0 ){
|
||||
op = TK_NULL;
|
||||
}else{
|
||||
op = pExpr->op;
|
||||
}
|
||||
switch( op ){
|
||||
case TK_AGG_COLUMN: {
|
||||
sqlite3ExplainPrintf(pOut, "AGG{%d:%d}",
|
||||
pExpr->iTable, pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( pExpr->iTable<0 ){
|
||||
/* This only happens when coding check constraints */
|
||||
sqlite3ExplainPrintf(pOut, "COLUMN(%d)", pExpr->iColumn);
|
||||
}else{
|
||||
sqlite3ExplainPrintf(pOut, "{%d:%d}",
|
||||
pExpr->iTable, pExpr->iColumn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
if( pExpr->flags & EP_IntValue ){
|
||||
sqlite3ExplainPrintf(pOut, "%d", pExpr->u.iValue);
|
||||
}else{
|
||||
sqlite3ExplainPrintf(pOut, "%s", pExpr->u.zToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
case TK_FLOAT: {
|
||||
sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_STRING: {
|
||||
sqlite3ExplainPrintf(pOut,"%Q", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
case TK_NULL: {
|
||||
sqlite3ExplainPrintf(pOut,"NULL");
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
||||
case TK_BLOB: {
|
||||
sqlite3ExplainPrintf(pOut,"%s", pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case TK_VARIABLE: {
|
||||
sqlite3ExplainPrintf(pOut,"VARIABLE(%s,%d)",
|
||||
pExpr->u.zToken, pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_REGISTER: {
|
||||
sqlite3ExplainPrintf(pOut,"REGISTER(%d)", pExpr->iTable);
|
||||
break;
|
||||
}
|
||||
case TK_AS: {
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CAST
|
||||
case TK_CAST: {
|
||||
/* Expressions of the form: CAST(pLeft AS token) */
|
||||
const char *zAff = "unk";
|
||||
switch( sqlite3AffinityType(pExpr->u.zToken) ){
|
||||
case SQLITE_AFF_TEXT: zAff = "TEXT"; break;
|
||||
case SQLITE_AFF_NONE: zAff = "NONE"; break;
|
||||
case SQLITE_AFF_NUMERIC: zAff = "NUMERIC"; break;
|
||||
case SQLITE_AFF_INTEGER: zAff = "INTEGER"; break;
|
||||
case SQLITE_AFF_REAL: zAff = "REAL"; break;
|
||||
}
|
||||
sqlite3ExplainPrintf(pOut, "CAST-%s(", zAff);
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut, ")");
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_CAST */
|
||||
case TK_LT: zBinOp = "LT"; break;
|
||||
case TK_LE: zBinOp = "LE"; break;
|
||||
case TK_GT: zBinOp = "GT"; break;
|
||||
case TK_GE: zBinOp = "GE"; break;
|
||||
case TK_NE: zBinOp = "NE"; break;
|
||||
case TK_EQ: zBinOp = "EQ"; break;
|
||||
case TK_IS: zBinOp = "IS"; break;
|
||||
case TK_ISNOT: zBinOp = "ISNOT"; break;
|
||||
case TK_AND: zBinOp = "AND"; break;
|
||||
case TK_OR: zBinOp = "OR"; break;
|
||||
case TK_PLUS: zBinOp = "ADD"; break;
|
||||
case TK_STAR: zBinOp = "MUL"; break;
|
||||
case TK_MINUS: zBinOp = "SUB"; break;
|
||||
case TK_REM: zBinOp = "REM"; break;
|
||||
case TK_BITAND: zBinOp = "BITAND"; break;
|
||||
case TK_BITOR: zBinOp = "BITOR"; break;
|
||||
case TK_SLASH: zBinOp = "DIV"; break;
|
||||
case TK_LSHIFT: zBinOp = "LSHIFT"; break;
|
||||
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
|
||||
case TK_CONCAT: zBinOp = "CONCAT"; break;
|
||||
|
||||
case TK_UMINUS: zUniOp = "UMINUS"; break;
|
||||
case TK_UPLUS: zUniOp = "UPLUS"; break;
|
||||
case TK_BITNOT: zUniOp = "BITNOT"; break;
|
||||
case TK_NOT: zUniOp = "NOT"; break;
|
||||
case TK_ISNULL: zUniOp = "ISNULL"; break;
|
||||
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
pFarg = pExpr->x.pList;
|
||||
}
|
||||
sqlite3ExplainPrintf(pOut, "%sFUNCTION:%s(",
|
||||
op==TK_AGG_FUNCTION ? "AGG_" : "",
|
||||
pExpr->u.zToken);
|
||||
if( pFarg ){
|
||||
sqlite3ExplainExprList(pOut, pFarg);
|
||||
}
|
||||
sqlite3ExplainPrintf(pOut, ")");
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case TK_EXISTS: {
|
||||
sqlite3ExplainPrintf(pOut, "EXISTS(");
|
||||
sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
|
||||
sqlite3ExplainPrintf(pOut,")");
|
||||
break;
|
||||
}
|
||||
case TK_SELECT: {
|
||||
sqlite3ExplainPrintf(pOut, "(");
|
||||
sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
|
||||
sqlite3ExplainPrintf(pOut, ")");
|
||||
break;
|
||||
}
|
||||
case TK_IN: {
|
||||
sqlite3ExplainPrintf(pOut, "IN(");
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut, ",");
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
sqlite3ExplainSelect(pOut, pExpr->x.pSelect);
|
||||
}else{
|
||||
sqlite3ExplainExprList(pOut, pExpr->x.pList);
|
||||
}
|
||||
sqlite3ExplainPrintf(pOut, ")");
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** x BETWEEN y AND z
|
||||
**
|
||||
** This is equivalent to
|
||||
**
|
||||
** x>=y AND x<=z
|
||||
**
|
||||
** X is stored in pExpr->pLeft.
|
||||
** Y is stored in pExpr->pList->a[0].pExpr.
|
||||
** Z is stored in pExpr->pList->a[1].pExpr.
|
||||
*/
|
||||
case TK_BETWEEN: {
|
||||
Expr *pX = pExpr->pLeft;
|
||||
Expr *pY = pExpr->x.pList->a[0].pExpr;
|
||||
Expr *pZ = pExpr->x.pList->a[1].pExpr;
|
||||
sqlite3ExplainPrintf(pOut, "BETWEEN(");
|
||||
sqlite3ExplainExpr(pOut, pX);
|
||||
sqlite3ExplainPrintf(pOut, ",");
|
||||
sqlite3ExplainExpr(pOut, pY);
|
||||
sqlite3ExplainPrintf(pOut, ",");
|
||||
sqlite3ExplainExpr(pOut, pZ);
|
||||
sqlite3ExplainPrintf(pOut, ")");
|
||||
break;
|
||||
}
|
||||
case TK_TRIGGER: {
|
||||
/* If the opcode is TK_TRIGGER, then the expression is a reference
|
||||
** to a column in the new.* or old.* pseudo-tables available to
|
||||
** trigger programs. In this case Expr.iTable is set to 1 for the
|
||||
** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
|
||||
** is set to the column of the pseudo-table to read, or to -1 to
|
||||
** read the rowid field.
|
||||
*/
|
||||
sqlite3ExplainPrintf(pOut, "%s(%d)",
|
||||
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
|
||||
break;
|
||||
}
|
||||
case TK_CASE: {
|
||||
sqlite3ExplainPrintf(pOut, "CASE(");
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut, ",");
|
||||
sqlite3ExplainExprList(pOut, pExpr->x.pList);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
const char *zType = "unk";
|
||||
switch( pExpr->affinity ){
|
||||
case OE_Rollback: zType = "rollback"; break;
|
||||
case OE_Abort: zType = "abort"; break;
|
||||
case OE_Fail: zType = "fail"; break;
|
||||
case OE_Ignore: zType = "ignore"; break;
|
||||
}
|
||||
sqlite3ExplainPrintf(pOut, "RAISE-%s(%s)", zType, pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( zBinOp ){
|
||||
sqlite3ExplainPrintf(pOut,"%s(", zBinOp);
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut,",");
|
||||
sqlite3ExplainExpr(pOut, pExpr->pRight);
|
||||
sqlite3ExplainPrintf(pOut,")");
|
||||
}else if( zUniOp ){
|
||||
sqlite3ExplainPrintf(pOut,"%s(", zUniOp);
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut,")");
|
||||
}
|
||||
}
|
||||
#endif /* defined(SQLITE_ENABLE_TREE_EXPLAIN) */
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
/*
|
||||
** Generate a human-readable explanation of an expression list.
|
||||
*/
|
||||
void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
|
||||
int i;
|
||||
if( pList==0 || pList->nExpr==0 ){
|
||||
sqlite3ExplainPrintf(pOut, "(empty-list)");
|
||||
return;
|
||||
}else if( pList->nExpr==1 ){
|
||||
sqlite3ExplainExpr(pOut, pList->a[0].pExpr);
|
||||
}else{
|
||||
sqlite3ExplainPush(pOut);
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
sqlite3ExplainPrintf(pOut, "item[%d] = ", i);
|
||||
sqlite3ExplainPush(pOut);
|
||||
sqlite3ExplainExpr(pOut, pList->a[i].pExpr);
|
||||
sqlite3ExplainPop(pOut);
|
||||
if( i<pList->nExpr-1 ){
|
||||
sqlite3ExplainNL(pOut);
|
||||
}
|
||||
}
|
||||
sqlite3ExplainPop(pOut);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Return TRUE if pExpr is an constant expression that is appropriate
|
||||
** for factoring out of a loop. Appropriate expressions are:
|
||||
@@ -4030,11 +3762,3 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
|
||||
pParse->iRangeReg = iReg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark all temporary registers as being unavailable for reuse.
|
||||
*/
|
||||
void sqlite3ClearTempRegCache(Parse *pParse){
|
||||
pParse->nTempReg = 0;
|
||||
pParse->nRangeReg = 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
500, /* nLookaside */
|
||||
{0,0,0,0,0,0,0,0}, /* m */
|
||||
{0,0,0,0,0,0,0,0,0}, /* mutex */
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
|
||||
{0,0,0,0,0,0,0,0,0,0,0}, /* pcache2 */
|
||||
(void*)0, /* pHeap */
|
||||
0, /* nHeap */
|
||||
0, 0, /* mnHeap, mxHeap */
|
||||
|
||||
@@ -239,7 +239,6 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
memId = p->regCtr;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
||||
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
|
||||
|
||||
+15
-24
@@ -1659,6 +1659,7 @@ static int createCollation(
|
||||
sqlite3* db,
|
||||
const char *zName,
|
||||
u8 enc,
|
||||
u8 collType,
|
||||
void* pCtx,
|
||||
int(*xCompare)(void*,int,const void*,int,const void*),
|
||||
void(*xDel)(void*)
|
||||
@@ -1723,6 +1724,7 @@ static int createCollation(
|
||||
pColl->pUser = pCtx;
|
||||
pColl->xDel = xDel;
|
||||
pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED));
|
||||
pColl->type = collType;
|
||||
sqlite3Error(db, SQLITE_OK, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2183,10 +2185,14 @@ static int openDatabase(
|
||||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
*/
|
||||
createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
|
||||
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0,
|
||||
binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16BE, SQLITE_COLL_BINARY, 0,
|
||||
binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16LE, SQLITE_COLL_BINARY, 0,
|
||||
binCollFunc, 0);
|
||||
createCollation(db, "RTRIM", SQLITE_UTF8, SQLITE_COLL_USER, (void*)1,
|
||||
binCollFunc, 0);
|
||||
if( db->mallocFailed ){
|
||||
goto opendb_out;
|
||||
}
|
||||
@@ -2194,7 +2200,8 @@ static int openDatabase(
|
||||
assert( db->pDfltColl!=0 );
|
||||
|
||||
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0,
|
||||
nocaseCollatingFunc, 0);
|
||||
|
||||
/* Parse the filename/URI argument. */
|
||||
db->openFlags = flags;
|
||||
@@ -2390,7 +2397,7 @@ int sqlite3_create_collation(
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, 0);
|
||||
rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
@@ -2410,7 +2417,7 @@ int sqlite3_create_collation_v2(
|
||||
int rc;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
assert( !db->mallocFailed );
|
||||
rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xDel);
|
||||
rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, xDel);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
@@ -2433,7 +2440,7 @@ int sqlite3_create_collation16(
|
||||
assert( !db->mallocFailed );
|
||||
zName8 = sqlite3Utf16to8(db, zName, -1, SQLITE_UTF16NATIVE);
|
||||
if( zName8 ){
|
||||
rc = createCollation(db, zName8, (u8)enc, pCtx, xCompare, 0);
|
||||
rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0);
|
||||
sqlite3DbFree(db, zName8);
|
||||
}
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
@@ -2943,22 +2950,6 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT,
|
||||
** sqlite3_stmt*,const char**);
|
||||
**
|
||||
** If compiled with SQLITE_ENABLE_TREE_EXPLAIN, each sqlite3_stmt holds
|
||||
** a string that describes the optimized parse tree. This test-control
|
||||
** returns a pointer to that string.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_EXPLAIN_STMT: {
|
||||
sqlite3_stmt *pStmt = va_arg(ap, sqlite3_stmt*);
|
||||
const char **pzRet = va_arg(ap, const char**);
|
||||
*pzRet = sqlite3VdbeExplanation((Vdbe*)pStmt);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
||||
+12
-77
@@ -26,47 +26,10 @@
|
||||
*/
|
||||
#ifdef SQLITE_SYSTEM_MALLOC
|
||||
|
||||
/*
|
||||
** Windows systems have malloc_usable_size() but it is called _msize()
|
||||
*/
|
||||
#if !defined(HAVE_MALLOC_USABLE_SIZE) && SQLITE_OS_WIN
|
||||
# define HAVE_MALLOC_USABLE_SIZE 1
|
||||
# define malloc_usable_size _msize
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
||||
/*
|
||||
** Use the zone allocator available on apple products
|
||||
*/
|
||||
#include <sys/sysctl.h>
|
||||
#include <malloc/malloc.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
static malloc_zone_t* _sqliteZone_;
|
||||
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
|
||||
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
|
||||
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
|
||||
#define SQLITE_MALLOCSIZE(x) \
|
||||
(_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
|
||||
|
||||
#else /* if not __APPLE__ */
|
||||
|
||||
/*
|
||||
** Use standard C library malloc and free on non-Apple systems.
|
||||
*/
|
||||
#define SQLITE_MALLOC(x) malloc(x)
|
||||
#define SQLITE_FREE(x) free(x)
|
||||
#define SQLITE_REALLOC(x,y) realloc((x),(y))
|
||||
|
||||
#ifdef HAVE_MALLOC_USABLE_SIZE
|
||||
#include <malloc.h>
|
||||
#define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
|
||||
#else
|
||||
#undef SQLITE_MALLOCSIZE
|
||||
#endif
|
||||
|
||||
#endif /* __APPLE__ or not __APPLE__ */
|
||||
|
||||
/*
|
||||
** Like malloc(), but remember the size of the allocation
|
||||
** so that we can find it later using sqlite3MemSize().
|
||||
@@ -76,8 +39,8 @@ static malloc_zone_t* _sqliteZone_;
|
||||
** routines.
|
||||
*/
|
||||
static void *sqlite3MemMalloc(int nByte){
|
||||
#ifdef SQLITE_MALLOCSIZE
|
||||
void *p = SQLITE_MALLOC( 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);
|
||||
@@ -87,7 +50,7 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
sqlite3_int64 *p;
|
||||
assert( nByte>0 );
|
||||
nByte = ROUND8(nByte);
|
||||
p = SQLITE_MALLOC( nByte+8 );
|
||||
p = malloc( nByte+8 );
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
@@ -108,13 +71,13 @@ static void *sqlite3MemMalloc(int nByte){
|
||||
** by higher-level routines.
|
||||
*/
|
||||
static void sqlite3MemFree(void *pPrior){
|
||||
#ifdef SQLITE_MALLOCSIZE
|
||||
SQLITE_FREE(pPrior);
|
||||
#if HAVE_MALLOC_USABLE_SIZE
|
||||
free(pPrior);
|
||||
#else
|
||||
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
|
||||
assert( pPrior!=0 );
|
||||
p--;
|
||||
SQLITE_FREE(p);
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -123,8 +86,8 @@ static void sqlite3MemFree(void *pPrior){
|
||||
** or xRealloc().
|
||||
*/
|
||||
static int sqlite3MemSize(void *pPrior){
|
||||
#ifdef SQLITE_MALLOCSIZE
|
||||
return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
|
||||
#if HAVE_MALLOC_USABLE_SIZE
|
||||
return pPrior ? (int)malloc_usable_size(pPrior) : 0;
|
||||
#else
|
||||
sqlite3_int64 *p;
|
||||
if( pPrior==0 ) return 0;
|
||||
@@ -145,13 +108,13 @@ static int sqlite3MemSize(void *pPrior){
|
||||
** routines and redirected to xFree.
|
||||
*/
|
||||
static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
#ifdef SQLITE_MALLOCSIZE
|
||||
void *p = SQLITE_REALLOC(pPrior, 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",
|
||||
SQLITE_MALLOCSIZE(pPrior), nByte);
|
||||
malloc_usable_size(pPrior), nByte);
|
||||
}
|
||||
return p;
|
||||
#else
|
||||
@@ -159,7 +122,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
||||
assert( pPrior!=0 && nByte>0 );
|
||||
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
|
||||
p--;
|
||||
p = SQLITE_REALLOC(p, nByte+8 );
|
||||
p = realloc(p, nByte+8 );
|
||||
if( p ){
|
||||
p[0] = nByte;
|
||||
p++;
|
||||
@@ -184,34 +147,6 @@ static int sqlite3MemRoundup(int n){
|
||||
** Initialize this module.
|
||||
*/
|
||||
static int sqlite3MemInit(void *NotUsed){
|
||||
#if defined(__APPLE__)
|
||||
int cpuCount;
|
||||
size_t len;
|
||||
if( _sqliteZone_ ){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
len = sizeof(cpuCount);
|
||||
/* One usually wants to use hw.acctivecpu for MT decisions, but not here */
|
||||
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
|
||||
if( cpuCount>1 ){
|
||||
/* defer MT decisions to system malloc */
|
||||
_sqliteZone_ = malloc_default_zone();
|
||||
}else{
|
||||
/* only 1 core, use our own zone to contention over global locks,
|
||||
** e.g. we have our own dedicated locks */
|
||||
bool success;
|
||||
malloc_zone_t* newzone = malloc_create_zone(4096, 0);
|
||||
malloc_set_zone_name(newzone, "Sqlite_Heap");
|
||||
do{
|
||||
success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
|
||||
(void * volatile *)&_sqliteZone_);
|
||||
}while(!_sqliteZone_);
|
||||
if( !success ){
|
||||
/* somebody registered a zone first */
|
||||
malloc_destroy_zone(newzone);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,17 @@
|
||||
# endif
|
||||
#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
|
||||
|
||||
|
||||
/*
|
||||
** Define the maximum size of a temporary filename
|
||||
*/
|
||||
@@ -91,11 +102,23 @@
|
||||
|
||||
/*
|
||||
** 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 defined(_WIN32_WINNT)
|
||||
#if SQLITE_OS_WIN && !defined(SQLITE_OS_WINNT)
|
||||
# define SQLITE_OS_WINNT 1
|
||||
#else
|
||||
# define SQLITE_OS_WINNT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -2015,8 +2015,8 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
|
||||
rc = osRmdir(zLockFile);
|
||||
if( rc<0 && errno==ENOTDIR ) rc = osUnlink(zLockFile);
|
||||
if( rc<0 ){
|
||||
int rc = 0;
|
||||
int tErrno = errno;
|
||||
rc = 0;
|
||||
if( ENOENT != tErrno ){
|
||||
rc = SQLITE_IOERR_UNLOCK;
|
||||
}
|
||||
|
||||
+29
-54
@@ -918,9 +918,6 @@ static LPWSTR utf8ToUnicode(const char *zFilename){
|
||||
LPWSTR zWideFilename;
|
||||
|
||||
nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
|
||||
if( nChar==0 ){
|
||||
return 0;
|
||||
}
|
||||
zWideFilename = sqlite3_malloc( nChar*sizeof(zWideFilename[0]) );
|
||||
if( zWideFilename==0 ){
|
||||
return 0;
|
||||
@@ -943,9 +940,6 @@ static char *unicodeToUtf8(LPCWSTR zWideFilename){
|
||||
char *zFilename;
|
||||
|
||||
nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
|
||||
if( nByte == 0 ){
|
||||
return 0;
|
||||
}
|
||||
zFilename = sqlite3_malloc( nByte );
|
||||
if( zFilename==0 ){
|
||||
return 0;
|
||||
@@ -973,9 +967,6 @@ static LPWSTR mbcsToUnicode(const char *zFilename){
|
||||
|
||||
nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
|
||||
0)*sizeof(WCHAR);
|
||||
if( nByte==0 ){
|
||||
return 0;
|
||||
}
|
||||
zMbcsFilename = sqlite3_malloc( nByte*sizeof(zMbcsFilename[0]) );
|
||||
if( zMbcsFilename==0 ){
|
||||
return 0;
|
||||
@@ -1002,9 +993,6 @@ static char *unicodeToMbcs(LPCWSTR zWideFilename){
|
||||
int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
||||
|
||||
nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
|
||||
if( nByte == 0 ){
|
||||
return 0;
|
||||
}
|
||||
zFilename = sqlite3_malloc( nByte );
|
||||
if( zFilename==0 ){
|
||||
return 0;
|
||||
@@ -1182,14 +1170,12 @@ static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
|
||||
** to see if it should be retried. Return TRUE to retry. Return FALSE
|
||||
** to give up with an error.
|
||||
*/
|
||||
static int retryIoerr(int *pnRetry, DWORD *pError){
|
||||
DWORD e = osGetLastError();
|
||||
static int retryIoerr(int *pnRetry){
|
||||
DWORD e;
|
||||
if( *pnRetry>=win32IoerrRetry ){
|
||||
if( pError ){
|
||||
*pError = e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
e = osGetLastError();
|
||||
if( e==ERROR_ACCESS_DENIED ||
|
||||
e==ERROR_LOCK_VIOLATION ||
|
||||
e==ERROR_SHARING_VIOLATION ){
|
||||
@@ -1197,9 +1183,6 @@ static int retryIoerr(int *pnRetry, DWORD *pError){
|
||||
++*pnRetry;
|
||||
return 1;
|
||||
}
|
||||
if( pError ){
|
||||
*pError = e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1556,7 +1539,6 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
|
||||
LONG upperBits; /* Most sig. 32 bits of new offset */
|
||||
LONG lowerBits; /* Least sig. 32 bits of new offset */
|
||||
DWORD dwRet; /* Value returned by SetFilePointer() */
|
||||
DWORD lastErrno; /* Value returned by GetLastError() */
|
||||
|
||||
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
|
||||
lowerBits = (LONG)(iOffset & 0xffffffff);
|
||||
@@ -1569,10 +1551,8 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
|
||||
** GetLastError().
|
||||
*/
|
||||
dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
|
||||
if( (dwRet==INVALID_SET_FILE_POINTER
|
||||
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
if( (dwRet==INVALID_SET_FILE_POINTER && osGetLastError()!=NO_ERROR) ){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
|
||||
"seekWinFile", pFile->zPath);
|
||||
return 1;
|
||||
@@ -1648,9 +1628,8 @@ static int winRead(
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
|
||||
DWORD lastErrno;
|
||||
if( retryIoerr(&nRetry, &lastErrno) ) continue;
|
||||
pFile->lastErrno = lastErrno;
|
||||
if( retryIoerr(&nRetry) ) continue;
|
||||
pFile->lastErrno = osGetLastError();
|
||||
return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
|
||||
"winRead", pFile->zPath);
|
||||
}
|
||||
@@ -1690,11 +1669,10 @@ static int winWrite(
|
||||
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
|
||||
int nRem = amt; /* Number of bytes yet to be written */
|
||||
DWORD nWrite; /* Bytes written by each WriteFile() call */
|
||||
DWORD lastErrno = NO_ERROR; /* Value returned by GetLastError() */
|
||||
|
||||
while( nRem>0 ){
|
||||
if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
|
||||
if( retryIoerr(&nRetry, &lastErrno) ) continue;
|
||||
if( retryIoerr(&nRetry) ) continue;
|
||||
break;
|
||||
}
|
||||
if( nWrite<=0 ) break;
|
||||
@@ -1702,7 +1680,7 @@ static int winWrite(
|
||||
nRem -= nWrite;
|
||||
}
|
||||
if( nRem>0 ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
pFile->lastErrno = osGetLastError();
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
@@ -1832,15 +1810,15 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
|
||||
DWORD upperBits;
|
||||
DWORD lowerBits;
|
||||
winFile *pFile = (winFile*)id;
|
||||
DWORD lastErrno;
|
||||
DWORD error;
|
||||
|
||||
assert( id!=0 );
|
||||
SimulateIOError(return SQLITE_IOERR_FSTAT);
|
||||
lowerBits = osGetFileSize(pFile->h, &upperBits);
|
||||
if( (lowerBits == INVALID_FILE_SIZE)
|
||||
&& ((lastErrno = osGetLastError())!=NO_ERROR) )
|
||||
&& ((error = osGetLastError()) != NO_ERROR) )
|
||||
{
|
||||
pFile->lastErrno = lastErrno;
|
||||
pFile->lastErrno = error;
|
||||
return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno,
|
||||
"winFileSize", pFile->zPath);
|
||||
}
|
||||
@@ -1891,7 +1869,6 @@ static int getReadLock(winFile *pFile){
|
||||
*/
|
||||
static int unlockReadLock(winFile *pFile){
|
||||
int res;
|
||||
DWORD lastErrno;
|
||||
if( isNT() ){
|
||||
res = osUnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
|
||||
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
|
||||
@@ -1901,8 +1878,8 @@ static int unlockReadLock(winFile *pFile){
|
||||
res = osUnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
|
||||
#endif
|
||||
}
|
||||
if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
if( res==0 && osGetLastError()!=ERROR_NOT_LOCKED ){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
|
||||
"unlockReadLock", pFile->zPath);
|
||||
}
|
||||
@@ -1941,7 +1918,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
int newLocktype; /* Set pFile->locktype to this value before exiting */
|
||||
int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
|
||||
winFile *pFile = (winFile*)id;
|
||||
DWORD lastErrno = NO_ERROR;
|
||||
DWORD error = NO_ERROR;
|
||||
|
||||
assert( id!=0 );
|
||||
OSTRACE(("LOCK %d %d was %d(%d)\n",
|
||||
@@ -1983,7 +1960,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
}
|
||||
gotPendingLock = res;
|
||||
if( !res ){
|
||||
lastErrno = osGetLastError();
|
||||
error = osGetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1995,7 +1972,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
if( res ){
|
||||
newLocktype = SHARED_LOCK;
|
||||
}else{
|
||||
lastErrno = osGetLastError();
|
||||
error = osGetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2007,7 +1984,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
if( res ){
|
||||
newLocktype = RESERVED_LOCK;
|
||||
}else{
|
||||
lastErrno = osGetLastError();
|
||||
error = osGetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2028,8 +2005,8 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
if( res ){
|
||||
newLocktype = EXCLUSIVE_LOCK;
|
||||
}else{
|
||||
lastErrno = osGetLastError();
|
||||
OSTRACE(("error-code = %d\n", lastErrno));
|
||||
error = osGetLastError();
|
||||
OSTRACE(("error-code = %d\n", error));
|
||||
getReadLock(pFile);
|
||||
}
|
||||
}
|
||||
@@ -2049,7 +2026,7 @@ static int winLock(sqlite3_file *id, int locktype){
|
||||
}else{
|
||||
OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
|
||||
locktype, newLocktype));
|
||||
pFile->lastErrno = lastErrno;
|
||||
pFile->lastErrno = error;
|
||||
rc = SQLITE_BUSY;
|
||||
}
|
||||
pFile->locktype = (u8)newLocktype;
|
||||
@@ -2991,7 +2968,6 @@ static int winOpen(
|
||||
int *pOutFlags /* Status return flags */
|
||||
){
|
||||
HANDLE h;
|
||||
DWORD lastErrno;
|
||||
DWORD dwDesiredAccess;
|
||||
DWORD dwShareMode;
|
||||
DWORD dwCreationDisposition;
|
||||
@@ -3128,7 +3104,7 @@ static int winOpen(
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL))==INVALID_HANDLE_VALUE &&
|
||||
retryIoerr(&cnt, &lastErrno) ){}
|
||||
retryIoerr(&cnt) ){}
|
||||
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
|
||||
** Since the ANSI version of these Windows API do not exist for WINCE,
|
||||
** it's important to not reference them for WINCE builds.
|
||||
@@ -3141,7 +3117,7 @@ static int winOpen(
|
||||
dwCreationDisposition,
|
||||
dwFlagsAndAttributes,
|
||||
NULL))==INVALID_HANDLE_VALUE &&
|
||||
retryIoerr(&cnt, &lastErrno) ){}
|
||||
retryIoerr(&cnt) ){}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3152,7 +3128,7 @@ static int winOpen(
|
||||
h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
|
||||
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
pFile->lastErrno = lastErrno;
|
||||
pFile->lastErrno = osGetLastError();
|
||||
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
|
||||
sqlite3_free(zConverted);
|
||||
if( isReadWrite && !isExclusive ){
|
||||
@@ -3219,7 +3195,6 @@ static int winDelete(
|
||||
){
|
||||
int cnt = 0;
|
||||
int rc;
|
||||
DWORD lastErrno;
|
||||
void *zConverted;
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
UNUSED_PARAMETER(syncDir);
|
||||
@@ -3232,7 +3207,7 @@ static int winDelete(
|
||||
if( isNT() ){
|
||||
rc = 1;
|
||||
while( osGetFileAttributesW(zConverted)!=INVALID_FILE_ATTRIBUTES &&
|
||||
(rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
|
||||
(rc = osDeleteFileW(zConverted))==0 && retryIoerr(&cnt) ){}
|
||||
rc = rc ? SQLITE_OK : SQLITE_ERROR;
|
||||
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
|
||||
** Since the ANSI version of these Windows API do not exist for WINCE,
|
||||
@@ -3242,12 +3217,12 @@ static int winDelete(
|
||||
}else{
|
||||
rc = 1;
|
||||
while( osGetFileAttributesA(zConverted)!=INVALID_FILE_ATTRIBUTES &&
|
||||
(rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt, &lastErrno) ){}
|
||||
(rc = osDeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){}
|
||||
rc = rc ? SQLITE_OK : SQLITE_ERROR;
|
||||
#endif
|
||||
}
|
||||
if( rc ){
|
||||
rc = winLogError(SQLITE_IOERR_DELETE, lastErrno,
|
||||
rc = winLogError(SQLITE_IOERR_DELETE, osGetLastError(),
|
||||
"winDelete", zFilename);
|
||||
}else{
|
||||
logIoerr(cnt);
|
||||
@@ -3268,7 +3243,6 @@ static int winAccess(
|
||||
){
|
||||
DWORD attr;
|
||||
int rc = 0;
|
||||
DWORD lastErrno;
|
||||
void *zConverted;
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
|
||||
@@ -3283,7 +3257,7 @@ static int winAccess(
|
||||
memset(&sAttrData, 0, sizeof(sAttrData));
|
||||
while( !(rc = osGetFileAttributesExW((LPCWSTR)zConverted,
|
||||
GetFileExInfoStandard,
|
||||
&sAttrData)) && retryIoerr(&cnt, &lastErrno) ){}
|
||||
&sAttrData)) && retryIoerr(&cnt) ){}
|
||||
if( rc ){
|
||||
/* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file
|
||||
** as if it does not exist.
|
||||
@@ -3296,6 +3270,7 @@ static int winAccess(
|
||||
attr = sAttrData.dwFileAttributes;
|
||||
}
|
||||
}else{
|
||||
DWORD lastErrno = osGetLastError();
|
||||
logIoerr(cnt);
|
||||
if( lastErrno!=ERROR_FILE_NOT_FOUND ){
|
||||
winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename);
|
||||
|
||||
+17
-27
@@ -616,7 +616,6 @@ struct Pager {
|
||||
u8 noSync; /* Do not sync the journal if true */
|
||||
u8 fullSync; /* Do extra syncs of the journal for robustness */
|
||||
u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
|
||||
u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
|
||||
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
@@ -787,7 +786,7 @@ static int pagerUseWal(Pager *pPager){
|
||||
#else
|
||||
# define pagerUseWal(x) 0
|
||||
# define pagerRollbackWal(x) 0
|
||||
# define pagerWalFrames(v,w,x,y) 0
|
||||
# define pagerWalFrames(v,w,x,y,z) 0
|
||||
# define pagerOpenWalIfPresent(z) SQLITE_OK
|
||||
# define pagerBeginReadTransaction(z) SQLITE_OK
|
||||
#endif
|
||||
@@ -2486,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 );
|
||||
@@ -2956,7 +2955,8 @@ static int pagerWalFrames(
|
||||
Pager *pPager, /* Pager object */
|
||||
PgHdr *pList, /* List of frames to log */
|
||||
Pgno nTruncate, /* Database size after this commit */
|
||||
int isCommit /* True if this is a commit */
|
||||
int isCommit, /* True if this is a commit */
|
||||
int syncFlags /* Flags to pass to OsSync() (or 0) */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
|
||||
@@ -2987,7 +2987,7 @@ static int pagerWalFrames(
|
||||
|
||||
if( pList->pgno==1 ) pager_write_changecounter(pList);
|
||||
rc = sqlite3WalFrames(pPager->pWal,
|
||||
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
|
||||
pPager->pageSize, pList, nTruncate, isCommit, syncFlags
|
||||
);
|
||||
if( rc==SQLITE_OK && pPager->pBackup ){
|
||||
PgHdr *p;
|
||||
@@ -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 );
|
||||
@@ -3367,10 +3367,6 @@ void sqlite3PagerSetSafetyLevel(
|
||||
pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
||||
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
|
||||
}
|
||||
pPager->walSyncFlags = pPager->syncFlags;
|
||||
if( pPager->fullSync ){
|
||||
pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3508,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;
|
||||
@@ -4125,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);
|
||||
@@ -4198,7 +4194,7 @@ static int pagerStress(void *p, PgHdr *pPg){
|
||||
rc = subjournalPage(pPg);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pagerWalFrames(pPager, pPg, 0, 0);
|
||||
rc = pagerWalFrames(pPager, pPg, 0, 0, 0);
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -4537,17 +4533,9 @@ int sqlite3PagerOpen(
|
||||
pPager->readOnly = (u8)readOnly;
|
||||
assert( useJournal || pPager->tempFile );
|
||||
pPager->noSync = pPager->tempFile;
|
||||
if( pPager->noSync ){
|
||||
assert( pPager->fullSync==0 );
|
||||
assert( pPager->syncFlags==0 );
|
||||
assert( pPager->walSyncFlags==0 );
|
||||
assert( pPager->ckptSyncFlags==0 );
|
||||
}else{
|
||||
pPager->fullSync = 1;
|
||||
pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
||||
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
|
||||
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
|
||||
}
|
||||
pPager->fullSync = pPager->noSync ?0:1;
|
||||
pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
|
||||
pPager->ckptSyncFlags = pPager->syncFlags;
|
||||
/* pPager->pFirst = 0; */
|
||||
/* pPager->pFirstSynced = 0; */
|
||||
/* pPager->pLast = 0; */
|
||||
@@ -5777,7 +5765,9 @@ int sqlite3PagerCommitPhaseOne(
|
||||
}
|
||||
assert( rc==SQLITE_OK );
|
||||
if( ALWAYS(pList) ){
|
||||
rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1);
|
||||
rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
|
||||
(pPager->fullSync ? pPager->syncFlags : 0)
|
||||
);
|
||||
}
|
||||
sqlite3PagerUnref(pPageOne);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+2
-3
@@ -33,10 +33,12 @@
|
||||
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
|
||||
assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
|
||||
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
|
||||
pParse->parseError = 1;
|
||||
}
|
||||
%stack_overflow {
|
||||
UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
|
||||
sqlite3ErrorMsg(pParse, "parser stack overflow");
|
||||
pParse->parseError = 1;
|
||||
}
|
||||
|
||||
// The name of the generated procedure that implements the parser
|
||||
@@ -394,9 +396,6 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
cmd ::= select(X). {
|
||||
SelectDest dest = {SRT_Output, 0, 0, 0, 0};
|
||||
sqlite3Select(pParse, X, &dest);
|
||||
sqlite3ExplainBegin(pParse->pVdbe);
|
||||
sqlite3ExplainSelect(pParse->pVdbe, X);
|
||||
sqlite3ExplainFinish(pParse->pVdbe);
|
||||
sqlite3SelectDelete(pParse->db, X);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -136,7 +136,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
/*
|
||||
** Append N space characters to the given string buffer.
|
||||
*/
|
||||
void sqlite3AppendSpace(StrAccum *pAccum, int N){
|
||||
static void appendSpace(StrAccum *pAccum, int N){
|
||||
static const char zSpaces[] = " ";
|
||||
while( N>=(int)sizeof(zSpaces)-1 ){
|
||||
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
|
||||
@@ -664,7 +664,7 @@ void sqlite3VXPrintf(
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
appendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
if( length>0 ){
|
||||
@@ -674,7 +674,7 @@ void sqlite3VXPrintf(
|
||||
register int nspace;
|
||||
nspace = width-length;
|
||||
if( nspace>0 ){
|
||||
sqlite3AppendSpace(pAccum, nspace);
|
||||
appendSpace(pAccum, nspace);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zExtra);
|
||||
|
||||
+7
-7
@@ -799,7 +799,7 @@ static int resolveCompoundOrderBy(
|
||||
pE->pColl = pColl;
|
||||
pE->flags |= EP_IntValue | flags;
|
||||
pE->u.iValue = iCol;
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
pItem->iCol = (u16)iCol;
|
||||
pItem->done = 1;
|
||||
}else{
|
||||
moreToDo = 1;
|
||||
@@ -848,12 +848,12 @@ int sqlite3ResolveOrderGroupBy(
|
||||
pEList = pSelect->pEList;
|
||||
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
|
||||
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
||||
if( pItem->iOrderByCol ){
|
||||
if( pItem->iOrderByCol>pEList->nExpr ){
|
||||
if( pItem->iCol ){
|
||||
if( pItem->iCol>pEList->nExpr ){
|
||||
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
|
||||
return 1;
|
||||
}
|
||||
resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType);
|
||||
resolveAlias(pParse, pEList, pItem->iCol-1, pItem->pExpr, zType);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -900,7 +900,7 @@ static int resolveOrderGroupBy(
|
||||
** a copy of the iCol-th result-set column. The subsequent call to
|
||||
** sqlite3ResolveOrderGroupBy() will convert the expression to a
|
||||
** copy of the iCol-th result-set expression. */
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
pItem->iCol = (u16)iCol;
|
||||
continue;
|
||||
}
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
@@ -911,12 +911,12 @@ static int resolveOrderGroupBy(
|
||||
resolveOutOfRangeError(pParse, zType, i+1, nResult);
|
||||
return 1;
|
||||
}
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
pItem->iCol = (u16)iCol;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, treat the ORDER BY term as an ordinary expression */
|
||||
pItem->iOrderByCol = 0;
|
||||
pItem->iCol = 0;
|
||||
if( sqlite3ResolveExprNames(pNC, pE) ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
+87
-94
@@ -2219,8 +2219,8 @@ static int multiSelectOrderBy(
|
||||
for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
|
||||
struct ExprList_item *pItem;
|
||||
for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
|
||||
assert( pItem->iOrderByCol>0 );
|
||||
if( pItem->iOrderByCol==i ) break;
|
||||
assert( pItem->iCol>0 );
|
||||
if( pItem->iCol==i ) break;
|
||||
}
|
||||
if( j==nOrderBy ){
|
||||
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
|
||||
@@ -2228,7 +2228,7 @@ static int multiSelectOrderBy(
|
||||
pNew->flags |= EP_IntValue;
|
||||
pNew->u.iValue = i;
|
||||
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
|
||||
pOrderBy->a[nOrderBy++].iOrderByCol = (u16)i;
|
||||
pOrderBy->a[nOrderBy++].iCol = (u16)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2244,8 +2244,8 @@ static int multiSelectOrderBy(
|
||||
if( aPermute ){
|
||||
struct ExprList_item *pItem;
|
||||
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
||||
assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr );
|
||||
aPermute[i] = pItem->iOrderByCol - 1;
|
||||
assert( pItem->iCol>0 && pItem->iCol<=p->pEList->nExpr );
|
||||
aPermute[i] = pItem->iCol - 1;
|
||||
}
|
||||
pKeyMerge =
|
||||
sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1));
|
||||
@@ -2588,8 +2588,9 @@ static void substSelect(
|
||||
|
||||
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
||||
/*
|
||||
** This routine attempts to flatten subqueries as a performance optimization.
|
||||
** This routine returns 1 if it makes changes and 0 if no flattening occurs.
|
||||
** This routine attempts to flatten subqueries in order to speed
|
||||
** execution. It returns 1 if it makes changes and 0 if no flattening
|
||||
** occurs.
|
||||
**
|
||||
** To understand the concept of flattening, consider the following
|
||||
** query:
|
||||
@@ -2631,10 +2632,7 @@ static void substSelect(
|
||||
** (6) The subquery does not use aggregates or the outer query is not
|
||||
** DISTINCT.
|
||||
**
|
||||
** (7) The subquery has a FROM clause. TODO: For subqueries without
|
||||
** A FROM clause, consider adding a FROM close with the special
|
||||
** table sqlite_once that consists of a single row containing a
|
||||
** single NULL.
|
||||
** (7) The subquery has a FROM clause.
|
||||
**
|
||||
** (8) The subquery does not use LIMIT or the outer query is not a join.
|
||||
**
|
||||
@@ -2667,14 +2665,11 @@ static void substSelect(
|
||||
**
|
||||
** * is not itself part of a compound select,
|
||||
** * is not an aggregate or DISTINCT query, and
|
||||
** * is not a join
|
||||
** * has no other tables or sub-selects in the FROM clause.
|
||||
**
|
||||
** The parent and sub-query may contain WHERE clauses. Subject to
|
||||
** rules (11), (13) and (14), they may also contain ORDER BY,
|
||||
** LIMIT and OFFSET clauses. The subquery cannot use any compound
|
||||
** operator other than UNION ALL because all the other compound
|
||||
** operators have an implied DISTINCT which is disallowed by
|
||||
** restriction (4).
|
||||
** LIMIT and OFFSET clauses.
|
||||
**
|
||||
** (18) If the sub-query is a compound select, then all terms of the
|
||||
** ORDER by clause of the parent must be simple references to
|
||||
@@ -2686,7 +2681,7 @@ static void substSelect(
|
||||
** (20) If the sub-query is a compound select, then it must not use
|
||||
** an ORDER BY clause. Ticket #3773. We could relax this constraint
|
||||
** somewhat by saying that the terms of the ORDER BY clause must
|
||||
** appear as unmodified result columns in the outer query. But we
|
||||
** appear as unmodified result columns in the outer query. But
|
||||
** have other optimizations in mind to deal with that case.
|
||||
**
|
||||
** (21) The subquery does not use LIMIT or the outer query is not
|
||||
@@ -2815,21 +2810,19 @@ static int flattenSubquery(
|
||||
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
||||
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
|
||||
assert( pSub->pSrc!=0 );
|
||||
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
|
||||
|| (pSub1->pPrior && pSub1->op!=TK_ALL)
|
||||
|| pSub1->pSrc->nSrc<1
|
||||
|| NEVER(pSub1->pSrc==0) || pSub1->pSrc->nSrc!=1
|
||||
){
|
||||
return 0;
|
||||
}
|
||||
testcase( pSub1->pSrc->nSrc>1 );
|
||||
}
|
||||
|
||||
/* Restriction 18. */
|
||||
if( p->pOrderBy ){
|
||||
int ii;
|
||||
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
|
||||
if( p->pOrderBy->a[ii].iOrderByCol==0 ) return 0;
|
||||
if( p->pOrderBy->a[ii].iCol==0 ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3852,11 +3845,12 @@ int sqlite3Select(
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
|
||||
if( pItem->isCorrelated==0 ){
|
||||
if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
|
||||
/* If the subquery is no correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
onceAddr = sqlite3CodeOnce(pParse);
|
||||
int regOnce = ++pParse->nMem;
|
||||
onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
@@ -3866,7 +3860,7 @@ int sqlite3Select(
|
||||
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
|
||||
}
|
||||
if( /*pParse->nErr ||*/ db->mallocFailed ){
|
||||
goto select_end;
|
||||
@@ -4161,7 +4155,6 @@ int sqlite3Select(
|
||||
VdbeComment((v, "clear abort flag"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
||||
VdbeComment((v, "indicate accumulator empty"));
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
||||
|
||||
/* Begin a loop that will extract all source rows in GROUP BY order.
|
||||
** This might involve two separate loops with an OP_Sort in between, or
|
||||
@@ -4501,98 +4494,98 @@ select_end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
#if defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Generate a human-readable description of a the Select object.
|
||||
*******************************************************************************
|
||||
** The following code is used for testing and debugging only. The code
|
||||
** that follows does not appear in normal builds.
|
||||
**
|
||||
** These routines are used to print out the content of all or part of a
|
||||
** parse structures such as Select or Expr. Such printouts are useful
|
||||
** for helping to understand what is happening inside the code generator
|
||||
** during the execution of complex SELECT statements.
|
||||
**
|
||||
** These routine are not called anywhere from within the normal
|
||||
** code base. Then are intended to be called from within the debugger
|
||||
** or from temporary "printf" statements inserted for debugging.
|
||||
*/
|
||||
static void explainOneSelect(Vdbe *pVdbe, Select *p){
|
||||
sqlite3ExplainPrintf(pVdbe, "SELECT ");
|
||||
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
|
||||
if( p->selFlags & SF_Distinct ){
|
||||
sqlite3ExplainPrintf(pVdbe, "DISTINCT ");
|
||||
}
|
||||
if( p->selFlags & SF_Aggregate ){
|
||||
sqlite3ExplainPrintf(pVdbe, "agg_flag ");
|
||||
}
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3ExplainPrintf(pVdbe, " ");
|
||||
void sqlite3PrintExpr(Expr *p){
|
||||
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
|
||||
sqlite3DebugPrintf("(%s", p->u.zToken);
|
||||
}else{
|
||||
sqlite3DebugPrintf("(%d", p->op);
|
||||
}
|
||||
sqlite3ExplainExprList(pVdbe, p->pEList);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
if( p->pSrc && p->pSrc->nSrc ){
|
||||
if( p->pLeft ){
|
||||
sqlite3DebugPrintf(" ");
|
||||
sqlite3PrintExpr(p->pLeft);
|
||||
}
|
||||
if( p->pRight ){
|
||||
sqlite3DebugPrintf(" ");
|
||||
sqlite3PrintExpr(p->pRight);
|
||||
}
|
||||
sqlite3DebugPrintf(")");
|
||||
}
|
||||
void sqlite3PrintExprList(ExprList *pList){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
sqlite3PrintExpr(pList->a[i].pExpr);
|
||||
if( i<pList->nExpr-1 ){
|
||||
sqlite3DebugPrintf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
void sqlite3PrintSelect(Select *p, int indent){
|
||||
sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p);
|
||||
sqlite3PrintExprList(p->pEList);
|
||||
sqlite3DebugPrintf("\n");
|
||||
if( p->pSrc ){
|
||||
char *zPrefix;
|
||||
int i;
|
||||
sqlite3ExplainPrintf(pVdbe, "FROM ");
|
||||
sqlite3ExplainPush(pVdbe);
|
||||
zPrefix = "FROM";
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
struct SrcList_item *pItem = &p->pSrc->a[i];
|
||||
sqlite3ExplainPrintf(pVdbe, "{%d,*} = ", pItem->iCursor);
|
||||
sqlite3DebugPrintf("%*s ", indent+6, zPrefix);
|
||||
zPrefix = "";
|
||||
if( pItem->pSelect ){
|
||||
sqlite3ExplainSelect(pVdbe, pItem->pSelect);
|
||||
if( pItem->pTab ){
|
||||
sqlite3ExplainPrintf(pVdbe, " (tabname=%s)", pItem->pTab->zName);
|
||||
}
|
||||
sqlite3DebugPrintf("(\n");
|
||||
sqlite3PrintSelect(pItem->pSelect, indent+10);
|
||||
sqlite3DebugPrintf("%*s)", indent+8, "");
|
||||
}else if( pItem->zName ){
|
||||
sqlite3ExplainPrintf(pVdbe, "%s", pItem->zName);
|
||||
sqlite3DebugPrintf("%s", pItem->zName);
|
||||
}
|
||||
if( pItem->pTab ){
|
||||
sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName);
|
||||
}
|
||||
if( pItem->zAlias ){
|
||||
sqlite3ExplainPrintf(pVdbe, " (AS %s)", pItem->zAlias);
|
||||
sqlite3DebugPrintf(" AS %s", pItem->zAlias);
|
||||
}
|
||||
if( pItem->jointype & JT_LEFT ){
|
||||
sqlite3ExplainPrintf(pVdbe, " LEFT-JOIN");
|
||||
if( i<p->pSrc->nSrc-1 ){
|
||||
sqlite3DebugPrintf(",");
|
||||
}
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
sqlite3ExplainPop(pVdbe);
|
||||
}
|
||||
if( p->pWhere ){
|
||||
sqlite3ExplainPrintf(pVdbe, "WHERE ");
|
||||
sqlite3ExplainExpr(pVdbe, p->pWhere);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3DebugPrintf("%*s WHERE ", indent, "");
|
||||
sqlite3PrintExpr(p->pWhere);
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
if( p->pGroupBy ){
|
||||
sqlite3ExplainPrintf(pVdbe, "GROUPBY ");
|
||||
sqlite3ExplainExprList(pVdbe, p->pGroupBy);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3DebugPrintf("%*s GROUP BY ", indent, "");
|
||||
sqlite3PrintExprList(p->pGroupBy);
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
if( p->pHaving ){
|
||||
sqlite3ExplainPrintf(pVdbe, "HAVING ");
|
||||
sqlite3ExplainExpr(pVdbe, p->pHaving);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3DebugPrintf("%*s HAVING ", indent, "");
|
||||
sqlite3PrintExpr(p->pHaving);
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
if( p->pOrderBy ){
|
||||
sqlite3ExplainPrintf(pVdbe, "ORDERBY ");
|
||||
sqlite3ExplainExprList(pVdbe, p->pOrderBy);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
}
|
||||
if( p->pLimit ){
|
||||
sqlite3ExplainPrintf(pVdbe, "LIMIT ");
|
||||
sqlite3ExplainExpr(pVdbe, p->pLimit);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
}
|
||||
if( p->pOffset ){
|
||||
sqlite3ExplainPrintf(pVdbe, "OFFSET ");
|
||||
sqlite3ExplainExpr(pVdbe, p->pOffset);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3DebugPrintf("%*s ORDER BY ", indent, "");
|
||||
sqlite3PrintExprList(p->pOrderBy);
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
}
|
||||
void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
|
||||
if( p==0 ){
|
||||
sqlite3ExplainPrintf(pVdbe, "(null-select)");
|
||||
return;
|
||||
}
|
||||
while( p->pPrior ) p = p->pPrior;
|
||||
sqlite3ExplainPush(pVdbe);
|
||||
while( p ){
|
||||
explainOneSelect(pVdbe, p);
|
||||
p = p->pNext;
|
||||
if( p==0 ) break;
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op));
|
||||
}
|
||||
sqlite3ExplainPrintf(pVdbe, "END");
|
||||
sqlite3ExplainPop(pVdbe);
|
||||
}
|
||||
|
||||
/* End of the structure debug printing code
|
||||
*****************************************************************************/
|
||||
#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
|
||||
|
||||
+44
-29
@@ -1127,15 +1127,6 @@ static int shell_exec(
|
||||
fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
}
|
||||
|
||||
/* Output TESTCTRL_EXPLAIN text of requested */
|
||||
if( pArg && pArg->mode==MODE_Explain ){
|
||||
const char *zExplain = 0;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
|
||||
if( zExplain && zExplain[0] ){
|
||||
fprintf(pArg->out, "%s", zExplain);
|
||||
}
|
||||
}
|
||||
|
||||
/* perform the first step. this will tell us if we
|
||||
** have a result set or not and how wide it is.
|
||||
*/
|
||||
@@ -2666,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,
|
||||
@@ -2751,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;
|
||||
@@ -2780,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,
|
||||
@@ -2791,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);
|
||||
@@ -2877,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;
|
||||
}
|
||||
@@ -2886,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;
|
||||
}
|
||||
@@ -2921,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");
|
||||
|
||||
+1
-21
@@ -2944,25 +2944,6 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||
*/
|
||||
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
|
||||
**
|
||||
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
|
||||
** [prepared statement] S has been stepped at least once using
|
||||
** [sqlite3_step(S)] but has not run to completion and/or has not
|
||||
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
|
||||
** interface returns false if S is a NULL pointer. If S is not a
|
||||
** NULL pointer and is not a pointer to a valid [prepared statement]
|
||||
** object, then the behavior is undefined and probably undesirable.
|
||||
**
|
||||
** This interface can be used in combination [sqlite3_next_stmt()]
|
||||
** to locate all prepared statements associated with a database
|
||||
** connection that are in need of being reset. This can be used,
|
||||
** for example, in diagnostic routines to search for prepared
|
||||
** statements that are holding a transaction open.
|
||||
*/
|
||||
int sqlite3_stmt_busy(sqlite3_stmt*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Dynamically Typed Value Object
|
||||
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
|
||||
@@ -5694,8 +5675,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
||||
#define SQLITE_TESTCTRL_LAST 19
|
||||
#define SQLITE_TESTCTRL_LAST 18
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
||||
+32
-45
@@ -1144,11 +1144,20 @@ struct Column {
|
||||
struct CollSeq {
|
||||
char *zName; /* Name of the collating sequence, UTF-8 encoded */
|
||||
u8 enc; /* Text encoding handled by xCmp() */
|
||||
u8 type; /* One of the SQLITE_COLL_... values below */
|
||||
void *pUser; /* First argument to xCmp() */
|
||||
int (*xCmp)(void*,int, const void*, int, const void*);
|
||||
void (*xDel)(void*); /* Destructor for pUser */
|
||||
};
|
||||
|
||||
/*
|
||||
** Allowed values of CollSeq.type:
|
||||
*/
|
||||
#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */
|
||||
#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */
|
||||
#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */
|
||||
#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */
|
||||
|
||||
/*
|
||||
** A sort order can be either ASC or DESC.
|
||||
*/
|
||||
@@ -1434,7 +1443,7 @@ struct KeyInfo {
|
||||
struct UnpackedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
u8 flags; /* Boolean settings. UNPACKED_... below */
|
||||
u16 flags; /* Boolean settings. UNPACKED_... below */
|
||||
i64 rowid; /* Used by UNPACKED_PREFIX_SEARCH */
|
||||
Mem *aMem; /* Values */
|
||||
};
|
||||
@@ -1442,9 +1451,11 @@ struct UnpackedRecord {
|
||||
/*
|
||||
** Allowed values of UnpackedRecord.flags
|
||||
*/
|
||||
#define UNPACKED_INCRKEY 0x01 /* Make this key an epsilon larger */
|
||||
#define UNPACKED_PREFIX_MATCH 0x02 /* A prefix match is considered OK */
|
||||
#define UNPACKED_PREFIX_SEARCH 0x04 /* Ignore final (rowid) field */
|
||||
#define UNPACKED_NEED_FREE 0x0001 /* Memory is from sqlite3Malloc() */
|
||||
#define UNPACKED_NEED_DESTROY 0x0002 /* apMem[]s should all be destroyed */
|
||||
#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 */
|
||||
|
||||
/*
|
||||
** Each SQL index is represented in memory by an
|
||||
@@ -1707,10 +1718,10 @@ struct Expr {
|
||||
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
#define EP_Hint 0x1000 /* Optimizer hint. Not required for correctness */
|
||||
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
|
||||
|
||||
#define EP_Reduced 0x1000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
|
||||
#define EP_TokenOnly 0x2000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
|
||||
#define EP_Static 0x4000 /* Held in memory not obtained from malloc() */
|
||||
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags2 field.
|
||||
@@ -1772,7 +1783,7 @@ struct ExprList {
|
||||
char *zSpan; /* Original text of the expression */
|
||||
u8 sortOrder; /* 1 for DESC or 0 for ASC */
|
||||
u8 done; /* A flag to indicate when processing is finished */
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
u16 iCol; /* For ORDER BY, column number in result set */
|
||||
u16 iAlias; /* Index into Parse.aAlias[] for zName */
|
||||
} *a; /* One entry for each expression */
|
||||
};
|
||||
@@ -2072,13 +2083,13 @@ struct Select {
|
||||
** Allowed values for Select.selFlags. The "SF" prefix stands for
|
||||
** "Select Flag".
|
||||
*/
|
||||
#define SF_Distinct 0x01 /* Output should be DISTINCT */
|
||||
#define SF_Resolved 0x02 /* Identifiers have been resolved */
|
||||
#define SF_Aggregate 0x04 /* Contains aggregate functions */
|
||||
#define SF_UsesEphemeral 0x08 /* Uses the OpenEphemeral opcode */
|
||||
#define SF_Expanded 0x10 /* sqlite3SelectExpand() called on this */
|
||||
#define SF_HasTypeInfo 0x20 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x40 /* Sort using a sorter */
|
||||
#define SF_Distinct 0x0001 /* Output should be DISTINCT */
|
||||
#define SF_Resolved 0x0002 /* Identifiers have been resolved */
|
||||
#define SF_Aggregate 0x0004 /* Contains aggregate functions */
|
||||
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
|
||||
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2193,8 +2204,10 @@ struct Parse {
|
||||
char *zErrMsg; /* An error message */
|
||||
Vdbe *pVdbe; /* An engine for executing database bytecode */
|
||||
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
|
||||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||
u8 parseError; /* True after a parsing error. Ticket #1794 */
|
||||
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
|
||||
u8 nTempInUse; /* Number of aTempReg[] currently checked out */
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
@@ -2204,12 +2217,11 @@ struct Parse {
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nOnce; /* Number of OP_Once instructions so far */
|
||||
int ckBase; /* Base register of data during check constraints */
|
||||
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||
u8 nColCache; /* Number of entries in aColCache[] */
|
||||
u8 iColCache; /* Next entry in aColCache[] to replace */
|
||||
u8 nColCache; /* Number of entries in the column cache */
|
||||
u8 iColCache; /* Next entry of the cache to replace */
|
||||
struct yColCache {
|
||||
int iTable; /* Table cursor number */
|
||||
int iColumn; /* Table column number */
|
||||
@@ -2251,6 +2263,7 @@ struct Parse {
|
||||
char **azVar; /* Pointers to names of parameters */
|
||||
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
||||
int nAlias; /* Number of aliased result set columns */
|
||||
int nAliasAlloc; /* Number of allocated slots for aAlias[] */
|
||||
int *aAlias; /* Register used to hold aliased result */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
Token sNameToken; /* Token with unqualified schema object name */
|
||||
@@ -2651,29 +2664,6 @@ char *sqlite3MAppendf(sqlite3*,char*,const char*,...);
|
||||
#if defined(SQLITE_TEST)
|
||||
void *sqlite3TestTextToPtr(const char*);
|
||||
#endif
|
||||
|
||||
/* Output formatting for SQLITE_TESTCTRL_EXPLAIN */
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
void sqlite3ExplainBegin(Vdbe*);
|
||||
void sqlite3ExplainPrintf(Vdbe*, const char*, ...);
|
||||
void sqlite3ExplainNL(Vdbe*);
|
||||
void sqlite3ExplainPush(Vdbe*);
|
||||
void sqlite3ExplainPop(Vdbe*);
|
||||
void sqlite3ExplainFinish(Vdbe*);
|
||||
void sqlite3ExplainSelect(Vdbe*, Select*);
|
||||
void sqlite3ExplainExpr(Vdbe*, Expr*);
|
||||
void sqlite3ExplainExprList(Vdbe*, ExprList*);
|
||||
const char *sqlite3VdbeExplanation(Vdbe*);
|
||||
#else
|
||||
# define sqlite3ExplainBegin(X)
|
||||
# define sqlite3ExplainSelect(A,B)
|
||||
# define sqlite3ExplainExpr(A,B)
|
||||
# define sqlite3ExplainExprList(A,B)
|
||||
# define sqlite3ExplainFinish(X)
|
||||
# define sqlite3VdbeExplanation(X) 0
|
||||
#endif
|
||||
|
||||
|
||||
void sqlite3SetString(char **, sqlite3*, const char*, ...);
|
||||
void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
int sqlite3Dequote(char*);
|
||||
@@ -2684,7 +2674,6 @@ int sqlite3GetTempReg(Parse*);
|
||||
void sqlite3ReleaseTempReg(Parse*,int);
|
||||
int sqlite3GetTempRange(Parse*,int);
|
||||
void sqlite3ReleaseTempRange(Parse*,int,int);
|
||||
void sqlite3ClearTempRegCache(Parse*);
|
||||
Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
|
||||
Expr *sqlite3Expr(sqlite3*,int,const char*);
|
||||
void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
|
||||
@@ -2716,7 +2705,6 @@ void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
sqlite3_vfs**,char**,char **);
|
||||
int sqlite3CodeOnce(Parse *);
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
int sqlite3BitvecTest(Bitvec*, u32);
|
||||
@@ -3055,7 +3043,6 @@ int sqlite3OpenTempDatabase(Parse *);
|
||||
|
||||
void sqlite3StrAccumInit(StrAccum*, char*, int, int);
|
||||
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
|
||||
void sqlite3AppendSpace(StrAccum*,int);
|
||||
char *sqlite3StrAccumFinish(StrAccum*);
|
||||
void sqlite3StrAccumReset(StrAccum*);
|
||||
void sqlite3SelectDestInit(SelectDest*,int,int);
|
||||
|
||||
-28
@@ -2330,33 +2330,6 @@ static int test_stmt_readonly(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_stmt_busy STMT
|
||||
**
|
||||
** Return true if STMT is a non-NULL pointer to a statement
|
||||
** that has been stepped but not to completion.
|
||||
*/
|
||||
static int test_stmt_busy(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
rc = sqlite3_stmt_busy(pStmt);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: uses_stmt_journal STMT
|
||||
**
|
||||
@@ -6020,7 +5993,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_sql", test_sql ,0 },
|
||||
{ "sqlite3_next_stmt", test_next_stmt ,0 },
|
||||
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
|
||||
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
|
||||
{ "uses_stmt_journal", uses_stmt_journal ,0 },
|
||||
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
|
||||
+1
-1
@@ -391,7 +391,7 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
|
||||
while( rc==SQLITE_OK && iTrunk>0 ){
|
||||
u32 nLeaf;
|
||||
u32 iLeaf;
|
||||
sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize;
|
||||
sqlite3_int64 iOff = (i64)(iTrunk-1)*pMain->nPagesize;
|
||||
rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff);
|
||||
nLeaf = decodeUint32(&aData[4]);
|
||||
for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){
|
||||
|
||||
+10
-2
@@ -298,6 +298,7 @@ static sqlite3_file *multiplexSubOpen(
|
||||
** 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;
|
||||
}
|
||||
@@ -306,7 +307,6 @@ static sqlite3_file *multiplexSubOpen(
|
||||
*rc = multiplexSubFilename(pGroup, iChunk);
|
||||
if( (*rc)==SQLITE_OK && (pSubOpen = pGroup->aReal[iChunk].p)==0 ){
|
||||
int flags, bExists;
|
||||
createFlag = (pGroup->flags & SQLITE_OPEN_CREATE)!=0;
|
||||
flags = pGroup->flags;
|
||||
if( createFlag ){
|
||||
flags |= SQLITE_OPEN_CREATE;
|
||||
@@ -317,7 +317,13 @@ static sqlite3_file *multiplexSubOpen(
|
||||
}else{
|
||||
*rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[iChunk].z,
|
||||
SQLITE_ACCESS_EXISTS, &bExists);
|
||||
if( *rc || !bExists ) return 0;
|
||||
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 );
|
||||
@@ -329,6 +335,8 @@ static sqlite3_file *multiplexSubOpen(
|
||||
*rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen,
|
||||
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;
|
||||
|
||||
+30
-653
@@ -27,7 +27,7 @@
|
||||
** files within the group is less than the new quota, then the write
|
||||
** continues as if nothing had happened.
|
||||
*/
|
||||
#include "test_quota.h"
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -111,18 +111,6 @@ struct quotaConn {
|
||||
/* The underlying VFS sqlite3_file is appended to this object */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following object records the state of an
|
||||
** open file. This object is opaque to all users - the internal
|
||||
** structure is only visible to the functions below.
|
||||
*/
|
||||
struct quota_FILE {
|
||||
FILE *f; /* Open stdio file pointer */
|
||||
sqlite3_int64 iOfst; /* Current offset into the file */
|
||||
quotaFile *pFile; /* The file record in the quota system */
|
||||
};
|
||||
|
||||
|
||||
/************************* Global Variables **********************************/
|
||||
/*
|
||||
** All global variables used by this file are containing within the following
|
||||
@@ -237,11 +225,9 @@ static void quotaGroupDeref(quotaGroup *pGroup){
|
||||
**
|
||||
** [^...] Matches one character not in the enclosed list.
|
||||
**
|
||||
** / Matches "/" or "\\"
|
||||
**
|
||||
*/
|
||||
static int quotaStrglob(const char *zGlob, const char *z){
|
||||
int c, c2, cx;
|
||||
int c, c2;
|
||||
int invert;
|
||||
int seen;
|
||||
|
||||
@@ -258,9 +244,8 @@ static int quotaStrglob(const char *zGlob, const char *z){
|
||||
}
|
||||
return (*z)!=0;
|
||||
}
|
||||
cx = (c=='/') ? '\\' : c;
|
||||
while( (c2 = (*(z++)))!=0 ){
|
||||
while( c2!=c && c2!=cx ){
|
||||
while( c2!=c ){
|
||||
c2 = *(z++);
|
||||
if( c2==0 ) return 0;
|
||||
}
|
||||
@@ -298,9 +283,6 @@ static int quotaStrglob(const char *zGlob, const char *z){
|
||||
c2 = *(zGlob++);
|
||||
}
|
||||
if( c2==0 || (seen ^ invert)==0 ) return 0;
|
||||
}else if( c=='/' ){
|
||||
if( z[0]!='/' && z[0]!='\\' ) return 0;
|
||||
z++;
|
||||
}else{
|
||||
if( c!=(*(z++)) ) return 0;
|
||||
}
|
||||
@@ -331,131 +313,14 @@ static sqlite3_file *quotaSubOpen(sqlite3_file *pConn){
|
||||
/* Find a file in a quota group and return a pointer to that file.
|
||||
** Return NULL if the file is not in the group.
|
||||
*/
|
||||
static quotaFile *quotaFindFile(
|
||||
quotaGroup *pGroup, /* Group in which to look for the file */
|
||||
const char *zName, /* Full pathname of the file */
|
||||
int createFlag /* Try to create the file if not found */
|
||||
){
|
||||
static quotaFile *quotaFindFile(quotaGroup *pGroup, const char *zName){
|
||||
quotaFile *pFile = pGroup->pFiles;
|
||||
while( pFile && strcmp(pFile->zFilename, zName)!=0 ){
|
||||
pFile = pFile->pNext;
|
||||
}
|
||||
if( pFile==0 && createFlag ){
|
||||
int nName = strlen(zName);
|
||||
pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 );
|
||||
if( pFile ){
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
pFile->zFilename = (char*)&pFile[1];
|
||||
memcpy(pFile->zFilename, zName, nName+1);
|
||||
pFile->pNext = pGroup->pFiles;
|
||||
if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext;
|
||||
pFile->ppPrev = &pGroup->pFiles;
|
||||
pGroup->pFiles = pFile;
|
||||
pFile->pGroup = pGroup;
|
||||
}
|
||||
}
|
||||
return pFile;
|
||||
}
|
||||
|
||||
/*
|
||||
** Figure out if we are dealing with Unix, Windows, or some other
|
||||
** operating system. After the following block of preprocess macros,
|
||||
** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER
|
||||
** will defined to either 1 or 0. One of the four will be 1. The other
|
||||
** three will be 0.
|
||||
*/
|
||||
#if defined(SQLITE_OS_OTHER)
|
||||
# if SQLITE_OS_OTHER==1
|
||||
# undef SQLITE_OS_UNIX
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# undef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# undef SQLITE_OS_OS2
|
||||
# define SQLITE_OS_OS2 0
|
||||
# else
|
||||
# undef SQLITE_OS_OTHER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
|
||||
# define SQLITE_OS_OTHER 0
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) \
|
||||
|| defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define SQLITE_OS_WIN 1
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# define SQLITE_OS_OS2 0
|
||||
# elif defined(__EMX__) || defined(_OS2) || defined(OS2) \
|
||||
|| defined(_OS2_) || defined(__OS2__)
|
||||
# define SQLITE_OS_WIN 0
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# define SQLITE_OS_OS2 1
|
||||
# else
|
||||
# define SQLITE_OS_WIN 0
|
||||
# define SQLITE_OS_UNIX 1
|
||||
# define SQLITE_OS_OS2 0
|
||||
# endif
|
||||
# else
|
||||
# define SQLITE_OS_UNIX 0
|
||||
# define SQLITE_OS_OS2 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef SQLITE_OS_WIN
|
||||
# define SQLITE_OS_WIN 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_UNIX
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Translate UTF8 to MBCS for use in fopen() calls. Return a pointer to the
|
||||
** translated text.. Call quota_mbcs_free() to deallocate any memory
|
||||
** used to store the returned pointer when done.
|
||||
*/
|
||||
static char *quota_utf8_to_mbcs(const char *zUtf8){
|
||||
#if SQLITE_OS_WIN
|
||||
int n; /* Bytes in zUtf8 */
|
||||
int nWide; /* number of UTF-16 characters */
|
||||
int nMbcs; /* Bytes of MBCS */
|
||||
LPWSTR zTmpWide; /* The UTF16 text */
|
||||
char *zMbcs; /* The MBCS text */
|
||||
int codepage; /* Code page used by fopen() */
|
||||
|
||||
n = strlen(zUtf8);
|
||||
nWide = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0);
|
||||
if( nWide==0 ) return 0;
|
||||
zTmpWide = (LPWSTR)sqlite3_malloc( (nWide+1)*sizeof(zTmpWide[0]) );
|
||||
if( zTmpWide==0 ) return 0;
|
||||
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zTmpWide, nWide);
|
||||
codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
||||
nMbcs = WideCharToMultiByte(codepage, 0, zTmpWide, nWide, 0, 0, 0, 0);
|
||||
zMbcs = nMbcs ? (char*)sqlite3_malloc( nMbcs+1 ) : 0;
|
||||
if( zMbcs ){
|
||||
WideCharToMultiByte(codepage, 0, zTmpWide, nWide, zMbcs, nMbcs, 0, 0);
|
||||
}
|
||||
sqlite3_free(zTmpWide);
|
||||
return zMbcs;
|
||||
#else
|
||||
return (char*)zUtf8; /* No-op on unix */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Deallocate any memory allocated by quota_utf8_to_mbcs().
|
||||
*/
|
||||
static void quota_mbcs_free(char *zOld){
|
||||
#if SQLITE_OS_WIN
|
||||
sqlite3_free(zOld);
|
||||
#else
|
||||
/* No-op on unix */
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************* VFS Method Wrappers *****************************/
|
||||
/*
|
||||
** This is the xOpen method used for the "quota" VFS.
|
||||
@@ -499,13 +364,25 @@ static int quotaOpen(
|
||||
pSubOpen = quotaSubOpen(pConn);
|
||||
rc = pOrigVfs->xOpen(pOrigVfs, zName, pSubOpen, flags, pOutFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
pFile = quotaFindFile(pGroup, zName, 1);
|
||||
pFile = quotaFindFile(pGroup, zName);
|
||||
if( pFile==0 ){
|
||||
quotaLeave();
|
||||
pSubOpen->pMethods->xClose(pSubOpen);
|
||||
return SQLITE_NOMEM;
|
||||
int nName = strlen(zName);
|
||||
pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 );
|
||||
if( pFile==0 ){
|
||||
quotaLeave();
|
||||
pSubOpen->pMethods->xClose(pSubOpen);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
pFile->zFilename = (char*)&pFile[1];
|
||||
memcpy(pFile->zFilename, zName, nName+1);
|
||||
pFile->pNext = pGroup->pFiles;
|
||||
if( pGroup->pFiles ) pGroup->pFiles->ppPrev = &pFile->pNext;
|
||||
pFile->ppPrev = &pGroup->pFiles;
|
||||
pGroup->pFiles = pFile;
|
||||
pFile->pGroup = pGroup;
|
||||
pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0;
|
||||
}
|
||||
pFile->deleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE)!=0;
|
||||
pFile->nRef++;
|
||||
pQuotaOpen->pFile = pFile;
|
||||
if( pSubOpen->pMethods->iVersion==1 ){
|
||||
@@ -546,7 +423,7 @@ static int quotaDelete(
|
||||
quotaEnter();
|
||||
pGroup = quotaGroupFind(zName);
|
||||
if( pGroup ){
|
||||
pFile = quotaFindFile(pGroup, zName, 0);
|
||||
pFile = quotaFindFile(pGroup, zName);
|
||||
if( pFile ){
|
||||
if( pFile->nRef ){
|
||||
pFile->deleteOnClose = 1;
|
||||
@@ -578,10 +455,7 @@ static int quotaClose(sqlite3_file *pConn){
|
||||
pFile->nRef--;
|
||||
if( pFile->nRef==0 ){
|
||||
quotaGroup *pGroup = pFile->pGroup;
|
||||
if( pFile->deleteOnClose ){
|
||||
gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
|
||||
quotaRemoveFile(pFile);
|
||||
}
|
||||
if( pFile->deleteOnClose ) quotaRemoveFile(pFile);
|
||||
quotaGroupDeref(pGroup);
|
||||
}
|
||||
quotaLeave();
|
||||
@@ -716,11 +590,9 @@ static int quotaCheckReservedLock(sqlite3_file *pConn, int *pResOut){
|
||||
static int quotaFileControl(sqlite3_file *pConn, int op, void *pArg){
|
||||
sqlite3_file *pSubOpen = quotaSubOpen(pConn);
|
||||
int rc = pSubOpen->pMethods->xFileControl(pSubOpen, op, pArg);
|
||||
#if defined(SQLITE_FCNTL_VFSNAME)
|
||||
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
|
||||
*(char**)pArg = sqlite3_mprintf("quota/%z", *(char**)pArg);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -937,8 +809,7 @@ int sqlite3_quota_file(const char *zFilename){
|
||||
int rc;
|
||||
int outFlags = 0;
|
||||
sqlite3_int64 iSize;
|
||||
fd = (sqlite3_file*)sqlite3_malloc(gQuota.sThisVfs.szOsFile +
|
||||
gQuota.sThisVfs.mxPathname+1);
|
||||
fd = sqlite3_malloc(gQuota.sThisVfs.szOsFile + gQuota.sThisVfs.mxPathname+1);
|
||||
if( fd==0 ) return SQLITE_NOMEM;
|
||||
zFull = gQuota.sThisVfs.szOsFile + (char*)fd;
|
||||
rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
|
||||
@@ -956,7 +827,7 @@ int sqlite3_quota_file(const char *zFilename){
|
||||
quotaEnter();
|
||||
pGroup = quotaGroupFind(zFull);
|
||||
if( pGroup ){
|
||||
pFile = quotaFindFile(pGroup, zFull, 0);
|
||||
pFile = quotaFindFile(pGroup, zFull);
|
||||
if( pFile ) quotaRemoveFile(pFile);
|
||||
}
|
||||
quotaLeave();
|
||||
@@ -965,220 +836,6 @@ int sqlite3_quota_file(const char *zFilename){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a potentially quotaed file for I/O.
|
||||
*/
|
||||
quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode){
|
||||
quota_FILE *p = 0;
|
||||
char *zFull = 0;
|
||||
char *zFullTranslated;
|
||||
int rc;
|
||||
quotaGroup *pGroup;
|
||||
quotaFile *pFile;
|
||||
|
||||
zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
|
||||
if( zFull==0 ) return 0;
|
||||
rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
|
||||
gQuota.sThisVfs.mxPathname+1, zFull);
|
||||
if( rc ) goto quota_fopen_error;
|
||||
p = (quota_FILE*)sqlite3_malloc(sizeof(*p));
|
||||
if( p==0 ) goto quota_fopen_error;
|
||||
memset(p, 0, sizeof(*p));
|
||||
zFullTranslated = quota_utf8_to_mbcs(zFull);
|
||||
if( zFullTranslated==0 ) goto quota_fopen_error;
|
||||
p->f = fopen(zFullTranslated, zMode);
|
||||
quota_mbcs_free(zFullTranslated);
|
||||
if( p->f==0 ) goto quota_fopen_error;
|
||||
quotaEnter();
|
||||
pGroup = quotaGroupFind(zFull);
|
||||
if( pGroup ){
|
||||
pFile = quotaFindFile(pGroup, zFull, 1);
|
||||
if( pFile==0 ){
|
||||
quotaLeave();
|
||||
goto quota_fopen_error;
|
||||
}
|
||||
pFile->nRef++;
|
||||
p->pFile = pFile;
|
||||
}
|
||||
quotaLeave();
|
||||
sqlite3_free(zFull);
|
||||
return p;
|
||||
|
||||
quota_fopen_error:
|
||||
sqlite3_free(zFull);
|
||||
if( p && p->f ) fclose(p->f);
|
||||
sqlite3_free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read content from a quota_FILE
|
||||
*/
|
||||
size_t sqlite3_quota_fread(
|
||||
void *pBuf, /* Store the content here */
|
||||
size_t size, /* Size of each element */
|
||||
size_t nmemb, /* Number of elements to read */
|
||||
quota_FILE *p /* Read from this quota_FILE object */
|
||||
){
|
||||
return fread(pBuf, size, nmemb, p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write content into a quota_FILE. Invoke the quota callback and block
|
||||
** the write if we exceed quota.
|
||||
*/
|
||||
size_t sqlite3_quota_fwrite(
|
||||
void *pBuf, /* Take content to write from here */
|
||||
size_t size, /* Size of each element */
|
||||
size_t nmemb, /* Number of elements */
|
||||
quota_FILE *p /* Write to this quota_FILE objecct */
|
||||
){
|
||||
sqlite3_int64 iOfst;
|
||||
sqlite3_int64 iEnd;
|
||||
sqlite3_int64 szNew;
|
||||
quotaFile *pFile;
|
||||
|
||||
iOfst = ftell(p->f);
|
||||
iEnd = iOfst + size*nmemb;
|
||||
pFile = p->pFile;
|
||||
if( pFile && pFile->iSize<iEnd ){
|
||||
quotaGroup *pGroup = pFile->pGroup;
|
||||
quotaEnter();
|
||||
szNew = pGroup->iSize - pFile->iSize + iEnd;
|
||||
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
|
||||
if( pGroup->xCallback ){
|
||||
pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew,
|
||||
pGroup->pArg);
|
||||
}
|
||||
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
|
||||
iEnd = pGroup->iLimit - pGroup->iSize + pFile->iSize;
|
||||
nmemb = (iEnd - iOfst)/size;
|
||||
iEnd = iOfst + size*nmemb;
|
||||
szNew = pGroup->iSize - pFile->iSize + iEnd;
|
||||
}
|
||||
}
|
||||
pGroup->iSize = szNew;
|
||||
pFile->iSize = iEnd;
|
||||
quotaLeave();
|
||||
}
|
||||
return fwrite(pBuf, size, nmemb, p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an open quota_FILE stream.
|
||||
*/
|
||||
int sqlite3_quota_fclose(quota_FILE *p){
|
||||
int rc;
|
||||
quotaFile *pFile;
|
||||
rc = fclose(p->f);
|
||||
pFile = p->pFile;
|
||||
if( pFile ){
|
||||
quotaEnter();
|
||||
pFile->nRef--;
|
||||
if( pFile->nRef==0 ){
|
||||
quotaGroup *pGroup = pFile->pGroup;
|
||||
if( pFile->deleteOnClose ){
|
||||
gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
|
||||
quotaRemoveFile(pFile);
|
||||
}
|
||||
quotaGroupDeref(pGroup);
|
||||
}
|
||||
quotaLeave();
|
||||
}
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Flush memory buffers for a quota_FILE to disk.
|
||||
*/
|
||||
int sqlite3_quota_fflush(quota_FILE *p, int doFsync){
|
||||
int rc;
|
||||
rc = fflush(p->f);
|
||||
if( rc==0 && doFsync ){
|
||||
#if SQLITE_OS_UNIX
|
||||
rc = fsync(fileno(p->f));
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
rc = _commit(_fileno(p->f));
|
||||
#endif
|
||||
}
|
||||
return rc!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Seek on a quota_FILE stream.
|
||||
*/
|
||||
int sqlite3_quota_fseek(quota_FILE *p, long offset, int whence){
|
||||
return fseek(p->f, offset, whence);
|
||||
}
|
||||
|
||||
/*
|
||||
** rewind a quota_FILE stream.
|
||||
*/
|
||||
void sqlite3_quota_rewind(quota_FILE *p){
|
||||
rewind(p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Tell the current location of a quota_FILE stream.
|
||||
*/
|
||||
long sqlite3_quota_ftell(quota_FILE *p){
|
||||
return ftell(p->f);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove a managed file. Update quotas accordingly.
|
||||
*/
|
||||
int sqlite3_quota_remove(const char *zFilename){
|
||||
char *zFull; /* Full pathname for zFilename */
|
||||
int nFull; /* Number of bytes in zFilename */
|
||||
int rc; /* Result code */
|
||||
quotaGroup *pGroup; /* Group containing zFilename */
|
||||
quotaFile *pFile; /* A file in the group */
|
||||
quotaFile *pNextFile; /* next file in the group */
|
||||
int diff; /* Difference between filenames */
|
||||
char c; /* First character past end of pattern */
|
||||
|
||||
zFull = (char*)sqlite3_malloc(gQuota.sThisVfs.mxPathname + 1);
|
||||
if( zFull==0 ) return SQLITE_NOMEM;
|
||||
rc = gQuota.pOrigVfs->xFullPathname(gQuota.pOrigVfs, zFilename,
|
||||
gQuota.sThisVfs.mxPathname+1, zFull);
|
||||
if( rc ){
|
||||
sqlite3_free(zFull);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Figure out the length of the full pathname. If the name ends with
|
||||
** / (or \ on windows) then remove the trailing /.
|
||||
*/
|
||||
nFull = strlen(zFull);
|
||||
if( nFull>0 && (zFull[nFull-1]=='/' || zFull[nFull-1]=='\\') ){
|
||||
nFull--;
|
||||
zFull[nFull] = 0;
|
||||
}
|
||||
|
||||
quotaEnter();
|
||||
pGroup = quotaGroupFind(zFull);
|
||||
if( pGroup ){
|
||||
for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){
|
||||
pNextFile = pFile->pNext;
|
||||
diff = memcmp(zFull, pFile->zFilename, nFull);
|
||||
if( diff==0 && ((c = pFile->zFilename[nFull])==0 || c=='/' || c=='\\') ){
|
||||
if( pFile->nRef ){
|
||||
pFile->deleteOnClose = 1;
|
||||
}else{
|
||||
rc = gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0);
|
||||
quotaRemoveFile(pFile);
|
||||
quotaGroupDeref(pGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
quotaLeave();
|
||||
sqlite3_free(zFull);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***************************** Test Code ***********************************/
|
||||
#ifdef SQLITE_TEST
|
||||
@@ -1407,13 +1064,9 @@ static int test_quota_dump(
|
||||
Tcl_ListObjAppendElement(interp, pGroupTerm,
|
||||
Tcl_NewWideIntObj(pGroup->iSize));
|
||||
for(pFile=pGroup->pFiles; pFile; pFile=pFile->pNext){
|
||||
int i;
|
||||
char zTemp[1000];
|
||||
pFileTerm = Tcl_NewObj();
|
||||
sqlite3_snprintf(sizeof(zTemp), zTemp, "%s", pFile->zFilename);
|
||||
for(i=0; zTemp[i]; i++){ if( zTemp[i]=='\\' ) zTemp[i] = '/'; }
|
||||
Tcl_ListObjAppendElement(interp, pFileTerm,
|
||||
Tcl_NewStringObj(zTemp, -1));
|
||||
Tcl_NewStringObj(pFile->zFilename, -1));
|
||||
Tcl_ListObjAppendElement(interp, pFileTerm,
|
||||
Tcl_NewWideIntObj(pFile->iSize));
|
||||
Tcl_ListObjAppendElement(interp, pFileTerm,
|
||||
@@ -1429,272 +1082,6 @@ static int test_quota_dump(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fopen FILENAME MODE
|
||||
*/
|
||||
static int test_quota_fopen(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zFilename; /* File pattern to configure */
|
||||
const char *zMode; /* Mode string */
|
||||
quota_FILE *p; /* Open string object */
|
||||
char zReturn[50]; /* Name of pointer to return */
|
||||
|
||||
/* Process arguments */
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME MODE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zFilename = Tcl_GetString(objv[1]);
|
||||
zMode = Tcl_GetString(objv[2]);
|
||||
p = sqlite3_quota_fopen(zFilename, zMode);
|
||||
sqlite3_snprintf(sizeof(zReturn), zReturn, "%p", p);
|
||||
Tcl_SetResult(interp, zReturn, TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/* Defined in test1.c */
|
||||
extern void *sqlite3TestTextToPtr(const char*);
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM
|
||||
*/
|
||||
static int test_quota_fread(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
char *zBuf;
|
||||
int sz;
|
||||
int nElem;
|
||||
int got;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
|
||||
zBuf = (char*)sqlite3_malloc( sz*nElem + 1 );
|
||||
if( zBuf==0 ){
|
||||
Tcl_SetResult(interp, "out of memory", TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
got = sqlite3_quota_fread(zBuf, sz, nElem, p);
|
||||
if( got<0 ) got = 0;
|
||||
zBuf[got*sz] = 0;
|
||||
Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
|
||||
sqlite3_free(zBuf);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT
|
||||
*/
|
||||
static int test_quota_fwrite(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
char *zBuf;
|
||||
int sz;
|
||||
int nElem;
|
||||
int got;
|
||||
|
||||
if( objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE SIZE NELEM CONTENT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &sz) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &nElem) ) return TCL_ERROR;
|
||||
zBuf = Tcl_GetString(objv[4]);
|
||||
got = sqlite3_quota_fwrite(zBuf, sz, nElem, p);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(got));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fclose HANDLE
|
||||
*/
|
||||
static int test_quota_fclose(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
rc = sqlite3_quota_fclose(p);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC?
|
||||
*/
|
||||
static int test_quota_fflush(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
int rc;
|
||||
int doSync = 0;
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?HARDSYNC?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
if( objc==3 ){
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &doSync) ) return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_quota_fflush(p, doSync);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE
|
||||
*/
|
||||
static int test_quota_fseek(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
int ofst;
|
||||
const char *zWhence;
|
||||
int whence;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET WHENCE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &ofst) ) return TCL_ERROR;
|
||||
zWhence = Tcl_GetString(objv[3]);
|
||||
if( strcmp(zWhence, "SEEK_SET")==0 ){
|
||||
whence = SEEK_SET;
|
||||
}else if( strcmp(zWhence, "SEEK_CUR")==0 ){
|
||||
whence = SEEK_CUR;
|
||||
}else if( strcmp(zWhence, "SEEK_END")==0 ){
|
||||
whence = SEEK_END;
|
||||
}else{
|
||||
Tcl_AppendResult(interp,
|
||||
"WHENCE should be SEEK_SET, SEEK_CUR, or SEEK_END", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_quota_fseek(p, ofst, whence);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_rewind HANDLE
|
||||
*/
|
||||
static int test_quota_rewind(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
sqlite3_quota_rewind(p);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_ftell HANDLE
|
||||
*/
|
||||
static int test_quota_ftell(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
quota_FILE *p;
|
||||
sqlite3_int64 x;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
p = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
|
||||
x = sqlite3_quota_ftell(p);
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(x));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_remove FILENAME
|
||||
*/
|
||||
static int test_quota_remove(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zFilename; /* File pattern to configure */
|
||||
int rc;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zFilename = Tcl_GetString(objv[1]);
|
||||
rc = sqlite3_quota_remove(zFilename);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_quota_glob PATTERN TEXT
|
||||
**
|
||||
** Test the glob pattern matching. Return 1 if TEXT matches PATTERN
|
||||
** and return 0 if it does not.
|
||||
*/
|
||||
static int test_quota_glob(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zPattern; /* The glob pattern */
|
||||
const char *zText; /* Text to compare agains the pattern */
|
||||
int rc;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "PATTERN TEXT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zPattern = Tcl_GetString(objv[1]);
|
||||
zText = Tcl_GetString(objv[2]);
|
||||
rc = quotaStrglob(zPattern, zText);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine registers the custom TCL commands defined in this
|
||||
** module. This should be the only procedure visible from outside
|
||||
@@ -1706,20 +1093,10 @@ int Sqlitequota_Init(Tcl_Interp *interp){
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
} aCmd[] = {
|
||||
{ "sqlite3_quota_initialize", test_quota_initialize },
|
||||
{ "sqlite3_quota_shutdown", test_quota_shutdown },
|
||||
{ "sqlite3_quota_set", test_quota_set },
|
||||
{ "sqlite3_quota_file", test_quota_file },
|
||||
{ "sqlite3_quota_dump", test_quota_dump },
|
||||
{ "sqlite3_quota_fopen", test_quota_fopen },
|
||||
{ "sqlite3_quota_fread", test_quota_fread },
|
||||
{ "sqlite3_quota_fwrite", test_quota_fwrite },
|
||||
{ "sqlite3_quota_fclose", test_quota_fclose },
|
||||
{ "sqlite3_quota_fflush", test_quota_fflush },
|
||||
{ "sqlite3_quota_fseek", test_quota_fseek },
|
||||
{ "sqlite3_quota_rewind", test_quota_rewind },
|
||||
{ "sqlite3_quota_ftell", test_quota_ftell },
|
||||
{ "sqlite3_quota_remove", test_quota_remove },
|
||||
{ "sqlite3_quota_glob", test_quota_glob },
|
||||
{ "sqlite3_quota_shutdown", test_quota_shutdown },
|
||||
{ "sqlite3_quota_set", test_quota_set },
|
||||
{ "sqlite3_quota_file", test_quota_file },
|
||||
{ "sqlite3_quota_dump", test_quota_dump },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
** 2011 December 1
|
||||
**
|
||||
** 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 the interface definition for the quota a VFS shim.
|
||||
**
|
||||
** This particular shim enforces a quota system on files. One or more
|
||||
** database files are in a "quota group" that is defined by a GLOB
|
||||
** pattern. A quota is set for the combined size of all files in the
|
||||
** the group. A quota of zero means "no limit". If the total size
|
||||
** of all files in the quota group is greater than the limit, then
|
||||
** write requests that attempt to enlarge a file fail with SQLITE_FULL.
|
||||
**
|
||||
** However, before returning SQLITE_FULL, the write requests invoke
|
||||
** a callback function that is configurable for each quota group.
|
||||
** This callback has the opportunity to enlarge the quota. If the
|
||||
** callback does enlarge the quota such that the total size of all
|
||||
** files within the group is less than the new quota, then the write
|
||||
** continues as if nothing had happened.
|
||||
*/
|
||||
#ifndef _QUOTA_H_
|
||||
#include "sqlite3.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* Make this callable from C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize the quota VFS shim. Use the VFS named zOrigVfsName
|
||||
** as the VFS that does the actual work. Use the default if
|
||||
** zOrigVfsName==NULL.
|
||||
**
|
||||
** The quota VFS shim is named "quota". It will become the default
|
||||
** VFS if makeDefault is non-zero.
|
||||
**
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once
|
||||
** during start-up.
|
||||
*/
|
||||
int sqlite3_quota_initialize(const char *zOrigVfsName, int makeDefault);
|
||||
|
||||
/*
|
||||
** Shutdown the quota system.
|
||||
**
|
||||
** All SQLite database connections must be closed before calling this
|
||||
** routine.
|
||||
**
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
|
||||
** shutting down in order to free all remaining quota groups.
|
||||
*/
|
||||
int sqlite3_quota_shutdown(void);
|
||||
|
||||
/*
|
||||
** Create or destroy a quota group.
|
||||
**
|
||||
** The quota group is defined by the zPattern. When calling this routine
|
||||
** with a zPattern for a quota group that already exists, this routine
|
||||
** merely updates the iLimit, xCallback, and pArg values for that quota
|
||||
** group. If zPattern is new, then a new quota group is created.
|
||||
**
|
||||
** The zPattern is always compared against the full pathname of the file.
|
||||
** Even if APIs are called with relative pathnames, SQLite converts the
|
||||
** name to a full pathname before comparing it against zPattern. zPattern
|
||||
** is a glob pattern with the following matching rules:
|
||||
**
|
||||
** '*' Matches any sequence of zero or more characters.
|
||||
**
|
||||
** '?' Matches exactly one character.
|
||||
**
|
||||
** [...] Matches one character from the enclosed list of
|
||||
** characters. "]" can be part of the list if it is
|
||||
** the first character. Within the list "X-Y" matches
|
||||
** characters X or Y or any character in between the
|
||||
** two. Ex: "[0-9]" matches any digit.
|
||||
**
|
||||
** [^...] Matches one character not in the enclosed list.
|
||||
**
|
||||
** / Matches either / or \. This allows glob patterns
|
||||
** containing / to work on both unix and windows.
|
||||
**
|
||||
** Note that, unlike unix shell globbing, the directory separator "/"
|
||||
** can match a wildcard. So, for example, the pattern "/abc/xyz/" "*"
|
||||
** matches any files anywhere in the directory hierarchy beneath
|
||||
** /abc/xyz.
|
||||
**
|
||||
** The glob algorithm works on bytes. Multi-byte UTF8 characters are
|
||||
** matched as if each byte were a separate character.
|
||||
**
|
||||
** If the iLimit for a quota group is set to zero, then the quota group
|
||||
** is disabled and will be deleted when the last database connection using
|
||||
** the quota group is closed.
|
||||
**
|
||||
** Calling this routine on a zPattern that does not exist and with a
|
||||
** zero iLimit is a no-op.
|
||||
**
|
||||
** A quota group must exist with a non-zero iLimit prior to opening
|
||||
** database connections if those connections are to participate in the
|
||||
** quota group. Creating a quota group does not affect database connections
|
||||
** that are already open.
|
||||
**
|
||||
** The patterns that define the various quota groups should be distinct.
|
||||
** If the same filename matches more than one quota group pattern, then
|
||||
** the behavior of this package is undefined.
|
||||
*/
|
||||
int sqlite3_quota_set(
|
||||
const char *zPattern, /* The filename pattern */
|
||||
sqlite3_int64 iLimit, /* New quota to set for this quota group */
|
||||
void (*xCallback)( /* Callback invoked when going over quota */
|
||||
const char *zFilename, /* Name of file whose size increases */
|
||||
sqlite3_int64 *piLimit, /* IN/OUT: The current limit */
|
||||
sqlite3_int64 iSize, /* Total size of all files in the group */
|
||||
void *pArg /* Client data */
|
||||
),
|
||||
void *pArg, /* client data passed thru to callback */
|
||||
void (*xDestroy)(void*) /* Optional destructor for pArg */
|
||||
);
|
||||
|
||||
/*
|
||||
** Bring the named file under quota management, assuming its name matches
|
||||
** the glob pattern of some quota group. Or if it is already under
|
||||
** management, update its size. If zFilename does not match the glob
|
||||
** pattern of any quota group, this routine is a no-op.
|
||||
*/
|
||||
int sqlite3_quota_file(const char *zFilename);
|
||||
|
||||
/*
|
||||
** The following object serves the same role as FILE in the standard C
|
||||
** library. It represents an open connection to a file on disk for I/O.
|
||||
**
|
||||
** A single quota_FILE should not be used by two or more threads at the
|
||||
** same time. Multiple threads can be using different quota_FILE objects
|
||||
** simultaneously, but not the same quota_FILE object.
|
||||
*/
|
||||
typedef struct quota_FILE quota_FILE;
|
||||
|
||||
/*
|
||||
** Create a new quota_FILE object used to read and/or write to the
|
||||
** file zFilename. The zMode parameter is as with standard library zMode.
|
||||
*/
|
||||
quota_FILE *sqlite3_quota_fopen(const char *zFilename, const char *zMode);
|
||||
|
||||
/*
|
||||
** Perform I/O against a quota_FILE object. When doing writes, the
|
||||
** quota mechanism may result in a short write, in order to prevent
|
||||
** the sum of sizes of all files from going over quota.
|
||||
*/
|
||||
size_t sqlite3_quota_fread(void*, size_t, size_t, quota_FILE*);
|
||||
size_t sqlite3_quota_fwrite(void*, size_t, size_t, quota_FILE*);
|
||||
|
||||
/*
|
||||
** Flush all written content held in memory buffers out to disk.
|
||||
** This is the equivalent of fflush() in the standard library.
|
||||
**
|
||||
** If the hardSync parameter is true (non-zero) then this routine
|
||||
** also forces OS buffers to disk - the equivalent of fsync().
|
||||
**
|
||||
** This routine return zero on success and non-zero if something goes
|
||||
** wrong.
|
||||
*/
|
||||
int sqlite3_quota_fflush(quota_FILE*, int hardSync);
|
||||
|
||||
/*
|
||||
** Close a quota_FILE object and free all associated resources. The
|
||||
** file remains under quota management.
|
||||
*/
|
||||
int sqlite3_quota_fclose(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Move the read/write pointer for a quota_FILE object. Or tell the
|
||||
** current location of the read/write pointer.
|
||||
*/
|
||||
int sqlite3_quota_fseek(quota_FILE*, long, int);
|
||||
void sqlite3_quota_rewind(quota_FILE*);
|
||||
long sqlite3_quota_ftell(quota_FILE*);
|
||||
|
||||
/*
|
||||
** Delete a file from the disk, if that file is under quota management.
|
||||
** Adjust quotas accordingly.
|
||||
**
|
||||
** If zFilename is the name of a directory that matches one of the
|
||||
** quota glob patterns, then all files under quota management that
|
||||
** are contained within that directory are deleted.
|
||||
**
|
||||
** A standard SQLite result code is returned (SQLITE_OK, SQLITE_NOMEM, etc.)
|
||||
** When deleting a directory of files, if the deletion of any one
|
||||
** file fails (for example due to an I/O error), then this routine
|
||||
** returns immediately, with the error code, and does not try to
|
||||
** delete any of the other files in the specified directory.
|
||||
**
|
||||
** All files are removed from quota management and deleted from disk.
|
||||
** However, no attempt is made to remove empty directories.
|
||||
**
|
||||
** This routine is a no-op for files that are not under quota management.
|
||||
*/
|
||||
int sqlite3_quota_remove(const char *zFilename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of the 'extern "C"' block */
|
||||
#endif
|
||||
#endif /* _QUOTA_H_ */
|
||||
+1
-1
@@ -369,7 +369,7 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
||||
|
||||
/* The default page size and offset */
|
||||
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
|
||||
pCsr->iOffset = pCsr->szPage * (pCsr->iPageno - 1);
|
||||
pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
|
||||
|
||||
/* If connected to a ZIPVFS backend, override the page size and
|
||||
** offset with actual values obtained from ZIPVFS.
|
||||
|
||||
@@ -904,7 +904,6 @@ static TriggerPrg *codeRowTrigger(
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
pProgram->nCsr = pSubParse->nTab;
|
||||
pProgram->nOnce = pSubParse->nOnce;
|
||||
pProgram->token = (void *)pTrigger;
|
||||
pPrg->aColmask[0] = pSubParse->oldmask;
|
||||
pPrg->aColmask[1] = pSubParse->newmask;
|
||||
|
||||
+5
-6
@@ -126,8 +126,8 @@ void sqlite3Update(
|
||||
int regRowCount = 0; /* A count of rows changed */
|
||||
int regOldRowid; /* The old rowid */
|
||||
int regNewRowid; /* The new rowid */
|
||||
int regNew; /* Content of the NEW.* table in triggers */
|
||||
int regOld = 0; /* Content of OLD.* table in triggers */
|
||||
int regNew;
|
||||
int regOld = 0;
|
||||
int regRowSet = 0; /* Rowset of rows to be updated */
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
@@ -276,7 +276,6 @@ void sqlite3Update(
|
||||
#endif
|
||||
|
||||
/* Allocate required registers. */
|
||||
regRowSet = ++pParse->nMem;
|
||||
regOldRowid = regNewRowid = ++pParse->nMem;
|
||||
if( pTrigger || hasFK ){
|
||||
regOld = pParse->nMem + 1;
|
||||
@@ -311,7 +310,7 @@ void sqlite3Update(
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
|
||||
);
|
||||
@@ -322,6 +321,7 @@ void sqlite3Update(
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
|
||||
if( !okOnePass ){
|
||||
regRowSet = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
||||
}
|
||||
|
||||
@@ -425,10 +425,9 @@ void sqlite3Update(
|
||||
newmask = sqlite3TriggerColmask(
|
||||
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
|
||||
);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
/*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
|
||||
}else{
|
||||
j = aXRef[i];
|
||||
if( j>=0 ){
|
||||
|
||||
+22
-42
@@ -764,8 +764,7 @@ case OP_Goto: { /* jump */
|
||||
** Write the current address onto register P1
|
||||
** and then jump to address P2.
|
||||
*/
|
||||
case OP_Gosub: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
||||
case OP_Gosub: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
@@ -962,25 +961,12 @@ case OP_String: { /* out2-prerelease */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Null * P2 P3 * *
|
||||
/* Opcode: Null * P2 * * *
|
||||
**
|
||||
** Write a NULL into registers P2. If P3 greater than P2, then also write
|
||||
** NULL into register P3 and ever register in between P2 and P3. If P3
|
||||
** is less than P2 (typically P3 is zero) then only register P2 is
|
||||
** set to NULL
|
||||
** Write a NULL into register P2.
|
||||
*/
|
||||
case OP_Null: { /* out2-prerelease */
|
||||
int cnt;
|
||||
cnt = pOp->p3-pOp->p2;
|
||||
assert( pOp->p3<=p->nMem );
|
||||
pOut->flags = MEM_Null;
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
memAboutToChange(p, pOut);
|
||||
MemReleaseExt(pOut);
|
||||
pOut->flags = MEM_Null;
|
||||
cnt--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2037,33 +2023,27 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
|
||||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
** Jump to P2 if the value in register P1 is a not null or zero. If
|
||||
** the value is NULL or zero, fall through and change the P1 register
|
||||
** to an integer 1.
|
||||
**
|
||||
** See also: JumpOnce
|
||||
** When P1 is not used otherwise in a program, this opcode falls through
|
||||
** once and jumps on all subsequent invocations. It is the equivalent
|
||||
** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
if( p->aOnceFlag[pOp->p1] ){
|
||||
pc = pOp->p2-1;
|
||||
}else{
|
||||
p->aOnceFlag[pOp->p1] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: If P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is true. The value
|
||||
** is considered true if it is numeric and non-zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is non-zero.
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
*/
|
||||
/* Opcode: IfNot P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is False. The value
|
||||
** is considered false if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is zero.
|
||||
** is considered true if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
*/
|
||||
case OP_Once: /* jump, in1 */
|
||||
case OP_If: /* jump, in1 */
|
||||
case OP_IfNot: { /* jump, in1 */
|
||||
int c;
|
||||
@@ -2080,6 +2060,12 @@ case OP_IfNot: { /* jump, in1 */
|
||||
}
|
||||
if( c ){
|
||||
pc = pOp->p2-1;
|
||||
}else if( pOp->opcode==OP_Once ){
|
||||
assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
pIn1->flags = MEM_Int;
|
||||
pIn1->u.i = 1;
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5085,6 +5071,7 @@ case OP_Program: { /* jump */
|
||||
|
||||
pProgram = pOp->p4.pProgram;
|
||||
pRt = &aMem[pOp->p3];
|
||||
assert( memIsValid(pRt) );
|
||||
assert( pProgram->nOp>0 );
|
||||
|
||||
/* If the p5 flag is clear, then recursive invocation of triggers is
|
||||
@@ -5123,8 +5110,7 @@ case OP_Program: { /* jump */
|
||||
nMem = pProgram->nMem + pProgram->nCsr;
|
||||
nByte = ROUND8(sizeof(VdbeFrame))
|
||||
+ nMem * sizeof(Mem)
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *)
|
||||
+ pProgram->nOnce * sizeof(u8);
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *);
|
||||
pFrame = sqlite3DbMallocZero(db, nByte);
|
||||
if( !pFrame ){
|
||||
goto no_mem;
|
||||
@@ -5144,12 +5130,10 @@ case OP_Program: { /* jump */
|
||||
pFrame->aOp = p->aOp;
|
||||
pFrame->nOp = p->nOp;
|
||||
pFrame->token = pProgram->token;
|
||||
pFrame->aOnceFlag = p->aOnceFlag;
|
||||
pFrame->nOnceFlag = p->nOnceFlag;
|
||||
|
||||
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
|
||||
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
|
||||
pMem->flags = MEM_Invalid;
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -5171,11 +5155,7 @@ case OP_Program: { /* jump */
|
||||
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
|
||||
p->aOp = aOp = pProgram->aOp;
|
||||
p->nOp = pProgram->nOp;
|
||||
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
|
||||
p->nOnceFlag = pProgram->nOnce;
|
||||
p->nOp = pProgram->nOp;
|
||||
pc = -1;
|
||||
memset(p->aOnceFlag, 0, p->nOnceFlag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ struct SubProgram {
|
||||
int nOp; /* Elements in aOp[] */
|
||||
int nMem; /* Number of memory cells required */
|
||||
int nCsr; /* Number of cursors required */
|
||||
int nOnce; /* Number of OP_Once instructions */
|
||||
void *token; /* id that may be used to recursive triggers */
|
||||
SubProgram *pNext; /* Next sub-program already visited */
|
||||
};
|
||||
|
||||
@@ -33,9 +33,6 @@ typedef unsigned char Bool;
|
||||
/* Opaque type used by code in vdbesort.c */
|
||||
typedef struct VdbeSorter VdbeSorter;
|
||||
|
||||
/* Opaque type used by the explainer */
|
||||
typedef struct Explain Explain;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
@@ -120,8 +117,6 @@ struct VdbeFrame {
|
||||
int nOp; /* Size of aOp array */
|
||||
Mem *aMem; /* Array of memory cells for parent frame */
|
||||
int nMem; /* Number of entries in aMem */
|
||||
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
|
||||
int nOnceFlag; /* Number of entries in aOnceFlag */
|
||||
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
|
||||
u16 nCursor; /* Number of entries in apCsr */
|
||||
void *token; /* Copy of SubProgram.token */
|
||||
@@ -260,18 +255,6 @@ struct sqlite3_context {
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
};
|
||||
|
||||
/*
|
||||
** An Explain object accumulates indented output which is helpful
|
||||
** in describing recursive data structures.
|
||||
*/
|
||||
struct Explain {
|
||||
Vdbe *pVdbe; /* Attach the explanation to this Vdbe */
|
||||
StrAccum str; /* The string being accumulated */
|
||||
int nIndent; /* Number of elements in aIndent */
|
||||
u16 aIndent[100]; /* Levels of indentation */
|
||||
char zBase[100]; /* Initial space */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the virtual machine. This structure contains the complete
|
||||
** state of the virtual machine.
|
||||
@@ -337,18 +320,12 @@ struct Vdbe {
|
||||
void *pFree; /* Free this when deleting the vdbe */
|
||||
#ifdef SQLITE_DEBUG
|
||||
FILE *trace; /* Write an execution trace here, if not NULL */
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_TREE_EXPLAIN
|
||||
Explain *pExplain; /* The explainer */
|
||||
char *zExplain; /* Explanation of data structures */
|
||||
#endif
|
||||
VdbeFrame *pFrame; /* Parent frame */
|
||||
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
|
||||
int nFrame; /* Number of frames in pFrame list */
|
||||
u32 expmask; /* Binding to these vars invalidates VM */
|
||||
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
|
||||
int nOnceFlag; /* Size of array aOnceFlag[] */
|
||||
u8 *aOnceFlag; /* Flags for OP_Once */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1277,14 +1277,6 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
|
||||
return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the prepared statement is in need of being reset.
|
||||
*/
|
||||
int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
return v!=0 && v->pc>0 && v->magic==VDBE_MAGIC_RUN;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the next prepared statement after pStmt associated
|
||||
** with database connection pDb. If pStmt is NULL, return the first
|
||||
|
||||
+9
-28
@@ -913,14 +913,13 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
}
|
||||
case P4_MEM: {
|
||||
Mem *pMem = pOp->p4.pMem;
|
||||
assert( (pMem->flags & MEM_Null)==0 );
|
||||
if( pMem->flags & MEM_Str ){
|
||||
zP4 = pMem->z;
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
|
||||
}else if( pMem->flags & MEM_Real ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
|
||||
}else if( pMem->flags & MEM_Null ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "NULL");
|
||||
}else{
|
||||
assert( pMem->flags & MEM_Blob );
|
||||
zP4 = "(blob)";
|
||||
@@ -1095,7 +1094,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
p->zMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Invalid;
|
||||
p->flags = MEM_Null;
|
||||
}
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
@@ -1470,7 +1469,6 @@ void sqlite3VdbeMakeReady(
|
||||
int nMem; /* Number of VM memory registers */
|
||||
int nCursor; /* Number of cursors required */
|
||||
int nArg; /* Number of arguments in subprograms */
|
||||
int nOnce; /* Number of OP_Once instructions */
|
||||
int n; /* Loop counter */
|
||||
u8 *zCsr; /* Memory available for allocation */
|
||||
u8 *zEnd; /* First byte past allocated memory */
|
||||
@@ -1486,7 +1484,6 @@ void sqlite3VdbeMakeReady(
|
||||
nMem = pParse->nMem;
|
||||
nCursor = pParse->nTab;
|
||||
nArg = pParse->nMaxArg;
|
||||
nOnce = pParse->nOnce;
|
||||
|
||||
/* For each cursor required, also allocate a memory cell. Memory
|
||||
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
|
||||
@@ -1533,7 +1530,6 @@ void sqlite3VdbeMakeReady(
|
||||
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
||||
&zCsr, zEnd, &nByte);
|
||||
p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
|
||||
if( nByte ){
|
||||
p->pFree = sqlite3DbMallocZero(db, nByte);
|
||||
}
|
||||
@@ -1542,7 +1538,6 @@ void sqlite3VdbeMakeReady(
|
||||
}while( nByte && !db->mallocFailed );
|
||||
|
||||
p->nCursor = (u16)nCursor;
|
||||
p->nOnceFlag = nOnce;
|
||||
if( p->aVar ){
|
||||
p->nVar = (ynVar)nVar;
|
||||
for(n=0; n<nVar; n++){
|
||||
@@ -1559,7 +1554,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Invalid;
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
@@ -1601,8 +1596,6 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
*/
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
||||
Vdbe *v = pFrame->v;
|
||||
v->aOnceFlag = pFrame->aOnceFlag;
|
||||
v->nOnceFlag = pFrame->nOnceFlag;
|
||||
v->aOp = pFrame->aOp;
|
||||
v->nOp = pFrame->nOp;
|
||||
v->aMem = pFrame->aMem;
|
||||
@@ -1665,10 +1658,8 @@ static void Cleanup(Vdbe *p){
|
||||
/* Execute assert() statements to ensure that the Vdbe.apCsr[] and
|
||||
** Vdbe.aMem[] arrays have already been cleaned up. */
|
||||
int i;
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
|
||||
}
|
||||
for(i=0; i<p->nCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 );
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem==0 || p->aMem[i].flags==MEM_Null );
|
||||
#endif
|
||||
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
@@ -1842,16 +1833,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
if( zMaster==0 ) return SQLITE_NOMEM;
|
||||
do {
|
||||
u32 iRandom;
|
||||
if( retryCount ){
|
||||
if( retryCount>100 ){
|
||||
sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
|
||||
sqlite3OsDelete(pVfs, zMaster, 0);
|
||||
break;
|
||||
}else if( retryCount==1 ){
|
||||
sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
|
||||
}
|
||||
if( retryCount++>100 ){
|
||||
sqlite3_log(SQLITE_FULL, "cannot find unique master-journal");
|
||||
sqlite3OsDelete(pVfs, zMaster, 0);
|
||||
break;
|
||||
}
|
||||
retryCount++;
|
||||
sqlite3_randomness(sizeof(iRandom), &iRandom);
|
||||
sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
|
||||
(iRandom>>8)&0xffffff, iRandom&0xff);
|
||||
@@ -2151,7 +2137,6 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
if( p->db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
|
||||
closeAllCursors(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
@@ -2489,10 +2474,6 @@ void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
sqlite3DbFree(db, p->zExplain);
|
||||
sqlite3DbFree(db, p->pExplain);
|
||||
#endif
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
|
||||
-117
@@ -12,8 +12,6 @@
|
||||
**
|
||||
** This file contains code used to insert the values of host parameters
|
||||
** (aka "wildcards") into the SQL text output by sqlite3_trace().
|
||||
**
|
||||
** The Vdbe parse-tree explainer is also found here.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
@@ -154,118 +152,3 @@ char *sqlite3VdbeExpandSql(
|
||||
}
|
||||
|
||||
#endif /* #ifndef SQLITE_OMIT_TRACE */
|
||||
|
||||
/*****************************************************************************
|
||||
** The following code implements the data-structure explaining logic
|
||||
** for the Vdbe.
|
||||
*/
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
|
||||
/*
|
||||
** Allocate a new Explain object
|
||||
*/
|
||||
void sqlite3ExplainBegin(Vdbe *pVdbe){
|
||||
if( pVdbe ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
Explain *p = sqlite3_malloc( sizeof(Explain) );
|
||||
if( p ){
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pVdbe = pVdbe;
|
||||
sqlite3_free(pVdbe->pExplain);
|
||||
pVdbe->pExplain = p;
|
||||
sqlite3StrAccumInit(&p->str, p->zBase, sizeof(p->zBase),
|
||||
SQLITE_MAX_LENGTH);
|
||||
p->str.useMalloc = 2;
|
||||
}else{
|
||||
sqlite3EndBenignMalloc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the Explain ends with a new-line.
|
||||
*/
|
||||
static int endsWithNL(Explain *p){
|
||||
return p && p->str.zText && p->str.nChar
|
||||
&& p->str.zText[p->str.nChar-1]=='\n';
|
||||
}
|
||||
|
||||
/*
|
||||
** Append text to the indentation
|
||||
*/
|
||||
void sqlite3ExplainPrintf(Vdbe *pVdbe, const char *zFormat, ...){
|
||||
Explain *p;
|
||||
if( pVdbe && (p = pVdbe->pExplain)!=0 ){
|
||||
va_list ap;
|
||||
if( p->nIndent && endsWithNL(p) ){
|
||||
int n = p->nIndent;
|
||||
if( n>ArraySize(p->aIndent) ) n = ArraySize(p->aIndent);
|
||||
sqlite3AppendSpace(&p->str, p->aIndent[n-1]);
|
||||
}
|
||||
va_start(ap, zFormat);
|
||||
sqlite3VXPrintf(&p->str, 1, zFormat, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Append a '\n' if there is not already one.
|
||||
*/
|
||||
void sqlite3ExplainNL(Vdbe *pVdbe){
|
||||
Explain *p;
|
||||
if( pVdbe && (p = pVdbe->pExplain)!=0 && !endsWithNL(p) ){
|
||||
sqlite3StrAccumAppend(&p->str, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Push a new indentation level. Subsequent lines will be indented
|
||||
** so that they begin at the current cursor position.
|
||||
*/
|
||||
void sqlite3ExplainPush(Vdbe *pVdbe){
|
||||
Explain *p;
|
||||
if( pVdbe && (p = pVdbe->pExplain)!=0 ){
|
||||
if( p->str.zText && p->nIndent<ArraySize(p->aIndent) ){
|
||||
const char *z = p->str.zText;
|
||||
int i = p->str.nChar-1;
|
||||
int x;
|
||||
while( i>=0 && z[i]!='\n' ){ i--; }
|
||||
x = (p->str.nChar - 1) - i;
|
||||
if( p->nIndent && x<p->aIndent[p->nIndent-1] ){
|
||||
x = p->aIndent[p->nIndent-1];
|
||||
}
|
||||
p->aIndent[p->nIndent] = x;
|
||||
}
|
||||
p->nIndent++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Pop the indentation stack by one level.
|
||||
*/
|
||||
void sqlite3ExplainPop(Vdbe *p){
|
||||
if( p && p->pExplain ) p->pExplain->nIndent--;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free the indentation structure
|
||||
*/
|
||||
void sqlite3ExplainFinish(Vdbe *pVdbe){
|
||||
if( pVdbe && pVdbe->pExplain ){
|
||||
sqlite3_free(pVdbe->zExplain);
|
||||
sqlite3ExplainNL(pVdbe);
|
||||
pVdbe->zExplain = sqlite3StrAccumFinish(&pVdbe->pExplain->str);
|
||||
sqlite3_free(pVdbe->pExplain);
|
||||
pVdbe->pExplain = 0;
|
||||
sqlite3EndBenignMalloc();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the explanation of a virtual machine.
|
||||
*/
|
||||
const char *sqlite3VdbeExplanation(Vdbe *pVdbe){
|
||||
return (pVdbe && pVdbe->zExplain) ? pVdbe->zExplain : 0;
|
||||
}
|
||||
#endif /* defined(SQLITE_DEBUG) */
|
||||
|
||||
@@ -414,17 +414,13 @@ struct Wal {
|
||||
u32 iCallback; /* Value to pass to log callback (or 0) */
|
||||
i64 mxWalSize; /* Truncate WAL to this size upon reset */
|
||||
int nWiData; /* Size of array apWiData */
|
||||
int szFirstBlock; /* Size of first block written to WAL file */
|
||||
volatile u32 **apWiData; /* Pointer to wal-index content in memory */
|
||||
u32 szPage; /* Database page size */
|
||||
i16 readLock; /* Which read lock is being held. -1 for none */
|
||||
u8 syncFlags; /* Flags to use to sync header writes */
|
||||
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
|
||||
u8 writeLock; /* True if in a write transaction */
|
||||
u8 ckptLock; /* True if holding a checkpoint lock */
|
||||
u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
|
||||
u8 truncateOnCommit; /* True to truncate WAL file on commit */
|
||||
u8 noSyncHeader; /* Avoid WAL header fsyncs if true */
|
||||
WalIndexHdr hdr; /* Wal-index header for current transaction */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
@@ -1299,8 +1295,6 @@ int sqlite3WalOpen(
|
||||
sqlite3OsClose(pRet->pWalFd);
|
||||
sqlite3_free(pRet);
|
||||
}else{
|
||||
int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
|
||||
if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->noSyncHeader = 1; }
|
||||
*ppWal = pRet;
|
||||
WALTRACE(("WAL%d: opened\n", pRet));
|
||||
}
|
||||
@@ -1787,24 +1781,6 @@ static int walCheckpoint(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the WAL file is currently larger than nMax bytes in size, truncate
|
||||
** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
|
||||
*/
|
||||
static void walLimitSize(Wal *pWal, i64 nMax){
|
||||
i64 sz;
|
||||
int rx;
|
||||
sqlite3BeginBenignMalloc();
|
||||
rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
|
||||
if( rx==SQLITE_OK && (sz > nMax ) ){
|
||||
rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
if( rx ){
|
||||
sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a connection to a log file.
|
||||
*/
|
||||
@@ -1828,29 +1804,16 @@ int sqlite3WalClose(
|
||||
*/
|
||||
rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bPersistWal = -1;
|
||||
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
|
||||
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
|
||||
}
|
||||
rc = sqlite3WalCheckpoint(
|
||||
pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
int bPersist = -1;
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist);
|
||||
if( bPersist!=1 ){
|
||||
/* Try to delete the WAL file if the checkpoint completed and
|
||||
** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
|
||||
** mode (!bPersist) */
|
||||
isDelete = 1;
|
||||
}else if( pWal->mxWalSize>=0 ){
|
||||
/* Try to truncate the WAL file to zero bytes if the checkpoint
|
||||
** completed and fsynced (rc==SQLITE_OK) and we are in persistent
|
||||
** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
|
||||
** non-negative value (pWal->mxWalSize>=0). Note that we truncate
|
||||
** to zero bytes as truncating to the journal_size_limit might
|
||||
** leave a corrupt WAL file on disk. */
|
||||
walLimitSize(pWal, 0);
|
||||
}
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
|
||||
if( rc==SQLITE_OK && bPersistWal!=1 ){
|
||||
isDelete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2459,7 +2422,6 @@ int sqlite3WalEndWriteTransaction(Wal *pWal){
|
||||
if( pWal->writeLock ){
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
pWal->writeLock = 0;
|
||||
pWal->truncateOnCommit = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2556,7 +2518,6 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called just before writing a set of frames to the log
|
||||
** file (see sqlite3WalFrames()). It checks to see if, instead of appending
|
||||
@@ -2594,6 +2555,23 @@ static int walRestartLog(Wal *pWal){
|
||||
int i; /* Loop counter */
|
||||
u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
|
||||
|
||||
/* Limit the size of WAL file if the journal_size_limit PRAGMA is
|
||||
** set to a non-negative value. Log errors encountered
|
||||
** during the truncation attempt. */
|
||||
if( pWal->mxWalSize>=0 ){
|
||||
i64 sz;
|
||||
int rx;
|
||||
sqlite3BeginBenignMalloc();
|
||||
rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
|
||||
if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){
|
||||
rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize);
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
if( rx ){
|
||||
sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
|
||||
}
|
||||
}
|
||||
|
||||
pWal->nCkpt++;
|
||||
pWal->hdr.mxFrame = 0;
|
||||
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
|
||||
@@ -2622,44 +2600,6 @@ static int walRestartLog(Wal *pWal){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write iAmt bytes of content into the WAL file beginning at iOffset.
|
||||
**
|
||||
** When crossing the boundary between the first and second sectors of the
|
||||
** file, first write all of the first sector content, then fsync(), then
|
||||
** continue writing content for the second sector. This ensures that
|
||||
** the WAL header is overwritten before the first commit mark.
|
||||
*/
|
||||
static int walWriteToLog(
|
||||
Wal *pWal, /* WAL to write to */
|
||||
void *pContent, /* Content to be written */
|
||||
int iAmt, /* Number of bytes to write */
|
||||
sqlite3_int64 iOffset /* Start writing at this offset */
|
||||
){
|
||||
int rc;
|
||||
if( iOffset>=pWal->szFirstBlock
|
||||
|| iOffset+iAmt<pWal->szFirstBlock
|
||||
|| pWal->syncFlags==0
|
||||
){
|
||||
/* The common and fast case. Just write the data. */
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, pContent, iAmt, iOffset);
|
||||
}else{
|
||||
/* If this write will cross the first sector boundary, it has to
|
||||
** be split it two with a sync in between. */
|
||||
int iFirstAmt = pWal->szFirstBlock - iOffset;
|
||||
assert( iFirstAmt>0 && iFirstAmt<iAmt );
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, pContent, iFirstAmt, iOffset);
|
||||
if( rc ) return rc;
|
||||
assert( pWal->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
|
||||
rc = sqlite3OsSync(pWal->pWalFd, pWal->syncFlags);
|
||||
if( rc ) return rc;
|
||||
pContent = (void*)(iFirstAmt + (char*)pContent);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, pContent,
|
||||
iAmt-iFirstAmt, iOffset+iFirstAmt);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a set of frames to the log. The caller must hold the write-lock
|
||||
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
|
||||
@@ -2719,7 +2659,6 @@ int sqlite3WalFrames(
|
||||
pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
|
||||
pWal->hdr.aFrameCksum[0] = aCksum[0];
|
||||
pWal->hdr.aFrameCksum[1] = aCksum[1];
|
||||
pWal->truncateOnCommit = 1;
|
||||
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
|
||||
WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
|
||||
@@ -2729,16 +2668,6 @@ int sqlite3WalFrames(
|
||||
}
|
||||
assert( (int)pWal->szPage==szPage );
|
||||
|
||||
/* Setup information needed to do the WAL header sync */
|
||||
if( pWal->noSyncHeader ){
|
||||
assert( pWal->szFirstBlock==0 );
|
||||
assert( pWal->syncFlags==0 );
|
||||
}else{
|
||||
pWal->szFirstBlock = sqlite3OsSectorSize(pWal->pWalFd);
|
||||
if( szPage>pWal->szFirstBlock ) pWal->szFirstBlock = szPage;
|
||||
pWal->syncFlags = sync_flags & SQLITE_SYNC_MASK;
|
||||
}
|
||||
|
||||
/* Write the log file. */
|
||||
for(p=pList; p; p=p->pDirty){
|
||||
u32 nDbsize; /* Db-size field for frame header */
|
||||
@@ -2756,13 +2685,13 @@ int sqlite3WalFrames(
|
||||
pData = p->pData;
|
||||
#endif
|
||||
walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
|
||||
rc = walWriteToLog(pWal, aFrame, sizeof(aFrame), iOffset);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Write the page data */
|
||||
rc = walWriteToLog(pWal, pData, szPage, iOffset+sizeof(aFrame));
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset+sizeof(aFrame));
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -2770,10 +2699,11 @@ int sqlite3WalFrames(
|
||||
}
|
||||
|
||||
/* Sync the log file if the 'isSync' flag was specified. */
|
||||
if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
|
||||
if( sync_flags ){
|
||||
i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd);
|
||||
i64 iOffset = walFrameOffset(iFrame+1, szPage);
|
||||
|
||||
assert( isCommit );
|
||||
assert( iSegment>0 );
|
||||
|
||||
iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment);
|
||||
@@ -2786,12 +2716,12 @@ int sqlite3WalFrames(
|
||||
#endif
|
||||
walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
|
||||
rc = walWriteToLog(pWal, aFrame, sizeof(aFrame), iOffset);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, aFrame, sizeof(aFrame), iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
iOffset += WAL_FRAME_HDRSIZE;
|
||||
rc = walWriteToLog(pWal, pData, szPage, iOffset);
|
||||
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -2799,16 +2729,7 @@ int sqlite3WalFrames(
|
||||
iOffset += szPage;
|
||||
}
|
||||
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
|
||||
}
|
||||
|
||||
if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
|
||||
i64 sz = pWal->mxWalSize;
|
||||
if( walFrameOffset(iFrame+nLast+1, szPage)>pWal->mxWalSize ){
|
||||
sz = walFrameOffset(iFrame+nLast+1, szPage);
|
||||
}
|
||||
walLimitSize(pWal, sz);
|
||||
pWal->truncateOnCommit = 0;
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* Append data to the wal-index. It is not necessary to lock the
|
||||
|
||||
@@ -87,12 +87,6 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
|
||||
/* Write a frame or frames to the log. */
|
||||
int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
|
||||
|
||||
/* Additional values that can be added to the sync_flags argument of
|
||||
** sqlite3WalFrames():
|
||||
*/
|
||||
#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
|
||||
#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
|
||||
|
||||
/* Copy pages from the log to the database file */
|
||||
int sqlite3WalCheckpoint(
|
||||
Wal *pWal, /* Write-ahead log connection */
|
||||
|
||||
+3
-1
@@ -2005,6 +2005,7 @@ static void constructAutomaticIndex(
|
||||
int nByte; /* Byte of memory needed for pIdx */
|
||||
Index *pIdx; /* Object describing the transient index */
|
||||
Vdbe *v; /* Prepared statement under construction */
|
||||
int regIsInit; /* Register set by initialization */
|
||||
int addrInit; /* Address of the initialization bypass jump */
|
||||
Table *pTable; /* The table being indexed */
|
||||
KeyInfo *pKeyinfo; /* Key information for the index */
|
||||
@@ -2021,7 +2022,8 @@ static void constructAutomaticIndex(
|
||||
** transient index on 2nd and subsequent iterations of the loop. */
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
addrInit = sqlite3CodeOnce(pParse);
|
||||
regIsInit = ++pParse->nMem;
|
||||
addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
|
||||
|
||||
/* Count the number of columns that will be added to the index
|
||||
** and used to match WHERE clause constraints */
|
||||
|
||||
@@ -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
|
||||
+1
-25
@@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file is devoted to testing the sqlite3_next_stmt and
|
||||
# sqlite3_stmt_readonly and sqlite3_stmt_busy interfaces.
|
||||
# sqlite3_stmt_readonly interfaces.
|
||||
#
|
||||
# $Id: capi3d.test,v 1.2 2008/07/14 15:11:20 drh Exp $
|
||||
#
|
||||
@@ -112,29 +112,5 @@ do_test capi3-2.99 {
|
||||
sqlite3_stmt_readonly 0
|
||||
} 1
|
||||
|
||||
# Tests for sqlite3_stmt_busy
|
||||
#
|
||||
do_test capi3d-3.1 {
|
||||
db eval {INSERT INTO t1 VALUES(6); INSERT INTO t1 VALUES(7);}
|
||||
set STMT [sqlite3_prepare db {SELECT * FROM t1} -1 TAIL]
|
||||
sqlite3_stmt_busy $STMT
|
||||
} {0}
|
||||
do_test capi3d-3.2 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_stmt_busy $STMT
|
||||
} {1}
|
||||
do_test capi3d-3.3 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_stmt_busy $STMT
|
||||
} {1}
|
||||
do_test capi3d-3.4 {
|
||||
sqlite3_reset $STMT
|
||||
sqlite3_stmt_busy $STMT
|
||||
} {0}
|
||||
|
||||
do_test capi3d-3.99 {
|
||||
sqlite3_finalize $STMT
|
||||
sqlite3_stmt_busy 0
|
||||
} {0}
|
||||
|
||||
finish_test
|
||||
|
||||
+4
-4
@@ -573,10 +573,10 @@ set chunkconfig [fts3_configure_incr_load 1 1]
|
||||
foreach {tn create pending} {
|
||||
1 "fts4(a, b)" 1
|
||||
2 "fts4(a, b, order=ASC, prefix=1)" 1
|
||||
3 "fts4(a, b, order=ASC, prefix=1,3)" 0
|
||||
4 "fts4(a, b, order=DESC, prefix=2,4)" 0
|
||||
5 "fts4(a, b, order=DESC, prefix=1)" 0
|
||||
6 "fts4(a, b, order=ASC, prefix=1,3)" 0
|
||||
3 "fts4(a, b, order=ASC, prefix=\"1,3\")" 0
|
||||
4 "fts4(a, b, order=DESC, prefix=\"2,4\")" 0
|
||||
5 "fts4(a, b, order=DESC, prefix=\"1\")" 0
|
||||
6 "fts4(a, b, order=ASC, prefix=\"1,3\")" 0
|
||||
} {
|
||||
|
||||
execsql [subst {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# 2012 January 25
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS3 module.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3prefix2
|
||||
|
||||
ifcapable !fts3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 { PRAGMA page_size = 512 }
|
||||
do_execsql_test 1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(x, prefix="2,3");
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('T TX T TX T TX T TX T TX');
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 4
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 8
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 16
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 32
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 64
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 128
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 256
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 512
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 1024
|
||||
INSERT INTO t1 SELECT * FROM t1; -- 2048
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
INSERT INTO t1 SELECT * FROM t1 LIMIT 10;
|
||||
DELETE FROM t1 WHERE docid > 5;
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
SELECT * FROM t1 WHERE t1 MATCH 'T*';
|
||||
} {
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
{T TX T TX T TX T TX T TX}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+10
-2
@@ -156,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 {
|
||||
@@ -192,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
|
||||
|
||||
+54
-5
@@ -14,9 +14,12 @@ 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 } }
|
||||
|
||||
@@ -44,10 +47,10 @@ do_multiclient_test tn {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
|
||||
do_test multiplex-1.$tn.1 { sql1 { SELECT count(*) FROM t1 } } 512
|
||||
do_test multiplex-1.$tn.2 { sql2 { SELECT count(*) FROM t1 } } 512
|
||||
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 multiplex-1.$tn.3 { sql1 { SELECT count(*) FROM t1 } } 0
|
||||
do_test 1.$tn.3 { sql1 { SELECT count(*) FROM t1 } } 0
|
||||
|
||||
sql1 {
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(4000)); -- 1
|
||||
@@ -63,8 +66,54 @@ do_multiclient_test tn {
|
||||
SELECT count(*) FROM t1;
|
||||
}
|
||||
|
||||
do_test multiplex-1.$tn.4 { sql2 { SELECT count(*) FROM t1 } } 512
|
||||
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
|
||||
|
||||
@@ -21,7 +21,7 @@ set ::testprefix multiplex3
|
||||
|
||||
ifcapable !8_3_names {
|
||||
puts -nonewline "SQLite compiled without SQLITE_ENABLE_8_3_NAMES. "
|
||||
puts "Skipping tests multiplex3-*."
|
||||
puts "Skipping tests zipvfsD-*."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
# 2011 December 1
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for the glob-style string compare operator embedded in the
|
||||
# quota shim.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
catch { unset testnum }
|
||||
catch { unset pattern }
|
||||
catch { unset text }
|
||||
catch { unset ans }
|
||||
|
||||
foreach {testnum pattern text ans} {
|
||||
1 abcdefg abcdefg 1
|
||||
2 abcdefG abcdefg 0
|
||||
3 abcdef abcdefg 0
|
||||
4 abcdefgh abcdefg 0
|
||||
5 abcdef? abcdefg 1
|
||||
6 abcdef? abcdef 0
|
||||
7 abcdef? abcdefgh 0
|
||||
8 abcdefg abcdef? 0
|
||||
9 abcdef? abcdef? 1
|
||||
10 abc/def abc/def 1
|
||||
11 abc//def abc/def 0
|
||||
12 */abc/* x/abc/y 1
|
||||
13 */abc/* /abc/ 1
|
||||
16 */abc/* x///a/ab/abc 0
|
||||
17 */abc/* x//a/ab/abc/ 1
|
||||
16 */abc/* x///a/ab/abc 0
|
||||
17 */abc/* x//a/ab/abc/ 1
|
||||
18 **/abc/** x//a/ab/abc/ 1
|
||||
19 *?/abc/*? x//a/ab/abc/y 1
|
||||
20 ?*/abc/?* x//a/ab/abc/y 1
|
||||
21 {abc[cde]efg} abcbefg 0
|
||||
22 {abc[cde]efg} abccefg 1
|
||||
23 {abc[cde]efg} abcdefg 1
|
||||
24 {abc[cde]efg} abceefg 1
|
||||
25 {abc[cde]efg} abcfefg 0
|
||||
26 {abc[^cde]efg} abcbefg 1
|
||||
27 {abc[^cde]efg} abccefg 0
|
||||
28 {abc[^cde]efg} abcdefg 0
|
||||
29 {abc[^cde]efg} abceefg 0
|
||||
30 {abc[^cde]efg} abcfefg 1
|
||||
31 {abc[c-e]efg} abcbefg 0
|
||||
32 {abc[c-e]efg} abccefg 1
|
||||
33 {abc[c-e]efg} abcdefg 1
|
||||
34 {abc[c-e]efg} abceefg 1
|
||||
35 {abc[c-e]efg} abcfefg 0
|
||||
36 {abc[^c-e]efg} abcbefg 1
|
||||
37 {abc[^c-e]efg} abccefg 0
|
||||
38 {abc[^c-e]efg} abcdefg 0
|
||||
39 {abc[^c-e]efg} abceefg 0
|
||||
40 {abc[^c-e]efg} abcfefg 1
|
||||
41 {abc[c-e]efg} abc-efg 0
|
||||
42 {abc[-ce]efg} abc-efg 1
|
||||
43 {abc[ce-]efg} abc-efg 1
|
||||
44 {abc[][*?]efg} {abc]efg} 1
|
||||
45 {abc[][*?]efg} {abc*efg} 1
|
||||
46 {abc[][*?]efg} {abc?efg} 1
|
||||
47 {abc[][*?]efg} {abc[efg} 1
|
||||
48 {abc[^][*?]efg} {abc]efg} 0
|
||||
49 {abc[^][*?]efg} {abc*efg} 0
|
||||
50 {abc[^][*?]efg} {abc?efg} 0
|
||||
51 {abc[^][*?]efg} {abc[efg} 0
|
||||
52 {abc[^][*?]efg} {abcdefg} 1
|
||||
53 {*[xyz]efg} {abcxefg} 1
|
||||
54 {*[xyz]efg} {abcwefg} 0
|
||||
} {
|
||||
do_test quota-glob-$testnum.1 {
|
||||
sqlite3_quota_glob $::pattern $::text
|
||||
} $::ans
|
||||
do_test quota-glob-$testnum.2 {
|
||||
sqlite3_quota_glob $::pattern [string map {/ \\} $::text]
|
||||
} $::ans
|
||||
}
|
||||
finish_test
|
||||
@@ -50,7 +50,6 @@ do_test quota-1.8 { sqlite3_quota_shutdown } {SQLITE_OK}
|
||||
#
|
||||
sqlite3_quota_initialize "" 1
|
||||
|
||||
unset -nocomplain quota_request_ok
|
||||
proc quota_check {filename limitvar size} {
|
||||
upvar $limitvar limit
|
||||
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
# 2011 December 1
|
||||
#
|
||||
# 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
|
||||
|
||||
db close
|
||||
sqlite3_quota_initialize "" 1
|
||||
|
||||
foreach dir {quota2a/x1 quota2a/x2 quota2a quota2b quota2c} {
|
||||
file delete -force $dir
|
||||
}
|
||||
foreach dir {quota2a quota2a/x1 quota2a/x2 quota2b quota2c} {
|
||||
file mkdir $dir
|
||||
}
|
||||
|
||||
# The standard_path procedure converts a pathname into a standard format
|
||||
# that is the same across platforms.
|
||||
#
|
||||
unset -nocomplain ::quota_pwd ::quota_mapping
|
||||
set ::quota_pwd [string map {\\ /} [pwd]]
|
||||
set ::quota_mapping [list $::quota_pwd PWD]
|
||||
proc standard_path {x} {
|
||||
set x [string map {\\ /} $x]
|
||||
return [string map $::quota_mapping $x]
|
||||
}
|
||||
|
||||
# The quota_check procedure is a callback from the quota handler.
|
||||
# It has three arguments which are (1) the full pathname of the file
|
||||
# that has gone over quota, (2) the quota limit, (3) the requested
|
||||
# new quota size to cover the last write. These three values are
|
||||
# appended to the global variable $::quota. The filename is processed
|
||||
# to convert every \ character into / and to change the name of the
|
||||
# working directory to PWD.
|
||||
#
|
||||
# The quota is increased to the request if the ::quota_request_ok
|
||||
# global variable is true.
|
||||
#
|
||||
set ::quota {}
|
||||
set ::quota_request_ok 0
|
||||
|
||||
proc quota_check {filename limitvar size} {
|
||||
upvar $limitvar limit
|
||||
lappend ::quota [standard_path $filename] [set limit] $size
|
||||
if {$::quota_request_ok} {set limit $size}
|
||||
}
|
||||
|
||||
sqlite3_quota_set */quota2a/* 4000 quota_check
|
||||
sqlite3_quota_set */quota2b/* 5000 quota_check
|
||||
|
||||
unset -nocomplain bigtext
|
||||
for {set i 1} {$i<=1000} {incr i} {
|
||||
if {$i%10==0} {
|
||||
append bigtext [format "%06d\n" $i]
|
||||
} else {
|
||||
append bigtext [format "%06d " $i]
|
||||
}
|
||||
}
|
||||
|
||||
catch { unset h1 }
|
||||
catch { unset x }
|
||||
do_test quota2-1.1 {
|
||||
set ::h1 [sqlite3_quota_fopen quota2a/xyz.txt w+b]
|
||||
sqlite3_quota_fwrite $::h1 1 7000 $bigtext
|
||||
} {4000}
|
||||
do_test quota2-1.2 {
|
||||
set ::quota
|
||||
} {PWD/quota2a/xyz.txt 4000 7000}
|
||||
do_test quota2-1.3 {
|
||||
sqlite3_quota_rewind $::h1
|
||||
set ::x [sqlite3_quota_fread $::h1 1001 7]
|
||||
string length $::x
|
||||
} {3003}
|
||||
do_test quota2-1.4 {
|
||||
string match $::x [string range $::bigtext 0 3002]
|
||||
} {1}
|
||||
do_test quota2-1.5 {
|
||||
sqlite3_quota_fseek $::h1 0 SEEK_END
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {4000}
|
||||
do_test quota2-1.6 {
|
||||
sqlite3_quota_fseek $::h1 -100 SEEK_END
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {3900}
|
||||
do_test quota2-1.7 {
|
||||
sqlite3_quota_fseek $::h1 -100 SEEK_CUR
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {3800}
|
||||
do_test quota2-1.8 {
|
||||
sqlite3_quota_fseek $::h1 50 SEEK_CUR
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {3850}
|
||||
do_test quota2-1.9 {
|
||||
sqlite3_quota_fseek $::h1 50 SEEK_SET
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {50}
|
||||
do_test quota2-1.10 {
|
||||
sqlite3_quota_rewind $::h1
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {0}
|
||||
do_test quota2-1.11 {
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 1 0}}}
|
||||
do_test quota2-1.12 {
|
||||
sqlite3_quota_fclose $::h1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 4000 {PWD/quota2a/xyz.txt 4000 0 0}}}
|
||||
do_test quota2-1.13 {
|
||||
sqlite3_quota_remove quota2a/xyz.txt
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
|
||||
|
||||
|
||||
set quota {}
|
||||
do_test quota2-2.1 {
|
||||
set ::h1 [sqlite3_quota_fopen quota2c/xyz.txt w+b]
|
||||
sqlite3_quota_fwrite $::h1 1 7000 $bigtext
|
||||
} {7000}
|
||||
do_test quota2-2.2 {
|
||||
set ::quota
|
||||
} {}
|
||||
do_test quota2-2.3 {
|
||||
sqlite3_quota_rewind $::h1
|
||||
set ::x [sqlite3_quota_fread $::h1 1001 7]
|
||||
string length $::x
|
||||
} {6006}
|
||||
do_test quota2-2.4 {
|
||||
string match $::x [string range $::bigtext 0 6005]
|
||||
} {1}
|
||||
do_test quota2-2.5 {
|
||||
sqlite3_quota_fseek $::h1 0 SEEK_END
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {7000}
|
||||
do_test quota2-2.6 {
|
||||
sqlite3_quota_fseek $::h1 -100 SEEK_END
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {6900}
|
||||
do_test quota2-2.7 {
|
||||
sqlite3_quota_fseek $::h1 -100 SEEK_CUR
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {6800}
|
||||
do_test quota2-2.8 {
|
||||
sqlite3_quota_fseek $::h1 50 SEEK_CUR
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {6850}
|
||||
do_test quota2-2.9 {
|
||||
sqlite3_quota_fseek $::h1 50 SEEK_SET
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {50}
|
||||
do_test quota2-2.10 {
|
||||
sqlite3_quota_rewind $::h1
|
||||
sqlite3_quota_ftell $::h1
|
||||
} {0}
|
||||
do_test quota2-2.11 {
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
|
||||
do_test quota2-2.12 {
|
||||
sqlite3_quota_fclose $::h1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2b/* 5000 0} {*/quota2a/* 4000 0}}
|
||||
|
||||
do_test quota2-3.1 {
|
||||
sqlite3_quota_set */quota2b/* 0 quota_check
|
||||
set ::h1 [sqlite3_quota_fopen quota2a/x1/a.txt a]
|
||||
sqlite3_quota_fwrite $::h1 10 10 $bigtext
|
||||
} {10}
|
||||
do_test quota2-3.2 {
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}}
|
||||
do_test quota2-3.3a {
|
||||
sqlite3_quota_fflush $::h1 0
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}}
|
||||
do_test quota2-3.3b {
|
||||
sqlite3_quota_fflush $::h1 1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}}
|
||||
do_test quota2-3.3c {
|
||||
sqlite3_quota_fflush $::h1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 1 0}}}
|
||||
do_test quota2-3.4 {
|
||||
sqlite3_quota_fclose $::h1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 100 {PWD/quota2a/x1/a.txt 100 0 0}}}
|
||||
do_test quota2-3.5 {
|
||||
set ::h2 [sqlite3_quota_fopen quota2a/x2/b.txt a]
|
||||
sqlite3_quota_fwrite $::h2 10 20 $bigtext
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 300 {PWD/quota2a/x2/b.txt 200 1 0} {PWD/quota2a/x1/a.txt 100 0 0}}}
|
||||
do_test quota2-3.6 {
|
||||
set ::h3 [sqlite3_quota_fopen quota2a/x1/c.txt a]
|
||||
sqlite3_quota_fwrite $::h3 10 50 $bigtext
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 800 {PWD/quota2a/x1/c.txt 500 1 0} {PWD/quota2a/x2/b.txt 200 1 0} {PWD/quota2a/x1/a.txt 100 0 0}}}
|
||||
do_test quota2-3.7 {
|
||||
file exists quota2a/x1/a.txt
|
||||
} {1}
|
||||
do_test quota2-3.8 {
|
||||
file exists quota2a/x2/b.txt
|
||||
} {1}
|
||||
do_test quota2-3.9 {
|
||||
file exists quota2a/x1/c.txt
|
||||
} {1}
|
||||
do_test quota2-3.10 {
|
||||
sqlite3_quota_remove quota2a/x1
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 700 {PWD/quota2a/x1/c.txt 500 1 1} {PWD/quota2a/x2/b.txt 200 1 0}}}
|
||||
do_test quota2-3.11 {
|
||||
sqlite3_quota_fclose $::h2
|
||||
sqlite3_quota_fclose $::h3
|
||||
standard_path [sqlite3_quota_dump]
|
||||
} {{*/quota2a/* 4000 200 {PWD/quota2a/x2/b.txt 200 0 0}}}
|
||||
do_test quota2-3.12 {
|
||||
file exists quota2a/x1/a.txt
|
||||
} {0}
|
||||
do_test quota2-3.13 {
|
||||
file exists quota2a/x2/b.txt
|
||||
} {1}
|
||||
do_test quota2-3.14 {
|
||||
file exists quota2a/x1/c.txt
|
||||
} {0}
|
||||
|
||||
catch { sqlite3_quota_shutdown }
|
||||
catch { unset quota_request_ok }
|
||||
finish_test
|
||||
+13
-58
@@ -194,28 +194,19 @@ do_test selectB-3.0 {
|
||||
}
|
||||
} {}
|
||||
|
||||
for {set ii 3} {$ii <= 6} {incr ii} {
|
||||
for {set ii 3} {$ii <= 4} {incr ii} {
|
||||
|
||||
switch $ii {
|
||||
4 {
|
||||
optimization_control db query-flattener off
|
||||
}
|
||||
5 {
|
||||
optimization_control db query-flattener on
|
||||
do_test selectB-5.0 {
|
||||
execsql {
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
CREATE INDEX i3 ON t1(c);
|
||||
CREATE INDEX i4 ON t2(d);
|
||||
CREATE INDEX i5 ON t2(e);
|
||||
CREATE INDEX i6 ON t2(f);
|
||||
}
|
||||
} {}
|
||||
}
|
||||
6 {
|
||||
optimization_control db query-flattener off
|
||||
}
|
||||
if {$ii == 4} {
|
||||
do_test selectB-4.0 {
|
||||
execsql {
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(b);
|
||||
CREATE INDEX i3 ON t1(c);
|
||||
CREATE INDEX i4 ON t2(d);
|
||||
CREATE INDEX i5 ON t2(e);
|
||||
CREATE INDEX i6 ON t2(f);
|
||||
}
|
||||
} {}
|
||||
}
|
||||
|
||||
do_test selectB-$ii.1 {
|
||||
@@ -380,47 +371,11 @@ for {set ii 3} {$ii <= 6} {incr ii} {
|
||||
}
|
||||
} {2 4 6 3 6 9 8 10 12 12 15 18 14 16 18 21 24 27}
|
||||
|
||||
do_test selectB-$ii.22 {
|
||||
do_test selectB-$ii.21 {
|
||||
execsql {
|
||||
SELECT * FROM (SELECT 345 UNION ALL SELECT d FROM t2) ORDER BY 1;
|
||||
}
|
||||
} {3 12 21 345}
|
||||
|
||||
do_test selectB-$ii.23 {
|
||||
execsql {
|
||||
SELECT x, y FROM (
|
||||
SELECT a AS x, b AS y FROM t1
|
||||
UNION ALL
|
||||
SELECT a*10 + 0.1, f*10 + 0.1 FROM t1 JOIN t2 ON (c=d)
|
||||
UNION ALL
|
||||
SELECT a*100, b*100 FROM t1
|
||||
) ORDER BY 1;
|
||||
}
|
||||
} {2 4 8 10 14 16 80.1 180.1 200 400 800 1000 1400 1600}
|
||||
|
||||
do_test selectB-$ii.24 {
|
||||
execsql {
|
||||
SELECT x, y FROM (
|
||||
SELECT a AS x, b AS y FROM t1
|
||||
UNION ALL
|
||||
SELECT a*10 + 0.1, f*10 + 0.1 FROM t1 LEFT JOIN t2 ON (c=d)
|
||||
UNION ALL
|
||||
SELECT a*100, b*100 FROM t1
|
||||
) ORDER BY 1;
|
||||
}
|
||||
} {2 4 8 10 14 16 20.1 {} 80.1 180.1 140.1 {} 200 400 800 1000 1400 1600}
|
||||
|
||||
do_test selectB-$ii.25 {
|
||||
execsql {
|
||||
SELECT x+y FROM (
|
||||
SELECT a AS x, b AS y FROM t1
|
||||
UNION ALL
|
||||
SELECT a*10 + 0.1, f*10 + 0.1 FROM t1 LEFT JOIN t2 ON (c=d)
|
||||
UNION ALL
|
||||
SELECT a*100, b*100 FROM t1
|
||||
) WHERE y+x NOT NULL ORDER BY 1;
|
||||
}
|
||||
} {6 18 30 260.2 600 1800 3000}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# 2011 December 06
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests to verify that ticket [3a77c9714e] has been
|
||||
# fixed.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set testprefix "tkt-3a77c9714e"
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(t1_id INTEGER PRIMARY KEY, t1_title TEXT);
|
||||
CREATE TABLE t2(t2_id INTEGER PRIMARY KEY, t2_title TEXT);
|
||||
CREATE TABLE t3(t3_id INTEGER PRIMARY KEY, t3_title TEXT);
|
||||
|
||||
INSERT INTO t1 (t1_id, t1_title) VALUES (888, 'ABCDEF');
|
||||
INSERT INTO t2 (t2_id, t2_title) VALUES (999, 'ABCDEF');
|
||||
INSERT INTO t3 (t3_id, t3_title) VALUES (999, 'ABCDEF');
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
SELECT t1_title, t2_title
|
||||
FROM t1 LEFT JOIN t2
|
||||
WHERE
|
||||
t2_id = (SELECT t3_id FROM
|
||||
( SELECT t3_id FROM t3 WHERE t3_title=t1_title LIMIT 500 )
|
||||
)
|
||||
} {ABCDEF ABCDEF}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE [Beginnings] (
|
||||
[Id] INTEGER PRIMARY KEY AUTOINCREMENT,[Title] TEXT, [EndingId] INTEGER
|
||||
);
|
||||
CREATE TABLE [Endings] (Id INT,Title TEXT,EndingId INT);
|
||||
INSERT INTO Beginnings (Id, Title, EndingId) VALUES (1, 'FACTOR', 18);
|
||||
INSERT INTO Beginnings (Id, Title, EndingId) VALUES (2, 'SWIMM', 18);
|
||||
INSERT INTO Endings (Id, Title, EndingId) VALUES (1, 'ING', 18);
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT
|
||||
SrcWord, Beginnings.Title
|
||||
FROM
|
||||
(SELECT 'FACTORING' AS SrcWord UNION SELECT 'SWIMMING' AS SrcWord )
|
||||
LEFT JOIN
|
||||
Beginnings
|
||||
WHERE Beginnings.Id= (
|
||||
SELECT BeginningId FROM (
|
||||
SELECT SrcWord, B.Id as BeginningId, B.Title || E.Title As Connected
|
||||
FROM Beginnings B LEFT JOIN Endings E ON B.EndingId=E.EndingId
|
||||
WHERE Connected=SrcWord LIMIT 1
|
||||
)
|
||||
)
|
||||
} {FACTORING FACTOR SWIMMING SWIMM}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
# 2011 December 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests to verify that ticket [7bbfb7d442] has been
|
||||
# fixed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix tkt-7bbfb7d442
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
|
||||
CREATE TABLE t2(c, d);
|
||||
INSERT INTO t2 VALUES('one', 'I');
|
||||
INSERT INTO t2 VALUES('two', 'II');
|
||||
INSERT INTO t2 VALUES('three', 'III');
|
||||
|
||||
CREATE TABLE t3(t3_a PRIMARY KEY, t3_d);
|
||||
CREATE TRIGGER t3t AFTER INSERT ON t3 WHEN new.t3_d IS NULL BEGIN
|
||||
UPDATE t3 SET t3_d = (
|
||||
SELECT d FROM
|
||||
(SELECT * FROM t2 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10),
|
||||
(SELECT * FROM t1 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10)
|
||||
WHERE a = new.t3_a AND b = c
|
||||
) WHERE t3_a = new.t3_a;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t3(t3_a) VALUES(1);
|
||||
INSERT INTO t3(t3_a) VALUES(2);
|
||||
INSERT INTO t3(t3_a) VALUES(3);
|
||||
SELECT * FROM t3;
|
||||
} {1 I 2 II 3 III}
|
||||
|
||||
do_execsql_test 1.3 { DELETE FROM t3 }
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
INSERT INTO t3(t3_a) SELECT 1 UNION SELECT 2 UNION SELECT 3;
|
||||
SELECT * FROM t3;
|
||||
} {1 I 2 II 3 III}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following test case - 2.* - is from the original bug report as
|
||||
# posted to the mailing list.
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE InventoryControl (
|
||||
InventoryControlId INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
ControlDate DATE NOT NULL,
|
||||
ControlState INTEGER NOT NULL DEFAULT -1,
|
||||
DeliveredQty VARCHAR(30)
|
||||
);
|
||||
|
||||
CREATE TRIGGER TGR_InventoryControl_AfterInsert
|
||||
AFTER INSERT ON InventoryControl
|
||||
FOR EACH ROW WHEN NEW.ControlState=-1 BEGIN
|
||||
|
||||
INSERT OR REPLACE INTO InventoryControl(
|
||||
InventoryControlId,SKU,Variant,ControlDate,ControlState,DeliveredQty
|
||||
) SELECT
|
||||
T1.InventoryControlId AS InventoryControlId,
|
||||
T1.SKU AS SKU,
|
||||
T1.Variant AS Variant,
|
||||
T1.ControlDate AS ControlDate,
|
||||
1 AS ControlState,
|
||||
COALESCE(T2.DeliveredQty,0) AS DeliveredQty
|
||||
FROM (
|
||||
SELECT
|
||||
NEW.InventoryControlId AS InventoryControlId,
|
||||
II.SKU AS SKU,
|
||||
II.Variant AS Variant,
|
||||
COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS ControlDate
|
||||
FROM
|
||||
InventoryItem II
|
||||
LEFT JOIN
|
||||
InventoryControl LastClosedIC
|
||||
ON LastClosedIC.InventoryControlId IN ( SELECT 99999 )
|
||||
WHERE
|
||||
II.SKU=NEW.SKU AND
|
||||
II.Variant=NEW.Variant
|
||||
) T1
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
TD.SKU AS SKU,
|
||||
TD.Variant AS Variant,
|
||||
10 AS DeliveredQty
|
||||
FROM
|
||||
TransactionDetail TD
|
||||
WHERE
|
||||
TD.SKU=NEW.SKU AND
|
||||
TD.Variant=NEW.Variant
|
||||
) T2
|
||||
ON T2.SKU=T1.SKU AND
|
||||
T2.Variant=T1.Variant;
|
||||
END;
|
||||
|
||||
CREATE TABLE InventoryItem (
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
DeptCode INTEGER NOT NULL,
|
||||
GroupCode INTEGER NOT NULL,
|
||||
ItemDescription VARCHAR(120) NOT NULL,
|
||||
PRIMARY KEY(SKU, Variant)
|
||||
);
|
||||
|
||||
INSERT INTO InventoryItem VALUES(220,0,1,170,'Scoth Tampon Recurer');
|
||||
INSERT INTO InventoryItem VALUES(31,0,1,110,'Fromage');
|
||||
|
||||
CREATE TABLE TransactionDetail (
|
||||
TransactionId INTEGER NOT NULL,
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(TransactionId, SKU, Variant)
|
||||
);
|
||||
INSERT INTO TransactionDetail(TransactionId, SKU, Variant) VALUES(44, 31, 0);
|
||||
|
||||
|
||||
INSERT INTO InventoryControl(SKU, Variant, ControlDate) SELECT
|
||||
II.SKU AS SKU, II.Variant AS Variant, '2011-08-30' AS ControlDate
|
||||
FROM InventoryItem II;
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT SKU, DeliveredQty FROM InventoryControl WHERE SKU=31
|
||||
} {31 10}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT CASE WHEN DeliveredQty=10 THEN "TEST PASSED!" ELSE "TEST FAILED!" END
|
||||
FROM InventoryControl WHERE SKU=31;
|
||||
} {{TEST PASSED!}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+21
-29
@@ -1176,9 +1176,9 @@ if {$::tcl_platform(platform) == "unix"} {
|
||||
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
|
||||
#
|
||||
foreach {tn sql reslist} {
|
||||
1 { } {10 0 4 0 6 0}
|
||||
2 { PRAGMA checkpoint_fullfsync = 1 } {10 4 4 2 6 2}
|
||||
3 { PRAGMA checkpoint_fullfsync = 0 } {10 0 4 0 6 0}
|
||||
1 { } {8 0 3 0 5 0}
|
||||
2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
|
||||
3 { PRAGMA checkpoint_fullfsync = 0 } {8 0 3 0 5 0}
|
||||
} {
|
||||
faultsim_delete_and_reopen
|
||||
|
||||
@@ -1192,12 +1192,12 @@ foreach {tn sql reslist} {
|
||||
do_execsql_test wal2-14.$tn.2 {
|
||||
PRAGMA wal_autocheckpoint = 10;
|
||||
CREATE TABLE t1(a, b); -- 2 wal syncs
|
||||
INSERT INTO t1 VALUES(1, 2); -- 2 wal sync
|
||||
INSERT INTO t1 VALUES(1, 2); -- 1 wal sync
|
||||
PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
COMMIT; -- 2 wal sync
|
||||
COMMIT; -- 1 wal sync
|
||||
PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync
|
||||
} {10 0 5 5 0 2 2}
|
||||
|
||||
@@ -1233,22 +1233,22 @@ catch { db close }
|
||||
# PRAGMA fullfsync
|
||||
# PRAGMA synchronous
|
||||
#
|
||||
foreach {tn settings restart_sync commit_sync ckpt_sync} {
|
||||
1 {0 0 off} {0 0} {0 0} {0 0}
|
||||
2 {0 0 normal} {1 0} {0 0} {2 0}
|
||||
3 {0 0 full} {2 0} {1 0} {2 0}
|
||||
foreach {tn settings commit_sync ckpt_sync} {
|
||||
1 {0 0 off} {0 0} {0 0}
|
||||
2 {0 0 normal} {0 0} {2 0}
|
||||
3 {0 0 full} {1 0} {2 0}
|
||||
|
||||
4 {0 1 off} {0 0} {0 0} {0 0}
|
||||
5 {0 1 normal} {0 1} {0 0} {0 2}
|
||||
6 {0 1 full} {0 2} {0 1} {0 2}
|
||||
4 {0 1 off} {0 0} {0 0}
|
||||
5 {0 1 normal} {0 0} {0 2}
|
||||
6 {0 1 full} {0 1} {0 2}
|
||||
|
||||
7 {1 0 off} {0 0} {0 0} {0 0}
|
||||
8 {1 0 normal} {1 0} {0 0} {0 2}
|
||||
9 {1 0 full} {2 0} {1 0} {0 2}
|
||||
7 {1 0 off} {0 0} {0 0}
|
||||
8 {1 0 normal} {0 0} {0 2}
|
||||
9 {1 0 full} {1 0} {0 2}
|
||||
|
||||
10 {1 1 off} {0 0} {0 0} {0 0}
|
||||
11 {1 1 normal} {0 1} {0 0} {0 2}
|
||||
12 {1 1 full} {0 2} {0 1} {0 2}
|
||||
10 {1 1 off} {0 0} {0 0}
|
||||
11 {1 1 normal} {0 0} {0 2}
|
||||
12 {1 1 full} {0 1} {0 2}
|
||||
} {
|
||||
forcedelete test.db
|
||||
|
||||
@@ -1262,35 +1262,27 @@ foreach {tn settings restart_sync commit_sync ckpt_sync} {
|
||||
sqlite3 db test.db
|
||||
do_execsql_test 15.$tn.1 "
|
||||
CREATE TABLE t1(x);
|
||||
PRAGMA wal_autocheckpoint = OFF;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA checkpoint_fullfsync = [lindex $settings 0];
|
||||
PRAGMA fullfsync = [lindex $settings 1];
|
||||
PRAGMA synchronous = [lindex $settings 2];
|
||||
" {0 wal}
|
||||
" {wal}
|
||||
|
||||
do_test 15.$tn.2 {
|
||||
set sync(normal) 0
|
||||
set sync(full) 0
|
||||
execsql { INSERT INTO t1 VALUES('abc') }
|
||||
list $::sync(normal) $::sync(full)
|
||||
} $restart_sync
|
||||
|
||||
do_test 15.$tn.3 {
|
||||
set sync(normal) 0
|
||||
set sync(full) 0
|
||||
execsql { INSERT INTO t1 VALUES('abc') }
|
||||
list $::sync(normal) $::sync(full)
|
||||
} $commit_sync
|
||||
|
||||
do_test 15.$tn.4 {
|
||||
do_test 15.$tn.3 {
|
||||
set sync(normal) 0
|
||||
set sync(full) 0
|
||||
execsql { INSERT INTO t1 VALUES('def') }
|
||||
list $::sync(normal) $::sync(full)
|
||||
} $commit_sync
|
||||
|
||||
do_test 15.$tn.5 {
|
||||
do_test 15.$tn.4 {
|
||||
set sync(normal) 0
|
||||
set sync(full) 0
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
|
||||
@@ -217,7 +217,6 @@ foreach {tn syncmode synccount} {
|
||||
|
||||
execsql "PRAGMA synchronous = $syncmode"
|
||||
execsql { PRAGMA journal_mode = WAL }
|
||||
execsql { CREATE TABLE filler(a,b,c); }
|
||||
|
||||
set ::syncs [list]
|
||||
T filter xSync
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# 2011 December 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 test simulates an application crash immediately following a
|
||||
# system call to truncate a file. Specifically, the system call that
|
||||
# truncates the WAL file if "PRAGMA journal_size_limit" is configured.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !wal {finish_test ; return }
|
||||
set testprefix walcrash3
|
||||
|
||||
db close
|
||||
testvfs tvfs
|
||||
tvfs filter {xTruncate xWrite}
|
||||
tvfs script tvfs_callback
|
||||
proc tvfs_callback {args} {}
|
||||
|
||||
sqlite3 db test.db -vfs tvfs
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA wal_autocheckpoint = 128;
|
||||
PRAGMA journal_size_limit = 16384;
|
||||
|
||||
CREATE TABLE t1(a BLOB, b BLOB, UNIQUE(a, b));
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(1000));
|
||||
} {wal 128 16384}
|
||||
|
||||
proc tvfs_callback {method file arglist} {
|
||||
if {$::state==1} {
|
||||
foreach f [glob -nocomplain xx_test.*] { forcedelete $f }
|
||||
foreach f [glob -nocomplain test.*] { forcecopy $f "xx_$f" }
|
||||
set ::state 2
|
||||
}
|
||||
if {$::state==0 && $method=="xTruncate" && [file tail $file]=="test.db-wal"} {
|
||||
set ::state 1
|
||||
}
|
||||
}
|
||||
|
||||
for {set i 2} {$i<1000} {incr i} {
|
||||
|
||||
# If the WAL file is truncated within the following, within the following
|
||||
# xWrite call the [tvfs_callback] makes a copy of the database and WAL
|
||||
# files set sets $::state to 2. So that the copied files are in the same
|
||||
# state as the real database and WAL files would be if an application crash
|
||||
# occurred immediately following the xTruncate().
|
||||
#
|
||||
set ::state 0
|
||||
do_execsql_test 1.$i.1 {
|
||||
INSERT INTO t1 VALUES(randomblob(10), randomblob(1000));
|
||||
}
|
||||
|
||||
# If a copy was made, open it and run the integrity-check.
|
||||
#
|
||||
if {$::state==2} {
|
||||
sqlite3 db2 xx_test.db
|
||||
do_test 1.$i.2 { execsql { PRAGMA integrity_check } db2 } "ok"
|
||||
do_test 1.$i.3 { execsql { SELECT count(*) FROM t1 } db2 } [expr $i-1]
|
||||
db2 close
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-23
@@ -67,28 +67,7 @@ do_test walpersist-1.11 {
|
||||
list [file exists test.db] [file exists test.db-wal] [file exists test.db-shm]
|
||||
} {1 1 1}
|
||||
|
||||
# Make sure the journal_size_limit works to limit the size of the
|
||||
# persisted wal file. In persistent-wal mode, any non-negative
|
||||
# journal_size_limit causes the WAL file to be truncated to zero bytes
|
||||
# when closing.
|
||||
#
|
||||
forcedelete test.db test.db-shm test.db-wal
|
||||
do_test walpersist-2.1 {
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
PRAGMA journal_mode=WAL;
|
||||
PRAGMA wal_autocheckpoint=OFF;
|
||||
PRAGMA journal_size_limit=12000;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(randomblob(50000));
|
||||
UPDATE t1 SET x=randomblob(50000);
|
||||
}
|
||||
expr {[file size test.db-wal]>100000}
|
||||
} {1}
|
||||
do_test walpersist-2.2 {
|
||||
file_control_persist_wal db 1
|
||||
db close
|
||||
concat [file exists test.db-wal] [file size test.db-wal]
|
||||
} {1 0}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user