aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/btree.c10
-rw-r--r--src/pager.c6
-rw-r--r--src/shell.c.in9
-rw-r--r--src/sqlite.h.in12
-rw-r--r--src/test1.c28
-rw-r--r--src/vdbeapi.c8
6 files changed, 63 insertions, 10 deletions
diff --git a/src/btree.c b/src/btree.c
index d13339565..03451cf30 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -5552,7 +5552,7 @@ int sqlite3BtreeMovetoUnpacked(
sqlite3_free(pCellKey);
goto moveto_finish;
}
- c = xRecordCompare(nCell, pCellKey, pIdxKey);
+ c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
sqlite3_free(pCellKey);
}
assert(
@@ -7152,8 +7152,9 @@ static int editPage(
int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
if( iCell>=0 && iCell<nNew ){
pCellptr = &pPg->aCellIdx[iCell * 2];
- assert( nCell>=iCell );
- memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ if( nCell>iCell ){
+ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ }
nCell++;
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
@@ -9268,6 +9269,9 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
assert( sqlite3BtreeHoldsMutex(p) );
assert( p->inTrans==TRANS_WRITE );
assert( iTable>=2 );
+ if( iTable>btreePagecount(pBt) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
diff --git a/src/pager.c b/src/pager.c
index 9dd3dfe00..24c7a2d56 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -7177,8 +7177,12 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
*/
pPg->flags &= ~PGHDR_NEED_SYNC;
pPgOld = sqlite3PagerLookup(pPager, pgno);
- assert( !pPgOld || pPgOld->nRef==1 );
+ assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB );
if( pPgOld ){
+ if( pPgOld->nRef>1 ){
+ sqlite3PagerUnrefNotNull(pPgOld);
+ return SQLITE_CORRUPT_BKPT;
+ }
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
if( pPager->tempFile ){
/* Do not discard pages from an in-memory database since we might
diff --git a/src/shell.c.in b/src/shell.c.in
index df81c2e99..d4c24eac8 100644
--- a/src/shell.c.in
+++ b/src/shell.c.in
@@ -3058,7 +3058,7 @@ static int shell_exec(
}
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
- if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
+ if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
sqlite3_stmt *pExplain;
char *zEQP;
int triggerEQP = 0;
@@ -3107,13 +3107,10 @@ static int shell_exec(
if( pArg ){
pArg->cMode = pArg->mode;
if( pArg->autoExplain ){
- if( sqlite3_column_count(pStmt)==8
- && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
- ){
+ if( sqlite3_stmt_isexplain(pStmt)==1 ){
pArg->cMode = MODE_Explain;
}
- if( sqlite3_column_count(pStmt)==4
- && sqlite3_strlike("EXPLAIN QUERY PLAN%", zStmtSql,0)==0 ){
+ if( sqlite3_stmt_isexplain(pStmt)==2 ){
pArg->cMode = MODE_EQP;
}
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 21382be20..848b2bc3c 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -3895,6 +3895,18 @@ const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the
+** prepared statement S is an EXPLAIN statement, or 2 if the
+** statement S is an EXPLAIN QUERY PLAN.
+** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is
+** an ordinary statement or a NULL pointer.
+*/
+int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
**
diff --git a/src/test1.c b/src/test1.c
index d8a0c8642..bd288a2b7 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -2675,6 +2675,33 @@ static int SQLITE_TCLAPI test_stmt_readonly(
}
/*
+** Usage: sqlite3_stmt_isexplain STMT
+**
+** Return 1, 2, or 0 respectively if STMT is an EXPLAIN statement, an
+** EXPLAIN QUERY PLAN statement or an ordinary statement or NULL pointer.
+*/
+static int SQLITE_TCLAPI test_stmt_isexplain(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt;
+ int rc;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
+ return TCL_ERROR;
+ }
+
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ rc = sqlite3_stmt_isexplain(pStmt);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_stmt_busy STMT
**
** Return true if STMT is a non-NULL pointer to a statement
@@ -7840,6 +7867,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
{ "sqlite3_next_stmt", test_next_stmt ,0 },
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
+ { "sqlite3_stmt_isexplain", test_stmt_isexplain,0 },
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
{ "uses_stmt_journal", uses_stmt_journal ,0 },
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 2aa93e60a..82138258a 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -1609,6 +1609,14 @@ int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
}
/*
+** Return 1 if the statement is an EXPLAIN and return 2 if the
+** statement is an EXPLAIN QUERY PLAN
+*/
+int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
+ return pStmt ? ((Vdbe*)pStmt)->explain : 0;
+}
+
+/*
** Return true if the prepared statement is in need of being reset.
*/
int sqlite3_stmt_busy(sqlite3_stmt *pStmt){