mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-22 20:22:44 +03:00
Merge in all trunk changes up through the 3.7.17 release.
FossilOrigin-Name: 14ab6675e5eab3761256a06dad23d2b11220788a
This commit is contained in:
51
src/btree.c
51
src/btree.c
@@ -2517,6 +2517,29 @@ page1_init_failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** Return the number of cursors open on pBt. This is for use
|
||||
** in assert() expressions, so it is only compiled if NDEBUG is not
|
||||
** defined.
|
||||
**
|
||||
** Only write cursors are counted if wrOnly is true. If wrOnly is
|
||||
** false then all cursors are counted.
|
||||
**
|
||||
** For the purposes of this routine, a cursor is any cursor that
|
||||
** is capable of reading or writing to the databse. Cursors that
|
||||
** have been tripped into the CURSOR_FAULT state are not counted.
|
||||
*/
|
||||
static int countValidCursors(BtShared *pBt, int wrOnly){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If there are no outstanding cursors and we are not in the middle
|
||||
** of a transaction but there is a read lock on the database, then
|
||||
@@ -2527,7 +2550,7 @@ page1_init_failed:
|
||||
*/
|
||||
static void unlockBtreeIfUnused(BtShared *pBt){
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
assert( pBt->pCursor==0 || pBt->inTransaction>TRANS_NONE );
|
||||
assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE );
|
||||
if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){
|
||||
assert( pBt->pPage1->aData );
|
||||
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
|
||||
@@ -3255,7 +3278,6 @@ static void btreeEndTransaction(Btree *p){
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
pBt->bDoTruncate = 0;
|
||||
#endif
|
||||
btreeClearHasContent(pBt);
|
||||
if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
|
||||
/* If there are other active statements that belong to this database
|
||||
** handle, downgrade to a read-only transaction. The other statements
|
||||
@@ -3330,6 +3352,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
||||
return rc;
|
||||
}
|
||||
pBt->inTransaction = TRANS_READ;
|
||||
btreeClearHasContent(pBt);
|
||||
}
|
||||
|
||||
btreeEndTransaction(p);
|
||||
@@ -3351,27 +3374,6 @@ int sqlite3BtreeCommit(Btree *p){
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** Return the number of write-cursors open on this handle. This is for use
|
||||
** in assert() expressions, so it is only compiled if NDEBUG is not
|
||||
** defined.
|
||||
**
|
||||
** For the purposes of this routine, a write-cursor is any cursor that
|
||||
** is capable of writing to the databse. That means the cursor was
|
||||
** originally opened for writing and the cursor has not be disabled
|
||||
** by having its state changed to CURSOR_FAULT.
|
||||
*/
|
||||
static int countWriteCursors(BtShared *pBt){
|
||||
BtCursor *pCur;
|
||||
int r = 0;
|
||||
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
||||
if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine sets the state to CURSOR_FAULT and the error
|
||||
** code to errCode for every cursor on BtShared that pBtree
|
||||
@@ -3451,8 +3453,9 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
|
||||
pBt->nPage = nPage;
|
||||
releasePage(pPage1);
|
||||
}
|
||||
assert( countWriteCursors(pBt)==0 );
|
||||
assert( countValidCursors(pBt, 1)==0 );
|
||||
pBt->inTransaction = TRANS_READ;
|
||||
btreeClearHasContent(pBt);
|
||||
}
|
||||
|
||||
btreeEndTransaction(p);
|
||||
|
||||
18
src/build.c
18
src/build.c
@@ -2659,10 +2659,8 @@ Index *sqlite3CreateIndex(
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
if( pExpr ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( pColl ){
|
||||
nExtra += (1 + sqlite3Strlen30(pColl->zName));
|
||||
}
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2723,7 +2721,6 @@ Index *sqlite3CreateIndex(
|
||||
const char *zColName = pListItem->zName;
|
||||
Column *pTabCol;
|
||||
int requestedSortOrder;
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
char *zColl; /* Collation sequence name */
|
||||
|
||||
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
|
||||
@@ -2736,11 +2733,10 @@ Index *sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->aiColumn[i] = j;
|
||||
if( pListItem->pExpr
|
||||
&& (pColl = sqlite3ExprCollSeq(pParse, pListItem->pExpr))!=0
|
||||
){
|
||||
if( pListItem->pExpr ){
|
||||
int nColl;
|
||||
zColl = pColl->zName;
|
||||
assert( pListItem->pExpr->op==TK_COLLATE );
|
||||
zColl = pListItem->pExpr->u.zToken;
|
||||
nColl = sqlite3Strlen30(zColl) + 1;
|
||||
assert( nExtra>=nColl );
|
||||
memcpy(zExtra, zColl, nColl);
|
||||
@@ -2749,9 +2745,7 @@ Index *sqlite3CreateIndex(
|
||||
nExtra -= nColl;
|
||||
}else{
|
||||
zColl = pTab->aCol[j].zColl;
|
||||
if( !zColl ){
|
||||
zColl = "BINARY";
|
||||
}
|
||||
if( !zColl ) zColl = "BINARY";
|
||||
}
|
||||
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
goto exit_create_index;
|
||||
|
||||
@@ -116,12 +116,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
|
||||
if( op==TK_COLLATE ){
|
||||
if( db->init.busy ){
|
||||
/* Do not report errors when parsing while the schema */
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), p->u.zToken, 0);
|
||||
}else{
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
}
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
if( p->pTab!=0
|
||||
|
||||
16
src/main.c
16
src/main.c
@@ -902,6 +902,12 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
** go ahead and free all resources.
|
||||
*/
|
||||
|
||||
/* If a transaction is open, roll it back. This also ensures that if
|
||||
** any database schemas have been modified by an uncommitted transaction
|
||||
** they are reset. And that the required b-tree mutex is held to make
|
||||
** the pager rollback and schema reset an atomic operation. */
|
||||
sqlite3RollbackAll(db, SQLITE_OK);
|
||||
|
||||
/* Free any outstanding Savepoint structures. */
|
||||
sqlite3CloseSavepoints(db);
|
||||
|
||||
@@ -1002,6 +1008,15 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
int inTrans = 0;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
sqlite3BeginBenignMalloc();
|
||||
|
||||
/* Obtain all b-tree mutexes before making any calls to BtreeRollback().
|
||||
** This is important in case the transaction being rolled back has
|
||||
** modified the database schema. If the b-tree mutexes are not taken
|
||||
** here, then another shared-cache connection might sneak in between
|
||||
** the database rollback and schema reset, which can cause false
|
||||
** corruption reports in some cases. */
|
||||
sqlite3BtreeEnterAll(db);
|
||||
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *p = db->aDb[i].pBt;
|
||||
if( p ){
|
||||
@@ -1019,6 +1034,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
|
||||
/* Any deferred constraint violations have now been resolved. */
|
||||
db->nDeferredCons = 0;
|
||||
|
||||
@@ -5153,7 +5153,7 @@ static int fillInUnixFile(
|
||||
pNew->pVfs = pVfs;
|
||||
pNew->zPath = zFilename;
|
||||
pNew->ctrlFlags = (u8)ctrlFlags;
|
||||
pNew->mmapSizeMax = sqlite3GlobalConfig.mxMmap;
|
||||
pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
|
||||
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
pNew->ctrlFlags |= UNIXFILE_PSOW;
|
||||
|
||||
@@ -2937,8 +2937,6 @@ static int winDeviceCharacteristics(sqlite3_file *id){
|
||||
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
/*
|
||||
** Windows will only let you create file view mappings
|
||||
** on allocation size granularity boundaries.
|
||||
@@ -2947,6 +2945,8 @@ static int winDeviceCharacteristics(sqlite3_file *id){
|
||||
*/
|
||||
SYSTEM_INFO winSysInfo;
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
/*
|
||||
** Helper functions to obtain and relinquish the global mutex. The
|
||||
** global mutex is used to protect the winLockInfo objects used by
|
||||
@@ -4246,7 +4246,7 @@ static int winOpen(
|
||||
pFile->pMapRegion = 0;
|
||||
pFile->mmapSize = 0;
|
||||
pFile->mmapSizeActual = 0;
|
||||
pFile->mmapSizeMax = sqlite3GlobalConfig.mxMmap;
|
||||
pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
#endif
|
||||
|
||||
OpenCounter(+1);
|
||||
|
||||
@@ -1159,8 +1159,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
** re-evaluated for each reference to it.
|
||||
*/
|
||||
sNC.pEList = p->pEList;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
||||
sNC.ncFlags |= NC_AsMaybe;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
||||
sNC.ncFlags &= ~NC_AsMaybe;
|
||||
|
||||
|
||||
25
src/test1.c
25
src/test1.c
@@ -681,6 +681,30 @@ static int sqlite_test_close(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_close_v2 DB
|
||||
**
|
||||
** Closes the database opened by sqlite3_open.
|
||||
*/
|
||||
static int sqlite_test_close_v2(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" FILENAME\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||
rc = sqlite3_close_v2(db);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the x_coalesce() function.
|
||||
** Return the first argument non-NULL argument.
|
||||
@@ -6077,6 +6101,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
|
||||
#endif
|
||||
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
|
||||
{ "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 },
|
||||
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
|
||||
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate },
|
||||
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func },
|
||||
|
||||
@@ -69,13 +69,13 @@
|
||||
** the xNextSystemCall() VFS method.
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "sqlite3.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#if SQLITE_OS_UNIX
|
||||
|
||||
/* From main.c */
|
||||
|
||||
@@ -142,14 +142,14 @@ char *sqlite3VdbeExpandSql(
|
||||
#endif
|
||||
nOut = pVar->n;
|
||||
#ifdef SQLITE_TRACE_SIZE_LIMIT
|
||||
if( n>SQLITE_TRACE_SIZE_LIMIT ){
|
||||
if( nOut>SQLITE_TRACE_SIZE_LIMIT ){
|
||||
nOut = SQLITE_TRACE_SIZE_LIMIT;
|
||||
while( nOut<pVar->n && (pVar->z[n]&0xc0)==0x80 ){ n++; }
|
||||
while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
|
||||
}
|
||||
#endif
|
||||
sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
|
||||
#ifdef SQLITE_TRACE_SIZE_LIMIT
|
||||
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
|
||||
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
|
||||
@@ -169,7 +169,7 @@ char *sqlite3VdbeExpandSql(
|
||||
}
|
||||
sqlite3StrAccumAppend(&out, "'", 1);
|
||||
#ifdef SQLITE_TRACE_SIZE_LIMIT
|
||||
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-n);
|
||||
if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user