aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sqlite.h.in7
-rw-r--r--src/tclsqlite.c2
-rw-r--r--src/test_config.c6
-rw-r--r--src/where.c24
-rw-r--r--src/whereInt.h4
5 files changed, 34 insertions, 9 deletions
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 4a66626b8..21e200486 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -956,13 +956,16 @@ struct sqlite3_io_methods {
** pointed to by the pArg argument. This capability is used during testing
** and only needs to be supported when SQLITE_TEST is defined.
**
-** <li>[[SQLITE_FCNTL_WAL_BLOCK]]
+* <li>[[SQLITE_FCNTL_WAL_BLOCK]]
** The [SQLITE_FCNTL_WAL_BLOCK] is a signal to the VFS layer that it might
** be advantageous to block on the next WAL lock if the lock is not immediately
** available. The WAL subsystem issues this signal during rare
** circumstances in order to fix a problem with priority inversion.
** Applications should <em>not</em> use this file-control.
**
+** <li>[[SQLITE_FCNTL_ZIPVFS]]
+** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other
+** VFS should return SQLITE_NOTFOUND for this opcode.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -988,6 +991,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
#define SQLITE_FCNTL_WIN32_SET_HANDLE 23
#define SQLITE_FCNTL_WAL_BLOCK 24
+#define SQLITE_FCNTL_ZIPVFS 25
+#define SQLITE_FCNTL_OTA 26
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index b44f5b8fa..24114e92f 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -3760,6 +3760,7 @@ static void init_all(Tcl_Interp *interp){
extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*);
extern int SqlitetestSyscall_Init(Tcl_Interp*);
+ extern int SqliteOta_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
@@ -3803,6 +3804,7 @@ static void init_all(Tcl_Interp *interp){
Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp);
+ SqliteOta_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp);
diff --git a/src/test_config.c b/src/test_config.c
index 0be2a23d3..03ec8fe57 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -430,6 +430,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_OTA
+ Tcl_SetVar2(interp, "sqlite_options", "ota", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "ota", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY);
#else
diff --git a/src/where.c b/src/where.c
index 85eb00b46..a89aba7c8 100644
--- a/src/where.c
+++ b/src/where.c
@@ -363,7 +363,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
+ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS;
}
/*
@@ -416,6 +416,8 @@ static u16 operatorMask(int op){
c = WO_IN;
}else if( op==TK_ISNULL ){
c = WO_ISNULL;
+ }else if( op==TK_IS ){
+ c = WO_IS;
}else{
assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff );
c = (u16)(WO_EQ<<(op-TK_EQ));
@@ -2792,7 +2794,7 @@ static int codeEqualityTerm(
int iReg; /* Register holding results */
assert( iTarget>0 );
- if( pX->op==TK_EQ ){
+ if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
}else if( pX->op==TK_ISNULL ){
iReg = iTarget;
@@ -2977,7 +2979,7 @@ static int codeAllEqualityTerms(
testcase( pTerm->eOperator & WO_IN );
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
Expr *pRight = pTerm->pExpr->pRight;
- if( sqlite3ExprCanBeNull(pRight) ){
+ if( sqlite3ExprCanBeNull(pRight) && pTerm->eOperator!=WO_IS ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
VdbeCoverage(v);
}
@@ -4315,6 +4317,9 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
+ if( pWInfo->bShortcut ){
+ whereLoopClear(db, pWInfo->a[0].pWLoop);
+ }
sqlite3DbFree(db, pWInfo);
}
}
@@ -5565,7 +5570,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
- whereLoopInit(pNew);
for(iTab=0, pItem=pTabList->a; iTab<nTabList; iTab++, pItem++){
pNew->iTab = iTab;
pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor);
@@ -6281,7 +6285,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** no-frills query planner. Return zero if this query needs the
** general-purpose query planner.
*/
-static int whereShortCut(WhereLoopBuilder *pBuilder){
+static int whereShortCut(sqlite3 *db, WhereLoopBuilder *pBuilder){
WhereInfo *pWInfo;
struct SrcList_item *pItem;
WhereClause *pWC;
@@ -6314,13 +6318,18 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->rRun = 33; /* 33==sqlite3LogEst(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ u32 mask = WO_EQ;
assert( pLoop->aLTermSpace==pLoop->aLTerm );
+ if( HasRowid(pTab)==0 && IsPrimaryKeyIndex(pIdx) ){
+ mask |= WO_IS;
+ if( whereLoopResize(db, pLoop, pIdx->nKeyCol) ) return 1;
+ }else
if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
for(j=0; j<pIdx->nKeyCol; j++){
- pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
+ pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, mask, pIdx);
if( pTerm==0 ) break;
pLoop->aLTerm[j] = pTerm;
}
@@ -6350,6 +6359,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
#ifdef SQLITE_DEBUG
pLoop->cId = '0';
#endif
+ pWInfo->bShortcut = 1;
return 1;
}
return 0;
@@ -6620,7 +6630,7 @@ WhereInfo *sqlite3WhereBegin(
}
#endif
- if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
+ if( nTabList!=1 || whereShortCut(db, &sWLB)==0 ){
rc = whereLoopAddAll(&sWLB);
if( rc ) goto whereBeginError;
diff --git a/src/whereInt.h b/src/whereInt.h
index 04cc2029d..ccef368eb 100644
--- a/src/whereInt.h
+++ b/src/whereInt.h
@@ -412,6 +412,7 @@ struct WhereInfo {
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
u8 nLevel; /* Number of nested loop */
+ u8 bShortcut; /* Plan generated by whereShortCut() */
int iTop; /* The very beginning of the WHERE loop */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
@@ -440,8 +441,9 @@ struct WhereInfo {
#define WO_AND 0x200 /* Two or more AND-connected terms */
#define WO_EQUIV 0x400 /* Of the form A==B, both columns */
#define WO_NOOP 0x800 /* This term does not restrict search space */
+#define WO_IS 0x1000 /* The IS operator */
-#define WO_ALL 0xfff /* Mask of all possible WO_* values */
+#define WO_ALL 0x1fff /* Mask of all possible WO_* values */
#define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
/*