SQLite

Changes On Branch death-cursor
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch death-cursor Excluding Merge-Ins

This is equivalent to a diff from 123b154ce3 to 58ffd5d97e

2024-08-09
13:56
Add SQLITE_TESTCTRL_EDITSTMT for making rogue changes to the statement bytecode, to test the death-cursor error detection mechanism. (Closed-Leaf check-in: 58ffd5d97e user: drh tags: death-cursor)
12:19
Remove unused static var cBadGroup from ext/consio/console_io.c to resolve a compiler warning reported in the fossil forum. This is a build fix, not a functional change. (check-in: fa047c3ea7 user: stephan tags: trunk)
02:10
Change the null-cursor in the previous check-in into a death-cursor. Any access of the cursor causes the prepared statement to return an SQLITE_INTERNAL error. We'll need to add a way to edit the bytecode using sqlite3_test_control() in order to test the death-cursor code path. (check-in: 8894b243ef user: drh tags: death-cursor)
01:38
If there is any question about whether or not the WHERE_IDX_ONLY flag in the query planner is correct, create a backup null-cursor for the table, so that we never try to run an OP_Column against an unopened cursor. (check-in: 7f1617f7bf user: drh tags: death-cursor)
2024-08-08
19:45
Do not allow the WHERE_IDX_ONLY query planner result in cases where a partial index is used on an UPDATE or a DELETE, since the code might still need to access the original table due to parameterized terms in the WHERE clause of the partial index. (Closed-Leaf check-in: 7058d93b09 user: drh tags: partial-index-terms-patch)
16:04
In the vdbe_addoptrace output, show OP_Column opcodes that fail to translate from table to index. This is an aid to testing and analysis only. No changes to production code. (Closed-Leaf check-in: 7f464793fc user: drh tags: extra-debug)
15:42
Ensure sqlite3expert.c unregisters any SQL user-functions it registers with the database handle before returning. (check-in: 2708314448 user: dan tags: branch-3.46)
15:26
Ensure sqlite3expert.c unregisters any SQL user-functions it registers with the database handle before returning. (check-in: 123b154ce3 user: dan tags: trunk)
15:07
Add assert() statements and reorganize code slightly in fts3 and fts5 to make it easier to follow. (check-in: 797b0a13fd user: dan tags: trunk)

Changes to src/expr.c.
5435
5436
5437
5438
5439
5440
5441








5442
5443
5444
5445
5446
5447
5448
        sqlite3VdbeAddOp3(v, OP_Halt, 
             pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
             pExpr->affExpr, r1);
      }
      break;
    }
#endif








  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;
}

/*







>
>
>
>
>
>
>
>







5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
        sqlite3VdbeAddOp3(v, OP_Halt, 
             pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
             pExpr->affExpr, r1);
      }
      break;
    }
#endif

    /* Special opcode used to generate a cursor that raises an
    ** SQLITE_INTERNAL error if it is every accessed.  Used by the
    ** sqlite3OpenDeathCursor() routine. */
    case TK_TABLE: {
      sqlite3VdbeAddOp3(v, OP_OpenPseudo, pExpr->iTable, -99, 1);
      break;
    }
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;
}

/*
Changes to src/main.c.
4689
4690
4691
4692
4693
4694
4695
























4696
4697
4698
4699
4700
4701
4702
        *pOnOff = sqlite3Config.bJsonSelfcheck;
      }else{
        sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
      }
#endif
      break;
    }
























  }
  va_end(ap);
#endif /* SQLITE_UNTESTABLE */
  return rc;
}

/*







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
        *pOnOff = sqlite3Config.bJsonSelfcheck;
      }else{
        sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
      }
#endif
      break;
    }

    /* sqlite3_test_control(SQLITE_TESTCTRL_EDITSTMT, pStmt,iAddr,iField,iVal)
    **
    ** Make changes to the bytecode in prepared statement pStmt.  Modify
    ** instruction iAddr.  iField is 1, 2, or 3 for p1, p2, or p3.  iVal
    ** is the new value.
    **
    ** This operation is used to deliberately corrupt bytecode in order to
    ** exercise the internal self-checks that prevent crashes due to bugs in
    ** the query planner and/or code generator.
    */
    case SQLITE_TESTCTRL_EDITSTMT: {
      sqlite3_stmt *p;   /* The prepared statement */
      int iAddr;         /* Instruction to change */
      int iField;        /* 1, 2, or 3 for P1, P2, or P3 */
      int iVal;          /* New value */

      p = va_arg(ap, sqlite3_stmt*);
      iAddr = va_arg(ap, int);
      iField = va_arg(ap, int);
      iVal = va_arg(ap, int);
      sqlite3VdbeEditStmt(p,iAddr,iField,iVal);
      break;
    }
  }
  va_end(ap);
#endif /* SQLITE_UNTESTABLE */
  return rc;
}

/*
Changes to src/sqlite.h.in.
8326
8327
8328
8329
8330
8331
8332

8333
8334
8335
8336
8337
8338
8339
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14  /* NOT USED */
#define SQLITE_TESTCTRL_JSON_SELFCHECK          14
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */

#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      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







>







8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
#define SQLITE_TESTCTRL_PENDING_BYTE            11
#define SQLITE_TESTCTRL_ASSERT                  12
#define SQLITE_TESTCTRL_ALWAYS                  13
#define SQLITE_TESTCTRL_RESERVE                 14  /* NOT USED */
#define SQLITE_TESTCTRL_JSON_SELFCHECK          14
#define SQLITE_TESTCTRL_OPTIMIZATIONS           15
#define SQLITE_TESTCTRL_ISKEYWORD               16  /* NOT USED */
#define SQLITE_TESTCTRL_EDITSTMT                16
#define SQLITE_TESTCTRL_SCRATCHMALLOC           17  /* NOT USED */
#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS      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
Changes to src/vdbe.c.
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961




2962
2963
2964
2965
2966
2967
2968
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pC = p->apCsr[pOp->p1];
  p2 = (u32)pOp->p2;

op_column_restart:
  assert( pC!=0 );
  assert( p2<(u32)pC->nField
       || (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult==0) );
  aOffset = pC->aOffset;
  assert( aOffset==pC->aType+pC->nField );
  assert( pC->eCurType!=CURTYPE_VTAB );
  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
  assert( pC->eCurType!=CURTYPE_SORTER );

  if( pC->cacheStatus!=p->cacheCtr ){                /*OPTIMIZATION-IF-FALSE*/
    if( pC->nullRow ){
      if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){
        /* For the special case of as pseudo-cursor, the seekResult field
        ** identifies the register that holds the record */
        pReg = &aMem[pC->seekResult];
        assert( pReg->flags & MEM_Blob );
        assert( memIsValid(pReg) );
        pC->payloadSize = pC->szRow = pReg->n;
        pC->aRow = (u8*)pReg->z;




      }else{
        pDest = &aMem[pOp->p3];
        memAboutToChange(p, pDest);
        sqlite3VdbeMemSetNull(pDest);
        goto op_column_out;
      }
    }else{







|
















>
>
>
>







2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
  assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
  pC = p->apCsr[pOp->p1];
  p2 = (u32)pOp->p2;

op_column_restart:
  assert( pC!=0 );
  assert( p2<(u32)pC->nField
       || (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult<=0) );
  aOffset = pC->aOffset;
  assert( aOffset==pC->aType+pC->nField );
  assert( pC->eCurType!=CURTYPE_VTAB );
  assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
  assert( pC->eCurType!=CURTYPE_SORTER );

  if( pC->cacheStatus!=p->cacheCtr ){                /*OPTIMIZATION-IF-FALSE*/
    if( pC->nullRow ){
      if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){
        /* For the special case of as pseudo-cursor, the seekResult field
        ** identifies the register that holds the record */
        pReg = &aMem[pC->seekResult];
        assert( pReg->flags & MEM_Blob );
        assert( memIsValid(pReg) );
        pC->payloadSize = pC->szRow = pReg->n;
        pC->aRow = (u8*)pReg->z;
      }else if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult<0 ){
        rc = SQLITE_INTERNAL;
        sqlite3VdbeError(p, "bad bytecode");
        goto abort_due_to_error;
      }else{
        pDest = &aMem[pOp->p3];
        memAboutToChange(p, pDest);
        sqlite3VdbeMemSetNull(pDest);
        goto op_column_out;
      }
    }else{
Changes to src/vdbe.h.
262
263
264
265
266
267
268

269
270
271
272
273
274
275
#endif
void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
void sqlite3VdbeUsesBtree(Vdbe*, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
VdbeOp *sqlite3VdbeGetLastOp(Vdbe*);

int sqlite3VdbeMakeLabel(Parse*);
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeReusable(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);







>







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#endif
void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
void sqlite3VdbeUsesBtree(Vdbe*, int);
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
VdbeOp *sqlite3VdbeGetLastOp(Vdbe*);
void sqlite3VdbeEditStmt(sqlite3_stmt*,int,int,int);
int sqlite3VdbeMakeLabel(Parse*);
void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeReusable(Vdbe*);
void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
Changes to src/vdbeaux.c.
1701
1702
1703
1704
1705
1706
1707














1708
1709
1710
1711
1712
1713
1714
}

/* Return the most recently added opcode
*/
VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){
  return sqlite3VdbeGetOp(p, p->nOp - 1);
}















#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
** determined by character c.
*/
static int translateP(char c, const Op *pOp){







>
>
>
>
>
>
>
>
>
>
>
>
>
>







1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
}

/* Return the most recently added opcode
*/
VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){
  return sqlite3VdbeGetOp(p, p->nOp - 1);
}

/* Edit the bytecode of a runable prepared statement.  Used to implement
** SQLITE_TESTCTRL_EDITSTMT.
*/
void sqlite3VdbeEditStmt(sqlite3_stmt *p, int iAddr, int iField, int iVal){
  VdbeOp *pOp = &((Vdbe*)p)->aOp[iAddr];
  if( iField==1 ){
    pOp->p1 = iVal;
  }else if( iField==2 ){
    pOp->p2 = iVal;
  }else{
    pOp->p3 = iVal;
  }
}

#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
** determined by character c.
*/
static int translateP(char c, const Op *pOp){
Changes to src/where.c.
7074
7075
7076
7077
7078
7079
7080
7081
7082

7083
7084
7085
7086
7087

7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
    VdbeOp *pOp
  ){
    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
    sqlite3VdbePrintOp(0, pc, pOp);
  }
#endif

#ifdef SQLITE_DEBUG
/*

** Return true if cursor iCur is opened by instruction k of the
** bytecode.  Used inside of assert() only.
*/
static int cursorIsOpen(Vdbe *v, int iCur, int k){
  while( k>=0 ){

    VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
    if( pOp->p1!=iCur ) continue;
    if( pOp->opcode==OP_Close ) return 0;
    if( pOp->opcode==OP_OpenRead ) return 1;
    if( pOp->opcode==OP_OpenWrite ) return 1;
    if( pOp->opcode==OP_OpenDup ) return 1;
    if( pOp->opcode==OP_OpenAutoindex ) return 1;
    if( pOp->opcode==OP_OpenEphemeral ) return 1;
  }
  return 0;
}
#endif /* SQLITE_DEBUG */

/*
** Generate the end of the WHERE loop.  See comments on
** sqlite3WhereBegin() for additional information.
*/
void sqlite3WhereEnd(WhereInfo *pWInfo){
  Parse *pParse = pWInfo->pParse;







<

>
|
|

|
|
>
|
|
<
|
<
<
<
<
|
<
|
<







7074
7075
7076
7077
7078
7079
7080

7081
7082
7083
7084
7085
7086
7087
7088
7089
7090

7091




7092

7093

7094
7095
7096
7097
7098
7099
7100
    VdbeOp *pOp
  ){
    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
    sqlite3VdbePrintOp(0, pc, pOp);
  }
#endif


/*
** Make arrangements to open cursor number iCur in the startup code of
** the prepared statement.  If this cursor is every accessed via OP_Cursor,
** it will cause an SQLITE_INTERNAL error to be raised.
*/
static SQLITE_NOINLINE void sqlite3OpenDeathCursor(Parse *pParse, int iCur){
  Expr e;
  memset(&e, 0, sizeof(e));
  e.op = TK_TABLE;
  e.iTable = iCur;

  sqlite3ExprCodeRunJustOnce(pParse, &e, -1);




}




/*
** Generate the end of the WHERE loop.  See comments on
** sqlite3WhereBegin() for additional information.
*/
void sqlite3WhereEnd(WhereInfo *pWInfo){
  Parse *pParse = pWInfo->pParse;
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381

7382
7383
7384
7385
7386
7387
7388
7389
7390

7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
         || pOp->opcode==OP_Offset
#endif
        ){
          int x = pOp->p2;
          assert( pIdx->pTable==pTab );
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
          if( pOp->opcode==OP_Offset ){
            /* Do not need to translate the column number */
          }else
#endif

          if( !HasRowid(pTab) ){
            Index *pPk = sqlite3PrimaryKeyIndex(pTab);
            x = pPk->aiColumn[x];
            assert( x>=0 );
          }else{
            testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
            x = sqlite3StorageColumnToTable(pTab,x);
          }
          x = sqlite3TableColumnToIndex(pIdx, x);

          if( x>=0 ){
            pOp->p2 = x;
            pOp->p1 = pLevel->iIdxCur;
            OpcodeRewriteTrace(db, k, pOp);
          }else{
            /* Unable to translate the table reference into an index
            ** reference.  Verify that this is harmless - that the
            ** table being referenced really is open.
            */
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
            assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
                 || cursorIsOpen(v,pOp->p1,k)
                 || pOp->opcode==OP_Offset
            );
#else
            assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
                 || cursorIsOpen(v,pOp->p1,k)
            );
#endif
          }
        }else if( pOp->opcode==OP_Rowid ){
          pOp->p1 = pLevel->iIdxCur;
          pOp->opcode = OP_IdxRowid;
          OpcodeRewriteTrace(db, k, pOp);
        }else if( pOp->opcode==OP_IfNullRow ){
          pOp->p1 = pLevel->iIdxCur;







|


>
|
|
|
|
|
|
|
|
|
>




<
<
<
<
<
<
|
<
|
<
<
<
|
<
<







7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390






7391

7392



7393


7394
7395
7396
7397
7398
7399
7400
         || pOp->opcode==OP_Offset
#endif
        ){
          int x = pOp->p2;
          assert( pIdx->pTable==pTab );
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
          if( pOp->opcode==OP_Offset ){
            x = 0;
          }else
#endif
          {
            if( !HasRowid(pTab) ){
              Index *pPk = sqlite3PrimaryKeyIndex(pTab);
              x = pPk->aiColumn[x];
              assert( x>=0 );
            }else{
              testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
              x = sqlite3StorageColumnToTable(pTab,x);
            }
            x = sqlite3TableColumnToIndex(pIdx, x);
          }
          if( x>=0 ){
            pOp->p2 = x;
            pOp->p1 = pLevel->iIdxCur;
            OpcodeRewriteTrace(db, k, pOp);






          }else if( pLoop->wsFlags & WHERE_IDX_ONLY ){

            OpcodeRewriteTrace(db, k, pOp);



            sqlite3OpenDeathCursor(pParse, pLevel->iTabCur);


          }
        }else if( pOp->opcode==OP_Rowid ){
          pOp->p1 = pLevel->iIdxCur;
          pOp->opcode = OP_IdxRowid;
          OpcodeRewriteTrace(db, k, pOp);
        }else if( pOp->opcode==OP_IfNullRow ){
          pOp->p1 = pLevel->iIdxCur;