Merge various enhancements that were being held on a branch until after the
3.46.0 release. (1) Allow arbitrary expressions in the second argument to the RAISE() function. (2) Performance optimization to the OP_OpenRead and OP_OpenWrite bytecode operators. (3) Allow FTS5 tables to be dropped even if the associated tokenizer is not available. (4) Performance optimizations in FTS5. (5) Generate better bytecode to improve performance of ONEROW scans. FossilOrigin-Name: 1e5385ffc30743412ade1536583504eec36790cac5355042aa1e12d8d2271d1f
This commit is contained in:
+4
-5
@@ -5306,15 +5306,14 @@ expr_code_doover:
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
if( pExpr->affExpr==OE_Ignore ){
|
||||
sqlite3VdbeAddOp4(
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, OE_Ignore);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse,
|
||||
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
||||
sqlite3VdbeAddOp3(v, OP_Halt,
|
||||
pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
|
||||
pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
||||
pExpr->affExpr, r1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -1328,7 +1328,8 @@ static Trigger *fkActionTrigger(
|
||||
SrcList *pSrc;
|
||||
Expr *pRaise;
|
||||
|
||||
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
||||
pRaise = sqlite3Expr(db, TK_STRING, "FOREIGN KEY constraint failed"),
|
||||
pRaise = sqlite3PExpr(pParse, TK_RAISE, pRaise, 0);
|
||||
if( pRaise ){
|
||||
pRaise->affExpr = OE_Abort;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1658,8 +1658,8 @@ expr(A) ::= RAISE LP IGNORE RP. {
|
||||
A->affExpr = OE_Ignore;
|
||||
}
|
||||
}
|
||||
expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. {
|
||||
A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
|
||||
expr(A) ::= RAISE LP raisetype(T) COMMA expr(Z) RP. {
|
||||
A = sqlite3PExpr(pParse, TK_RAISE, Z, 0);
|
||||
if( A ) {
|
||||
A->affExpr = (char)T;
|
||||
}
|
||||
|
||||
+2
-1
@@ -820,7 +820,8 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
case OE_Ignore: zType = "ignore"; break;
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
|
||||
sqlite3TreeViewLine(pView, "RAISE %s", zType);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
+34
-22
@@ -1214,7 +1214,7 @@ case OP_HaltIfNull: { /* in3 */
|
||||
/* no break */ deliberate_fall_through
|
||||
}
|
||||
|
||||
/* Opcode: Halt P1 P2 * P4 P5
|
||||
/* Opcode: Halt P1 P2 P3 P4 P5
|
||||
**
|
||||
** Exit immediately. All open cursors, etc are closed
|
||||
** automatically.
|
||||
@@ -1227,18 +1227,22 @@ case OP_HaltIfNull: { /* in3 */
|
||||
** then back out all changes that have occurred during this execution of the
|
||||
** VDBE, but do not rollback the transaction.
|
||||
**
|
||||
** If P4 is not null then it is an error message string.
|
||||
** If P3 is not zero and P4 is NULL, then P3 is a register that holds the
|
||||
** text of an error message.
|
||||
**
|
||||
** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
|
||||
** If P3 is zero and P4 is not null then the error message string is held
|
||||
** in P4.
|
||||
**
|
||||
** P5 is a value between 1 and 4, inclusive, then the P4 error message
|
||||
** string is modified as follows:
|
||||
**
|
||||
** 0: (no change)
|
||||
** 1: NOT NULL constraint failed: P4
|
||||
** 2: UNIQUE constraint failed: P4
|
||||
** 3: CHECK constraint failed: P4
|
||||
** 4: FOREIGN KEY constraint failed: P4
|
||||
**
|
||||
** If P5 is not zero and P4 is NULL, then everything after the ":" is
|
||||
** omitted.
|
||||
** If P3 is zero and P5 is not zero and P4 is NULL, then everything after
|
||||
** the ":" is omitted.
|
||||
**
|
||||
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
|
||||
** every program. So a jump past the last instruction of the program
|
||||
@@ -1251,6 +1255,9 @@ case OP_Halt: {
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
|
||||
#endif
|
||||
assert( pOp->p4type==P4_NOTUSED
|
||||
|| pOp->p4type==P4_STATIC
|
||||
|| pOp->p4type==P4_DYNAMIC );
|
||||
|
||||
/* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
|
||||
** something is wrong with the code generator. Raise an assertion in order
|
||||
@@ -1281,7 +1288,12 @@ case OP_Halt: {
|
||||
p->errorAction = (u8)pOp->p2;
|
||||
assert( pOp->p5<=4 );
|
||||
if( p->rc ){
|
||||
if( pOp->p5 ){
|
||||
if( pOp->p3>0 && pOp->p4type==P4_NOTUSED ){
|
||||
const char *zErr;
|
||||
assert( pOp->p3<=(p->nMem + 1 - p->nCursor) );
|
||||
zErr = sqlite3ValueText(&aMem[pOp->p3], SQLITE_UTF8);
|
||||
sqlite3VdbeError(p, "%s", zErr);
|
||||
}else if( pOp->p5 ){
|
||||
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
|
||||
"FOREIGN KEY" };
|
||||
testcase( pOp->p5==1 );
|
||||
@@ -4324,23 +4336,23 @@ case OP_OpenWrite:
|
||||
if( pDb->pSchema->file_format < p->minWriteFileFormat ){
|
||||
p->minWriteFileFormat = pDb->pSchema->file_format;
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_P2ISREG ){
|
||||
assert( p2>0 );
|
||||
assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
assert( (pIn2->flags & MEM_Int)!=0 );
|
||||
sqlite3VdbeMemIntegerify(pIn2);
|
||||
p2 = (int)pIn2->u.i;
|
||||
/* The p2 value always comes from a prior OP_CreateBtree opcode and
|
||||
** that opcode will always set the p2 value to 2 or more or else fail.
|
||||
** If there were a failure, the prepared statement would have halted
|
||||
** before reaching this instruction. */
|
||||
assert( p2>=2 );
|
||||
}
|
||||
}else{
|
||||
wrFlag = 0;
|
||||
}
|
||||
if( pOp->p5 & OPFLAG_P2ISREG ){
|
||||
assert( p2>0 );
|
||||
assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
|
||||
assert( pOp->opcode==OP_OpenWrite );
|
||||
pIn2 = &aMem[p2];
|
||||
assert( memIsValid(pIn2) );
|
||||
assert( (pIn2->flags & MEM_Int)!=0 );
|
||||
sqlite3VdbeMemIntegerify(pIn2);
|
||||
p2 = (int)pIn2->u.i;
|
||||
/* The p2 value always comes from a prior OP_CreateBtree opcode and
|
||||
** that opcode will always set the p2 value to 2 or more or else fail.
|
||||
** If there were a failure, the prepared statement would have halted
|
||||
** before reaching this instruction. */
|
||||
assert( p2>=2 );
|
||||
assert( (pOp->p5 & OPFLAG_P2ISREG)==0 );
|
||||
}
|
||||
if( pOp->p4type==P4_KEYINFO ){
|
||||
pKeyInfo = pOp->p4.pKeyInfo;
|
||||
|
||||
+1
-1
@@ -3170,7 +3170,7 @@ static int whereLoopAddBtreeIndex(
|
||||
|| (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
|
||||
){
|
||||
if( iCol==XN_ROWID || pProbe->uniqNotNull
|
||||
|| (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
|
||||
|| (pProbe->nKeyCol==1 && pProbe->onError && (eOp & WO_EQ))
|
||||
){
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
}else{
|
||||
|
||||
Reference in New Issue
Block a user