aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2017-06-26 13:57:49 +0000
committerdrh <drh@noemail.net>2017-06-26 13:57:49 +0000
commit169dd928c521144e3be5b1fa81aefaa43eb2803f (patch)
tree3850004946f982cf534e9a94dd36a4e14de141df /src
parenta22dd3860a3491d621fec0d0d507c7a0a60d9b6b (diff)
downloadsqlite-169dd928c521144e3be5b1fa81aefaa43eb2803f.tar.gz
sqlite-169dd928c521144e3be5b1fa81aefaa43eb2803f.zip
Add the SQLITE_DBCONFIG_ENABLE_QPSG option to activate the query planner
stability guarantee. This involves refactoring the sqlite3.flags bitvector to carve out a free bit to use. FossilOrigin-Name: 7076e8283ebae1b45a5d85d9538b49b6da399d38c3c6935de100f948f814f6a9
Diffstat (limited to 'src')
-rw-r--r--src/btree.c10
-rw-r--r--src/main.c4
-rw-r--r--src/pragma.h4
-rw-r--r--src/prepare.c8
-rw-r--r--src/sqlite.h.in12
-rw-r--r--src/sqliteInt.h55
-rw-r--r--src/test1.c1
-rw-r--r--src/vdbe.c2
-rw-r--r--src/vdbeaux.c2
-rw-r--r--src/vdbemem.c6
10 files changed, 62 insertions, 42 deletions
diff --git a/src/btree.c b/src/btree.c
index 1f06e4503..be6c0dd17 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -152,7 +152,7 @@ static int hasSharedCacheTableLock(
** Return true immediately.
*/
if( (pBtree->sharable==0)
- || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
+ || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit))
){
return 1;
}
@@ -229,7 +229,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
if( p->pgnoRoot==iRoot
&& p->pBtree!=pBtree
- && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted)
+ && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit)
){
return 1;
}
@@ -251,7 +251,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
assert( sqlite3BtreeHoldsMutex(p) );
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
assert( p->db!=0 );
- assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 );
+ assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 );
/* If requesting a write-lock, then the Btree must have an open write
** transaction on this file. And, obviously, for this to be so there
@@ -329,7 +329,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
** obtain a read-lock using this function. The only read-lock obtained
** by a connection in read-uncommitted mode is on the sqlite_master
** table, and that lock is obtained in BtreeBeginTrans(). */
- assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK );
+ assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
/* This function should only be called on a sharable b-tree after it
** has been determined that no other b-tree holds a conflicting lock. */
@@ -3021,7 +3021,7 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
- if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
+ if( (pBt->db->flags & SQLITE_WriteSchema)==0 && nPage>nPageFile ){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
diff --git a/src/main.c b/src/main.c
index 6a48f93d1..f11942666 100644
--- a/src/main.c
+++ b/src/main.c
@@ -811,6 +811,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
+ { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -2916,6 +2917,9 @@ static int openDatabase(
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
| SQLITE_Fts3Tokenizer
#endif
+#if defined(SQLITE_ENABLE_QPSG)
+ | SQLITE_EnableQPSG
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
diff --git a/src/pragma.h b/src/pragma.h
index bf0f648f0..76e59cbc6 100644
--- a/src/pragma.h
+++ b/src/pragma.h
@@ -458,7 +458,7 @@ static const PragmaName aPragmaName[] = {
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
- /* iArg: */ SQLITE_ReadUncommitted },
+ /* iArg: */ SQLITE_ReadUncommit },
{/* zName: */ "recursive_triggers",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
@@ -610,7 +610,7 @@ static const PragmaName aPragmaName[] = {
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
- /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
+ /* iArg: */ SQLITE_WriteSchema },
#endif
};
/* Number of pragmas: 60 on by default, 74 total. */
diff --git a/src/prepare.c b/src/prepare.c
index 74127bc76..395b9e404 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -25,7 +25,7 @@ static void corruptSchema(
const char *zExtra /* Error information */
){
sqlite3 *db = pData->db;
- if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
+ if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
char *z;
if( zObj==0 ) zObj = "?";
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
@@ -312,8 +312,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = SQLITE_NOMEM_BKPT;
sqlite3ResetAllSchemasOfConnection(db);
}
- if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
- /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
+ if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){
+ /* Black magic: If the SQLITE_WriteSchema flag is set, then consider
** the schema loaded, even if errors occurred. In this situation the
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
@@ -561,7 +561,7 @@ static int sqlite3Prepare(
if( rc ){
const char *zDb = db->aDb[i].zDbSName;
sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
- testcase( db->flags & SQLITE_ReadUncommitted );
+ testcase( db->flags & SQLITE_ReadUncommit );
goto end_prepare;
}
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 1e4389215..2f72f83f5 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2007,6 +2007,17 @@ struct sqlite3_mem_methods {
** have been disabled - 0 if they are not disabled, 1 if they are.
** </dd>
**
+** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
+** <dd>The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
+** the [query planner stability guarantee] (QPSG). When the QPSG is active,
+** a single SQL query statement will always use the same algorithm regardless
+** of values of [bound parameters]. The QPSG disables some query optimizations
+** that look at the values of bound parameters, which can make some queries
+** slower. But the QPSG has the advantage of more predictable behavior. With
+** the QPSG active, SQLite will always use the same query plan in the field as
+** was used during testing in the lab.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2016,6 +2027,7 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */
/*
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index ee83a511f..cc51197d6 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1450,8 +1450,8 @@ struct sqlite3 {
** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
-#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
-#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
+#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */
+#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */
@@ -1462,29 +1462,34 @@ struct sqlite3 {
/* the count using a callback. */
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
-#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
-#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
-#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */
-#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */
-#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
-#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */
-#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */
-#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */
-#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */
-#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
-#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
-#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
-#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */
-#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */
-#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */
-#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */
-#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */
+#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
+#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
+#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
+#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
+#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */
+#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */
+#define SQLITE_EnableTrigger 0x00020000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x00040000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x00080000 /* Disable database changes */
+#define SQLITE_CellSizeCk 0x00100000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x00200000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableQPSG 0x00400000 /* Query Planner Stability Guarantee */
+/* The next four values are not used by PRAGMAs or by sqlite3_dbconfig() and
+** could be factored out into a separate bit vector of the sqlite3 object. */
+#define SQLITE_InternChanges 0x00800000 /* Uncommitted Hash table changes */
+#define SQLITE_LoadExtFunc 0x01000000 /* Enable load_extension() SQL func */
+#define SQLITE_PreferBuiltin 0x02000000 /* Preference to built-in funcs */
+#define SQLITE_Vacuum 0x04000000 /* Currently in a VACUUM */
+/* Flags used only if debugging */
+#ifdef SQLITE_DEBUG
+#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */
+#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */
+#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */
+#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */
+#endif
/*
diff --git a/src/test1.c b/src/test1.c
index 87b255c9e..eaafd8775 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -7317,6 +7317,7 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
{ "FTS3_TOKENIZER", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
{ "LOAD_EXTENSION", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "NO_CKPT_ON_CLOSE",SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
+ { "QPSG", SQLITE_DBCONFIG_ENABLE_QPSG },
};
int i;
int v;
diff --git a/src/vdbe.c b/src/vdbe.c
index 4a412b4e5..ecdd92be9 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -6571,7 +6571,7 @@ case OP_Expire: {
*/
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
- if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
+ if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
int p1 = pOp->p1;
assert( p1>=0 && p1<db->nDb );
assert( DbMaskTest(p->btreeMask, p1) );
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 5dfbe4f5b..846bf7c8d 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -4540,7 +4540,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe *v){
*/
sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){
assert( iVar>0 );
- if( v ){
+ if( v && (v->db->flags & SQLITE_EnableQPSG)==0 ){
Mem *pMem = &v->aVar[iVar-1];
if( 0==(pMem->flags & MEM_Null) ){
sqlite3_value *pRet = sqlite3ValueNew(v->db);
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 88c57f1ab..dc24f4468 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -1493,13 +1493,11 @@ static int stat4ValueFromExpr(
Vdbe *v;
int iBindVar = pExpr->iColumn;
sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
- if( (v = pParse->pReprepare)!=0 ){
+ if( (v = pParse->pReprepare)!=0 && (db->flags & SQLITE_EnableQPSG)==0 ){
pVal = valueNew(db, pAlloc);
if( pVal ){
rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
- if( rc==SQLITE_OK ){
- sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
- }
+ sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
pVal->db = pParse->db;
}
}