mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 06:21:07 +00:00
Snapshot of upstream SQLite 3.30.1
This commit is contained in:
+248
-138
@@ -44,7 +44,6 @@ char sqlite3TableColumnAffinity(Table *pTab, int iCol){
|
||||
*/
|
||||
char sqlite3ExprAffinity(Expr *pExpr){
|
||||
int op;
|
||||
if( pExpr->flags & EP_Generic ) return 0;
|
||||
while( ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
pExpr = pExpr->pLeft;
|
||||
@@ -71,7 +70,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
||||
);
|
||||
}
|
||||
return pExpr->affinity;
|
||||
return pExpr->affExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,10 +105,22 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip over any TK_COLLATE operators and any unlikely()
|
||||
** or likelihood() function at the root of an expression.
|
||||
** Skip over any TK_COLLATE operators.
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip over any TK_COLLATE operators and/or any unlikely()
|
||||
** or likelihood() or likely() functions at the root of an
|
||||
** expression.
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){
|
||||
if( ExprHasProperty(pExpr, EP_Unlikely) ){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
@@ -144,7 +155,6 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
Expr *p = pExpr;
|
||||
while( p ){
|
||||
int op = p->op;
|
||||
if( p->flags & EP_Generic ) break;
|
||||
if( op==TK_REGISTER ) op = p->op2;
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
|
||||
&& p->y.pTab!=0
|
||||
@@ -230,7 +240,7 @@ int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
|
||||
*/
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
char aff1 = sqlite3ExprAffinity(pExpr);
|
||||
if( aff1 && aff2 ){
|
||||
if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
|
||||
/* Both sides of the comparison are columns. If one has numeric
|
||||
** affinity, use that. Otherwise use no affinity.
|
||||
*/
|
||||
@@ -239,15 +249,10 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
||||
}else{
|
||||
return SQLITE_AFF_BLOB;
|
||||
}
|
||||
}else if( !aff1 && !aff2 ){
|
||||
/* Neither side of the comparison is a column. Compare the
|
||||
** results directly.
|
||||
*/
|
||||
return SQLITE_AFF_BLOB;
|
||||
}else{
|
||||
/* One side is a column, the other is not. Use the columns affinity. */
|
||||
assert( aff1==0 || aff2==0 );
|
||||
return (aff1 + aff2);
|
||||
assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE );
|
||||
return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,14 +285,13 @@ static char comparisonAffinity(Expr *pExpr){
|
||||
*/
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
||||
char aff = comparisonAffinity(pExpr);
|
||||
switch( aff ){
|
||||
case SQLITE_AFF_BLOB:
|
||||
return 1;
|
||||
case SQLITE_AFF_TEXT:
|
||||
return idx_affinity==SQLITE_AFF_TEXT;
|
||||
default:
|
||||
return sqlite3IsNumericAffinity(idx_affinity);
|
||||
if( aff<SQLITE_AFF_TEXT ){
|
||||
return 1;
|
||||
}
|
||||
if( aff==SQLITE_AFF_TEXT ){
|
||||
return idx_affinity==SQLITE_AFF_TEXT;
|
||||
}
|
||||
return sqlite3IsNumericAffinity(idx_affinity);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -901,7 +905,7 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
}else if( ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight) ){
|
||||
sqlite3ExprUnmapAndDelete(pParse, pLeft);
|
||||
sqlite3ExprUnmapAndDelete(pParse, pRight);
|
||||
return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
|
||||
return sqlite3Expr(db, TK_INTEGER, "0");
|
||||
}else{
|
||||
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
|
||||
}
|
||||
@@ -1040,15 +1044,18 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
|
||||
if( p->pRight ){
|
||||
assert( !ExprHasProperty(p, EP_WinFunc) );
|
||||
sqlite3ExprDeleteNN(db, p->pRight);
|
||||
}else if( ExprHasProperty(p, EP_xIsSelect) ){
|
||||
assert( !ExprHasProperty(p, EP_WinFunc) );
|
||||
sqlite3SelectDelete(db, p->x.pSelect);
|
||||
}else{
|
||||
sqlite3ExprListDelete(db, p->x.pList);
|
||||
}
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
assert( p->op==TK_FUNCTION );
|
||||
sqlite3WindowDelete(db, p->y.pWin);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( ExprHasProperty(p, EP_WinFunc) ){
|
||||
sqlite3WindowDelete(db, p->y.pWin);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
||||
@@ -1083,16 +1090,6 @@ static int exprStructSize(Expr *p){
|
||||
return EXPR_FULLSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy the complete content of an Expr node, taking care not to read
|
||||
** past the end of the structure for a reduced-size version of the source
|
||||
** Expr.
|
||||
*/
|
||||
static void exprNodeCopy(Expr *pDest, Expr *pSrc){
|
||||
memset(pDest, 0, sizeof(Expr));
|
||||
memcpy(pDest, pSrc, exprStructSize(pSrc));
|
||||
}
|
||||
|
||||
/*
|
||||
** The dupedExpr*Size() routines each return the number of bytes required
|
||||
** to store a copy of an expression or expression tree. They differ in
|
||||
@@ -1332,10 +1329,13 @@ static With *withDup(sqlite3 *db, With *p){
|
||||
** objects found there, assembling them onto the linked list at Select->pWin.
|
||||
*/
|
||||
static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_FUNCTION && pExpr->y.pWin!=0 ){
|
||||
assert( ExprHasProperty(pExpr, EP_WinFunc) );
|
||||
pExpr->y.pWin->pNextWin = pWalker->u.pSelect->pWin;
|
||||
pWalker->u.pSelect->pWin = pExpr->y.pWin;
|
||||
if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){
|
||||
Select *pSelect = pWalker->u.pSelect;
|
||||
Window *pWin = pExpr->y.pWin;
|
||||
assert( pWin );
|
||||
assert( IsWindowFunc(pExpr) );
|
||||
assert( pWin->ppThis==0 );
|
||||
sqlite3WindowLink(pSelect, pWin);
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -1409,8 +1409,9 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
||||
}
|
||||
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
|
||||
pItem->sortOrder = pOldItem->sortOrder;
|
||||
pItem->sortFlags = pOldItem->sortFlags;
|
||||
pItem->done = 0;
|
||||
pItem->bNulls = pOldItem->bNulls;
|
||||
pItem->bSpanIsTab = pOldItem->bSpanIsTab;
|
||||
pItem->bSorterRef = pOldItem->bSorterRef;
|
||||
pItem->u = pOldItem->u;
|
||||
@@ -1521,7 +1522,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
pNew->pWin = 0;
|
||||
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
|
||||
if( p->pWin ) gatherSelectWindows(pNew);
|
||||
if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
|
||||
#endif
|
||||
pNew->selId = p->selId;
|
||||
*pp = pNew;
|
||||
@@ -1630,6 +1631,10 @@ ExprList *sqlite3ExprListAppendVector(
|
||||
|
||||
for(i=0; i<pColumns->nId; i++){
|
||||
Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
|
||||
assert( pSubExpr!=0 || db->mallocFailed );
|
||||
assert( pSubExpr==0 || pSubExpr->iTable==0 );
|
||||
if( pSubExpr==0 ) continue;
|
||||
pSubExpr->iTable = pColumns->nId;
|
||||
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
|
||||
if( pList ){
|
||||
assert( pList->nExpr==iFirst+i+1 );
|
||||
@@ -1662,15 +1667,34 @@ vector_append_error:
|
||||
/*
|
||||
** Set the sort order for the last element on the given ExprList.
|
||||
*/
|
||||
void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
|
||||
void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
|
||||
struct ExprList_item *pItem;
|
||||
if( p==0 ) return;
|
||||
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
|
||||
assert( p->nExpr>0 );
|
||||
if( iSortOrder<0 ){
|
||||
assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC );
|
||||
return;
|
||||
|
||||
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 );
|
||||
assert( iSortOrder==SQLITE_SO_UNDEFINED
|
||||
|| iSortOrder==SQLITE_SO_ASC
|
||||
|| iSortOrder==SQLITE_SO_DESC
|
||||
);
|
||||
assert( eNulls==SQLITE_SO_UNDEFINED
|
||||
|| eNulls==SQLITE_SO_ASC
|
||||
|| eNulls==SQLITE_SO_DESC
|
||||
);
|
||||
|
||||
pItem = &p->a[p->nExpr-1];
|
||||
assert( pItem->bNulls==0 );
|
||||
if( iSortOrder==SQLITE_SO_UNDEFINED ){
|
||||
iSortOrder = SQLITE_SO_ASC;
|
||||
}
|
||||
pItem->sortFlags = (u8)iSortOrder;
|
||||
|
||||
if( eNulls!=SQLITE_SO_UNDEFINED ){
|
||||
pItem->bNulls = 1;
|
||||
if( iSortOrder!=eNulls ){
|
||||
pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
|
||||
}
|
||||
}
|
||||
p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2169,27 +2193,30 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
*/
|
||||
int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){
|
||||
u8 op;
|
||||
int unaryMinus = 0;
|
||||
if( aff==SQLITE_AFF_BLOB ) return 1;
|
||||
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; }
|
||||
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
|
||||
if( p->op==TK_UMINUS ) unaryMinus = 1;
|
||||
p = p->pLeft;
|
||||
}
|
||||
op = p->op;
|
||||
if( op==TK_REGISTER ) op = p->op2;
|
||||
switch( op ){
|
||||
case TK_INTEGER: {
|
||||
return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC;
|
||||
return aff>=SQLITE_AFF_NUMERIC;
|
||||
}
|
||||
case TK_FLOAT: {
|
||||
return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC;
|
||||
return aff>=SQLITE_AFF_NUMERIC;
|
||||
}
|
||||
case TK_STRING: {
|
||||
return aff==SQLITE_AFF_TEXT;
|
||||
return !unaryMinus && aff==SQLITE_AFF_TEXT;
|
||||
}
|
||||
case TK_BLOB: {
|
||||
return 1;
|
||||
return !unaryMinus;
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */
|
||||
return p->iColumn<0
|
||||
&& (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC);
|
||||
return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
@@ -2372,7 +2399,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
int sqlite3FindInIndex(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pX, /* The right-hand side (RHS) of the IN operator */
|
||||
Expr *pX, /* The IN expression */
|
||||
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
|
||||
int *prRhsHasNull, /* Register holding NULL status. See notes */
|
||||
int *aiMap, /* Mapping from Index fields to RHS fields */
|
||||
@@ -2797,9 +2824,9 @@ void sqlite3CodeRhsOfIN(
|
||||
int i;
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
struct ExprList_item *pItem;
|
||||
int r1, r2, r3;
|
||||
int r1, r2;
|
||||
affinity = sqlite3ExprAffinity(pLeft);
|
||||
if( !affinity ){
|
||||
if( affinity<=SQLITE_AFF_NONE ){
|
||||
affinity = SQLITE_AFF_BLOB;
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
@@ -2825,9 +2852,9 @@ void sqlite3CodeRhsOfIN(
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1);
|
||||
sqlite3ExprCode(pParse, pE2, r1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
@@ -2840,6 +2867,7 @@ void sqlite3CodeRhsOfIN(
|
||||
/* Subroutine return */
|
||||
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
@@ -2853,7 +2881,7 @@ void sqlite3CodeRhsOfIN(
|
||||
**
|
||||
** The pExpr parameter is the SELECT or EXISTS operator to be coded.
|
||||
**
|
||||
** The register that holds the result. For a multi-column SELECT,
|
||||
** Return the register that holds the result. For a multi-column SELECT,
|
||||
** the result is stored in a contiguous array of registers and the
|
||||
** return value is the register of the left-most result column.
|
||||
** Return 0 if an error occurs.
|
||||
@@ -2931,11 +2959,21 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init EXISTS result"));
|
||||
}
|
||||
pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0);
|
||||
if( pSel->pLimit ){
|
||||
sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft);
|
||||
/* The subquery already has a limit. If the pre-existing limit is X
|
||||
** then make the new limit X<>0 so that the new limit is either 1 or 0 */
|
||||
sqlite3 *db = pParse->db;
|
||||
pLimit = sqlite3Expr(db, TK_INTEGER, "0");
|
||||
if( pLimit ){
|
||||
pLimit->affExpr = SQLITE_AFF_NUMERIC;
|
||||
pLimit = sqlite3PExpr(pParse, TK_NE,
|
||||
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
|
||||
}
|
||||
sqlite3ExprDelete(db, pSel->pLimit->pLeft);
|
||||
pSel->pLimit->pLeft = pLimit;
|
||||
}else{
|
||||
/* If there is no pre-existing limit add a limit of 1 */
|
||||
pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
|
||||
}
|
||||
pSel->iLimit = 0;
|
||||
@@ -2950,6 +2988,7 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
/* Subroutine return */
|
||||
sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
||||
sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}
|
||||
|
||||
return rReg;
|
||||
@@ -3097,13 +3136,21 @@ static void sqlite3ExprCodeIN(
|
||||
int r2, regToFree;
|
||||
int regCkNull = 0;
|
||||
int ii;
|
||||
int bLhsReal; /* True if the LHS of the IN has REAL affinity */
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
if( destIfNull!=destIfFalse ){
|
||||
regCkNull = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
|
||||
}
|
||||
bLhsReal = sqlite3ExprAffinity(pExpr->pLeft)==SQLITE_AFF_REAL;
|
||||
for(ii=0; ii<pList->nExpr; ii++){
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
||||
if( bLhsReal ){
|
||||
r2 = regToFree = sqlite3GetTempReg(pParse);
|
||||
sqlite3ExprCode(pParse, pList->a[ii].pExpr, r2);
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, r2, 1, 0, "E", P4_STATIC);
|
||||
}else{
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
||||
}
|
||||
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
|
||||
}
|
||||
@@ -3388,7 +3435,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
|
||||
** the correct value for the expression.
|
||||
*/
|
||||
static void exprToRegister(Expr *pExpr, int iReg){
|
||||
Expr *p = sqlite3ExprSkipCollate(pExpr);
|
||||
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
p->op2 = p->op;
|
||||
p->op = TK_REGISTER;
|
||||
p->iTable = iReg;
|
||||
@@ -3489,7 +3536,7 @@ expr_code_doover:
|
||||
*/
|
||||
int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
|
||||
int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
||||
if( aff!=SQLITE_AFF_BLOB ){
|
||||
if( aff>SQLITE_AFF_BLOB ){
|
||||
static const char zAff[] = "B\000C\000D\000E";
|
||||
assert( SQLITE_AFF_BLOB=='A' );
|
||||
assert( SQLITE_AFF_TEXT=='B' );
|
||||
@@ -3505,7 +3552,19 @@ expr_code_doover:
|
||||
if( iTab<0 ){
|
||||
if( pParse->iSelfTab<0 ){
|
||||
/* Generating CHECK constraints or inserting into partial index */
|
||||
return pExpr->iColumn - pParse->iSelfTab;
|
||||
assert( pExpr->y.pTab!=0 );
|
||||
assert( pExpr->iColumn>=XN_ROWID );
|
||||
assert( pExpr->iColumn<pExpr->y.pTab->nCol );
|
||||
if( pExpr->iColumn>=0
|
||||
&& pExpr->y.pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
|
||||
){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, pExpr->iColumn - pParse->iSelfTab,
|
||||
target);
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
|
||||
return target;
|
||||
}else{
|
||||
return pExpr->iColumn - pParse->iSelfTab;
|
||||
}
|
||||
}else{
|
||||
/* Coding an expression that is part of an index where column names
|
||||
** in the index refer to the table to which the index belongs */
|
||||
@@ -3792,7 +3851,7 @@ expr_code_doover:
|
||||
assert( nFarg==1 );
|
||||
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
|
||||
sqlite3VdbeLoadString(v, target,
|
||||
aff ? azAff[aff-SQLITE_AFF_BLOB] : "none");
|
||||
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
|
||||
return target;
|
||||
}
|
||||
#endif
|
||||
@@ -3900,8 +3959,8 @@ expr_code_doover:
|
||||
pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
|
||||
}
|
||||
assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
|
||||
if( pExpr->iTable
|
||||
&& pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
|
||||
if( pExpr->iTable!=0
|
||||
&& pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
|
||||
pExpr->iTable, n);
|
||||
@@ -4004,10 +4063,23 @@ expr_code_doover:
|
||||
break;
|
||||
}
|
||||
|
||||
/* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions
|
||||
** that derive from the right-hand table of a LEFT JOIN. The
|
||||
** Expr.iTable value is the table number for the right-hand table.
|
||||
** The expression is only evaluated if that table is not currently
|
||||
** on a LEFT JOIN NULL row.
|
||||
*/
|
||||
case TK_IF_NULL_ROW: {
|
||||
int addrINR;
|
||||
u8 okConstFactor = pParse->okConstFactor;
|
||||
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
|
||||
/* Temporarily disable factoring of constant expressions, since
|
||||
** even though expressions may appear to be constant, they are not
|
||||
** really constant because they originate from the right-hand side
|
||||
** of a LEFT JOIN. */
|
||||
pParse->okConstFactor = 0;
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
pParse->okConstFactor = okConstFactor;
|
||||
sqlite3VdbeJumpHere(v, addrINR);
|
||||
sqlite3VdbeChangeP3(v, addrINR, inReg);
|
||||
break;
|
||||
@@ -4044,6 +4116,8 @@ expr_code_doover:
|
||||
Expr opCompare; /* The X==Ei expression */
|
||||
Expr *pX; /* The X expression */
|
||||
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
||||
assert(pExpr->x.pList->nExpr > 0);
|
||||
@@ -4052,13 +4126,17 @@ expr_code_doover:
|
||||
nExpr = pEList->nExpr;
|
||||
endLabel = sqlite3VdbeMakeLabel(pParse);
|
||||
if( (pX = pExpr->pLeft)!=0 ){
|
||||
exprNodeCopy(&tempX, pX);
|
||||
pDel = sqlite3ExprDup(db, pX, 0);
|
||||
if( db->mallocFailed ){
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
break;
|
||||
}
|
||||
testcase( pX->op==TK_COLUMN );
|
||||
exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1));
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
testcase( regFree1==0 );
|
||||
memset(&opCompare, 0, sizeof(opCompare));
|
||||
opCompare.op = TK_EQ;
|
||||
opCompare.pLeft = &tempX;
|
||||
opCompare.pLeft = pDel;
|
||||
pTest = &opCompare;
|
||||
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
|
||||
** The value in regFree1 might get SCopy-ed into the file result.
|
||||
@@ -4086,32 +4164,33 @@ expr_code_doover:
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
||||
}
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
sqlite3VdbeResolveLabel(v, endLabel);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
case TK_RAISE: {
|
||||
assert( pExpr->affinity==OE_Rollback
|
||||
|| pExpr->affinity==OE_Abort
|
||||
|| pExpr->affinity==OE_Fail
|
||||
|| pExpr->affinity==OE_Ignore
|
||||
assert( pExpr->affExpr==OE_Rollback
|
||||
|| pExpr->affExpr==OE_Abort
|
||||
|| pExpr->affExpr==OE_Fail
|
||||
|| pExpr->affExpr==OE_Ignore
|
||||
);
|
||||
if( !pParse->pTriggerTab ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"RAISE() may only be used within a trigger-program");
|
||||
return 0;
|
||||
}
|
||||
if( pExpr->affinity==OE_Abort ){
|
||||
if( pExpr->affExpr==OE_Abort ){
|
||||
sqlite3MayAbort(pParse);
|
||||
}
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
if( pExpr->affinity==OE_Ignore ){
|
||||
if( pExpr->affExpr==OE_Ignore ){
|
||||
sqlite3VdbeAddOp4(
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
||||
pExpr->affinity, pExpr->u.zToken, 0, 0);
|
||||
pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -4176,7 +4255,7 @@ int sqlite3ExprCodeAtInit(
|
||||
*/
|
||||
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||
int r2;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
|
||||
if( ConstFactorOk(pParse)
|
||||
&& pExpr->op!=TK_REGISTER
|
||||
&& sqlite3ExprIsConstantNotJoin(pExpr)
|
||||
@@ -4367,40 +4446,44 @@ static void exprCodeBetween(
|
||||
void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
|
||||
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
|
||||
){
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr exprAnd; /* The AND operator in x>=y AND x<=z */
|
||||
Expr compLeft; /* The x>=y term */
|
||||
Expr compRight; /* The x<=z term */
|
||||
Expr exprX; /* The x subexpression */
|
||||
int regFree1 = 0; /* Temporary use register */
|
||||
Expr *pDel = 0;
|
||||
sqlite3 *db = pParse->db;
|
||||
|
||||
memset(&compLeft, 0, sizeof(Expr));
|
||||
memset(&compRight, 0, sizeof(Expr));
|
||||
memset(&exprAnd, 0, sizeof(Expr));
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
exprNodeCopy(&exprX, pExpr->pLeft);
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = &exprX;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = &exprX;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
exprX.flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
|
||||
if( db->mallocFailed==0 ){
|
||||
exprAnd.op = TK_AND;
|
||||
exprAnd.pLeft = &compLeft;
|
||||
exprAnd.pRight = &compRight;
|
||||
compLeft.op = TK_GE;
|
||||
compLeft.pLeft = pDel;
|
||||
compLeft.pRight = pExpr->x.pList->a[0].pExpr;
|
||||
compRight.op = TK_LE;
|
||||
compRight.pLeft = pDel;
|
||||
compRight.pRight = pExpr->x.pList->a[1].pExpr;
|
||||
exprToRegister(pDel, exprCodeVector(pParse, pDel, ®Free1));
|
||||
if( xJump ){
|
||||
xJump(pParse, &exprAnd, dest, jumpIfNull);
|
||||
}else{
|
||||
/* Mark the expression is being from the ON or USING clause of a join
|
||||
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
||||
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
||||
** for clarity, but we are out of bits in the Expr.flags field so we
|
||||
** have to reuse the EP_FromJoin bit. Bummer. */
|
||||
pDel->flags |= EP_FromJoin;
|
||||
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regFree1);
|
||||
sqlite3ExprDelete(db, pDel);
|
||||
|
||||
/* Ensure adequate test coverage */
|
||||
testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
|
||||
@@ -4839,20 +4922,17 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
return 2;
|
||||
}
|
||||
if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
|
||||
if( pA->op==TK_FUNCTION ){
|
||||
if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
|
||||
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
/* Justification for the assert():
|
||||
** window functions have p->op==TK_FUNCTION but aggregate functions
|
||||
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
|
||||
** function and a window function should have failed before reaching
|
||||
** this point. And, it is not possible to have a window function and
|
||||
** a scalar function with the same name and number of arguments. So
|
||||
** if we reach this point, either A and B both window functions or
|
||||
** neither are a window functions. */
|
||||
assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) );
|
||||
assert( pA->op==pB->op );
|
||||
if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){
|
||||
return 2;
|
||||
}
|
||||
if( ExprHasProperty(pA,EP_WinFunc) ){
|
||||
if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=0 ) return 2;
|
||||
if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}else if( pA->op==TK_NULL ){
|
||||
@@ -4876,7 +4956,8 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
||||
){
|
||||
if( pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( pA->op2!=pB->op2 ) return 2;
|
||||
if( pA->iTable!=pB->iTable
|
||||
if( pA->op!=TK_IN
|
||||
&& pA->iTable!=pB->iTable
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
}
|
||||
}
|
||||
@@ -4906,7 +4987,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
||||
for(i=0; i<pA->nExpr; i++){
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
|
||||
if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
|
||||
if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -4918,42 +4999,47 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
||||
*/
|
||||
int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
|
||||
return sqlite3ExprCompare(0,
|
||||
sqlite3ExprSkipCollate(pA),
|
||||
sqlite3ExprSkipCollate(pB),
|
||||
sqlite3ExprSkipCollateAndLikely(pA),
|
||||
sqlite3ExprSkipCollateAndLikely(pB),
|
||||
iTab);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return non-zero if Expr p can only be true if pNN is not NULL.
|
||||
**
|
||||
** Or if seenNot is true, return non-zero if Expr p can only be
|
||||
** non-NULL if pNN is not NULL
|
||||
*/
|
||||
static int exprImpliesNotNull(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *p, /* The expression to be checked */
|
||||
Expr *pNN, /* The expression that is NOT NULL */
|
||||
int iTab, /* Table being evaluated */
|
||||
int seenNot /* True if p is an operand of NOT */
|
||||
int seenNot /* Return true only if p can be any non-NULL value */
|
||||
){
|
||||
assert( p );
|
||||
assert( pNN );
|
||||
if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ) return 1;
|
||||
if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){
|
||||
return pNN->op!=TK_NULL;
|
||||
}
|
||||
switch( p->op ){
|
||||
case TK_IN: {
|
||||
if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0;
|
||||
assert( ExprHasProperty(p,EP_xIsSelect)
|
||||
|| (p->x.pList!=0 && p->x.pList->nExpr>0) );
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_BETWEEN: {
|
||||
ExprList *pList = p->x.pList;
|
||||
assert( pList!=0 );
|
||||
assert( pList->nExpr==2 );
|
||||
if( seenNot ) return 0;
|
||||
if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, seenNot)
|
||||
|| exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, seenNot)
|
||||
if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1)
|
||||
|| exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_EQ:
|
||||
case TK_NE:
|
||||
@@ -4963,20 +5049,21 @@ static int exprImpliesNotNull(
|
||||
case TK_GE:
|
||||
case TK_PLUS:
|
||||
case TK_MINUS:
|
||||
case TK_BITOR:
|
||||
case TK_LSHIFT:
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT:
|
||||
seenNot = 1;
|
||||
/* Fall thru */
|
||||
case TK_STAR:
|
||||
case TK_REM:
|
||||
case TK_BITAND:
|
||||
case TK_BITOR:
|
||||
case TK_SLASH:
|
||||
case TK_LSHIFT:
|
||||
case TK_RSHIFT:
|
||||
case TK_CONCAT: {
|
||||
case TK_SLASH: {
|
||||
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
|
||||
/* Fall thru into the next case */
|
||||
}
|
||||
case TK_SPAN:
|
||||
case TK_COLLATE:
|
||||
case TK_BITNOT:
|
||||
case TK_UPLUS:
|
||||
case TK_UMINUS: {
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
@@ -4984,8 +5071,9 @@ static int exprImpliesNotNull(
|
||||
case TK_TRUTH: {
|
||||
if( seenNot ) return 0;
|
||||
if( p->op2!=TK_IS ) return 0;
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
case TK_BITNOT:
|
||||
case TK_NOT: {
|
||||
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
||||
}
|
||||
@@ -5051,7 +5139,6 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
||||
switch( pExpr->op ){
|
||||
case TK_ISNOT:
|
||||
case TK_NOT:
|
||||
case TK_ISNULL:
|
||||
case TK_NOTNULL:
|
||||
case TK_IS:
|
||||
@@ -5059,8 +5146,8 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
case TK_CASE:
|
||||
case TK_IN:
|
||||
case TK_FUNCTION:
|
||||
case TK_TRUTH:
|
||||
testcase( pExpr->op==TK_ISNOT );
|
||||
testcase( pExpr->op==TK_NOT );
|
||||
testcase( pExpr->op==TK_ISNULL );
|
||||
testcase( pExpr->op==TK_NOTNULL );
|
||||
testcase( pExpr->op==TK_IS );
|
||||
@@ -5068,6 +5155,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_CASE );
|
||||
testcase( pExpr->op==TK_IN );
|
||||
testcase( pExpr->op==TK_FUNCTION );
|
||||
testcase( pExpr->op==TK_TRUTH );
|
||||
return WRC_Prune;
|
||||
case TK_COLUMN:
|
||||
if( pWalker->u.iCur==pExpr->iTable ){
|
||||
@@ -5076,6 +5164,18 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
return WRC_Prune;
|
||||
|
||||
case TK_AND:
|
||||
if( sqlite3ExprImpliesNonNullRow(pExpr->pLeft, pWalker->u.iCur)
|
||||
&& sqlite3ExprImpliesNonNullRow(pExpr->pRight, pWalker->u.iCur)
|
||||
){
|
||||
pWalker->eCode = 1;
|
||||
}
|
||||
return WRC_Prune;
|
||||
|
||||
case TK_BETWEEN:
|
||||
sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
||||
return WRC_Prune;
|
||||
|
||||
/* Virtual tables are allowed to use constraints like x=NULL. So
|
||||
** a term of the form x=y does not prove that y is not null if x
|
||||
** is the column of a virtual table */
|
||||
@@ -5096,6 +5196,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
){
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
default:
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -5125,7 +5226,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
|
||||
Walker w;
|
||||
p = sqlite3ExprSkipCollate(p);
|
||||
p = sqlite3ExprSkipCollateAndLikely(p);
|
||||
while( p ){
|
||||
if( p->op==TK_NOTNULL ){
|
||||
p = p->pLeft;
|
||||
@@ -5231,7 +5332,10 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( i<nSrc ){
|
||||
p->nThis++;
|
||||
}else{
|
||||
}else if( nSrc==0 || pExpr->iTable<pSrc->a[0].iCursor ){
|
||||
/* In a well-formed parse tree (no name resolution errors),
|
||||
** TK_COLUMN nodes with smaller Expr.iTable values are in an
|
||||
** outer context. Those are the only ones to count as "other" */
|
||||
p->nOther++;
|
||||
}
|
||||
}
|
||||
@@ -5248,8 +5352,9 @@ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
||||
Walker w;
|
||||
struct SrcCount cnt;
|
||||
assert( pExpr->op==TK_AGG_FUNCTION );
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = exprSrcCount;
|
||||
w.xSelectCallback = 0;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
w.u.pSrcCount = &cnt;
|
||||
cnt.pSrc = pSrcList;
|
||||
cnt.nThis = 0;
|
||||
@@ -5518,6 +5623,11 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
|
||||
|
||||
/*
|
||||
** Mark all temporary registers as being unavailable for reuse.
|
||||
**
|
||||
** Always invoke this procedure after coding a subroutine or co-routine
|
||||
** that might be invoked from other parts of the code, to ensure that
|
||||
** the sub/co-routine does not use registers in common with the code that
|
||||
** invokes the sub/co-routine.
|
||||
*/
|
||||
void sqlite3ClearTempRegCache(Parse *pParse){
|
||||
pParse->nTempReg = 0;
|
||||
|
||||
Reference in New Issue
Block a user