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 | 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 | | > > > > | 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 | VdbeOp *pOp ){ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; sqlite3VdbePrintOp(0, pc, pOp); } #endif | < > | | | | > | | < | < < < < | < | < | 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 | || pOp->opcode==OP_Offset #endif ){ int x = pOp->p2; assert( pIdx->pTable==pTab ); #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC if( pOp->opcode==OP_Offset ){ | | > | | | | | | | | | > < < < < < < | < | < < < | < < | 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; |
︙ | ︙ |