Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Unified Diff: third_party/sqlite/src/src/vdbeapi.c

Issue 6990047: Import SQLite 3.7.6.3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/sqlite/src/src/vdbeInt.h ('k') | third_party/sqlite/src/src/vdbeaux.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/sqlite/src/src/vdbeapi.c
diff --git a/third_party/sqlite/src/src/vdbeapi.c b/third_party/sqlite/src/src/vdbeapi.c
index 634c29c45da0ebd97528401035cc3d63897abc90..90baaccc68a4e087f6ac6ddb5b146d1777b7d8d2 100644
--- a/third_party/sqlite/src/src/vdbeapi.c
+++ b/third_party/sqlite/src/src/vdbeapi.c
@@ -12,8 +12,6 @@
**
** This file contains code use to implement APIs that are part of the
** VDBE.
-**
-** $Id: vdbeapi.c,v 1.167 2009/06/25 01:47:12 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
@@ -34,6 +32,28 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
#endif
/*
+** Check on a Vdbe to make sure it has not been finalized. Log
+** an error and return true if it has been finalized (or is otherwise
+** invalid). Return false if it is ok.
+*/
+static int vdbeSafety(Vdbe *p){
+ if( p->db==0 ){
+ sqlite3_log(SQLITE_MISUSE, "API called with finalized prepared statement");
+ return 1;
+ }else{
+ return 0;
+ }
+}
+static int vdbeSafetyNotNull(Vdbe *p){
+ if( p==0 ){
+ sqlite3_log(SQLITE_MISUSE, "API called with NULL prepared statement");
+ return 1;
+ }else{
+ return vdbeSafety(p);
+ }
+}
+
+/*
** The following routine destroys a virtual machine that is created by
** the sqlite3_compile() routine. The integer returned is an SQLITE_
** success/failure code that describes the result of executing the virtual
@@ -45,12 +65,18 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
int sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
+ /* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
+ ** pointer is a harmless no-op. */
rc = SQLITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = v->db->mutex;
+ sqlite3_mutex *mutex;
+#endif
+ if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
+#if SQLITE_THREADSAFE
+ mutex = v->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
rc = sqlite3VdbeFinalize(v);
@@ -99,6 +125,9 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
sqlite3VdbeMemRelease(&p->aVar[i]);
p->aVar[i].flags = MEM_Null;
}
+ if( p->isPrepareV2 && p->expmask ){
+ p->expired = 1;
+ }
sqlite3_mutex_leave(mutex);
return rc;
}
@@ -114,7 +143,7 @@ const void *sqlite3_value_blob(sqlite3_value *pVal){
sqlite3VdbeMemExpandBlob(p);
p->flags &= ~MEM_Str;
p->flags |= MEM_Blob;
- return p->z;
+ return p->n ? p->z : 0;
}else{
return sqlite3_value_text(pVal);
}
@@ -280,6 +309,27 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
}
/*
+** This function is called after a transaction has been committed. It
+** invokes callbacks registered with sqlite3_wal_hook() as required.
+*/
+static int doWalCallbacks(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_WAL
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
+ if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
**
@@ -294,26 +344,45 @@ static int sqlite3Step(Vdbe *p){
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
- return SQLITE_MISUSE;
+ /* We used to require that sqlite3_reset() be called before retrying
+ ** sqlite3_step() after any error or after SQLITE_DONE. But beginning
+ ** with version 3.7.0, we changed this so that sqlite3_reset() would
+ ** be called automatically instead of throwing the SQLITE_MISUSE error.
+ ** This "automatic-reset" change is not technically an incompatibility,
+ ** since any application that receives an SQLITE_MISUSE is broken by
+ ** definition.
+ **
+ ** Nevertheless, some published applications that were originally written
+ ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
+ ** returns, and the so were broken by the automatic-reset change. As a
+ ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
+ ** legacy behavior of returning SQLITE_MISUSE for cases where the
+ ** previous sqlite3_step() returned something other than a SQLITE_LOCKED
+ ** or SQLITE_BUSY error.
+ */
+#ifdef SQLITE_OMIT_AUTORESET
+ if( p->rc==SQLITE_BUSY || p->rc==SQLITE_LOCKED ){
+ sqlite3_reset((sqlite3_stmt*)p);
+ }else{
+ return SQLITE_MISUSE_BKPT;
+ }
+#else
+ sqlite3_reset((sqlite3_stmt*)p);
+#endif
}
- /* Assert that malloc() has not failed */
+ /* Check that malloc() has not failed. If it has, return early. */
db = p->db;
if( db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
return SQLITE_NOMEM;
}
if( p->pc<=0 && p->expired ){
- if( ALWAYS(p->rc==SQLITE_OK) ){
- p->rc = SQLITE_SCHEMA;
- }
+ p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
goto end_of_step;
}
- if( sqlite3SafetyOn(db) ){
- p->rc = SQLITE_MISUSE;
- return SQLITE_MISUSE;
- }
if( p->pc<0 ){
/* If there are no other statements currently running, then
** reset the interrupt flag. This prevents a call to sqlite3_interrupt
@@ -323,11 +392,11 @@ static int sqlite3Step(Vdbe *p){
db->u1.isInterrupted = 0;
}
+ assert( db->writeVdbeCnt>0 || db->autoCommit==0 || db->nDeferredCons==0 );
+
#ifndef SQLITE_OMIT_TRACE
if( db->xProfile && !db->init.busy ){
- double rNow;
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}
#endif
@@ -341,27 +410,29 @@ static int sqlite3Step(Vdbe *p){
}else
#endif /* SQLITE_OMIT_EXPLAIN */
{
+ db->vdbeExecCnt++;
rc = sqlite3VdbeExec(p);
- }
-
- if( sqlite3SafetyOff(db) ){
- rc = SQLITE_MISUSE;
+ db->vdbeExecCnt--;
}
#ifndef SQLITE_OMIT_TRACE
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
- double rNow;
- u64 elapseTime;
-
- sqlite3OsCurrentTime(db->pVfs, &rNow);
- elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
- elapseTime -= p->startTime;
- db->xProfile(db->pProfileArg, p->zSql, elapseTime);
+ sqlite3_int64 iNow;
+ sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
+ db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
}
#endif
+ if( rc==SQLITE_DONE ){
+ assert( p->rc==SQLITE_OK );
+ p->rc = doWalCallbacks(db);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ }
+ }
+
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
@@ -394,39 +465,44 @@ end_of_step:
** call sqlite3Reprepare() and try again.
*/
int sqlite3_step(sqlite3_stmt *pStmt){
- int rc = SQLITE_MISUSE;
- if( pStmt ){
- int cnt = 0;
- Vdbe *v = (Vdbe*)pStmt;
- sqlite3 *db = v->db;
- sqlite3_mutex_enter(db->mutex);
- while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
- && cnt++ < 5
- && (rc = sqlite3Reprepare(v))==SQLITE_OK ){
- sqlite3_reset(pStmt);
- v->expired = 0;
- }
- if( rc==SQLITE_SCHEMA && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
- /* This case occurs after failing to recompile an sql statement.
- ** The error message from the SQL compiler has already been loaded
- ** into the database handle. This block copies the error message
- ** from the database handle into the statement and sets the statement
- ** program counter to 0 to ensure that when the statement is
- ** finalized or reset the parser error message is available via
- ** sqlite3_errmsg() and sqlite3_errcode().
- */
- const char *zErr = (const char *)sqlite3_value_text(db->pErr);
- sqlite3DbFree(db, v->zErrMsg);
- if( !db->mallocFailed ){
- v->zErrMsg = sqlite3DbStrDup(db, zErr);
- } else {
- v->zErrMsg = 0;
- v->rc = SQLITE_NOMEM;
- }
+ int rc = SQLITE_OK; /* Result from sqlite3Step() */
+ int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
+ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
+ int cnt = 0; /* Counter to prevent infinite loop of reprepares */
+ sqlite3 *db; /* The database connection */
+
+ if( vdbeSafetyNotNull(v) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ db = v->db;
+ sqlite3_mutex_enter(db->mutex);
+ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
+ && cnt++ < 5
+ && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
+ sqlite3_reset(pStmt);
+ v->expired = 0;
+ }
+ if( rc2!=SQLITE_OK && ALWAYS(v->isPrepareV2) && ALWAYS(db->pErr) ){
+ /* This case occurs after failing to recompile an sql statement.
+ ** The error message from the SQL compiler has already been loaded
+ ** into the database handle. This block copies the error message
+ ** from the database handle into the statement and sets the statement
+ ** program counter to 0 to ensure that when the statement is
+ ** finalized or reset the parser error message is available via
+ ** sqlite3_errmsg() and sqlite3_errcode().
+ */
+ const char *zErr = (const char *)sqlite3_value_text(db->pErr);
+ sqlite3DbFree(db, v->zErrMsg);
+ if( !db->mallocFailed ){
+ v->zErrMsg = sqlite3DbStrDup(db, zErr);
+ v->rc = rc2;
+ } else {
+ v->zErrMsg = 0;
+ v->rc = rc = SQLITE_NOMEM;
}
- rc = sqlite3ApiExit(db, rc);
- sqlite3_mutex_leave(db->mutex);
}
+ rc = sqlite3ApiExit(db, rc);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -442,6 +518,12 @@ void *sqlite3_user_data(sqlite3_context *p){
/*
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
+**
+** IMPLEMENTATION-OF: R-46798-50301 The sqlite3_context_db_handle() interface
+** returns a copy of the pointer to the database connection (the 1st
+** parameter) of the sqlite3_create_function() and
+** sqlite3_create_function16() routines that originally registered the
+** application defined function.
*/
sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
assert( p && p->pFunc );
@@ -480,8 +562,9 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
assert( sqlite3_mutex_held(p->s.db->mutex) );
pMem = p->pMem;
+ testcase( nByte<0 );
if( (pMem->flags & MEM_Agg)==0 ){
- if( nByte==0 ){
+ if( nByte<=0 ){
sqlite3VdbeMemReleaseExternal(pMem);
pMem->flags = MEM_Null;
pMem->z = 0;
@@ -599,13 +682,11 @@ int sqlite3_data_count(sqlite3_stmt *pStmt){
*/
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Vdbe *pVm;
- int vals;
Mem *pOut;
pVm = (Vdbe *)pStmt;
if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
sqlite3_mutex_enter(pVm->db->mutex);
- vals = sqlite3_data_count(pStmt);
pOut = &pVm->pResultSet[i];
}else{
/* If the value passed as the second argument is out of range, return
@@ -623,7 +704,11 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
__attribute__((aligned(8)))
#endif
- = {{0}, (double)0, 0, "", 0, MEM_Null, SQLITE_NULL, 0, 0, 0 };
+ = {0, "", (double)0, {0}, 0, MEM_Null, SQLITE_NULL, 0,
+#ifdef SQLITE_DEBUG
+ 0, 0, /* pScopyFrom, pFiller */
+#endif
+ 0, 0 };
if( pVm && ALWAYS(pVm->db) ){
sqlite3_mutex_enter(pVm->db->mutex);
@@ -650,8 +735,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** sqlite3_column_real()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
-**
-** But not for sqlite3_column_blob(), which never calls malloc().
+** sqiite3_column_blob()
*/
static void columnMallocFailure(sqlite3_stmt *pStmt)
{
@@ -895,12 +979,16 @@ const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
*/
static int vdbeUnbind(Vdbe *p, int i){
Mem *pVar;
- if( p==0 ) return SQLITE_MISUSE;
+ if( vdbeSafetyNotNull(p) ){
+ return SQLITE_MISUSE_BKPT;
+ }
sqlite3_mutex_enter(p->db->mutex);
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
sqlite3Error(p->db, SQLITE_MISUSE, 0);
sqlite3_mutex_leave(p->db->mutex);
- return SQLITE_MISUSE;
+ sqlite3_log(SQLITE_MISUSE,
+ "bind on a busy prepared statement: [%s]", p->zSql);
+ return SQLITE_MISUSE_BKPT;
}
if( i<1 || i>p->nVar ){
sqlite3Error(p->db, SQLITE_RANGE, 0);
@@ -912,6 +1000,21 @@ static int vdbeUnbind(Vdbe *p, int i){
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
sqlite3Error(p->db, SQLITE_OK, 0);
+
+ /* If the bit corresponding to this variable in Vdbe.expmask is set, then
+ ** binding a new value to this variable invalidates the current query plan.
+ **
+ ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
+ ** parameter in the WHERE clause might influence the choice of query plan
+ ** for a statement, then the statement will be automatically recompiled,
+ ** as if there had been a schema change, on the first sqlite3_step() call
+ ** following any change to the bindings of that parameter.
+ */
+ if( p->isPrepareV2 &&
+ ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
+ ){
+ p->expired = 1;
+ }
return SQLITE_OK;
}
@@ -942,6 +1045,8 @@ static int bindText(
rc = sqlite3ApiExit(p->db, rc);
}
sqlite3_mutex_leave(p->db->mutex);
+ }else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
+ xDel((void*)zData);
}
return rc;
}
@@ -1108,8 +1213,7 @@ const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
** with that name. If there is no variable with the given name,
** return 0.
*/
-int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
- Vdbe *p = (Vdbe*)pStmt;
+int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
int i;
if( p==0 ){
return 0;
@@ -1118,13 +1222,16 @@ int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
if( zName ){
for(i=0; i<p->nVar; i++){
const char *z = p->azVar[i];
- if( z && strcmp(z,zName)==0 ){
+ if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
return i+1;
}
}
}
return 0;
}
+int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
+ return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
+}
/*
** Transfer all bindings from the first statement over to the second.
@@ -1162,6 +1269,12 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
if( pFrom->nVar!=pTo->nVar ){
return SQLITE_ERROR;
}
+ if( pTo->isPrepareV2 && pTo->expmask ){
+ pTo->expired = 1;
+ }
+ if( pFrom->isPrepareV2 && pFrom->expmask ){
+ pFrom->expired = 1;
+ }
return sqlite3TransferBindings(pFromStmt, pToStmt);
}
#endif
@@ -1177,6 +1290,14 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
}
/*
+** Return true if the prepared statement is guaranteed to not modify the
+** database.
+*/
+int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+ return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
+}
+
+/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb. If pStmt is NULL, return the first
** prepared statement for the database connection. Return NULL if there
« no previous file with comments | « third_party/sqlite/src/src/vdbeInt.h ('k') | third_party/sqlite/src/src/vdbeaux.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698