aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2011-12-09 16:21:19 +0000
committerdrh <drh@noemail.net>2011-12-09 16:21:19 +0000
commitb8475df8093050de2eb79ad1e10067eea13a87a7 (patch)
treebd4c24e05483c98be8c8a9b2d25bdb27b1b035a5 /src
parent1d8cb21fdbd08180e65003df1ea015a8a16e6084 (diff)
downloadsqlite-b8475df8093050de2eb79ad1e10067eea13a87a7.tar.gz
sqlite-b8475df8093050de2eb79ad1e10067eea13a87a7.zip
Make no assumptions about the initial state of VDBE registers.
FossilOrigin-Name: 521d72bdf67b4b1972331307345a18c231a6e1d6
Diffstat (limited to 'src')
-rw-r--r--src/expr.c4
-rw-r--r--src/insert.c1
-rw-r--r--src/select.c4
-rw-r--r--src/update.c11
-rw-r--r--src/vdbe.c48
-rw-r--r--src/vdbeaux.c19
6 files changed, 63 insertions, 24 deletions
diff --git a/src/expr.c b/src/expr.c
index 195e4627d..3c69c564b 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1444,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 );
@@ -1454,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> */
@@ -1521,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);
}
}
}
@@ -1536,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;
diff --git a/src/insert.c b/src/insert.c
index eca3c12dd..65a98a6f7 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -240,6 +240,7 @@ void sqlite3AutoincrementBegin(Parse *pParse){
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, memId+1);
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
diff --git a/src/select.c b/src/select.c
index a89ffe25c..870db3f85 100644
--- a/src/select.c
+++ b/src/select.c
@@ -1947,13 +1947,12 @@ static int generateOutputSubroutine(
*/
if( regPrev ){
int j1, j2;
- j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev);
+ j1 = sqlite3VdbeAddOp1(v, OP_JumpOnce, pParse->nOnce++);
j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iMem, regPrev+1, pIn->nMem,
(char*)pKeyInfo, p4type);
sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2);
sqlite3VdbeJumpHere(v, j1);
sqlite3ExprCodeCopy(pParse, pIn->iMem, regPrev+1, pIn->nMem);
- sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
}
if( pParse->db->mallocFailed ) return 0;
@@ -4154,6 +4153,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/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 53cd4a2ef..7f763cfe6 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;
}
@@ -2025,6 +2039,8 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
**
** 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.
+**
+** See also: JumpOnce
*/
case OP_Once: { /* jump */
assert( pOp->p1<p->nOnceFlag );
@@ -2036,17 +2052,33 @@ case OP_Once: { /* jump */
break;
}
+/* Opcode: JumpOnce P1 P2 * * *
+**
+** Check if OP_Once flag P1 is clear. If so, set the flag and
+** jump to instruction P2. Otherwise fall through.
+**
+** See also: Once
+*/
+case OP_JumpOnce: { /* jump */
+ assert( pOp->p1<p->nOnceFlag );
+ if( !p->aOnceFlag[pOp->p1] ){
+ pc = pOp->p2-1;
+ 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_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
@@ -5069,7 +5101,7 @@ case OP_Program: { /* jump */
pProgram = pOp->p4.pProgram;
pRt = &aMem[pOp->p3];
- assert( memIsValid(pRt) );
+ /*assert( memIsValid(pRt) );*/
assert( pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
@@ -5246,7 +5278,7 @@ case OP_MemMax: { /* in2 */
}else{
pIn1 = &aMem[pOp->p1];
}
- assert( memIsValid(pIn1) );
+ /*assert( memIsValid(pIn1) ); FIXME */
sqlite3VdbeMemIntegerify(pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index b6e13f133..a14447bad 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;
}
@@ -1532,8 +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*sizeof(u8),
- &zCsr, zEnd, &nByte);
+ p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
if( nByte ){
p->pFree = sqlite3DbMallocZero(db, nByte);
}
@@ -1559,10 +1559,11 @@ 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;
}
}
+ if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
p->explain = pParse->explain;
sqlite3VdbeRewind(p);
}
@@ -1649,7 +1650,6 @@ static void closeAllCursors(Vdbe *p){
p->pDelFrame = pDel->pParent;
sqlite3VdbeFrameDelete(pDel);
}
- memset(p->aOnceFlag, 0, p->nOnceFlag);
}
/*
@@ -1666,8 +1666,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);
@@ -2135,6 +2137,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;