aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.msc3
-rw-r--r--manifest45
-rw-r--r--manifest.uuid2
-rw-r--r--src/expr.c24
-rw-r--r--src/insert.c1
-rw-r--r--src/mem1.c89
-rw-r--r--src/os.h30
-rw-r--r--src/os_win.c2
-rw-r--r--src/select.c6
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/trigger.c1
-rw-r--r--src/update.c11
-rw-r--r--src/vdbe.c64
-rw-r--r--src/vdbe.h1
-rw-r--r--src/vdbeInt.h4
-rw-r--r--src/vdbeaux.c20
-rw-r--r--src/wal.c41
-rw-r--r--src/where.c4
-rw-r--r--test/tkt-7bbfb7d442.test154
-rw-r--r--test/walpersist.test22
20 files changed, 411 insertions, 115 deletions
diff --git a/Makefile.msc b/Makefile.msc
index ea7efa758..f40936d91 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -49,9 +49,6 @@ 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.
diff --git a/manifest b/manifest
index 3aac83707..2040e5612 100644
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Additional\sdetail\sadded\sto\sthe\stree-explain\soutput\sfor\sSELECT\sstatements.
-D 2011-12-07T22:49:42.588
+C Merge\sthe\slatest\strunk\schanges\sinto\stree-explain\sbranch.
+D 2011-12-10T14:44:31.699
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
-F Makefile.msc 3bd3641a345d488a9601c0cc7f9d35aeede5d12b
+F Makefile.msc dcad80fa69f17d46fe6778ba873fc108ca16298d
F Makefile.vxworks 1deb39c8bb047296c30161ffa10c1b5423e632f9
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION af03cd6400f9d71d38bdb7a9d66a1aefdc2f3e0d
@@ -134,7 +134,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 51d32f0a9c880663e54ce309f52e40c325d5e112
-F src/expr.c 59a530af612b95d4d29c066bf81f12def813d16d
+F src/expr.c d3a969a22368077b0efcb6028faa1c48ba7d2598
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
@@ -142,7 +142,7 @@ F src/global.c 107ccaacb4b30895cf3a3a39decf417c804acfa1
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
-F src/insert.c 8f283d6734dd837ed7531b26d7622fda70874390
+F src/insert.c ea820fe9af748075b3b6827fb6f23f25079bf1f7
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
@@ -150,7 +150,7 @@ F src/loadext.c d0d2022a5a07274d408820b978b9e549189d314f
F src/main.c 0e0b9dd5b054ed1aa3861b257035910aff9e1842
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
-F src/mem1.c 7456e2ca0524609ebc06a9befeda5289d4575ad4
+F src/mem1.c 7998e7003a3047e323c849a26dda004debc04d03
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
@@ -163,11 +163,11 @@ F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c 28bbdab2170dfce84d86c45456a18eab1d0f99a9
-F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
+F src/os.h 549b1a2e5e0ed1e1499f252dac126c4973e7379c
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c 4fbb91726165e105c1679a2660f49a3f4c376e4f
-F src/os_win.c 6efe66a38215c38eaa7603ee5f76848159f8669d
+F src/os_win.c 8af100f78f157eb6185fd9153d7f35b829c4da04
F src/pager.c d981f3bfcc0e4460537d983899620700ccf8f539
F src/pager.h 5cd760857707529b403837d813d86b68938d6183
F src/parse.y fabb2e7047417d840e6fdb3ef0988a86849a08ba
@@ -180,11 +180,11 @@ F src/printf.c 7ffb4ebb8b341f67e049695ba031da717b3d2699
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 912bea602425df403c464c7da9a89a56281623a3
+F src/select.c 97275df6f40f1df1c389e275c2185a4edf202ad2
F src/shell.c a1eadb2fdbfa45e54307263f0c8da8ee8cd61b8b
F src/sqlite.h.in 1dc07194eb1a2c69c8ef75f88022b170be08024a
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
-F src/sqliteInt.h 96041958f4508dbc588c82298f75559ac683fe75
+F src/sqliteInt.h d781d89415ada4815794fc2587601cd44272f94d
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -234,25 +234,25 @@ F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
-F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
-F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d
+F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684
+F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
F src/util.c 01238e2b0f24a14779181dbf991fe02620a80e31
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
-F src/vdbe.c a7ab9993ec5a4d9479dc99671faec061fbf9b889
-F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
-F src/vdbeInt.h a2b8f17783c85995f64432d6cbd546a9183a56f3
+F src/vdbe.c 029add0c5197a61db588824a58570547330b9d8f
+F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
+F src/vdbeInt.h 72222af1a52bcdfa94e1165e083734484fc0863f
F src/vdbeapi.c 86189ebba2c49791d75eaa12929f3ce6527596bd
-F src/vdbeaux.c ed7205125304fd8aab32ab0ea975f2c1088cace5
+F src/vdbeaux.c 1b99a1f6c56aecfebc172ff6985ba9818f6c8caa
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c 7e5946109138ff6f7f94e79fc702755bf79373a8
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
-F src/wal.c 5fe1ba55b8fab9d3936bc9093af61ab9f1c580a1
+F src/wal.c 7e6e7fe68ee649505dca38c8ab83eda0d0d96ae5
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c f73752ca85c0ed221753fda98aeaf6b9d4616e0e
+F src/where.c af623942514571895818b9b7ae11db95ae3b3d88
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
@@ -737,6 +737,7 @@ 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
@@ -912,7 +913,7 @@ F test/walfault.test efb0d5724893133e71b8d9d90abdb781845a6bb0
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
-F test/walpersist.test fd40d33765b2693f721c90c66d97f99757559006
+F test/walpersist.test 710b1b6cf6f8333e984f437724d1fa9e0511c5aa
F test/walro.test e6bb27762c9f22601cbb8bff6e0acfd124e74b63
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
@@ -977,7 +978,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 0eb3f8b1e3a196811fb54a5e2645debe6119610a
-R c8f99de136cf931e1dc991f6945ded2c
+P 7b457ea4551ba411a4747d74fb78b795cc8d9ee6 256e27bd118ed3ab6ecb19ad6a6494b71ac9bdd5
+R aa2b80b8c93dd58f9be82d377cb63c4d
U drh
-Z 90b0a98552fa9f4d4fff3f8a611f18ca
+Z 940f9f8f15ab9108dec876188e59d100
diff --git a/manifest.uuid b/manifest.uuid
index 3c8a88f6d..253949ba5 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-7b457ea4551ba411a4747d74fb78b795cc8d9ee6 \ No newline at end of file
+1a360da0f8314f232c224c71829646bc7558892b \ No newline at end of file
diff --git a/src/expr.c b/src/expr.c
index 6af583ce0..8e51bee2f 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1376,6 +1376,15 @@ 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
** either to test for membership of the (...) set or to iterate through
@@ -1435,6 +1444,7 @@ 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 );
@@ -1445,7 +1455,6 @@ 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> */
@@ -1470,10 +1479,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
*/
assert(v);
if( iCol<0 ){
- int iMem = ++pParse->nMem;
int iAddr;
- iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
+ iAddr = sqlite3CodeOnce(pParse);
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
@@ -1499,12 +1507,11 @@ 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 = sqlite3VdbeAddOp1(v, OP_Once, iMem);
+ iAddr = sqlite3CodeOnce(pParse);
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
pKey,P4_KEYINFO_HANDOFF);
@@ -1514,6 +1521,7 @@ 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);
}
}
}
@@ -1529,6 +1537,7 @@ 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;
@@ -1601,9 +1610,8 @@ 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) && !pParse->pTriggerTab ){
- int mem = ++pParse->nMem;
- testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
+ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
+ testAddr = sqlite3CodeOnce(pParse);
}
#ifndef SQLITE_OMIT_EXPLAIN
diff --git a/src/insert.c b/src/insert.c
index eca3c12dd..dadb10acd 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -239,6 +239,7 @@ 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);
diff --git a/src/mem1.c b/src/mem1.c
index e0d1dd6e8..bf84ce090 100644
--- a/src/mem1.c
+++ b/src/mem1.c
@@ -26,10 +26,47 @@
*/
#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().
@@ -39,8 +76,8 @@
** routines.
*/
static void *sqlite3MemMalloc(int nByte){
-#ifdef HAVE_MALLOC_USABLE_SIZE
- void *p = malloc( nByte );
+#ifdef SQLITE_MALLOCSIZE
+ void *p = SQLITE_MALLOC( nByte );
if( p==0 ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
@@ -50,7 +87,7 @@ static void *sqlite3MemMalloc(int nByte){
sqlite3_int64 *p;
assert( nByte>0 );
nByte = ROUND8(nByte);
- p = malloc( nByte+8 );
+ p = SQLITE_MALLOC( nByte+8 );
if( p ){
p[0] = nByte;
p++;
@@ -71,13 +108,13 @@ static void *sqlite3MemMalloc(int nByte){
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
-#if HAVE_MALLOC_USABLE_SIZE
- free(pPrior);
+#ifdef SQLITE_MALLOCSIZE
+ SQLITE_FREE(pPrior);
#else
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 );
p--;
- free(p);
+ SQLITE_FREE(p);
#endif
}
@@ -86,8 +123,8 @@ static void sqlite3MemFree(void *pPrior){
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
-#if HAVE_MALLOC_USABLE_SIZE
- return pPrior ? (int)malloc_usable_size(pPrior) : 0;
+#ifdef SQLITE_MALLOCSIZE
+ return pPrior ? (int)SQLITE_MALLOCSIZE(pPrior) : 0;
#else
sqlite3_int64 *p;
if( pPrior==0 ) return 0;
@@ -108,13 +145,13 @@ static int sqlite3MemSize(void *pPrior){
** routines and redirected to xFree.
*/
static void *sqlite3MemRealloc(void *pPrior, int nByte){
-#if HAVE_MALLOC_USABLE_SIZE
- void *p = realloc(pPrior, nByte);
+#ifdef SQLITE_MALLOCSIZE
+ void *p = SQLITE_REALLOC(pPrior, nByte);
if( p==0 ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM,
"failed memory resize %u to %u bytes",
- malloc_usable_size(pPrior), nByte);
+ SQLITE_MALLOCSIZE(pPrior), nByte);
}
return p;
#else
@@ -122,7 +159,7 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
assert( pPrior!=0 && nByte>0 );
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
p--;
- p = realloc(p, nByte+8 );
+ p = SQLITE_REALLOC(p, nByte+8 );
if( p ){
p[0] = nByte;
p++;
@@ -147,6 +184,34 @@ 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;
}
diff --git a/src/os.h b/src/os.h
index 7f17c203e..80afc516f 100644
--- a/src/os.h
+++ b/src/os.h
@@ -66,17 +66,6 @@
#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
*/
#if SQLITE_OS_WIN
@@ -100,6 +89,25 @@
# define SQLITE_TEMPNAME_SIZE 200
#endif
+/*
+** Determine if we are dealing with Windows NT.
+*/
+#if defined(_WIN32_WINNT)
+# define SQLITE_OS_WINNT 1
+#else
+# define SQLITE_OS_WINNT 0
+#endif
+
+/*
+** Determine if we are dealing with WindowsCE - which has a much
+** reduced API.
+*/
+#if defined(_WIN32_WCE)
+# define SQLITE_OS_WINCE 1
+#else
+# define SQLITE_OS_WINCE 0
+#endif
+
/* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op
*/
diff --git a/src/os_win.c b/src/os_win.c
index 7e89a8cc0..ae110c541 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -181,7 +181,7 @@ static int sqlite3_os_type = 0;
# define SQLITE_WIN32_HAS_ANSI
#endif
-#if SQLITE_OS_WINCE || defined(_WIN32_WINNT)
+#if SQLITE_OS_WINCE || SQLITE_OS_WINNT
# define SQLITE_WIN32_HAS_WIDE
#endif
diff --git a/src/select.c b/src/select.c
index f761a0897..15b34e2b4 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3845,12 +3845,11 @@ 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 && pParse->pTriggerTab==0 ){
+ if( pItem->isCorrelated==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. */
- int regOnce = ++pParse->nMem;
- onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
+ onceAddr = sqlite3CodeOnce(pParse);
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
@@ -4155,6 +4154,7 @@ 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
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 1e7af8e34..7c57558ef 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2204,6 +2204,7 @@ 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 */
@@ -2715,6 +2716,7 @@ 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);
diff --git a/src/trigger.c b/src/trigger.c
index 22c4877b6..3c4bf62a1 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -904,6 +904,7 @@ 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;
diff --git a/src/update.c b/src/update.c
index 1e3052218..73d22690b 100644
--- a/src/update.c
+++ b/src/update.c
@@ -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;
- int regOld = 0;
+ int regNew; /* Content of the NEW.* table in triggers */
+ int regOld = 0; /* Content of OLD.* table in triggers */
int regRowSet = 0; /* Rowset of rows to be updated */
memset(&sContext, 0, sizeof(sContext));
@@ -276,6 +276,7 @@ void sqlite3Update(
#endif
/* Allocate required registers. */
+ regRowSet = ++pParse->nMem;
regOldRowid = regNewRowid = ++pParse->nMem;
if( pTrigger || hasFK ){
regOld = pParse->nMem + 1;
@@ -310,7 +311,7 @@ void sqlite3Update(
/* Begin the database scan
*/
- sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
pWInfo = sqlite3WhereBegin(
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
);
@@ -321,7 +322,6 @@ void sqlite3Update(
*/
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
if( !okOnePass ){
- regRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
}
@@ -425,9 +425,10 @@ 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 ){
diff --git a/src/vdbe.c b/src/vdbe.c
index e7fa05037..64ae54e3d 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -764,7 +764,8 @@ case OP_Goto: { /* jump */
** Write the current address onto register P1
** and then jump to address P2.
*/
-case OP_Gosub: { /* jump, in1 */
+case OP_Gosub: { /* jump */
+ assert( pOp->p1>0 && pOp->p1<=p->nMem );
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
memAboutToChange(p, pIn1);
@@ -961,12 +962,25 @@ case OP_String: { /* out2-prerelease */
break;
}
-/* Opcode: Null * P2 * * *
+/* Opcode: Null * P2 P3 * *
**
-** Write a NULL into register 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
*/
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;
}
@@ -2023,27 +2037,33 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
/* Opcode: Once P1 P2 * * *
**
-** 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.
+** 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.
**
-** 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".
+** See also: JumpOnce
*/
+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 true.
+** in P1 is NULL then take the jump if P3 is non-zero.
*/
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
-** 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.
+** 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.
*/
-case OP_Once: /* jump, in1 */
case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
int c;
@@ -2060,12 +2080,6 @@ 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;
}
@@ -5071,7 +5085,6 @@ 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
@@ -5110,7 +5123,8 @@ case OP_Program: { /* jump */
nMem = pProgram->nMem + pProgram->nCsr;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
- + pProgram->nCsr * sizeof(VdbeCursor *);
+ + pProgram->nCsr * sizeof(VdbeCursor *)
+ + pProgram->nOnce * sizeof(u8);
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
@@ -5130,10 +5144,12 @@ 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_Null;
+ pMem->flags = MEM_Invalid;
pMem->db = db;
}
}else{
@@ -5155,7 +5171,11 @@ 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;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index 948c73bca..90a43ce6e 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -82,6 +82,7 @@ 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 */
};
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 44071e685..fb49898a1 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -120,6 +120,8 @@ 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 */
@@ -343,6 +345,8 @@ struct Vdbe {
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 */
};
/*
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 510248a5f..1c67902f1 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -913,13 +913,14 @@ 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)";
@@ -1094,7 +1095,7 @@ static void releaseMemArray(Mem *p, int N){
p->zMalloc = 0;
}
- p->flags = MEM_Null;
+ p->flags = MEM_Invalid;
}
db->mallocFailed = malloc_failed;
}
@@ -1469,6 +1470,7 @@ 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 */
@@ -1484,6 +1486,7 @@ 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
@@ -1530,6 +1533,7 @@ 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);
}
@@ -1538,6 +1542,7 @@ 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++){
@@ -1554,7 +1559,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_Null;
+ p->aMem[n].flags = MEM_Invalid;
p->aMem[n].db = db;
}
}
@@ -1596,6 +1601,8 @@ 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;
@@ -1658,8 +1665,10 @@ 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;
- 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 );
+ 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 );
+ }
#endif
sqlite3DbFree(db, p->zErrMsg);
@@ -2127,6 +2136,7 @@ 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;
diff --git a/src/wal.c b/src/wal.c
index 2c905a29e..209c90975 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -1782,6 +1782,26 @@ static int walCheckpoint(
}
/*
+** Attempt to limit the WAL size to the size limit defined by
+** PRAGMA journal_size_limit.
+*/
+static void walLimitSize(Wal *pWal){
+ 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);
+ }
+ }
+}
+
+/*
** Close a connection to a log file.
*/
int sqlite3WalClose(
@@ -1814,6 +1834,8 @@ int sqlite3WalClose(
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersistWal);
if( rc==SQLITE_OK && bPersistWal!=1 ){
isDelete = 1;
+ }else{
+ walLimitSize(pWal);
}
}
@@ -2518,6 +2540,7 @@ 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
@@ -2555,23 +2578,7 @@ 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);
- }
- }
-
+ walLimitSize(pWal);
pWal->nCkpt++;
pWal->hdr.mxFrame = 0;
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
diff --git a/src/where.c b/src/where.c
index a604d788c..78efbf979 100644
--- a/src/where.c
+++ b/src/where.c
@@ -2005,7 +2005,6 @@ 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 */
@@ -2022,8 +2021,7 @@ static void constructAutomaticIndex(
** transient index on 2nd and subsequent iterations of the loop. */
v = pParse->pVdbe;
assert( v!=0 );
- regIsInit = ++pParse->nMem;
- addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
+ addrInit = sqlite3CodeOnce(pParse);
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
diff --git a/test/tkt-7bbfb7d442.test b/test/tkt-7bbfb7d442.test
new file mode 100644
index 000000000..e560a0d4d
--- /dev/null
+++ b/test/tkt-7bbfb7d442.test
@@ -0,0 +1,154 @@
+# 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
+
+
diff --git a/test/walpersist.test b/test/walpersist.test
index 175dcbf89..bf65bd1e1 100644
--- a/test/walpersist.test
+++ b/test/walpersist.test
@@ -67,7 +67,25 @@ 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.
+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
+ file size test.db-wal
+} {12000}
finish_test