mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
Merge the latest trunk changes into tree-explain branch.
FossilOrigin-Name: 1a360da0f8314f232c224c71829646bc7558892b
This commit is contained in:
@@ -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.
|
||||
|
||||
45
manifest
45
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
7b457ea4551ba411a4747d74fb78b795cc8d9ee6
|
||||
1a360da0f8314f232c224c71829646bc7558892b
|
||||
24
src/expr.c
24
src/expr.c
@@ -1375,6 +1375,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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
89
src/mem1.c
89
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;
|
||||
}
|
||||
|
||||
30
src/os.h
30
src/os.h
@@ -65,17 +65,6 @@
|
||||
# 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
|
||||
*/
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
11
src/update.c
11
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 ){
|
||||
|
||||
64
src/vdbe.c
64
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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
41
src/wal.c
41
src/wal.c
@@ -1781,6 +1781,26 @@ static int walCheckpoint(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
@@ -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]));
|
||||
|
||||
@@ -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 */
|
||||
|
||||
154
test/tkt-7bbfb7d442.test
Normal file
154
test/tkt-7bbfb7d442.test
Normal file
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user