aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c2
-rw-r--r--src/global.c3
-rw-r--r--src/main.c9
-rw-r--r--src/sqlite.h.in1
-rw-r--r--src/sqliteInt.h2
-rw-r--r--src/trigger.c1
-rw-r--r--src/vdbe.c42
-rw-r--r--src/vdbe.h1
-rw-r--r--src/vdbeInt.h4
-rw-r--r--src/vdbeaux.c10
10 files changed, 36 insertions, 39 deletions
diff --git a/src/expr.c b/src/expr.c
index abae812ea..14bde45bb 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1974,7 +1974,7 @@ static Select *isCandidateForInOpt(Expr *pX){
*/
int sqlite3CodeOnce(Parse *pParse){
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
- return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
+ return sqlite3VdbeAddOp0(v, OP_Once);
}
#ifndef SQLITE_OMIT_SUBQUERY
diff --git a/src/global.c b/src/global.c
index 76901a89b..8b676ef66 100644
--- a/src/global.c
+++ b/src/global.c
@@ -225,7 +225,8 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
#ifndef SQLITE_OMIT_BUILTIN_TEST
0, /* xTestCallback */
#endif
- 0 /* bLocaltimeFault */
+ 0, /* bLocaltimeFault */
+ 0x7ffffffe /* iOnceResetThreshold */
};
/*
diff --git a/src/main.c b/src/main.c
index c3700cd41..9c161d0ef 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3784,6 +3784,15 @@ int sqlite3_test_control(int op, ...){
break;
}
+ /* Set the threshold at which OP_Once counters reset back to zero.
+ ** By default this is 0xfffffffe (over 2 billion), but that value is
+ ** too big to test in a reasonable amount of time, so this control is
+ ** provided to set a small and easily reachable reset value.
+ */
+ case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
+ sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
+ break;
+ }
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
**
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 52b58370d..778d53d3d 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -6717,6 +6717,7 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
+#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index dbb18a745..ebae7e54a 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2896,7 +2896,6 @@ 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 nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
@@ -3230,6 +3229,7 @@ struct Sqlite3Config {
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
+ int iOnceResetThreshold; /* When to reset OP_Once counters */
};
/*
diff --git a/src/trigger.c b/src/trigger.c
index 5c8056011..7eb14bcf8 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -879,7 +879,6 @@ static TriggerPrg *codeRowTrigger(
}
pProgram->nMem = pSubParse->nMem;
pProgram->nCsr = pSubParse->nTab;
- pProgram->nOnce = pSubParse->nOnce;
pProgram->token = (void *)pTrigger;
pPrg->aColmask[0] = pSubParse->oldmask;
pPrg->aColmask[1] = pSubParse->newmask;
diff --git a/src/vdbe.c b/src/vdbe.c
index 4aa26d006..51092cfed 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2332,22 +2332,18 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
/* Opcode: Once P1 P2 * * *
**
-** Check the "once" flag number P1. If it is set, jump to instruction P2.
-** Otherwise, set the flag and fall through to the next instruction.
-** In other words, this opcode causes all following opcodes up through P2
-** (but not including P2) to run just once and to be skipped on subsequent
-** times through the loop.
-**
-** All "once" flags are initially cleared whenever a prepared statement
-** first begins to run.
+** If the P1 value is equal to the P1 value on the OP_Init opcode at
+** instruction 0, then jump to P2. If the two P1 values differ, then
+** set the P1 value on this opcode to equal the P1 value on the OP_Init
+** and fall through.
*/
case OP_Once: { /* jump */
- assert( pOp->p1<p->nOnceFlag );
- VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
- if( p->aOnceFlag[pOp->p1] ){
+ assert( p->aOp[0].opcode==OP_Init );
+ VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2);
+ if( p->aOp[0].p1==pOp->p1 ){
goto jump_to_p2;
}else{
- p->aOnceFlag[pOp->p1] = 1;
+ pOp->p1 = p->aOp[0].p1;
}
break;
}
@@ -5790,8 +5786,7 @@ case OP_Program: { /* jump */
if( pProgram->nCsr==0 ) nMem++;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
- + pProgram->nCsr * sizeof(VdbeCursor *)
- + pProgram->nOnce * sizeof(u8);
+ + pProgram->nCsr * sizeof(VdbeCursor *);
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
@@ -5811,8 +5806,6 @@ case OP_Program: { /* jump */
pFrame->aOp = p->aOp;
pFrame->nOp = p->nOp;
pFrame->token = pProgram->token;
- pFrame->aOnceFlag = p->aOnceFlag;
- pFrame->nOnceFlag = p->nOnceFlag;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pFrame->anExec = p->anExec;
#endif
@@ -5846,13 +5839,10 @@ case OP_Program: { /* jump */
p->apCsr = (VdbeCursor **)&aMem[p->nMem];
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
- p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
- p->nOnceFlag = pProgram->nOnce;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = 0;
#endif
pOp = &aOp[-1];
- memset(p->aOnceFlag, 0, p->nOnceFlag);
break;
}
@@ -6819,7 +6809,7 @@ case OP_MaxPgcnt: { /* out2 */
#endif
-/* Opcode: Init * P2 * P4 *
+/* Opcode: Init P1 P2 * P4 *
** Synopsis: Start at P2
**
** Programs contain a single instance of this opcode as the very first
@@ -6830,9 +6820,13 @@ case OP_MaxPgcnt: { /* out2 */
** Or if P4 is blank, use the string returned by sqlite3_sql().
**
** If P2 is not zero, jump to instruction P2.
+**
+** Increment the value of P1 so that OP_Once opcodes will jump the
+** first time they are evaluated for this run.
*/
case OP_Init: { /* jump */
char *zTrace;
+ int i;
/* If the P4 argument is not NULL, then it must be an SQL comment string.
** The "--" string is broken up to prevent false-positives with srcck1.c.
@@ -6844,6 +6838,7 @@ case OP_Init: { /* jump */
** sqlite3_expanded_sql(P) otherwise.
*/
assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
+ assert( pOp==p->aOp ); /* Always instruction 0 */
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
@@ -6881,6 +6876,13 @@ case OP_Init: { /* jump */
#endif /* SQLITE_DEBUG */
#endif /* SQLITE_OMIT_TRACE */
assert( pOp->p2>0 );
+ if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
+ for(i=1; i<p->nOp; i++){
+ if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
+ }
+ pOp->p1 = 0;
+ }
+ pOp->p1++;
goto jump_to_p2;
}
diff --git a/src/vdbe.h b/src/vdbe.h
index a7bc84cea..ecb2b0e3f 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -88,7 +88,6 @@ struct SubProgram {
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
- int nOnce; /* Number of OP_Once instructions */
void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
};
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index ecb4fc5f0..b1d7717a0 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -157,7 +157,6 @@ struct VdbeFrame {
Op *aOp; /* Program instructions for parent frame */
i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
- u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
@@ -166,7 +165,6 @@ struct VdbeFrame {
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
int nMem; /* Number of entries in aMem */
- int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
int nChange; /* Statement changes (Vdbe.nChange) */
@@ -410,8 +408,6 @@ 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 */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
i64 *anExec; /* Number of times each op has been executed */
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 56f00efcf..838a8f044 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -1869,7 +1869,6 @@ void sqlite3VdbeMakeReady(
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
int nArg; /* Number of arguments in subprograms */
- int nOnce; /* Number of OP_Once instructions */
int n; /* Loop counter */
struct ReusableSpace x; /* Reusable bulk memory */
@@ -1884,8 +1883,6 @@ void sqlite3VdbeMakeReady(
nMem = pParse->nMem;
nCursor = pParse->nTab;
nArg = pParse->nMaxArg;
- nOnce = pParse->nOnce;
- if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
/* Each cursor uses a memory cell. The first cursor (cursor 0) can
** use aMem[0] which is not otherwise used by the VDBE program. Allocate
@@ -1932,7 +1929,6 @@ void sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
- p->aOnceFlag = allocSpace(&x, p->aOnceFlag, nOnce);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
#endif
@@ -1942,7 +1938,6 @@ void sqlite3VdbeMakeReady(
}while( !db->mallocFailed );
p->nCursor = nCursor;
- p->nOnceFlag = nOnce;
if( p->aVar ){
p->nVar = (ynVar)nVar;
for(n=0; n<nVar; n++){
@@ -2030,8 +2025,6 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
v->anExec = pFrame->anExec;
#endif
- v->aOnceFlag = pFrame->aOnceFlag;
- v->nOnceFlag = pFrame->nOnceFlag;
v->aOp = pFrame->aOp;
v->nOp = pFrame->nOp;
v->aMem = pFrame->aMem;
@@ -2569,11 +2562,8 @@ int sqlite3VdbeHalt(Vdbe *p){
** one, or the complete transaction if there is no statement transaction.
*/
- assert( p->aOnceFlag!=0 || db->mallocFailed );
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM_BKPT;
- }else{
- memset(p->aOnceFlag, 0, p->nOnceFlag);
}
closeAllCursors(p);
if( p->magic!=VDBE_MAGIC_RUN ){