diff options
-rw-r--r-- | Makefile.msc | 3 | ||||
-rw-r--r-- | manifest | 45 | ||||
-rw-r--r-- | manifest.uuid | 2 | ||||
-rw-r--r-- | src/expr.c | 24 | ||||
-rw-r--r-- | src/insert.c | 1 | ||||
-rw-r--r-- | src/mem1.c | 89 | ||||
-rw-r--r-- | src/os.h | 30 | ||||
-rw-r--r-- | src/os_win.c | 2 | ||||
-rw-r--r-- | src/select.c | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 2 | ||||
-rw-r--r-- | src/trigger.c | 1 | ||||
-rw-r--r-- | src/update.c | 11 | ||||
-rw-r--r-- | src/vdbe.c | 64 | ||||
-rw-r--r-- | src/vdbe.h | 1 | ||||
-rw-r--r-- | src/vdbeInt.h | 4 | ||||
-rw-r--r-- | src/vdbeaux.c | 20 | ||||
-rw-r--r-- | src/wal.c | 41 | ||||
-rw-r--r-- | src/where.c | 4 | ||||
-rw-r--r-- | test/tkt-7bbfb7d442.test | 154 | ||||
-rw-r--r-- | test/walpersist.test | 22 |
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. @@ -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; } @@ -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; @@ -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 |