Snapshot of upstream SQLite 3.25.0

This commit is contained in:
Stephen Lombardo
2018-09-18 12:31:37 -04:00
parent 1f3bc22483
commit bf3fa86130
558 changed files with 76379 additions and 20890 deletions
+1211 -429
View File
File diff suppressed because it is too large Load Diff
+31 -6
View File
@@ -234,6 +234,10 @@ static void openStatTable(
"DELETE FROM %Q.%s WHERE %s=%Q",
pDb->zDbSName, zTab, zWhereType, zWhere
);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
}else if( db->xPreUpdateCallback ){
sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
#endif
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
@@ -481,6 +485,7 @@ static const FuncDef statInitFuncdef = {
0, /* pNext */
statInit, /* xSFunc */
0, /* xFinalize */
0, 0, /* xValue, xInverse */
"stat_init", /* zName */
{0}
};
@@ -797,6 +802,7 @@ static const FuncDef statPushFuncdef = {
0, /* pNext */
statPush, /* xSFunc */
0, /* xFinalize */
0, 0, /* xValue, xInverse */
"stat_push", /* zName */
{0}
};
@@ -948,6 +954,7 @@ static const FuncDef statGetFuncdef = {
0, /* pNext */
statGet, /* xSFunc */
0, /* xFinalize */
0, 0, /* xValue, xInverse */
"stat_get", /* zName */
{0}
};
@@ -998,6 +1005,9 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
pParse->nMem = MAX(pParse->nMem, iMem);
v = sqlite3GetVdbe(pParse);
@@ -1008,7 +1018,7 @@ static void analyzeOneTable(
/* Do not gather statistics on views or virtual tables */
return;
}
if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){
/* Do not gather statistics on system tables */
return;
}
@@ -1023,6 +1033,18 @@ static void analyzeOneTable(
}
#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
if( db->xPreUpdateCallback ){
pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
if( pStat1==0 ) return;
pStat1->zName = (char*)&pStat1[1];
memcpy(pStat1->zName, "sqlite_stat1", 13);
pStat1->nCol = 3;
pStat1->iPKey = -1;
sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
}
#endif
/* Establish a read-lock on the table at the shared-cache level.
** Open a read-only cursor on the table. Also allocate a cursor number
** to use for scanning indexes (iIdxCur). No index cursor is opened at
@@ -1224,6 +1246,9 @@ static void analyzeOneTable(
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
#endif
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
/* Add the entries to the stat3 or stat4 table. */
@@ -1249,10 +1274,7 @@ static void analyzeOneTable(
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
/* We know that the regSampleRowid row exists because it was read by
** the previous loop. Thus the not-found jump of seekOp will never
** be taken */
VdbeCoverageNeverTaken(v);
VdbeCoverage(v);
#ifdef SQLITE_ENABLE_STAT3
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
#else
@@ -1287,6 +1309,9 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
#endif
sqlite3VdbeJumpHere(v, jZeroRows);
}
}
@@ -1889,7 +1914,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
if( rc==SQLITE_OK ){
db->lookaside.bDisable++;
rc = loadStat4(db, sInfo.zDatabase);
db->lookaside.bDisable--;
+123 -81
View File
@@ -55,6 +55,10 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
**
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
** third argument.
**
** If the db->init.reopenMemdb flags is set, then instead of attaching a
** new database, close the database on db->init.iDb and reopen it as an
** empty MemDB.
*/
static void attachFunc(
sqlite3_context *context,
@@ -75,70 +79,86 @@ static void attachFunc(
sqlite3_vfs *pVfs;
UNUSED_PARAMETER(NotUsed);
zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]);
if( zFile==0 ) zFile = "";
if( zName==0 ) zName = "";
/* Check for the following errors:
**
** * Too many attached databases,
** * Transaction currently open
** * Specified database name already being used.
*/
if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
db->aLimit[SQLITE_LIMIT_ATTACHED]
);
goto attach_error;
}
if( !db->autoCommit ){
zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
#ifdef SQLITE_ENABLE_DESERIALIZE
# define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb)
#else
# define REOPEN_AS_MEMDB(db) (0)
#endif
if( REOPEN_AS_MEMDB(db) ){
/* This is not a real ATTACH. Instead, this routine is being called
** from sqlite3_deserialize() to close database db->init.iDb and
** reopen it as a MemDB */
pVfs = sqlite3_vfs_find("memdb");
if( pVfs==0 ) return;
pNew = &db->aDb[db->init.iDb];
if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
pNew->pBt = 0;
pNew->pSchema = 0;
rc = sqlite3BtreeOpen(pVfs, "x", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
}else{
/* This is a real ATTACH
**
** Check for the following errors:
**
** * Too many attached databases,
** * Transaction currently open
** * Specified database name already being used.
*/
if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
db->aLimit[SQLITE_LIMIT_ATTACHED]
);
goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
goto attach_error;
}
}
/* Allocate the new entry in the db->aDb[] array and initialize the schema
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
pNew = &db->aDb[db->nDb];
memset(pNew, 0, sizeof(*pNew));
/* Open the database file. If the btree is successfully opened, use
** it to obtain the database schema. At this point the schema may
** or may not be initialized.
*/
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
return;
}
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
sqlite3_free( zPath );
db->nDb++;
}
/* Allocate the new entry in the db->aDb[] array and initialize the schema
** hash tables.
*/
if( db->aDb==db->aDbStatic ){
aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
if( aNew==0 ) return;
memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
}else{
aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
if( aNew==0 ) return;
}
db->aDb = aNew;
pNew = &db->aDb[db->nDb];
memset(pNew, 0, sizeof(*pNew));
/* Open the database file. If the btree is successfully opened, use
** it to obtain the database schema. At this point the schema may
** or may not be initialized.
*/
flags = db->openFlags;
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
return;
}
assert( pVfs );
flags |= SQLITE_OPEN_MAIN_DB;
rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
sqlite3_free( zPath );
db->nDb++;
db->skipBtreeMutex = 0;
db->noSharedCache = 0;
if( rc==SQLITE_CONSTRAINT ){
rc = SQLITE_ERROR;
zErrDyn = sqlite3MPrintf(db, "database is already attached");
@@ -164,7 +184,7 @@ static void attachFunc(
sqlite3BtreeLeave(pNew->pBt);
}
pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
pNew->zDbSName = sqlite3DbStrDup(db, zName);
if( !REOPEN_AS_MEMDB(db) ) pNew->zDbSName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && pNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT;
}
@@ -204,13 +224,16 @@ static void attachFunc(
/* If the file was opened successfully, read the schema for the new database.
** If this fails, or if opening the file failed, then close the file and
** remove the entry from the db->aDb[] array. i.e. put everything back the way
** we found it.
** remove the entry from the db->aDb[] array. i.e. put everything back the
** way we found it.
*/
if( rc==SQLITE_OK ){
sqlite3BtreeEnterAll(db);
db->init.iDb = 0;
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
rc = sqlite3Init(db, &zErrDyn);
sqlite3BtreeLeaveAll(db);
assert( zErrDyn==0 || rc!=SQLITE_OK );
}
#ifdef SQLITE_USER_AUTHENTICATION
if( rc==SQLITE_OK ){
@@ -222,21 +245,23 @@ static void attachFunc(
}
#endif
if( rc ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
if( db->aDb[iDb].pBt ){
sqlite3BtreeClose(db->aDb[iDb].pBt);
db->aDb[iDb].pBt = 0;
db->aDb[iDb].pSchema = 0;
}
sqlite3ResetAllSchemasOfConnection(db);
db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
sqlite3DbFree(db, zErrDyn);
zErrDyn = sqlite3MPrintf(db, "out of memory");
}else if( zErrDyn==0 ){
zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
if( !REOPEN_AS_MEMDB(db) ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
if( db->aDb[iDb].pBt ){
sqlite3BtreeClose(db->aDb[iDb].pBt);
db->aDb[iDb].pBt = 0;
db->aDb[iDb].pSchema = 0;
}
sqlite3ResetAllSchemasOfConnection(db);
db->nDb = iDb;
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
sqlite3DbFree(db, zErrDyn);
zErrDyn = sqlite3MPrintf(db, "out of memory");
}else if( zErrDyn==0 ){
zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
}
}
goto attach_error;
}
@@ -288,11 +313,6 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
if( !db->autoCommit ){
sqlite3_snprintf(sizeof(zErr), zErr,
"cannot DETACH database within transaction");
goto detach_error;
}
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
@@ -394,6 +414,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
0, /* pNext */
detachFunc, /* xSFunc */
0, /* xFinalize */
0, 0, /* xValue, xInverse */
"sqlite_detach", /* zName */
{0}
};
@@ -413,6 +434,7 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
0, /* pNext */
attachFunc, /* xSFunc */
0, /* xFinalize */
0, 0, /* xValue, xInverse */
"sqlite_attach", /* zName */
{0}
};
@@ -483,6 +505,9 @@ int sqlite3FixSrcList(
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
return 1;
}
}
return 0;
}
@@ -513,8 +538,13 @@ int sqlite3FixSelect(
if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
return 1;
}
if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
return 1;
if( pSelect->pWith ){
int i;
for(i=0; i<pSelect->pWith->nCte; i++){
if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){
return 1;
}
}
}
pSelect = pSelect->pPrior;
}
@@ -577,6 +607,18 @@ int sqlite3FixTriggerStep(
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
#ifndef SQLITE_OMIT_UPSERT
if( pStep->pUpsert ){
Upsert *pUp = pStep->pUpsert;
if( sqlite3FixExprList(pFix, pUp->pUpsertTarget)
|| sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere)
|| sqlite3FixExprList(pFix, pUp->pUpsertSet)
|| sqlite3FixExpr(pFix, pUp->pUpsertWhere)
){
return 1;
}
}
#endif
pStep = pStep->pNext;
}
return 0;
+6 -8
View File
@@ -78,7 +78,7 @@ int sqlite3_set_authorizer(
sqlite3_mutex_enter(db->mutex);
db->xAuth = (sqlite3_xauth)xAuth;
db->pAuthArg = pArg;
sqlite3ExpirePreparedStatements(db);
sqlite3ExpirePreparedStatements(db, 0);
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -118,11 +118,9 @@ int sqlite3AuthReadCol(
#endif
);
if( rc==SQLITE_DENY ){
if( db->nDb>2 || iDb!=0 ){
sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
}else{
sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
}
char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse);
@@ -152,6 +150,7 @@ void sqlite3AuthRead(
int iDb; /* The index of the database the expression refers to */
int iCol; /* Index of column in table */
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
if( db->xAuth==0 ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
if( iDb<0 ){
@@ -160,7 +159,6 @@ void sqlite3AuthRead(
return;
}
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
if( pExpr->op==TK_TRIGGER ){
pTab = pParse->pTriggerTab;
}else{
@@ -209,7 +207,7 @@ int sqlite3AuthCheck(
/* Don't do any authorization checks if the database is initialising
** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
if( db->init.busy || IN_DECLARE_VTAB ){
if( db->init.busy || IN_SPECIAL_PARSE ){
return SQLITE_OK;
}
+3 -3
View File
@@ -382,7 +382,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** before this function exits.
*/
if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
bCloseTrans = 1;
}
@@ -398,10 +398,10 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
(int*)&p->iDestSchema))
){
p->bDestLocked = 1;
sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
}
/* Do not allow backup if the destination database is in WAL mode
+3 -3
View File
@@ -195,10 +195,10 @@ static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
skipOk = 0;
}
}
db->skipBtreeMutex = skipOk;
db->noSharedCache = skipOk;
}
void sqlite3BtreeEnterAll(sqlite3 *db){
if( db->skipBtreeMutex==0 ) btreeEnterAll(db);
if( db->noSharedCache==0 ) btreeEnterAll(db);
}
static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
int i;
@@ -210,7 +210,7 @@ static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
}
}
void sqlite3BtreeLeaveAll(sqlite3 *db){
if( db->skipBtreeMutex==0 ) btreeLeaveAll(db);
if( db->noSharedCache==0 ) btreeLeaveAll(db);
}
#ifndef NDEBUG
+616 -296
View File
File diff suppressed because it is too large Load Diff
+26 -4
View File
@@ -78,7 +78,7 @@ int sqlite3BtreeGetOptimalReserve(Btree*);
int sqlite3BtreeGetReserveNoMutex(Btree *p);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeBeginTrans(Btree*,int,int*);
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*);
@@ -230,6 +230,7 @@ int sqlite3BtreeCursor(
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
);
BtCursor *sqlite3BtreeFakeValidCursor(void);
int sqlite3BtreeCursorSize(void);
void sqlite3BtreeCursorZero(BtCursor*);
void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
@@ -258,13 +259,28 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
** entry in either an index or table btree.
**
** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
** an arbitrary key and no data. These btrees have pKey,nKey set to their
** key and pData,nData,nZero set to zero.
** an arbitrary key and no data. These btrees have pKey,nKey set to the
** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem
** fields give an array of Mem objects that are a decomposition of the key.
** The nMem field might be zero, indicating that no decomposition is available.
**
** Table btrees (used for rowid tables) contain an integer rowid used as
** the key and passed in the nKey field. The pKey field is zero.
** pData,nData hold the content of the new entry. nZero extra zero bytes
** are appended to the end of the content when constructing the entry.
** The aMem,nMem fields are uninitialized for table btrees.
**
** Field usage summary:
**
** Table BTrees Index Btrees
**
** pKey always NULL encoded key
** nKey the ROWID length of pKey
** pData data not used
** aMem not used decomposed key value
** nMem not used entries in aMem
** nData length of pData not used
** nZero extra zeros after pData not used
**
** This object is used to pass information into sqlite3BtreeInsert(). The
** same information used to be passed as five separate parameters. But placing
@@ -275,7 +291,7 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
struct BtreePayload {
const void *pKey; /* Key content for indexes. NULL for tables */
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
const void *pData; /* Data for tables. NULL for indexes */
const void *pData; /* Data for tables. */
sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
u16 nMem; /* Number of aMem[] value. Might be zero */
int nData; /* Size of pData. 0 if none. */
@@ -285,11 +301,17 @@ struct BtreePayload {
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int flags, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3BtreeSkipNext(BtCursor*);
#endif
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int flags);
i64 sqlite3BtreeIntegerKey(BtCursor*);
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
i64 sqlite3BtreeOffset(BtCursor*);
#endif
int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
+16 -15
View File
@@ -499,30 +499,31 @@ struct CellInfo {
** eState==FAULT: Cursor fault with skipNext as error code.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext; /* Forms a linked list of all cursors */
Pgno *aOverflow; /* Cache of overflow page locations */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 hints; /* As configured by CursorSetHints() */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
Btree *pBtree; /* The Btree to which this cursor belongs */
Pgno *aOverflow; /* Cache of overflow page locations */
void *pKey; /* Saved key that was cursor last known position */
/* All fields above are zeroed when the cursor is allocated. See
** sqlite3BtreeCursorZero(). Fields that follow must be manually
** initialized. */
#define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */
BtShared *pBt; /* The BtShared this cursor points to */
BtCursor *pNext; /* Forms a linked list of all cursors */
CellInfo info; /* A parse of the cell we are pointing at */
i64 nKey; /* Size of pKey, or last integer key */
Pgno pgnoRoot; /* The root page of this tree */
i8 iPage; /* Index of current page in apPage */
u8 curIntKey; /* Value of apPage[0]->intKey */
u16 ix; /* Current index for apPage[iPage] */
u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
MemPage *pPage; /* Current page */
MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
};
/*
@@ -565,8 +566,8 @@ struct BtCursor {
** Do nothing else with this cursor. Any attempt to use the cursor
** should return the error code stored in BtCursor.skipNext
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_VALID 0
#define CURSOR_INVALID 1
#define CURSOR_SKIPNEXT 2
#define CURSOR_REQUIRESEEK 3
#define CURSOR_FAULT 4
+347 -212
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -105,6 +105,7 @@ CollSeq *sqlite3GetCollSeq(
assert( !p || p->xCmp );
if( p==0 ){
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
}
return p;
}
@@ -374,7 +375,7 @@ FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
** If the SQLITE_PreferBuiltin flag is set, then search the built-in
** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
@@ -384,7 +385,7 @@ FuncDef *sqlite3FindFunction(
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
@@ -405,10 +406,12 @@ FuncDef *sqlite3FindFunction(
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
u8 *z;
pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy((char*)&pBest[1], zName, nName+1);
for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z];
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
@@ -457,8 +460,8 @@ void sqlite3SchemaClear(void *p){
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
/*
+14 -2
View File
@@ -30,6 +30,12 @@
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
** option requires a separate macro because legal values contain a single
** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
/*
** An array of names of all compile-time options. This array should
** be sorted A-Z.
@@ -113,7 +119,7 @@ static const char * const sqlite3azCompileOpt[] = {
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#ifdef SQLITE_DEFAULT_LOOKASIDE
"DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE),
"DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
#endif
#if SQLITE_DEFAULT_MEMSTATUS
"DEFAULT_MEMSTATUS",
@@ -184,8 +190,11 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE",
#endif
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
"ENABLE_BATCH_ATOMIC_WRITE",
#endif
#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD",
"ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
#endif
#if SQLITE_ENABLE_COLUMN_METADATA
"ENABLE_COLUMN_METADATA",
@@ -283,6 +292,9 @@ static const char * const sqlite3azCompileOpt[] = {
#if SQLITE_ENABLE_SNAPSHOT
"ENABLE_SNAPSHOT",
#endif
#if SQLITE_ENABLE_SORTER_REFERENCES
"ENABLE_SORTER_REFERENCES",
#endif
#if SQLITE_ENABLE_SQLLOG
"ENABLE_SQLLOG",
#endif
+1 -1
View File
@@ -39,7 +39,7 @@
**
** Jean Meeus
** Astronomical Algorithms, 2nd Edition, 1998
** ISBM 0-943396-61-1
** ISBN 0-943396-61-1
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
+411
View File
@@ -0,0 +1,411 @@
/*
** 2017-10-11
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains an implementation of the "sqlite_dbpage" virtual table.
**
** The sqlite_dbpage virtual table is used to read or write whole raw
** pages of the database file. The pager interface is used so that
** uncommitted changes and changes recorded in the WAL file are correctly
** retrieved.
**
** Usage example:
**
** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
**
** This is an eponymous virtual table so it does not need to be created before
** use. The optional argument to the sqlite_dbpage() table name is the
** schema for the database file that is to be read. The default schema is
** "main".
**
** The data field of sqlite_dbpage table can be updated. The new
** value must be a BLOB which is the correct page size, otherwise the
** update fails. Rows may not be deleted or inserted.
*/
#include "sqliteInt.h" /* Requires access to internal data structures */
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
typedef struct DbpageTable DbpageTable;
typedef struct DbpageCursor DbpageCursor;
struct DbpageCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
int pgno; /* Current page number */
int mxPgno; /* Last page to visit on this scan */
Pager *pPager; /* Pager being read/written */
DbPage *pPage1; /* Page 1 of the database */
int iDb; /* Index of database to analyze */
int szPage; /* Size of each page in bytes */
};
struct DbpageTable {
sqlite3_vtab base; /* Base class. Must be first */
sqlite3 *db; /* The database */
};
/* Columns */
#define DBPAGE_COLUMN_PGNO 0
#define DBPAGE_COLUMN_DATA 1
#define DBPAGE_COLUMN_SCHEMA 2
/*
** Connect to or create a dbpagevfs virtual table.
*/
static int dbpageConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
DbpageTable *pTab = 0;
int rc = SQLITE_OK;
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
}
assert( rc==SQLITE_OK || pTab==0 );
if( rc==SQLITE_OK ){
memset(pTab, 0, sizeof(DbpageTable));
pTab->db = db;
}
*ppVtab = (sqlite3_vtab*)pTab;
return rc;
}
/*
** Disconnect from or destroy a dbpagevfs virtual table.
*/
static int dbpageDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
return SQLITE_OK;
}
/*
** idxNum:
**
** 0 schema=main, full table scan
** 1 schema=main, pgno=?1
** 2 schema=?1, full table scan
** 3 schema=?1, pgno=?2
*/
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int i;
int iPlan = 0;
/* If there is a schema= constraint, it must be honored. Report a
** ridiculously large estimated cost if the schema= constraint is
** unavailable
*/
for(i=0; i<pIdxInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
if( !p->usable ){
/* No solution. Use the default SQLITE_BIG_DBL cost */
pIdxInfo->estimatedRows = 0x7fffffff;
return SQLITE_OK;
}
iPlan = 2;
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
pIdxInfo->aConstraintUsage[i].omit = 1;
break;
}
/* If we reach this point, it means that either there is no schema=
** constraint (in which case we use the "main" schema) or else the
** schema constraint was accepted. Lower the estimated cost accordingly
*/
pIdxInfo->estimatedCost = 1.0e6;
/* Check for constraints against pgno */
for(i=0; i<pIdxInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
pIdxInfo->estimatedRows = 1;
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
pIdxInfo->estimatedCost = 1.0;
pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
pIdxInfo->aConstraintUsage[i].omit = 1;
iPlan |= 1;
break;
}
}
pIdxInfo->idxNum = iPlan;
if( pIdxInfo->nOrderBy>=1
&& pIdxInfo->aOrderBy[0].iColumn<=0
&& pIdxInfo->aOrderBy[0].desc==0
){
pIdxInfo->orderByConsumed = 1;
}
return SQLITE_OK;
}
/*
** Open a new dbpagevfs cursor.
*/
static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
DbpageCursor *pCsr;
pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
if( pCsr==0 ){
return SQLITE_NOMEM_BKPT;
}else{
memset(pCsr, 0, sizeof(DbpageCursor));
pCsr->base.pVtab = pVTab;
pCsr->pgno = -1;
}
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
return SQLITE_OK;
}
/*
** Close a dbpagevfs cursor.
*/
static int dbpageClose(sqlite3_vtab_cursor *pCursor){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
sqlite3_free(pCsr);
return SQLITE_OK;
}
/*
** Move a dbpagevfs cursor to the next entry in the file.
*/
static int dbpageNext(sqlite3_vtab_cursor *pCursor){
int rc = SQLITE_OK;
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
pCsr->pgno++;
return rc;
}
static int dbpageEof(sqlite3_vtab_cursor *pCursor){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
return pCsr->pgno > pCsr->mxPgno;
}
/*
** idxNum:
**
** 0 schema=main, full table scan
** 1 schema=main, pgno=?1
** 2 schema=?1, full table scan
** 3 schema=?1, pgno=?2
**
** idxStr is not used
*/
static int dbpageFilter(
sqlite3_vtab_cursor *pCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
int rc;
sqlite3 *db = pTab->db;
Btree *pBt;
/* Default setting is no rows of result */
pCsr->pgno = 1;
pCsr->mxPgno = 0;
if( idxNum & 2 ){
const char *zSchema;
assert( argc>=1 );
zSchema = (const char*)sqlite3_value_text(argv[0]);
pCsr->iDb = sqlite3FindDbName(db, zSchema);
if( pCsr->iDb<0 ) return SQLITE_OK;
}else{
pCsr->iDb = 0;
}
pBt = db->aDb[pCsr->iDb].pBt;
if( pBt==0 ) return SQLITE_OK;
pCsr->pPager = sqlite3BtreePager(pBt);
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
if( idxNum & 1 ){
assert( argc>(idxNum>>1) );
pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
pCsr->pgno = 1;
pCsr->mxPgno = 0;
}else{
pCsr->mxPgno = pCsr->pgno;
}
}else{
assert( pCsr->pgno==1 );
}
if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
return rc;
}
static int dbpageColumn(
sqlite3_vtab_cursor *pCursor,
sqlite3_context *ctx,
int i
){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
int rc = SQLITE_OK;
switch( i ){
case 0: { /* pgno */
sqlite3_result_int(ctx, pCsr->pgno);
break;
}
case 1: { /* data */
DbPage *pDbPage = 0;
rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
SQLITE_TRANSIENT);
}
sqlite3PagerUnref(pDbPage);
break;
}
default: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
break;
}
}
return SQLITE_OK;
}
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
*pRowid = pCsr->pgno;
return SQLITE_OK;
}
static int dbpageUpdate(
sqlite3_vtab *pVtab,
int argc,
sqlite3_value **argv,
sqlite_int64 *pRowid
){
DbpageTable *pTab = (DbpageTable *)pVtab;
Pgno pgno;
DbPage *pDbPage = 0;
int rc = SQLITE_OK;
char *zErr = 0;
const char *zSchema;
int iDb;
Btree *pBt;
Pager *pPager;
int szPage;
if( argc==1 ){
zErr = "cannot delete";
goto update_fail;
}
pgno = sqlite3_value_int(argv[0]);
if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
zErr = "cannot insert";
goto update_fail;
}
zSchema = (const char*)sqlite3_value_text(argv[4]);
iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
if( iDb<0 ){
zErr = "no such schema";
goto update_fail;
}
pBt = pTab->db->aDb[iDb].pBt;
if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
zErr = "bad page number";
goto update_fail;
}
szPage = sqlite3BtreeGetPageSize(pBt);
if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|| sqlite3_value_bytes(argv[3])!=szPage
){
zErr = "bad page value";
goto update_fail;
}
pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
memcpy(sqlite3PagerGetData(pDbPage),
sqlite3_value_blob(argv[3]),
szPage);
}
}
sqlite3PagerUnref(pDbPage);
return rc;
update_fail:
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
return SQLITE_ERROR;
}
/* Since we do not know in advance which database files will be
** written by the sqlite_dbpage virtual table, start a write transaction
** on them all.
*/
static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab;
sqlite3 *db = pTab->db;
int i;
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
}
return SQLITE_OK;
}
/*
** Invoke this routine to register the "dbpage" virtual table module
*/
int sqlite3DbpageRegister(sqlite3 *db){
static sqlite3_module dbpage_module = {
0, /* iVersion */
dbpageConnect, /* xCreate */
dbpageConnect, /* xConnect */
dbpageBestIndex, /* xBestIndex */
dbpageDisconnect, /* xDisconnect */
dbpageDisconnect, /* xDestroy */
dbpageOpen, /* xOpen - open a cursor */
dbpageClose, /* xClose - close a cursor */
dbpageFilter, /* xFilter - configure scan constraints */
dbpageNext, /* xNext - advance a cursor */
dbpageEof, /* xEof - check for end of scan */
dbpageColumn, /* xColumn - read data */
dbpageRowid, /* xRowid - read data */
dbpageUpdate, /* xUpdate */
dbpageBegin, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
};
return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+1 -1
View File
@@ -424,7 +424,7 @@ static void statSizeAndOffset(StatCursor *pCsr){
*/
fd = sqlite3PagerFile(pPager);
x[0] = pCsr->iPageno;
if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
pCsr->iOffset = x[0];
pCsr->szPage = (int)x[1];
}
+91 -49
View File
@@ -90,6 +90,8 @@ void sqlite3MaterializeView(
Parse *pParse, /* Parsing context */
Table *pView, /* View definition */
Expr *pWhere, /* Optional WHERE clause to be added */
ExprList *pOrderBy, /* Optional ORDER BY clause */
Expr *pLimit, /* Optional LIMIT clause */
int iCur /* Cursor number for ephemeral table */
){
SelectDest dest;
@@ -106,8 +108,8 @@ void sqlite3MaterializeView(
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0,
SF_IncludeHidden, 0, 0);
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
SF_IncludeHidden, pLimit);
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pSel, &dest);
sqlite3SelectDelete(db, pSel);
@@ -129,29 +131,29 @@ Expr *sqlite3LimitWhere(
Expr *pWhere, /* The WHERE clause. May be null */
ExprList *pOrderBy, /* The ORDER BY clause. May be null */
Expr *pLimit, /* The LIMIT clause. May be null */
Expr *pOffset, /* The OFFSET clause. May be null */
char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
){
Expr *pWhereRowid = NULL; /* WHERE rowid .. */
sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
Expr *pSelectRowid = NULL; /* SELECT rowid ... */
ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
Table *pTab;
/* Check that there isn't an ORDER BY without a LIMIT clause.
*/
if( pOrderBy && (pLimit == 0) ) {
if( pOrderBy && pLimit==0 ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
goto limit_where_cleanup;
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
return 0;
}
/* We only need to generate a select expression if there
** is a limit/offset term to enforce.
*/
if( pLimit == 0 ) {
/* if pLimit is null, pOffset will always be null as well. */
assert( pOffset == 0 );
return pWhere;
}
@@ -164,36 +166,47 @@ Expr *sqlite3LimitWhere(
** );
*/
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
if( pSelectRowid == 0 ) goto limit_where_cleanup;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
if( pEList == 0 ) goto limit_where_cleanup;
pTab = pSrc->a[0].pTab;
if( HasRowid(pTab) ){
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
pEList = sqlite3ExprListAppend(
pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
if( pPk->nKeyCol==1 ){
const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
pLhs = sqlite3Expr(db, TK_ID, zName);
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
}else{
int i;
for(i=0; i<pPk->nKeyCol; i++){
Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
pEList = sqlite3ExprListAppend(pParse, pEList, p);
}
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
if( pLhs ){
pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
}
}
}
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSrc->a[0].pTab = 0;
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup;
}
pSrc->a[0].pTab = pTab;
pSrc->a[0].pIBIndex = 0;
/* generate the SELECT expression tree. */
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
pOrderBy,0,pLimit,pOffset);
if( pSelect == 0 ) return 0;
pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
pOrderBy,0,pLimit
);
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0;
pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
limit_where_cleanup:
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
sqlite3ExprDelete(pParse->db, pLimit);
sqlite3ExprDelete(pParse->db, pOffset);
return 0;
}
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
/* && !defined(SQLITE_OMIT_SUBQUERY) */
@@ -208,7 +221,9 @@ limit_where_cleanup:
void sqlite3DeleteFrom(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table from which we should delete things */
Expr *pWhere /* The WHERE clause. May be null */
Expr *pWhere, /* The WHERE clause. May be null */
ExprList *pOrderBy, /* ORDER BY clause. May be null */
Expr *pLimit /* LIMIT clause. May be null */
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
@@ -223,7 +238,7 @@ void sqlite3DeleteFrom(
AuthContext sContext; /* Authorization context */
NameContext sNC; /* Name context to resolve expressions in */
int iDb; /* Database number */
int memCnt = -1; /* Memory cell used for change counting */
int memCnt = 0; /* Memory cell used for change counting */
int rcauth; /* Value returned by authorization callback */
int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
@@ -253,6 +268,7 @@ void sqlite3DeleteFrom(
}
assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect
@@ -267,16 +283,26 @@ void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#else
# define pTrigger 0
# define isView 0
#endif
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
if( !isView ){
pWhere = sqlite3LimitWhere(
pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE"
);
pOrderBy = 0;
pLimit = 0;
}
#endif
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
@@ -317,15 +343,19 @@ void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3BeginWriteOperation(pParse, bComplex, iDb);
/* If we are trying to delete from a view, realize that view into
** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
sqlite3MaterializeView(pParse, pTab,
pWhere, pOrderBy, pLimit, iTabCur
);
iDataCur = iIdxCur = iTabCur;
pOrderBy = 0;
pLimit = 0;
}
#endif
@@ -341,7 +371,10 @@ void sqlite3DeleteFrom(
/* Initialize the counter of the number of rows deleted, if
** we are counting rows.
*/
if( db->flags & SQLITE_CountRows ){
if( (db->flags & SQLITE_CountRows)!=0
&& !pParse->nested
&& !pParse->pTriggerTab
){
memCnt = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
}
@@ -369,7 +402,7 @@ void sqlite3DeleteFrom(
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1,
pTab->zName, P4_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
@@ -414,9 +447,10 @@ void sqlite3DeleteFrom(
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
/* Keep track of the number of rows to be deleted */
if( db->flags & SQLITE_CountRows ){
if( memCnt ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
@@ -429,9 +463,8 @@ void sqlite3DeleteFrom(
}
iKey = iPk;
}else{
iKey = pParse->nMem + 1;
iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
if( iKey>pParse->nMem ) pParse->nMem = iKey;
iKey = ++pParse->nMem;
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey);
}
if( eOnePass!=ONEPASS_OFF ){
@@ -502,7 +535,11 @@ void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
if( IsVirtual(pTab) ){
sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
}else{
sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
}
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
@@ -515,13 +552,16 @@ void sqlite3DeleteFrom(
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
sqlite3MayAbort(pParse);
if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
pParse->isMultiWrite = 0;
if( eOnePass==ONEPASS_SINGLE ){
sqlite3VdbeAddOp1(v, OP_Close, iTabCur);
if( sqlite3IsToplevel(pParse) ){
pParse->isMultiWrite = 0;
}
}
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
}else
#endif
{
@@ -555,7 +595,7 @@ void sqlite3DeleteFrom(
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
if( memCnt ){
sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
@@ -565,6 +605,10 @@ delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(db, pWhere);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
#endif
sqlite3DbFree(db, aToOpen);
return;
}
@@ -722,7 +766,7 @@ void sqlite3GenerateRowDelete(
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
if( pParse->nested==0 ){
if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
}
if( eMode!=ONEPASS_OFF ){
@@ -853,7 +897,6 @@ int sqlite3GenerateIndexKey(
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iSelfTab = iDataCur + 1;
sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
pParse->iSelfTab = 0;
@@ -900,6 +943,5 @@ int sqlite3GenerateIndexKey(
void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
if( iLabel ){
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
sqlite3ExprCachePop(pParse);
}
}
+436 -363
View File
File diff suppressed because it is too large Load Diff
+11 -3
View File
@@ -331,6 +331,12 @@ static void fkLookupParent(
int iCur = pParse->nTab - 1; /* Cursor number to use */
int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */
sqlite3VdbeVerifyAbortable(v,
(!pFKey->isDeferred
&& !(pParse->db->flags & SQLITE_DeferFKs)
&& !pParse->pToplevel
&& !pParse->isMultiWrite) ? OE_Abort : OE_Ignore);
/* If nIncr is less than zero, then check at runtime if there are any
** outstanding constraints to resolve. If there are not, there is no need
** to check if deleting this row resolves any outstanding violations.
@@ -704,11 +710,12 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
*/
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
sqlite3 *db = pParse->db;
if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){
if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){
int iSkip = 0;
Vdbe *v = sqlite3GetVdbe(pParse);
assert( v ); /* VDBE has already been allocated */
assert( pTab->pSelect==0 ); /* Not a view */
if( sqlite3FkReferences(pTab)==0 ){
/* Search for a deferred foreign key constraint for which this table
** is the child table. If one cannot be found, return without
@@ -725,7 +732,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
}
pParse->disableTriggers = 1;
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
pParse->disableTriggers = 0;
/* If the DELETE has generated immediate foreign key constraint
@@ -738,6 +745,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** constraints are violated.
*/
if( (db->flags & SQLITE_DeferFKs)==0 ){
sqlite3VdbeVerifyAbortable(v, OE_Abort);
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
@@ -1283,7 +1291,7 @@ static Trigger *fkActionTrigger(
sqlite3ExprListAppend(pParse, 0, pRaise),
sqlite3SrcListAppend(db, 0, &tFrom, 0),
pWhere,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0
);
pWhere = 0;
}
+206 -62
View File
@@ -35,6 +35,8 @@ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
** iteration of the aggregate loop.
*/
static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
assert( context->isError<=0 );
context->isError = -1;
context->skipFlag = 1;
}
@@ -101,8 +103,6 @@ static void lengthFunc(
int argc,
sqlite3_value **argv
){
int len;
assert( argc==1 );
UNUSED_PARAMETER(argc);
switch( sqlite3_value_type(argv[0]) ){
@@ -114,13 +114,17 @@ static void lengthFunc(
}
case SQLITE_TEXT: {
const unsigned char *z = sqlite3_value_text(argv[0]);
const unsigned char *z0;
unsigned char c;
if( z==0 ) return;
len = 0;
while( *z ){
len++;
SQLITE_SKIP_UTF8(z);
z0 = z;
while( (c = *z)!=0 ){
z++;
if( c>=0xc0 ){
while( (*z & 0xc0)==0x80 ){ z++; z0++; }
}
}
sqlite3_result_int(context, len);
sqlite3_result_int(context, (int)(z-z0));
break;
}
default: {
@@ -247,7 +251,7 @@ static void printfFunc(
x.apArg = argv+1;
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
str.printfFlags = SQLITE_PRINTF_SQLFUNC;
sqlite3XPrintf(&str, zFormat, &x);
sqlite3_str_appendf(&str, zFormat, &x);
n = str.nChar;
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
SQLITE_DYNAMIC);
@@ -698,16 +702,20 @@ static int patternCompare(
** c or cx.
*/
if( c<=0x80 ){
u32 cx;
char zStop[3];
int bMatch;
if( noCase ){
cx = sqlite3Toupper(c);
c = sqlite3Tolower(c);
zStop[0] = sqlite3Toupper(c);
zStop[1] = sqlite3Tolower(c);
zStop[2] = 0;
}else{
cx = c;
zStop[0] = c;
zStop[1] = 0;
}
while( (c2 = *(zString++))!=0 ){
if( c2!=c && c2!=cx ) continue;
while(1){
zString += strcspn((const char*)zString, zStop);
if( zString[0]==0 ) break;
zString++;
bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
if( bMatch!=SQLITE_NOMATCH ) return bMatch;
}
@@ -865,7 +873,8 @@ static void likeFunc(
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
sqlite3_result_int(context,
patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
}
}
@@ -1190,6 +1199,8 @@ static void replaceFunc(
i64 nOut; /* Maximum size of zOut */
int loopLimit; /* Last zStr[] that might match zPattern[] */
int i, j; /* Loop counters */
unsigned cntExpand; /* Number zOut expansions */
sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==3 );
UNUSED_PARAMETER(argc);
@@ -1221,33 +1232,40 @@ static void replaceFunc(
return;
}
loopLimit = nStr - nPattern;
cntExpand = 0;
for(i=j=0; i<=loopLimit; i++){
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
zOut[j++] = zStr[i];
}else{
u8 *zOld;
sqlite3 *db = sqlite3_context_db_handle(context);
nOut += nRep - nPattern;
testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
sqlite3_free(zOut);
return;
}
zOld = zOut;
zOut = sqlite3_realloc64(zOut, (int)nOut);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
return;
if( nRep>nPattern ){
nOut += nRep - nPattern;
testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
sqlite3_free(zOut);
return;
}
cntExpand++;
if( (cntExpand&(cntExpand-1))==0 ){
/* Grow the size of the output buffer only on substitutions
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
u8 *zOld;
zOld = zOut;
zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
if( zOut==0 ){
sqlite3_result_error_nomem(context);
sqlite3_free(zOld);
return;
}
}
}
memcpy(&zOut[j], zRep, nRep);
j += nRep;
i += nPattern-1;
}
}
assert( j+nStr-i+1==nOut );
assert( j+nStr-i+1<=nOut );
memcpy(&zOut[j], &zStr[i], nStr-i);
j += nStr - i;
assert( j<=nOut );
@@ -1487,7 +1505,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
i64 v = sqlite3_value_int64(argv[0]);
p->rSum += v;
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
p->overflow = 1;
p->approx = p->overflow = 1;
}
}else{
p->rSum += sqlite3_value_double(argv[0]);
@@ -1495,6 +1513,32 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
SumCtx *p;
int type;
assert( argc==1 );
UNUSED_PARAMETER(argc);
p = sqlite3_aggregate_context(context, sizeof(*p));
type = sqlite3_value_numeric_type(argv[0]);
/* p is always non-NULL because sumStep() will have been called first
** to initialize it */
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
assert( type==SQLITE_INTEGER || p->approx );
if( type==SQLITE_INTEGER && p->approx==0 ){
i64 v = sqlite3_value_int64(argv[0]);
p->rSum -= v;
p->iSum -= v;
}else{
p->rSum -= sqlite3_value_double(argv[0]);
}
}
}
#else
# define sumInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void sumFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
@@ -1529,6 +1573,9 @@ static void totalFinalize(sqlite3_context *context){
typedef struct CountCtx CountCtx;
struct CountCtx {
i64 n;
#ifdef SQLITE_DEBUG
int bInverse; /* True if xInverse() ever called */
#endif
};
/*
@@ -1546,7 +1593,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
** sure it still operates correctly, verify that its count agrees with our
** internal count when using count(*) and when the total count can be
** expressed as a 32-bit integer. */
assert( argc==1 || p==0 || p->n>0x7fffffff
assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
|| p->n==sqlite3_aggregate_count(context) );
#endif
}
@@ -1555,6 +1602,21 @@ static void countFinalize(sqlite3_context *context){
p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int64(context, p ? p->n : 0);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
CountCtx *p;
p = sqlite3_aggregate_context(ctx, sizeof(*p));
/* p is always non-NULL since countStep() will have been called first */
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){
p->n--;
#ifdef SQLITE_DEBUG
p->bInverse = 1;
#endif
}
}
#else
# define countInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Routines to implement min() and max() aggregate functions.
@@ -1571,7 +1633,7 @@ static void minmaxStep(
pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
if( !pBest ) return;
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
if( sqlite3_value_type(pArg)==SQLITE_NULL ){
if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
}else if( pBest->flags ){
int max;
@@ -1597,16 +1659,26 @@ static void minmaxStep(
sqlite3VdbeMemCopy(pBest, pArg);
}
}
static void minMaxFinalize(sqlite3_context *context){
static void minMaxValueFinalize(sqlite3_context *context, int bValue){
sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
if( pRes->flags ){
sqlite3_result_value(context, pRes);
}
sqlite3VdbeMemRelease(pRes);
if( bValue==0 ) sqlite3VdbeMemRelease(pRes);
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void minMaxValue(sqlite3_context *context){
minMaxValueFinalize(context, 1);
}
#else
# define minMaxValue 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void minMaxFinalize(sqlite3_context *context){
minMaxValueFinalize(context, 0);
}
/*
** group_concat(EXPR, ?SEPARATOR?)
@@ -1636,20 +1708,52 @@ static void groupConcatStep(
zSep = ",";
nSep = 1;
}
if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
if( zSep ) sqlite3_str_append(pAccum, zSep, nSep);
}
zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]);
if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatInverse(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int n;
StrAccum *pAccum;
assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
/* pAccum is always non-NULL since groupConcatStep() will have always
** run frist to initialize it */
if( ALWAYS(pAccum) ){
n = sqlite3_value_bytes(argv[0]);
if( argc==2 ){
n += sqlite3_value_bytes(argv[1]);
}else{
n++;
}
if( n>=(int)pAccum->nChar ){
pAccum->nChar = 0;
}else{
pAccum->nChar -= n;
memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
}
if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
}
}
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum;
pAccum = sqlite3_aggregate_context(context, 0);
if( pAccum ){
if( pAccum->accError==STRACCUM_TOOBIG ){
if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context);
}else if( pAccum->accError==STRACCUM_NOMEM ){
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
@@ -1657,6 +1761,24 @@ static void groupConcatFinalize(sqlite3_context *context){
}
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){
sqlite3_str *pAccum;
pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
if( pAccum ){
if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
}else{
const char *zText = sqlite3_str_value(pAccum);
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
}
}
}
#else
# define groupConcatValue 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** This routine does per-connection function registration. Most
@@ -1694,10 +1816,10 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
}
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
(struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0);
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
setLikeOptFlag(db, "like",
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
@@ -1706,9 +1828,14 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
/*
** pExpr points to an expression which implements a function. If
** it is appropriate to apply the LIKE optimization to that function
** then set aWc[0] through aWc[2] to the wildcard characters and
** return TRUE. If the function is not a LIKE-style function then
** return FALSE.
** then set aWc[0] through aWc[2] to the wildcard characters and the
** escape character and then return TRUE. If the function is not a
** LIKE-style function then return FALSE.
**
** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
** operator if c is a string literal that is exactly one byte in length.
** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
** no ESCAPE clause.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
@@ -1717,17 +1844,26 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
*/
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
if( pExpr->op!=TK_FUNCTION
|| !pExpr->x.pList
|| pExpr->x.pList->nExpr!=2
){
int nExpr;
if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
nExpr = pExpr->x.pList->nExpr;
pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
if( nExpr<3 ){
aWc[3] = 0;
}else{
Expr *pEscape = pExpr->x.pList->a[2].pExpr;
char *zEscape;
if( pEscape->op!=TK_STRING ) return 0;
zEscape = pEscape->u.zToken;
if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
aWc[3] = zEscape[0];
}
/* The memcpy() statement assumes that the wildcard characters are
** the first three statements in the compareInfo structure. The
@@ -1779,6 +1915,10 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_DEBUG
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
#endif
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
SQLITE_FUNC_TYPEOF),
#endif
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
@@ -1788,11 +1928,11 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
@@ -1823,14 +1963,17 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
SQLITE_FUNC_COUNT ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
WAGGREGATE(count, 0,0,0, countStep,
countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
WAGGREGATE(count, 1,0,0, countStep,
countFinalize, countFinalize, countInverse, 0 ),
WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -1850,6 +1993,7 @@ void sqlite3RegisterBuiltinFunctions(void){
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
sqlite3WindowFunctions();
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
+10 -4
View File
@@ -199,6 +199,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -211,9 +212,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
SQLITE_MAX_MMAP_SIZE, /* mxMmap */
(void*)0, /* pScratch */
0, /* szScratch */
0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
@@ -242,7 +240,8 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xTestCallback */
#endif
0, /* bLocaltimeFault */
0x7ffffffe /* iOnceResetThreshold */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE /* szSorterRef */
};
/*
@@ -260,6 +259,13 @@ const Token sqlite3IntTokens[] = {
{ "1", 1 }
};
#ifdef VDBE_PROFILE
/*
** The following performance counter can be used in place of
** sqlite3Hwtime() for profiling. This is a no-op on standard builds.
*/
sqlite3_uint64 sqlite3NProfileCnt = 0;
#endif
/*
** The value of the "pending" byte must be 0x40000000 (1 byte past the
+211 -68
View File
@@ -210,11 +210,12 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
** first use of table pTab. On 2nd and subsequent uses, the original
** AutoincInfo structure is used.
**
** Three memory locations are allocated:
** Four consecutive registers are allocated:
**
** (1) Register to hold the name of the pTab table.
** (2) Register to hold the maximum ROWID of pTab.
** (3) Register to hold the rowid in sqlite_sequence of pTab
** (1) The name of the pTab table.
** (2) The maximum ROWID of pTab.
** (3) The rowid in sqlite_sequence of pTab
** (4) The original value of the max ROWID in pTab, or NULL if none
**
** The 2nd register is the one that is returned. That is all the
** insert routine needs to know about.
@@ -225,11 +226,26 @@ static int autoIncBegin(
Table *pTab /* The table we are writing to */
){
int memId = 0; /* Register holding maximum rowid */
assert( pParse->db->aDb[iDb].pSchema!=0 );
if( (pTab->tabFlags & TF_Autoincrement)!=0
&& (pParse->db->flags & SQLITE_Vacuum)==0
&& (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab;
/* Verify that the sqlite_sequence table exists and is an ordinary
** rowid table with exactly two columns.
** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
if( pSeqTab==0
|| !HasRowid(pSeqTab)
|| IsVirtual(pSeqTab)
|| pSeqTab->nCol!=2
){
pParse->nErr++;
pParse->rc = SQLITE_CORRUPT_SEQUENCE;
return 0;
}
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
@@ -242,7 +258,7 @@ static int autoIncBegin(
pInfo->iDb = iDb;
pToplevel->nMem++; /* Register to hold name of table */
pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */
pToplevel->nMem++; /* Rowid in sqlite_sequence */
pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */
}
memId = pInfo->regCtr;
}
@@ -270,15 +286,17 @@ void sqlite3AutoincrementBegin(Parse *pParse){
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList autoInc[] = {
/* 0 */ {OP_Null, 0, 0, 0},
/* 1 */ {OP_Rewind, 0, 9, 0},
/* 1 */ {OP_Rewind, 0, 10, 0},
/* 2 */ {OP_Column, 0, 0, 0},
/* 3 */ {OP_Ne, 0, 7, 0},
/* 3 */ {OP_Ne, 0, 9, 0},
/* 4 */ {OP_Rowid, 0, 0, 0},
/* 5 */ {OP_Column, 0, 1, 0},
/* 6 */ {OP_Goto, 0, 9, 0},
/* 7 */ {OP_Next, 0, 2, 0},
/* 8 */ {OP_Integer, 0, 0, 0},
/* 9 */ {OP_Close, 0, 0, 0}
/* 6 */ {OP_AddImm, 0, 0, 0},
/* 7 */ {OP_Copy, 0, 0, 0},
/* 8 */ {OP_Goto, 0, 11, 0},
/* 9 */ {OP_Next, 0, 2, 0},
/* 10 */ {OP_Integer, 0, 0, 0},
/* 11 */ {OP_Close, 0, 0, 0}
};
VdbeOp *aOp;
pDb = &db->aDb[p->iDb];
@@ -289,14 +307,17 @@ void sqlite3AutoincrementBegin(Parse *pParse){
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
if( aOp==0 ) break;
aOp[0].p2 = memId;
aOp[0].p3 = memId+1;
aOp[0].p3 = memId+2;
aOp[2].p3 = memId;
aOp[3].p1 = memId-1;
aOp[3].p3 = memId;
aOp[3].p5 = SQLITE_JUMPIFNULL;
aOp[4].p2 = memId+1;
aOp[5].p3 = memId;
aOp[8].p2 = memId;
aOp[6].p1 = memId;
aOp[7].p2 = memId+2;
aOp[7].p1 = memId;
aOp[10].p2 = memId;
}
}
@@ -343,6 +364,8 @@ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId);
VdbeCoverage(v);
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
if( aOp==0 ) break;
@@ -480,11 +503,11 @@ void sqlite3Insert(
SrcList *pTabList, /* Name of table into which we are inserting */
Select *pSelect, /* A SELECT statement to use as the data source */
IdList *pColumn, /* Column names corresponding to IDLIST. */
int onError /* How to handle constraint errors */
int onError, /* How to handle constraint errors */
Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */
){
sqlite3 *db; /* The main database structure */
Table *pTab; /* The table to insert into. aka TABLE */
char *zTab; /* Name of the table into which we are inserting */
int i, j; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
@@ -540,8 +563,6 @@ void sqlite3Insert(
/* Locate the table into which we will be inserting new information.
*/
assert( pTabList->nSrc==1 );
zTab = pTabList->a[0].zName;
if( NEVER(zTab==0) ) goto insert_cleanup;
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ){
goto insert_cleanup;
@@ -778,7 +799,10 @@ void sqlite3Insert(
/* Initialize the count of rows to be inserted
*/
if( db->flags & SQLITE_CountRows ){
if( (db->flags & SQLITE_CountRows)!=0
&& !pParse->nested
&& !pParse->pTriggerTab
){
regRowCount = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
@@ -798,6 +822,19 @@ void sqlite3Insert(
pParse->nMem += pIdx->nColumn;
}
}
#ifndef SQLITE_OMIT_UPSERT
if( pUpsert ){
pTabList->a[0].iCursor = iDataCur;
pUpsert->pUpsertSrc = pTabList;
pUpsert->regData = regData;
pUpsert->iDataCur = iDataCur;
pUpsert->iIdxCur = iIdxCur;
if( pUpsert->pUpsertTarget ){
sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert);
}
}
#endif
/* This is the top of the main insertion loop */
if( useTempTable ){
@@ -912,7 +949,8 @@ void sqlite3Insert(
VdbeOp *pOp;
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
pOp = sqlite3VdbeGetOp(v, -1);
if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
assert( pOp!=0 );
if( pOp->opcode==OP_Null && !IsVirtual(pTab) ){
appendFlag = 1;
pOp->opcode = OP_NewRowid;
pOp->p1 = iDataCur;
@@ -999,7 +1037,7 @@ void sqlite3Insert(
int isReplace; /* Set to true if constraints may cause a replace */
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
@@ -1022,7 +1060,7 @@ void sqlite3Insert(
/* Update the count of rows that are inserted
*/
if( (db->flags & SQLITE_CountRows)!=0 ){
if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
@@ -1059,7 +1097,7 @@ insert_end:
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
@@ -1068,6 +1106,7 @@ insert_end:
insert_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pList);
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
sqlite3DbFree(db, aRegIdx);
@@ -1234,7 +1273,8 @@ void sqlite3GenerateConstraintChecks(
u8 overrideError, /* Override onError to this if not OE_Default */
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */
int *aiChng /* column i is unchanged if aiChng[i]<0 */
int *aiChng, /* column i is unchanged if aiChng[i]<0 */
Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
Vdbe *v; /* VDBE under constrution */
Index *pIdx; /* Pointer to one of the indices */
@@ -1247,10 +1287,13 @@ void sqlite3GenerateConstraintChecks(
int addr1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
int ipkTop = 0; /* Top of the rowid change constraint check */
int ipkBottom = 0; /* Bottom of the rowid change constraint check */
Index *pUpIdx = 0; /* Index to which to apply the upsert */
u8 isUpdate; /* True if this is an UPDATE operation */
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
int ipkTop = 0; /* Top of the IPK uniqueness check */
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
isUpdate = regOldData!=0;
db = pParse->db;
@@ -1340,6 +1383,7 @@ void sqlite3GenerateConstraintChecks(
Expr *pExpr = pCheck->a[i].pExpr;
if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
allOk = sqlite3VdbeMakeLabel(v);
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
@@ -1357,6 +1401,50 @@ void sqlite3GenerateConstraintChecks(
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
/* UNIQUE and PRIMARY KEY constraints should be handled in the following
** order:
**
** (1) OE_Update
** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
** (3) OE_Replace
**
** OE_Fail and OE_Ignore must happen before any changes are made.
** OE_Update guarantees that only a single row will change, so it
** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback
** could happen in any order, but they are grouped up front for
** convenience.
**
** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
** The order of constraints used to have OE_Update as (2) and OE_Abort
** and so forth as (1). But apparently PostgreSQL checks the OE_Update
** constraint before any others, so it had to be moved.
**
** Constraint checking code is generated in this order:
** (A) The rowid constraint
** (B) Unique index constraints that do not have OE_Replace as their
** default conflict resolution strategy
** (C) Unique index that do use OE_Replace by default.
**
** The ordering of (2) and (3) is accomplished by making sure the linked
** list of indexes attached to a table puts all OE_Replace indexes last
** in the list. See sqlite3CreateIndex() for where that happens.
*/
if( pUpsert ){
if( pUpsert->pUpsertTarget==0 ){
/* An ON CONFLICT DO NOTHING clause, without a constraint-target.
** Make all unique constraint resolution be OE_Ignore */
assert( pUpsert->pUpsertSet==0 );
overrideError = OE_Ignore;
pUpsert = 0;
}else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
/* If the constraint-target uniqueness check must be run first.
** Jump to that uniqueness check now */
upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
VdbeComment((v, "UPSERT constraint goes first"));
}
}
/* If rowid is changing, make sure the new rowid does not previously
** exist in the table.
*/
@@ -1371,6 +1459,28 @@ void sqlite3GenerateConstraintChecks(
onError = OE_Abort;
}
/* figure out whether or not upsert applies in this case */
if( pUpsert && pUpsert->pUpsertIdx==0 ){
if( pUpsert->pUpsertSet==0 ){
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
}else{
onError = OE_Update; /* DO UPDATE */
}
}
/* If the response to a rowid conflict is REPLACE but the response
** to some other UNIQUE constraint is FAIL or IGNORE, then we need
** to defer the running of the rowid conflict checking until after
** the UNIQUE constraints have run.
*/
if( onError==OE_Replace /* IPK rule is REPLACE */
&& onError!=overrideError /* Rules for other contraints are different */
&& pTab->pIndex /* There exist other constraints */
){
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
VdbeComment((v, "defer IPK REPLACE until last"));
}
if( isUpdate ){
/* pkChng!=0 does not mean that the rowid has changed, only that
** it might have changed. Skip the conflict logic below if the rowid
@@ -1380,26 +1490,13 @@ void sqlite3GenerateConstraintChecks(
VdbeCoverage(v);
}
/* If the response to a rowid conflict is REPLACE but the response
** to some other UNIQUE constraint is FAIL or IGNORE, then we need
** to defer the running of the rowid conflict checking until after
** the UNIQUE constraints have run.
*/
if( onError==OE_Replace && overrideError!=OE_Replace ){
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto);
break;
}
}
}
/* Check to see if the new rowid already exists in the table. Skip
** the following conflict logic if it does not. */
VdbeNoopComment((v, "uniqueness check for ROWID"));
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
VdbeCoverage(v);
/* Generate code that deals with a rowid collision */
switch( onError ){
default: {
onError = OE_Abort;
@@ -1408,6 +1505,9 @@ void sqlite3GenerateConstraintChecks(
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
testcase( onError==OE_Rollback );
testcase( onError==OE_Abort );
testcase( onError==OE_Fail );
sqlite3RowidConstraint(pParse, onError, pTab);
break;
}
@@ -1444,14 +1544,13 @@ void sqlite3GenerateConstraintChecks(
regNewData, 1, 0, OE_Replace, 1, -1);
}else{
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
if( HasRowid(pTab) ){
/* This OP_Delete opcode fires the pre-update-hook only. It does
** not modify the b-tree. It is more efficient to let the coming
** OP_Insert replace the existing entry than it is to delete the
** existing entry and then insert a new one. */
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
assert( HasRowid(pTab) );
/* This OP_Delete opcode fires the pre-update-hook only. It does
** not modify the b-tree. It is more efficient to let the coming
** OP_Insert replace the existing entry than it is to delete the
** existing entry and then insert a new one. */
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
if( pTab->pIndex ){
sqlite3MultiWrite(pParse);
@@ -1461,8 +1560,14 @@ void sqlite3GenerateConstraintChecks(
seenReplace = 1;
break;
}
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
/* Fall through */
}
#endif
case OE_Ignore: {
/*assert( seenReplace==0 );*/
testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
@@ -1470,7 +1575,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeResolveLabel(v, addrRowidOk);
if( ipkTop ){
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, ipkTop);
sqlite3VdbeJumpHere(v, ipkTop-1);
}
}
@@ -1488,12 +1593,21 @@ void sqlite3GenerateConstraintChecks(
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
if( bAffinityDone==0 ){
if( pUpIdx==pIdx ){
addrUniqueOk = upsertJump+1;
upsertBypass = sqlite3VdbeGoto(v, 0);
VdbeComment((v, "Skip upsert subroutine"));
sqlite3VdbeJumpHere(v, upsertJump);
}else{
addrUniqueOk = sqlite3VdbeMakeLabel(v);
}
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
iThisCur = iIdxCur+ix;
addrUniqueOk = sqlite3VdbeMakeLabel(v);
/* Skip partial indices for which the WHERE clause is not true */
if( pIdx->pPartIdxWhere ){
@@ -1553,6 +1667,15 @@ void sqlite3GenerateConstraintChecks(
onError = OE_Abort;
}
/* Figure out if the upsert clause applies to this index */
if( pUpIdx==pIdx ){
if( pUpsert->pUpsertSet==0 ){
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
}else{
onError = OE_Update; /* DO UPDATE */
}
}
/* Collision detection may be omitted if all of the following are true:
** (1) The conflict resolution algorithm is REPLACE
** (2) The table is a WITHOUT ROWID table
@@ -1573,6 +1696,7 @@ void sqlite3GenerateConstraintChecks(
}
/* Check to see if the new index entry will be unique */
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
@@ -1634,25 +1758,37 @@ void sqlite3GenerateConstraintChecks(
/* Generate code that executes if the new index entry is not unique */
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
|| onError==OE_Ignore || onError==OE_Replace || onError==OE_Update );
switch( onError ){
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
testcase( onError==OE_Rollback );
testcase( onError==OE_Abort );
testcase( onError==OE_Fail );
sqlite3UniqueConstraint(pParse, onError, pIdx);
break;
}
#ifndef SQLITE_OMIT_UPSERT
case OE_Update: {
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
/* Fall through */
}
#endif
case OE_Ignore: {
testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
default: {
Trigger *pTrigger = 0;
assert( onError==OE_Replace );
sqlite3MultiWrite(pParse);
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
@@ -1660,14 +1796,22 @@ void sqlite3GenerateConstraintChecks(
break;
}
}
sqlite3VdbeResolveLabel(v, addrUniqueOk);
if( pUpIdx==pIdx ){
sqlite3VdbeGoto(v, upsertJump+1);
sqlite3VdbeJumpHere(v, upsertBypass);
}else{
sqlite3VdbeResolveLabel(v, addrUniqueOk);
}
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
/* If the IPK constraint is a REPLACE, run it last */
if( ipkTop ){
sqlite3VdbeGoto(v, ipkTop+1);
VdbeComment((v, "Do IPK REPLACE"));
sqlite3VdbeJumpHere(v, ipkBottom);
}
*pbMayReplace = seenReplace;
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
}
@@ -1763,7 +1907,6 @@ void sqlite3CompleteInsertion(
sqlite3SetMakeRecordP5(v, pTab);
if( !bAffinityDone ){
sqlite3TableAffinity(v, pTab, 0);
sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
}
if( pParse->nested ){
pik_flags = 0;
@@ -2009,7 +2152,6 @@ static int xferOptimization(
if( pSelect->pLimit ){
return 0; /* SELECT may not have a LIMIT clause */
}
assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
if( pSelect->pPrior ){
return 0; /* SELECT may not be a compound query */
}
@@ -2059,7 +2201,7 @@ static int xferOptimization(
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
if( (db->flags & SQLITE_Vacuum)==0
if( (db->mDbFlags & DBFLAG_Vacuum)==0
&& (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0; /* Neither table may have __hidden__ columns */
@@ -2135,15 +2277,15 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
if( (db->flags & SQLITE_Vacuum)==0 && (
if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
)){
/* In some circumstances, we are able to run the xfer optimization
** only if the destination table is initially empty. Unless the
** SQLITE_Vacuum flag is set, this block generates code to make
** that determination. If SQLITE_Vacuum is set, then the destination
** DBFLAG_Vacuum flag is set, this block generates code to make
** that determination. If DBFLAG_Vacuum is set, then the destination
** table is always empty.
**
** Conditions under which the destination must be empty:
@@ -2167,6 +2309,7 @@ static int xferOptimization(
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
if( pDest->iPKey>=0 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
sqlite3VdbeVerifyAbortable(v, onError);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
VdbeCoverage(v);
sqlite3RowidConstraint(pParse, onError, pDest);
@@ -2179,8 +2322,8 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
if( db->flags & SQLITE_Vacuum ){
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
if( db->mDbFlags & DBFLAG_Vacuum ){
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
}else{
@@ -2211,13 +2354,13 @@ static int xferOptimization(
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
if( db->flags & SQLITE_Vacuum ){
if( db->mDbFlags & DBFLAG_Vacuum ){
/* This INSERT command is part of a VACUUM operation, which guarantees
** that the destination table is empty. If all indexed columns use
** collation sequence BINARY, then it can also be assumed that the
** index will be populated by inserting keys in strictly sorted
** order. In this case, instead of seeking within the b-tree as part
** of every OP_IdxInsert opcode, an OP_Last is added before the
** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
** OP_IdxInsert to seek to the point within the b-tree where each key
** should be inserted. This is faster.
**
@@ -2232,7 +2375,7 @@ static int xferOptimization(
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT;
sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
}
}
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
+22 -1
View File
@@ -430,7 +430,28 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_prepare16_v3,
sqlite3_bind_pointer,
sqlite3_result_pointer,
sqlite3_value_pointer
sqlite3_value_pointer,
/* Version 3.22.0 and later */
sqlite3_vtab_nochange,
sqlite3_value_nochange,
sqlite3_vtab_collation,
/* Version 3.24.0 and later */
sqlite3_keyword_count,
sqlite3_keyword_name,
sqlite3_keyword_check,
sqlite3_str_new,
sqlite3_str_finish,
sqlite3_str_appendf,
sqlite3_str_vappendf,
sqlite3_str_append,
sqlite3_str_appendall,
sqlite3_str_appendchar,
sqlite3_str_reset,
sqlite3_str_errcode,
sqlite3_str_length,
sqlite3_str_value,
/* Version 3.25.0 and later */
sqlite3_create_window_function
};
/*
+308 -145
View File
@@ -22,7 +22,7 @@
#ifdef SQLITE_ENABLE_RTREE
# include "rtree.h"
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
# include "sqliteicu.h"
#endif
#ifdef SQLITE_ENABLE_JSON1
@@ -47,9 +47,11 @@ const char sqlite3_version[] = SQLITE_VERSION;
*/
const char *sqlite3_libversion(void){ return sqlite3_version; }
/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
** SQLITE_SOURCE_ID C preprocessor macro.
** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using
** an edited copy of the amalgamation, then the last four characters of
** the hash might be different from SQLITE_SOURCE_ID.
*/
const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
@@ -237,6 +239,11 @@ int sqlite3_initialize(void){
sqlite3GlobalConfig.isPCacheInit = 1;
rc = sqlite3OsInit();
}
#ifdef SQLITE_ENABLE_DESERIALIZE
if( rc==SQLITE_OK ){
rc = sqlite3MemdbInit();
}
#endif
if( rc==SQLITE_OK ){
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
@@ -269,7 +276,7 @@ int sqlite3_initialize(void){
#ifndef NDEBUG
#ifndef SQLITE_OMIT_FLOATING_POINT
/* This section of code's only "output" is via assert() statements. */
if ( rc==SQLITE_OK ){
if( rc==SQLITE_OK ){
u64 x = (((u64)1)<<63)-1;
double y;
assert(sizeof(x)==8);
@@ -436,14 +443,8 @@ int sqlite3_config(int op, ...){
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_SCRATCH: {
/* EVIDENCE-OF: R-08404-60887 There are three arguments to
** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
** which the scratch allocations will be drawn, the size of each scratch
** allocation (sz), and the maximum number of scratch allocations (N). */
sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
sqlite3GlobalConfig.szScratch = va_arg(ap, int);
sqlite3GlobalConfig.nScratch = va_arg(ap, int);
case SQLITE_CONFIG_SMALL_MALLOC: {
sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
@@ -641,6 +642,17 @@ int sqlite3_config(int op, ...){
break;
}
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
case SQLITE_CONFIG_SORTERREF_SIZE: {
int iVal = va_arg(ap, int);
if( iVal<0 ){
iVal = SQLITE_DEFAULT_SORTERREF_SIZE;
}
sqlite3GlobalConfig.szSorterRef = (u32)iVal;
break;
}
#endif /* SQLITE_ENABLE_SORTER_REFERENCES */
default: {
rc = SQLITE_ERROR;
break;
@@ -664,7 +676,8 @@ int sqlite3_config(int op, ...){
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
if( db->lookaside.nOut ){
if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
}
/* Free any existing lookaside buffer for this handle before
@@ -692,16 +705,18 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
pStart = pBuf;
}
db->lookaside.pStart = pStart;
db->lookaside.pInit = 0;
db->lookaside.pFree = 0;
db->lookaside.sz = (u16)sz;
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > (int)sizeof(LookasideSlot*) );
db->lookaside.nSlot = cnt;
p = (LookasideSlot*)pStart;
for(i=cnt-1; i>=0; i--){
p->pNext = db->lookaside.pFree;
db->lookaside.pFree = p;
p->pNext = db->lookaside.pInit;
db->lookaside.pInit = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
db->lookaside.pEnd = p;
@@ -712,6 +727,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -817,6 +833,8 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
{ SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
{ SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG },
{ SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP },
{ SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -824,14 +842,14 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
int oldFlags = db->flags;
u32 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
db->flags &= ~aFlagOp[i].mask;
}
if( oldFlags!=db->flags ){
sqlite3ExpirePreparedStatements(db);
sqlite3ExpirePreparedStatements(db, 0);
}
if( pRes ){
*pRes = (db->flags & aFlagOp[i].mask)!=0;
@@ -892,6 +910,15 @@ static int binCollFunc(
return rc;
}
/*
** Return true if CollSeq is the default built-in BINARY.
*/
int sqlite3IsBinary(const CollSeq *p){
assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0
|| strcmp(p->zName,"BINARY")==0 );
return p==0 || (p->xCmp==binCollFunc && p->pUser==0);
}
/*
** Another built-in collating sequence: NOCASE.
**
@@ -1013,7 +1040,7 @@ static void disconnectAllVtab(sqlite3 *db){
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( db->aDb[i].pSchema ){
if( pSchema ){
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
Table *pTab = (Table *)sqliteHashData(p);
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
@@ -1231,7 +1258,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED;
sqlite3_mutex_free(db->mutex);
assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */
assert( sqlite3LookasideUsed(db,0)==0 );
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
@@ -1259,7 +1286,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -1273,8 +1300,8 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
sqlite3ExpirePreparedStatements(db);
if( schemaChange ){
sqlite3ExpirePreparedStatements(db, 0);
sqlite3ResetAllSchemasOfConnection(db);
}
sqlite3BtreeLeaveAll(db);
@@ -1302,6 +1329,7 @@ const char *sqlite3ErrName(int rc){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
@@ -1314,9 +1342,10 @@ const char *sqlite3ErrName(int rc){
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
case SQLITE_READONLY_CANTINIT: zName = "SQLITE_READONLY_CANTINIT"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break;
case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
@@ -1436,6 +1465,8 @@ const char *sqlite3ErrStr(int rc){
/* SQLITE_FORMAT */ 0,
/* SQLITE_RANGE */ "column index out of range",
/* SQLITE_NOTADB */ "file is not a database",
/* SQLITE_NOTICE */ "notification message",
/* SQLITE_WARNING */ "warning message",
};
const char *zErr = "unknown error";
switch( rc ){
@@ -1443,6 +1474,14 @@ const char *sqlite3ErrStr(int rc){
zErr = "abort due to ROLLBACK";
break;
}
case SQLITE_ROW: {
zErr = "another row available";
break;
}
case SQLITE_DONE: {
zErr = "no more rows available";
break;
}
default: {
rc &= 0xff;
if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){
@@ -1459,21 +1498,40 @@ const char *sqlite3ErrStr(int rc){
** again until a timeout value is reached. The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
**
** Return non-zero to retry the lock. Return zero to stop trying
** and cause SQLite to return SQLITE_BUSY.
*/
static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
void *ptr, /* Database connection */
int count, /* Number of times table has been busy */
sqlite3_file *pFile /* The file on which the lock occurred */
){
#if SQLITE_OS_WIN || HAVE_USLEEP
/* This case is for systems that have support for sleeping for fractions of
** a second. Examples: All windows systems, unix systems with usleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY ArraySize(delays)
sqlite3 *db = (sqlite3 *)ptr;
int timeout = db->busyTimeout;
int tmout = db->busyTimeout;
int delay, prior;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
if( count ){
tmout = 0;
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
return 0;
}else{
return 1;
}
}
#else
UNUSED_PARAMETER(pFile);
#endif
assert( count>=0 );
if( count < NDELAY ){
delay = delays[count];
@@ -1482,16 +1540,19 @@ static int sqliteDefaultBusyCallback(
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
}
if( prior + delay > timeout ){
delay = timeout - prior;
if( prior + delay > tmout ){
delay = tmout - prior;
if( delay<=0 ) return 0;
}
sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
/* This case for unix systems that lack usleep() support. Sleeping
** must be done in increments of whole seconds */
sqlite3 *db = (sqlite3 *)ptr;
int timeout = ((sqlite3 *)ptr)->busyTimeout;
if( (count+1)*1000 > timeout ){
int tmout = ((sqlite3 *)ptr)->busyTimeout;
UNUSED_PARAMETER(pFile);
if( (count+1)*1000 > tmout ){
return 0;
}
sqlite3OsSleep(db->pVfs, 1000000);
@@ -1502,14 +1563,25 @@ static int sqliteDefaultBusyCallback(
/*
** Invoke the given busy handler.
**
** This routine is called when an operation failed with a lock.
** This routine is called when an operation failed to acquire a
** lock on VFS file pFile.
**
** If this routine returns non-zero, the lock is retried. If it
** returns 0, the operation aborts with an SQLITE_BUSY error.
*/
int sqlite3InvokeBusyHandler(BusyHandler *p){
int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
int rc;
if( NEVER(p==0) || p->xFunc==0 || p->nBusy<0 ) return 0;
rc = p->xFunc(p->pArg, p->nBusy);
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
if( p->bExtraFileArg ){
/* Add an extra parameter with the pFile pointer to the end of the
** callback argument list */
int (*xTra)(void*,int,sqlite3_file*);
xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
rc = xTra(p->pBusyArg, p->nBusy, pFile);
}else{
/* Legacy style busy handler callback */
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
}
if( rc==0 ){
p->nBusy = -1;
}else{
@@ -1531,9 +1603,10 @@ int sqlite3_busy_handler(
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.xBusyHandler = xBusy;
db->busyHandler.pBusyArg = pArg;
db->busyHandler.nBusy = 0;
db->busyHandler.bExtraFileArg = 0;
db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -1581,8 +1654,10 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
db->busyHandler.bExtraFileArg = 1;
}else{
sqlite3_busy_handler(db, 0, 0);
}
@@ -1618,6 +1693,8 @@ int sqlite3CreateFunc(
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
FuncDestructor *pDestructor
){
FuncDef *p;
@@ -1625,12 +1702,14 @@ int sqlite3CreateFunc(
int extraFlags;
assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
(xSFunc && (xFinal || xStep)) ||
(!xSFunc && (xFinal && !xStep)) ||
(!xSFunc && (!xFinal && xStep)) ||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
assert( xValue==0 || xSFunc==0 );
if( zFunctionName==0 /* Must have a valid name */
|| (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */
|| ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
|| ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
|| (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
|| (255<(nName = sqlite3Strlen30( zFunctionName)))
){
return SQLITE_MISUSE_BKPT;
}
@@ -1651,10 +1730,10 @@ int sqlite3CreateFunc(
}else if( enc==SQLITE_ANY ){
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
pUserData, xSFunc, xStep, xFinal, pDestructor);
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
pUserData, xSFunc, xStep, xFinal, pDestructor);
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -1671,14 +1750,14 @@ int sqlite3CreateFunc(
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
assert( !db->mallocFailed );
return SQLITE_BUSY;
}else{
sqlite3ExpirePreparedStatements(db);
sqlite3ExpirePreparedStatements(db, 0);
}
}
@@ -1700,11 +1779,68 @@ int sqlite3CreateFunc(
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xSFunc = xSFunc ? xSFunc : xStep;
p->xFinalize = xFinal;
p->xValue = xValue;
p->xInverse = xInverse;
p->pUserData = pUserData;
p->nArg = (u16)nArg;
return SQLITE_OK;
}
/*
** Worker function used by utf-8 APIs that create new functions:
**
** sqlite3_create_function()
** sqlite3_create_function_v2()
** sqlite3_create_window_function()
*/
static int createFunctionApi(
sqlite3 *db,
const char *zFunc,
int nArg,
int enc,
void *p,
void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*)
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor));
if( !pArg ){
sqlite3OomFault(db);
xDestroy(p);
goto out;
}
pArg->nRef = 0;
pArg->xDestroy = xDestroy;
pArg->pUserData = p;
}
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p,
xSFunc, xStep, xFinal, xValue, xInverse, pArg
);
if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK );
xDestroy(p);
sqlite3_free(pArg);
}
out:
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** Create new user functions.
*/
@@ -1718,10 +1854,9 @@ int sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*)
){
return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
xFinal, 0);
return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
xFinal, 0, 0, 0);
}
int sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunc,
@@ -1733,35 +1868,23 @@ int sqlite3_create_function_v2(
void (*xFinal)(sqlite3_context*),
void (*xDestroy)(void *)
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
if( !pArg ){
xDestroy(p);
goto out;
}
pArg->xDestroy = xDestroy;
pArg->pUserData = p;
}
rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK );
xDestroy(p);
sqlite3DbFree(db, pArg);
}
out:
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
xFinal, 0, 0, xDestroy);
}
int sqlite3_create_window_function(
sqlite3 *db,
const char *zFunc,
int nArg,
int enc,
void *p,
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
void (*xDestroy)(void *)
){
return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep,
xFinal, xValue, xInverse, xDestroy);
}
#ifndef SQLITE_OMIT_UTF16
@@ -1784,7 +1907,7 @@ int sqlite3_create_function16(
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -1793,6 +1916,28 @@ int sqlite3_create_function16(
#endif
/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context. The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
** for name resolution but are actually overloaded by the xFindFunction
** method of virtual tables.
*/
static void sqlite3InvalidFunction(
sqlite3_context *context, /* The function calling context */
int NotUsed, /* Number of arguments to the function */
sqlite3_value **NotUsed2 /* Value of each argument */
){
const char *zName = (const char*)sqlite3_user_data(context);
char *zErr;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
zErr = sqlite3_mprintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
}
/*
** Declare that a function has been overloaded by a virtual table.
**
@@ -1810,7 +1955,8 @@ int sqlite3_overload_function(
const char *zName,
int nArg
){
int rc = SQLITE_OK;
int rc;
char *zCopy;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
@@ -1818,13 +1964,13 @@ int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
rc = sqlite3ApiExit(db, rc);
rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
sqlite3_mutex_leave(db->mutex);
return rc;
if( rc ) return SQLITE_OK;
zCopy = sqlite3_mprintf(zName);
if( zCopy==0 ) return SQLITE_NOMEM;
return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
}
#ifndef SQLITE_OMIT_TRACE
@@ -2175,7 +2321,8 @@ int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases.
**
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
** or TRUNCATE.
*/
int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; /* Return code */
@@ -2385,7 +2532,7 @@ static int createCollation(
"unable to delete/modify collation sequence due to active statements");
return SQLITE_BUSY;
}
sqlite3ExpirePreparedStatements(db);
sqlite3ExpirePreparedStatements(db, 0);
/* If collation sequence pColl was created directly by a call to
** sqlite3_create_collation, and not generated by synthCollSeq(),
@@ -2821,6 +2968,7 @@ static int openDatabase(
}else{
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
}
if( flags & SQLITE_OPEN_PRIVATECACHE ){
flags &= ~SQLITE_OPEN_SHAREDCACHE;
}else if( sqlite3GlobalConfig.sharedCacheEnabled ){
@@ -2853,13 +3001,20 @@ static int openDatabase(
/* Allocate the sqlite data structure */
db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
if( isThreadsafe ){
if( isThreadsafe
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|| sqlite3GlobalConfig.bCoreMutex
#endif
){
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( db->mutex==0 ){
sqlite3_free(db);
db = 0;
goto opendb_out;
}
if( isThreadsafe==0 ){
sqlite3MutexWarnOnContention(db->mutex);
}
}
sqlite3_mutex_enter(db->mutex);
db->errMask = 0xff;
@@ -3041,7 +3196,7 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
}
@@ -3053,6 +3208,12 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_DBPAGE_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3DbpageRegister(db);
}
#endif
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3DbstatRegister(db);
@@ -3337,37 +3498,37 @@ int sqlite3_get_autocommit(sqlite3 *db){
** 2. Invoke sqlite3_log() to provide the source code location where
** a low-level error is first detected.
*/
static int reportError(int iErr, int lineno, const char *zType){
int sqlite3ReportError(int iErr, int lineno, const char *zType){
sqlite3_log(iErr, "%s at line %d of [%.10s]",
zType, lineno, 20+sqlite3_sourceid());
return iErr;
}
int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_CORRUPT, lineno, "database corruption");
return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
}
int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_MISUSE, lineno, "misuse");
return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
}
int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
}
#ifdef SQLITE_DEBUG
int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
char zMsg[100];
sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_CORRUPT, lineno, zMsg);
return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
}
int sqlite3NomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_NOMEM, lineno, "OOM");
return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
}
int sqlite3IoerrnomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
}
#endif
@@ -3560,10 +3721,11 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
}else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
*(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
rc = SQLITE_OK;
}else if( fd->pMethods ){
rc = sqlite3OsFileControl(fd, op, pArg);
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
rc = SQLITE_OK;
}else{
rc = SQLITE_NOTFOUND;
rc = sqlite3OsFileControl(fd, op, pArg);
}
sqlite3BtreeLeave(pBtree);
}
@@ -3712,7 +3874,7 @@ int sqlite3_test_control(int op, ...){
** This action provides a run-time test to see how the ALWAYS and
** NEVER macros were defined at compile-time.
**
** The return value is ALWAYS(X).
** The return value is ALWAYS(X) if X is true, or 0 if X is false.
**
** The recommended test is X==2. If the return value is 2, that means
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
@@ -3735,7 +3897,7 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
rc = ALWAYS(x);
rc = x ? ALWAYS(x) : 0;
break;
}
@@ -3784,40 +3946,6 @@ int sqlite3_test_control(int op, ...){
break;
}
#ifdef SQLITE_N_KEYWORD
/* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord)
**
** If zWord is a keyword recognized by the parser, then return the
** number of keywords. Or if zWord is not a keyword, return 0.
**
** This test feature is only available in the amalgamation since
** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite
** is built using separate source files.
*/
case SQLITE_TESTCTRL_ISKEYWORD: {
const char *zWord = va_arg(ap, const char*);
int n = sqlite3Strlen30(zWord);
rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0;
break;
}
#endif
/* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
**
** Pass pFree into sqlite3ScratchFree().
** If sz>0 then allocate a scratch buffer into pNew.
*/
case SQLITE_TESTCTRL_SCRATCHMALLOC: {
void *pFree, **ppNew;
int sz;
sz = va_arg(ap, int);
ppNew = va_arg(ap, void**);
pFree = va_arg(ap, void*);
if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
sqlite3ScratchFree(pFree);
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
**
** If parameter onoff is non-zero, configure the wrappers so that all
@@ -3859,7 +3987,8 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
#ifdef SQLITE_VDBE_COVERAGE
typedef void (*branch_callback)(void*,int,u8,u8);
typedef void (*branch_callback)(void*,unsigned int,
unsigned char,unsigned char);
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
@@ -3911,6 +4040,22 @@ int sqlite3_test_control(int op, ...){
sqlite3_mutex_leave(db->mutex);
break;
}
#if defined(YYCOVERAGE)
/* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
**
** This test control (only available when SQLite is compiled with
** -DYYCOVERAGE) writes a report onto "out" that shows all
** state/lookahead combinations in the parser state machine
** which are never exercised. If any state is missed, make the
** return code SQLITE_ERROR.
*/
case SQLITE_TESTCTRL_PARSER_COVERAGE: {
FILE *out = va_arg(ap, FILE*);
if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
break;
}
#endif /* defined(YYCOVERAGE) */
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
@@ -3959,7 +4104,7 @@ sqlite3_int64 sqlite3_uri_int64(
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
bDflt = v;
}
return bDflt;
@@ -4030,7 +4175,7 @@ int sqlite3_snapshot_get(
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
}
@@ -4065,11 +4210,29 @@ int sqlite3_snapshot_open(
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
if( sqlite3BtreeIsInTrans(pBt)==0 ){
Pager *pPager = sqlite3BtreePager(pBt);
int bUnlock = 0;
if( sqlite3BtreeIsInReadTrans(pBt) ){
if( db->nVdbeActive==0 ){
rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
if( rc==SQLITE_OK ){
bUnlock = 1;
rc = sqlite3BtreeCommit(pBt);
}
}
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot);
}
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
sqlite3PagerSnapshotOpen(pPager, 0);
}
if( bUnlock ){
sqlite3PagerSnapshotUnlock(pPager);
}
}
}
@@ -4100,7 +4263,7 @@ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
sqlite3BtreeCommit(pBt);
+21 -148
View File
@@ -32,14 +32,6 @@ int sqlite3_release_memory(int n){
#endif
}
/*
** An instance of the following object records the location of
** each unused scratch buffer.
*/
typedef struct ScratchFreeslot {
struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
} ScratchFreeslot;
/*
** State information local to the memory allocation subsystem.
*/
@@ -47,22 +39,12 @@ static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
sqlite3_int64 alarmThreshold; /* The soft heap limit */
/*
** Pointers to the end of sqlite3GlobalConfig.pScratch memory
** (so that a range test can be used to determine if an allocation
** being freed came from pScratch) and a pointer to the list of
** unused scratch allocations.
*/
void *pScratchEnd;
ScratchFreeslot *pScratchFree;
u32 nScratchFree;
/*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
} mem0 = { 0, 0, 0, 0, 0, 0 };
} mem0 = { 0, 0, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -132,28 +114,6 @@ int sqlite3MallocInit(void){
}
memset(&mem0, 0, sizeof(mem0));
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
&& sqlite3GlobalConfig.nScratch>0 ){
int i, n, sz;
ScratchFreeslot *pSlot;
sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
sqlite3GlobalConfig.szScratch = sz;
pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
n = sqlite3GlobalConfig.nScratch;
mem0.pScratchFree = pSlot;
mem0.nScratchFree = n;
for(i=0; i<n-1; i++){
pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
pSlot = pSlot->pNext;
}
pSlot->pNext = 0;
mem0.pScratchEnd = (void*)&pSlot[1];
}else{
mem0.pScratchEnd = 0;
sqlite3GlobalConfig.pScratch = 0;
sqlite3GlobalConfig.szScratch = 0;
sqlite3GlobalConfig.nScratch = 0;
}
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|| sqlite3GlobalConfig.nPage<=0 ){
sqlite3GlobalConfig.pPage = 0;
@@ -304,105 +264,6 @@ void *sqlite3_malloc64(sqlite3_uint64 n){
return sqlite3Malloc(n);
}
/*
** Each thread may only have a single outstanding allocation from
** xScratchMalloc(). We verify this constraint in the single-threaded
** case by setting scratchAllocOut to 1 when an allocation
** is outstanding clearing it when the allocation is freed.
*/
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
static int scratchAllocOut = 0;
#endif
/*
** Allocate memory that is to be used and released right away.
** This routine is similar to alloca() in that it is not intended
** for situations where the memory might be held long-term. This
** routine is intended to get memory to old large transient data
** structures that would not normally fit on the stack of an
** embedded processor.
*/
void *sqlite3ScratchMalloc(int n){
void *p;
assert( n>0 );
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n);
if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
p = mem0.pScratchFree;
mem0.pScratchFree = mem0.pScratchFree->pNext;
mem0.nScratchFree--;
sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3_mutex_leave(mem0.mutex);
p = sqlite3Malloc(n);
if( sqlite3GlobalConfig.bMemstat && p ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
sqlite3_mutex_leave(mem0.mutex);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
}
assert( sqlite3_mutex_notheld(mem0.mutex) );
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
/* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
** buffers per thread.
**
** This can only be checked in single-threaded mode.
*/
assert( scratchAllocOut==0 );
if( p ) scratchAllocOut++;
#endif
return p;
}
void sqlite3ScratchFree(void *p){
if( p ){
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
/* Verify that no more than two scratch allocation per thread
** is outstanding at one time. (This is only checked in the
** single-threaded case since checking in the multi-threaded case
** would be much more complicated.) */
assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
scratchAllocOut--;
#endif
if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){
/* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
ScratchFreeslot *pSlot;
pSlot = (ScratchFreeslot*)p;
sqlite3_mutex_enter(mem0.mutex);
pSlot->pNext = mem0.pScratchFree;
mem0.pScratchFree = pSlot;
mem0.nScratchFree++;
assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
sqlite3_mutex_leave(mem0.mutex);
}else{
/* Release memory back to the heap */
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
sqlite3GlobalConfig.m.xFree(p);
sqlite3_mutex_leave(mem0.mutex);
}else{
sqlite3GlobalConfig.m.xFree(p);
}
}
}
}
/*
** TRUE if p is a lookaside memory allocation from db
*/
@@ -493,7 +354,6 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
return;
}
}
@@ -654,16 +514,16 @@ void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db->mallocFailed==0 );
if( n>db->lookaside.sz ){
db->lookaside.anStat[1]++;
}else if( (pBuf = db->lookaside.pFree)==0 ){
db->lookaside.anStat[2]++;
}else{
}else if( (pBuf = db->lookaside.pFree)!=0 ){
db->lookaside.pFree = pBuf->pNext;
db->lookaside.nOut++;
db->lookaside.anStat[0]++;
if( db->lookaside.nOut>db->lookaside.mxOut ){
db->lookaside.mxOut = db->lookaside.nOut;
}
return (void*)pBuf;
}else if( (pBuf = db->lookaside.pInit)!=0 ){
db->lookaside.pInit = pBuf->pNext;
db->lookaside.anStat[0]++;
return (void*)pBuf;
}else{
db->lookaside.anStat[2]++;
}
}else if( db->mallocFailed ){
return 0;
@@ -767,6 +627,19 @@ char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
return zNew;
}
/*
** The text between zStart and zEnd represents a phrase within a larger
** SQL statement. Make a copy of this phrase in space obtained form
** sqlite3DbMalloc(). Omit leading and trailing whitespace.
*/
char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
int n;
while( sqlite3Isspace(zStart[0]) ) zStart++;
n = (int)(zEnd - zStart);
while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
return sqlite3DbStrNDup(db, zStart, n);
}
/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
+589
View File
@@ -0,0 +1,589 @@
/*
** 2016-09-07
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file implements an in-memory VFS. A database is held as a contiguous
** block of memory.
**
** This file also implements interface sqlite3_serialize() and
** sqlite3_deserialize().
*/
#include "sqliteInt.h"
#ifdef SQLITE_ENABLE_DESERIALIZE
/*
** Forward declaration of objects used by this utility
*/
typedef struct sqlite3_vfs MemVfs;
typedef struct MemFile MemFile;
/* Access to a lower-level VFS that (might) implement dynamic loading,
** access to randomness, etc.
*/
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
/* An open file */
struct MemFile {
sqlite3_file base; /* IO methods */
sqlite3_int64 sz; /* Size of the file */
sqlite3_int64 szMax; /* Space allocated to aData */
unsigned char *aData; /* content of the file */
int nMmap; /* Number of memory mapped pages */
unsigned mFlags; /* Flags */
int eLock; /* Most recent lock against this file */
};
/*
** Methods for MemFile
*/
static int memdbClose(sqlite3_file*);
static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
static int memdbSync(sqlite3_file*, int flags);
static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int memdbLock(sqlite3_file*, int);
/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
static int memdbFileControl(sqlite3_file*, int op, void *pArg);
/* static int memdbSectorSize(sqlite3_file*); // not used */
static int memdbDeviceCharacteristics(sqlite3_file*);
static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/*
** Methods for MemVfs
*/
static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */
static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename);
static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
static void memdbDlClose(sqlite3_vfs*, void*);
static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int memdbSleep(sqlite3_vfs*, int microseconds);
/* static int memdbCurrentTime(sqlite3_vfs*, double*); */
static int memdbGetLastError(sqlite3_vfs*, int, char *);
static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static sqlite3_vfs memdb_vfs = {
2, /* iVersion */
0, /* szOsFile (set when registered) */
1024, /* mxPathname */
0, /* pNext */
"memdb", /* zName */
0, /* pAppData (set when registered) */
memdbOpen, /* xOpen */
0, /* memdbDelete, */ /* xDelete */
memdbAccess, /* xAccess */
memdbFullPathname, /* xFullPathname */
memdbDlOpen, /* xDlOpen */
memdbDlError, /* xDlError */
memdbDlSym, /* xDlSym */
memdbDlClose, /* xDlClose */
memdbRandomness, /* xRandomness */
memdbSleep, /* xSleep */
0, /* memdbCurrentTime, */ /* xCurrentTime */
memdbGetLastError, /* xGetLastError */
memdbCurrentTimeInt64 /* xCurrentTimeInt64 */
};
static const sqlite3_io_methods memdb_io_methods = {
3, /* iVersion */
memdbClose, /* xClose */
memdbRead, /* xRead */
memdbWrite, /* xWrite */
memdbTruncate, /* xTruncate */
memdbSync, /* xSync */
memdbFileSize, /* xFileSize */
memdbLock, /* xLock */
memdbLock, /* xUnlock - same as xLock in this case */
0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
memdbFileControl, /* xFileControl */
0, /* memdbSectorSize,*/ /* xSectorSize */
memdbDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
memdbFetch, /* xFetch */
memdbUnfetch /* xUnfetch */
};
/*
** Close an memdb-file.
**
** The pData pointer is owned by the application, so there is nothing
** to free.
*/
static int memdbClose(sqlite3_file *pFile){
MemFile *p = (MemFile *)pFile;
if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData);
return SQLITE_OK;
}
/*
** Read data from an memdb-file.
*/
static int memdbRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
MemFile *p = (MemFile *)pFile;
if( iOfst+iAmt>p->sz ){
memset(zBuf, 0, iAmt);
if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
return SQLITE_IOERR_SHORT_READ;
}
memcpy(zBuf, p->aData+iOfst, iAmt);
return SQLITE_OK;
}
/*
** Try to enlarge the memory allocation to hold at least sz bytes
*/
static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
unsigned char *pNew;
if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
return SQLITE_FULL;
}
pNew = sqlite3_realloc64(p->aData, newSz);
if( pNew==0 ) return SQLITE_NOMEM;
p->aData = pNew;
p->szMax = newSz;
return SQLITE_OK;
}
/*
** Write data to an memdb-file.
*/
static int memdbWrite(
sqlite3_file *pFile,
const void *z,
int iAmt,
sqlite_int64 iOfst
){
MemFile *p = (MemFile *)pFile;
if( iOfst+iAmt>p->sz ){
int rc;
if( iOfst+iAmt>p->szMax
&& (rc = memdbEnlarge(p, (iOfst+iAmt)*2))!=SQLITE_OK
){
return rc;
}
if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
p->sz = iOfst+iAmt;
}
memcpy(p->aData+iOfst, z, iAmt);
return SQLITE_OK;
}
/*
** Truncate an memdb-file.
**
** In rollback mode (which is always the case for memdb, as it does not
** support WAL mode) the truncate() method is only used to reduce
** the size of a file, never to increase the size.
*/
static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
MemFile *p = (MemFile *)pFile;
if( NEVER(size>p->sz) ) return SQLITE_FULL;
p->sz = size;
return SQLITE_OK;
}
/*
** Sync an memdb-file.
*/
static int memdbSync(sqlite3_file *pFile, int flags){
return SQLITE_OK;
}
/*
** Return the current file-size of an memdb-file.
*/
static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
MemFile *p = (MemFile *)pFile;
*pSize = p->sz;
return SQLITE_OK;
}
/*
** Lock an memdb-file.
*/
static int memdbLock(sqlite3_file *pFile, int eLock){
MemFile *p = (MemFile *)pFile;
p->eLock = eLock;
return SQLITE_OK;
}
#if 0 /* Never used because memdbAccess() always returns false */
/*
** Check if another file-handle holds a RESERVED lock on an memdb-file.
*/
static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
*pResOut = 0;
return SQLITE_OK;
}
#endif
/*
** File control method. For custom operations on an memdb-file.
*/
static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
MemFile *p = (MemFile *)pFile;
int rc = SQLITE_NOTFOUND;
if( op==SQLITE_FCNTL_VFSNAME ){
*(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
rc = SQLITE_OK;
}
return rc;
}
#if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */
/*
** Return the sector-size in bytes for an memdb-file.
*/
static int memdbSectorSize(sqlite3_file *pFile){
return 1024;
}
#endif
/*
** Return the device characteristic flags supported by an memdb-file.
*/
static int memdbDeviceCharacteristics(sqlite3_file *pFile){
return SQLITE_IOCAP_ATOMIC |
SQLITE_IOCAP_POWERSAFE_OVERWRITE |
SQLITE_IOCAP_SAFE_APPEND |
SQLITE_IOCAP_SEQUENTIAL;
}
/* Fetch a page of a memory-mapped file */
static int memdbFetch(
sqlite3_file *pFile,
sqlite3_int64 iOfst,
int iAmt,
void **pp
){
MemFile *p = (MemFile *)pFile;
p->nMmap++;
*pp = (void*)(p->aData + iOfst);
return SQLITE_OK;
}
/* Release a memory-mapped page */
static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
MemFile *p = (MemFile *)pFile;
p->nMmap--;
return SQLITE_OK;
}
/*
** Open an mem file handle.
*/
static int memdbOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
MemFile *p = (MemFile*)pFile;
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
}
memset(p, 0, sizeof(*p));
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
*pOutFlags = flags | SQLITE_OPEN_MEMORY;
p->base.pMethods = &memdb_io_methods;
return SQLITE_OK;
}
#if 0 /* Only used to delete rollback journals, master journals, and WAL
** files, none of which exist in memdb. So this routine is never used */
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return SQLITE_IOERR_DELETE;
}
#endif
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
**
** With memdb, no files ever exist on disk. So always return false.
*/
static int memdbAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
*pResOut = 0;
return SQLITE_OK;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (INST_MAX_PATHNAME+1) bytes.
*/
static int memdbFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
sqlite3_snprintf(nOut, zOut, "%s", zPath);
return SQLITE_OK;
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
}
/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
** utf-8 string describing the most recent error encountered associated
** with dynamic libraries.
*/
static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
}
/*
** Close the dynamic library handle pHandle.
*/
static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){
return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
}
#if 0 /* Never used. Modern cores only call xCurrentTimeInt64() */
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
}
#endif
static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
}
static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
}
/*
** Translate a database connection pointer and schema name into a
** MemFile pointer.
*/
static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
MemFile *p = 0;
int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
if( rc ) return 0;
if( p->base.pMethods!=&memdb_io_methods ) return 0;
return p;
}
/*
** Return the serialization of a database
*/
unsigned char *sqlite3_serialize(
sqlite3 *db, /* The database connection */
const char *zSchema, /* Which database within the connection */
sqlite3_int64 *piSize, /* Write size here, if not NULL */
unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */
){
MemFile *p;
int iDb;
Btree *pBt;
sqlite3_int64 sz;
int szPage = 0;
sqlite3_stmt *pStmt = 0;
unsigned char *pOut;
char *zSql;
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
p = memdbFromDbSchema(db, zSchema);
iDb = sqlite3FindDbName(db, zSchema);
if( piSize ) *piSize = -1;
if( iDb<0 ) return 0;
if( p ){
if( piSize ) *piSize = p->sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = p->aData;
}else{
pOut = sqlite3_malloc64( p->sz );
if( pOut ) memcpy(pOut, p->aData, p->sz);
}
return pOut;
}
pBt = db->aDb[iDb].pBt;
if( pBt==0 ) return 0;
szPage = sqlite3BtreeGetPageSize(pBt);
zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
sqlite3_free(zSql);
if( rc ) return 0;
rc = sqlite3_step(pStmt);
if( rc!=SQLITE_ROW ){
pOut = 0;
}else{
sz = sqlite3_column_int64(pStmt, 0)*szPage;
if( piSize ) *piSize = sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = 0;
}else{
pOut = sqlite3_malloc64( sz );
if( pOut ){
int nPage = sqlite3_column_int(pStmt, 0);
Pager *pPager = sqlite3BtreePager(pBt);
int pgno;
for(pgno=1; pgno<=nPage; pgno++){
DbPage *pPage = 0;
unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
if( rc==SQLITE_OK ){
memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
}else{
memset(pTo, 0, szPage);
}
sqlite3PagerUnref(pPage);
}
}
}
}
sqlite3_finalize(pStmt);
return pOut;
}
/* Convert zSchema to a MemDB and initialize its content.
*/
int sqlite3_deserialize(
sqlite3 *db, /* The database connection */
const char *zSchema, /* Which DB to reopen with the deserialization */
unsigned char *pData, /* The serialized database content */
sqlite3_int64 szDb, /* Number bytes in the deserialization */
sqlite3_int64 szBuf, /* Total size of buffer pData[] */
unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
){
MemFile *p;
char *zSql;
sqlite3_stmt *pStmt = 0;
int rc;
int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
if( szDb<0 ) return SQLITE_MISUSE_BKPT;
if( szBuf<0 ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
iDb = sqlite3FindDbName(db, zSchema);
if( iDb<0 ){
rc = SQLITE_ERROR;
goto end_deserialize;
}
zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ) goto end_deserialize;
db->init.iDb = (u8)iDb;
db->init.reopenMemdb = 1;
rc = sqlite3_step(pStmt);
db->init.reopenMemdb = 0;
if( rc!=SQLITE_DONE ){
rc = SQLITE_ERROR;
goto end_deserialize;
}
p = memdbFromDbSchema(db, zSchema);
if( p==0 ){
rc = SQLITE_ERROR;
}else{
p->aData = pData;
p->sz = szDb;
p->szMax = szBuf;
p->mFlags = mFlags;
rc = SQLITE_OK;
}
end_deserialize:
sqlite3_finalize(pStmt);
sqlite3_mutex_leave(db->mutex);
return rc;
}
/*
** This routine is called when the extension is loaded.
** Register the new VFS.
*/
int sqlite3MemdbInit(void){
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
int sz = pLower->szOsFile;
memdb_vfs.pAppData = pLower;
/* In all known configurations of SQLite, the size of a default
** sqlite3_file is greater than the size of a memdb sqlite3_file.
** Should that ever change, remove the following NEVER() */
if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
memdb_vfs.szOsFile = sz;
return sqlite3_vfs_register(&memdb_vfs, 0);
}
#endif /* SQLITE_ENABLE_DESERIALIZE */
+24 -8
View File
@@ -96,7 +96,8 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
@@ -215,7 +216,8 @@ static int memjrnlWrite(
** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
@@ -384,17 +386,31 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
/*
** If the argument p points to a MemJournal structure that is not an
** in-memory-only journal file (i.e. is one that was opened with a +ve
** nSpill parameter), and the underlying file has not yet been created,
** create it now.
** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
** file has not yet been created, create it now.
*/
int sqlite3JournalCreate(sqlite3_file *p){
int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
rc = memjrnlCreateFile((MemJournal*)p);
MemJournal *p = (MemJournal*)pJfd;
if( p->pMethod==&MemJournalMethods && (
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
p->nSpill>0
#else
/* While this appears to not be possible without ATOMIC_WRITE, the
** paths are complex, so it seems prudent to leave the test in as
** a NEVER(), in case our analysis is subtly flawed. */
NEVER(p->nSpill>0)
#endif
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|| (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
#endif
)){
rc = memjrnlCreateFile(p);
}
return rc;
}
+191
View File
@@ -26,6 +26,193 @@ static SQLITE_WSD int mutexIsInit = 0;
#ifndef SQLITE_MUTEX_OMIT
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
/*
** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
** the implementation of a wrapper around the system default mutex
** implementation (sqlite3DefaultMutex()).
**
** Most calls are passed directly through to the underlying default
** mutex implementation. Except, if a mutex is configured by calling
** sqlite3MutexWarnOnContention() on it, then if contention is ever
** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
**
** This type of mutex is used as the database handle mutex when testing
** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
*/
/*
** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
** allocated by the system mutex implementation. Variable iType is usually set
** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
** or one of the static mutex identifiers. Or, if this is a recursive mutex
** that has been configured using sqlite3MutexWarnOnContention(), it is
** set to SQLITE_MUTEX_WARNONCONTENTION.
*/
typedef struct CheckMutex CheckMutex;
struct CheckMutex {
int iType;
sqlite3_mutex *mutex;
};
#define SQLITE_MUTEX_WARNONCONTENTION (-1)
/*
** Pointer to real mutex methods object used by the CheckMutex
** implementation. Set by checkMutexInit().
*/
static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
#ifdef SQLITE_DEBUG
static int checkMutexHeld(sqlite3_mutex *p){
return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
}
static int checkMutexNotheld(sqlite3_mutex *p){
return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
}
#endif
/*
** Initialize and deinitialize the mutex subsystem.
*/
static int checkMutexInit(void){
pGlobalMutexMethods = sqlite3DefaultMutex();
return SQLITE_OK;
}
static int checkMutexEnd(void){
pGlobalMutexMethods = 0;
return SQLITE_OK;
}
/*
** Allocate a mutex.
*/
static sqlite3_mutex *checkMutexAlloc(int iType){
static CheckMutex staticMutexes[] = {
{2, 0}, {3, 0}, {4, 0}, {5, 0},
{6, 0}, {7, 0}, {8, 0}, {9, 0},
{10, 0}, {11, 0}, {12, 0}, {13, 0}
};
CheckMutex *p = 0;
assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
if( iType<2 ){
p = sqlite3MallocZero(sizeof(CheckMutex));
if( p==0 ) return 0;
p->iType = iType;
}else{
#ifdef SQLITE_ENABLE_API_ARMOR
if( iType-2>=ArraySize(staticMutexes) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
p = &staticMutexes[iType-2];
}
if( p->mutex==0 ){
p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
if( p->mutex==0 ){
if( iType<2 ){
sqlite3_free(p);
}
p = 0;
}
}
return (sqlite3_mutex*)p;
}
/*
** Free a mutex.
*/
static void checkMutexFree(sqlite3_mutex *p){
assert( SQLITE_MUTEX_RECURSIVE<2 );
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
#if SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
CheckMutex *pCheck = (CheckMutex*)p;
pGlobalMutexMethods->xMutexFree(pCheck->mutex);
sqlite3_free(pCheck);
}
#ifdef SQLITE_ENABLE_API_ARMOR
else{
(void)SQLITE_MISUSE_BKPT;
}
#endif
}
/*
** Enter the mutex.
*/
static void checkMutexEnter(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
return;
}
sqlite3_log(SQLITE_MISUSE,
"illegal multi-threaded access to database connection"
);
}
pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
}
/*
** Enter the mutex (do not block).
*/
static int checkMutexTry(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
}
/*
** Leave the mutex.
*/
static void checkMutexLeave(sqlite3_mutex *p){
CheckMutex *pCheck = (CheckMutex*)p;
pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
}
sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
static const sqlite3_mutex_methods sMutex = {
checkMutexInit,
checkMutexEnd,
checkMutexAlloc,
checkMutexFree,
checkMutexEnter,
checkMutexTry,
checkMutexLeave,
#ifdef SQLITE_DEBUG
checkMutexHeld,
checkMutexNotheld
#else
0,
0
#endif
};
return &sMutex;
}
/*
** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
** one on which there should be no contention.
*/
void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
CheckMutex *pCheck = (CheckMutex*)p;
assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
}
}
#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
/*
** Initialize the mutex system.
*/
@@ -41,7 +228,11 @@ int sqlite3MutexInit(void){
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
if( sqlite3GlobalConfig.bCoreMutex ){
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
pFrom = multiThreadedCheckMutex();
#else
pFrom = sqlite3DefaultMutex();
#endif
}else{
pFrom = sqlite3NoopMutex();
}
+23 -16
View File
@@ -50,11 +50,12 @@ struct sqlite3_mutex {
#endif
};
#if SQLITE_MUTEX_NREF
#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0}
# define SQLITE3_MUTEX_INITIALIZER(id) \
{PTHREAD_MUTEX_INITIALIZER,id,0,(pthread_t)0,0}
#elif defined(SQLITE_ENABLE_API_ARMOR)
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 }
# define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER, id }
#else
#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER }
#endif
/*
@@ -151,18 +152,18 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
SQLITE3_MUTEX_INITIALIZER(2),
SQLITE3_MUTEX_INITIALIZER(3),
SQLITE3_MUTEX_INITIALIZER(4),
SQLITE3_MUTEX_INITIALIZER(5),
SQLITE3_MUTEX_INITIALIZER(6),
SQLITE3_MUTEX_INITIALIZER(7),
SQLITE3_MUTEX_INITIALIZER(8),
SQLITE3_MUTEX_INITIALIZER(9),
SQLITE3_MUTEX_INITIALIZER(10),
SQLITE3_MUTEX_INITIALIZER(11),
SQLITE3_MUTEX_INITIALIZER(12),
SQLITE3_MUTEX_INITIALIZER(13)
};
sqlite3_mutex *p;
switch( iType ){
@@ -180,6 +181,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
pthread_mutexattr_settype(&recursiveAttr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
p->id = SQLITE_MUTEX_RECURSIVE;
#endif
}
break;
@@ -188,6 +192,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
pthread_mutex_init(&p->mutex, 0);
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
p->id = SQLITE_MUTEX_FAST;
#endif
}
break;
}
@@ -203,7 +210,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
}
}
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
if( p ) p->id = iType;
assert( p==0 || p->id==iType );
#endif
return p;
}
+17 -17
View File
@@ -40,7 +40,7 @@ struct sqlite3_mutex {
#ifdef SQLITE_DEBUG
volatile int nRef; /* Number of enterances */
volatile DWORD owner; /* Thread holding this mutex */
volatile int trace; /* True to trace changes */
volatile LONG trace; /* True to trace changes */
#endif
};
@@ -52,10 +52,10 @@ struct sqlite3_mutex {
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
#ifdef SQLITE_DEBUG
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \
0L, (DWORD)0, 0 }
#else
#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }
#endif
#ifdef SQLITE_DEBUG
@@ -98,18 +98,18 @@ void sqlite3MemoryBarrier(void){
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
SQLITE3_MUTEX_INITIALIZER(2),
SQLITE3_MUTEX_INITIALIZER(3),
SQLITE3_MUTEX_INITIALIZER(4),
SQLITE3_MUTEX_INITIALIZER(5),
SQLITE3_MUTEX_INITIALIZER(6),
SQLITE3_MUTEX_INITIALIZER(7),
SQLITE3_MUTEX_INITIALIZER(8),
SQLITE3_MUTEX_INITIALIZER(9),
SQLITE3_MUTEX_INITIALIZER(10),
SQLITE3_MUTEX_INITIALIZER(11),
SQLITE3_MUTEX_INITIALIZER(12),
SQLITE3_MUTEX_INITIALIZER(13)
};
static int winMutex_isInit = 0;
@@ -239,15 +239,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
}
#endif
p = &winMutex_staticMutexes[iType-2];
p->id = iType;
#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
p->trace = 1;
InterlockedCompareExchange(&p->trace, 1, 0);
#endif
#endif
break;
}
}
assert( p==0 || p->id==iType );
return p;
}
+13 -5
View File
@@ -98,7 +98,7 @@ int sqlite3OsTruncate(sqlite3_file *id, i64 size){
}
int sqlite3OsSync(sqlite3_file *id, int flags){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xSync(id, flags);
return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
}
int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
@@ -125,8 +125,11 @@ int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
** routine has no return value since the return value would be meaningless.
*/
int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
if( id->pMethods==0 ) return SQLITE_NOTFOUND;
#ifdef SQLITE_TEST
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO
&& op!=SQLITE_FCNTL_LOCK_TIMEOUT
){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
@@ -143,7 +146,7 @@ int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
return id->pMethods->xFileControl(id, op, pArg);
}
void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
(void)id->pMethods->xFileControl(id, op, pArg);
if( id->pMethods ) (void)id->pMethods->xFileControl(id, op, pArg);
}
int sqlite3OsSectorSize(sqlite3_file *id){
@@ -153,6 +156,7 @@ int sqlite3OsSectorSize(sqlite3_file *id){
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
#ifndef SQLITE_OMIT_WAL
int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
return id->pMethods->xShmLock(id, offset, n, flags);
}
@@ -172,6 +176,7 @@ int sqlite3OsShmMap(
DO_OS_MALLOC_TEST(id);
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
#endif /* SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
@@ -405,9 +410,12 @@ int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
** Unregister a VFS so that it is no longer accessible.
*/
int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
MUTEX_LOGIC(sqlite3_mutex *mutex;)
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
if( rc ) return rc;
#endif
MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
sqlite3_mutex_leave(mutex);
+2
View File
@@ -174,10 +174,12 @@ void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
#ifndef SQLITE_OMIT_WAL
int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
void sqlite3OsShmBarrier(sqlite3_file *id);
int sqlite3OsShmUnmap(sqlite3_file *id, int);
#endif /* SQLITE_OMIT_WAL */
int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
+403 -163
View File
File diff suppressed because it is too large Load Diff
+213 -97
View File
@@ -315,22 +315,6 @@ struct winVfsAppData {
# define SQLITE_WIN32_DBG_BUF_SIZE ((int)(4096-sizeof(DWORD)))
#endif
/*
* The value used with sqlite3_win32_set_directory() to specify that
* the data directory should be changed.
*/
#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE
# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1)
#endif
/*
* The value used with sqlite3_win32_set_directory() to specify that
* the temporary directory should be changed.
*/
#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE
# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2)
#endif
/*
* If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
* various Win32 API heap functions instead of our own.
@@ -1927,13 +1911,13 @@ char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
}
/*
** This function sets the data directory or the temporary directory based on
** the provided arguments. The type argument must be 1 in order to set the
** data directory or 2 in order to set the temporary directory. The zValue
** argument is the name of the directory to use. The return value will be
** SQLITE_OK if successful.
** This function is the same as sqlite3_win32_set_directory (below); however,
** it accepts a UTF-8 string.
*/
int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
int sqlite3_win32_set_directory8(
unsigned long type, /* Identifier for directory being set or reset */
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -1949,20 +1933,53 @@ int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
);
assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
if( ppDirectory ){
char *zValueUtf8 = 0;
char *zCopy = 0;
if( zValue && zValue[0] ){
zValueUtf8 = winUnicodeToUtf8(zValue);
if ( zValueUtf8==0 ){
zCopy = sqlite3_mprintf("%s", zValue);
if ( zCopy==0 ){
return SQLITE_NOMEM_BKPT;
}
}
sqlite3_free(*ppDirectory);
*ppDirectory = zValueUtf8;
*ppDirectory = zCopy;
return SQLITE_OK;
}
return SQLITE_ERROR;
}
/*
** This function is the same as sqlite3_win32_set_directory (below); however,
** it accepts a UTF-16 string.
*/
int sqlite3_win32_set_directory16(
unsigned long type, /* Identifier for directory being set or reset */
const void *zValue /* New value for directory being set or reset */
){
int rc;
char *zUtf8 = 0;
if( zValue ){
zUtf8 = sqlite3_win32_unicode_to_utf8(zValue);
if( zUtf8==0 ) return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_win32_set_directory8(type, zUtf8);
if( zUtf8 ) sqlite3_free(zUtf8);
return rc;
}
/*
** This function sets the data directory or the temporary directory based on
** the provided arguments. The type argument must be 1 in order to set the
** data directory or 2 in order to set the temporary directory. The zValue
** argument is the name of the directory to use. The return value will be
** SQLITE_OK if successful.
*/
int sqlite3_win32_set_directory(
unsigned long type, /* Identifier for directory being set or reset */
void *zValue /* New value for directory being set or reset */
){
return sqlite3_win32_set_directory16(type, zValue);
}
/*
** The return value of winGetLastErrorMsg
** is zero if the error message fits in the buffer, or non-zero
@@ -2887,6 +2904,9 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
DWORD lastErrno;
#if SQLITE_MAX_MMAP_SIZE>0
sqlite3_int64 oldMmapSize;
#endif
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
@@ -2902,6 +2922,15 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
#if SQLITE_MAX_MMAP_SIZE>0
if( pFile->pMapRegion ){
oldMmapSize = pFile->mmapSize;
}else{
oldMmapSize = 0;
}
winUnmapfile(pFile);
#endif
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( winSeekFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
@@ -2914,12 +2943,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
}
#if SQLITE_MAX_MMAP_SIZE>0
/* If the file was truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
*/
if( pFile->pMapRegion && nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
if( rc==SQLITE_OK && oldMmapSize>0 ){
if( oldMmapSize>nByte ){
winMapfile(pFile, -1);
}else{
winMapfile(pFile, oldMmapSize);
}
}
#endif
@@ -3559,6 +3588,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
/* The value of newLimit may be eventually cast to (SIZE_T) and passed
** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
** least a 64-bit type. */
if( newLimit>0 && sizeof(SIZE_T)<8 ){
newLimit = (newLimit & 0x7FFFFFFF);
}
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -3623,15 +3660,16 @@ static SYSTEM_INFO winSysInfo;
** assert( winShmMutexHeld() );
** winShmLeaveMutex()
*/
static sqlite3_mutex *winBigLock = 0;
static void winShmEnterMutex(void){
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
sqlite3_mutex_enter(winBigLock);
}
static void winShmLeaveMutex(void){
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
sqlite3_mutex_leave(winBigLock);
}
#ifndef NDEBUG
static int winShmMutexHeld(void) {
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
return sqlite3_mutex_held(winBigLock);
}
#endif
@@ -3665,6 +3703,9 @@ struct winShmNode {
int szRegion; /* Size of shared-memory regions */
int nRegion; /* Size of array apRegion */
u8 isReadonly; /* True if read-only */
u8 isUnlocked; /* True if no DMS lock held */
struct ShmRegion {
HANDLE hMap; /* File handle from CreateFileMapping */
void *pMap;
@@ -3731,7 +3772,7 @@ static int winShmSystemLock(
int rc = 0; /* Result code form Lock/UnlockFileEx() */
/* Access to the winShmNode object is serialized by the caller */
assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
pFile->hFile.h, lockType, ofst, nByte));
@@ -3812,6 +3853,37 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
}
}
/*
** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
** take it now. Return SQLITE_OK if successful, or an SQLite error
** code otherwise.
**
** If the DMS cannot be locked because this is a readonly_shm=1
** connection and no other process already holds a lock, return
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
*/
static int winLockSharedMemory(winShmNode *pShmNode){
int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
if( rc==SQLITE_OK ){
if( pShmNode->isReadonly ){
pShmNode->isUnlocked = 1;
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
return SQLITE_READONLY_CANTINIT;
}else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winLockSharedMemory", pShmNode->zFilename);
}
}
if( rc==SQLITE_OK ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
}
return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
/*
** Open the shared-memory area associated with database file pDbFd.
**
@@ -3821,9 +3893,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
*/
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p; /* The connection to be opened */
struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
int rc; /* Result code */
struct winShmNode *pNew; /* Newly allocated winShmNode */
winShmNode *pShmNode = 0; /* The underlying mmapped file */
int rc = SQLITE_OK; /* Result code */
winShmNode *pNew; /* Newly allocated winShmNode */
int nName; /* Size of zName in bytes */
assert( pDbFd->pShm==0 ); /* Not previously opened */
@@ -3856,6 +3928,9 @@ static int winOpenSharedMemory(winFile *pDbFd){
if( pShmNode ){
sqlite3_free(pNew);
}else{
int inFlags = SQLITE_OPEN_WAL;
int outFlags = 0;
pShmNode = pNew;
pNew = 0;
((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
@@ -3870,30 +3945,23 @@ static int winOpenSharedMemory(winFile *pDbFd){
}
}
rc = winOpen(pDbFd->pVfs,
pShmNode->zFilename, /* Name of the file (UTF-8) */
(sqlite3_file*)&pShmNode->hFile, /* File handle here */
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
0);
if( SQLITE_OK!=rc ){
if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
}else{
inFlags |= SQLITE_OPEN_READONLY;
}
rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,
(sqlite3_file*)&pShmNode->hFile,
inFlags, &outFlags);
if( rc!=SQLITE_OK ){
rc = winLogError(rc, osGetLastError(), "winOpenShm",
pShmNode->zFilename);
goto shm_open_err;
}
if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winOpenShm", pDbFd->zPath);
}
}
if( rc==SQLITE_OK ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
rc = winLockSharedMemory(pShmNode);
if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
}
/* Make the new connection a child of the winShmNode */
@@ -3916,7 +3984,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
sqlite3_mutex_leave(pShmNode->mutex);
return SQLITE_OK;
return rc;
/* Jump here on any error */
shm_open_err:
@@ -4120,6 +4188,8 @@ static int winShmMap(
winFile *pDbFd = (winFile*)fd;
winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
DWORD protect = PAGE_READWRITE;
DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
int rc = SQLITE_OK;
if( !pShm ){
@@ -4130,6 +4200,11 @@ static int winShmMap(
pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->isUnlocked ){
rc = winLockSharedMemory(pShmNode);
if( rc!=SQLITE_OK ) goto shmpage_out;
pShmNode->isUnlocked = 0;
}
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
@@ -4176,21 +4251,26 @@ static int winShmMap(
}
pShmNode->aRegion = apNew;
if( pShmNode->isReadonly ){
protect = PAGE_READONLY;
flags = FILE_MAP_READ;
}
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
NULL, PAGE_READWRITE, nByte, NULL
NULL, protect, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
NULL, protect, 0, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
hMap = osCreateFileMappingA(pShmNode->hFile.h,
NULL, PAGE_READWRITE, 0, nByte, NULL
NULL, protect, 0, nByte, NULL
);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
@@ -4200,11 +4280,11 @@ static int winShmMap(
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
#if SQLITE_OS_WINRT
pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
pMap = osMapViewOfFileFromApp(hMap, flags,
iOffset - iOffsetShift, szRegion + iOffsetShift
);
#else
pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
pMap = osMapViewOfFile(hMap, flags,
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
#endif
@@ -4235,6 +4315,7 @@ shmpage_out:
}else{
*pp = 0;
}
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
@@ -4871,6 +4952,14 @@ static int winIsDir(const void *zConverted){
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
}
/* forward reference */
static int winAccess(
sqlite3_vfs *pVfs, /* Not used on win32 */
const char *zFilename, /* Name of file to check */
int flags, /* Type of test to make on this file */
int *pResOut /* OUT: Result */
);
/*
** Open a file.
*/
@@ -5047,37 +5136,58 @@ static int winOpen(
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParameters.lpSecurityAttributes = NULL;
extendedParameters.hTemplateFile = NULL;
while( (h = osCreateFile2((LPCWSTR)zConverted,
dwDesiredAccess,
dwShareMode,
dwCreationDisposition,
&extendedParameters))==INVALID_HANDLE_VALUE &&
winRetryIoerr(&cnt, &lastErrno) ){
/* Noop */
}
do{
h = osCreateFile2((LPCWSTR)zConverted,
dwDesiredAccess,
dwShareMode,
dwCreationDisposition,
&extendedParameters);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
}while( winRetryIoerr(&cnt, &lastErrno) );
#else
while( (h = osCreateFileW((LPCWSTR)zConverted,
dwDesiredAccess,
dwShareMode, NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL))==INVALID_HANDLE_VALUE &&
winRetryIoerr(&cnt, &lastErrno) ){
/* Noop */
}
do{
h = osCreateFileW((LPCWSTR)zConverted,
dwDesiredAccess,
dwShareMode, NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
}while( winRetryIoerr(&cnt, &lastErrno) );
#endif
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
while( (h = osCreateFileA((LPCSTR)zConverted,
dwDesiredAccess,
dwShareMode, NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL))==INVALID_HANDLE_VALUE &&
winRetryIoerr(&cnt, &lastErrno) ){
/* Noop */
}
do{
h = osCreateFileA((LPCSTR)zConverted,
dwDesiredAccess,
dwShareMode, NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL);
if( h!=INVALID_HANDLE_VALUE ) break;
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
}while( winRetryIoerr(&cnt, &lastErrno) );
}
#endif
winLogIoerr(cnt, __LINE__);
@@ -5086,8 +5196,6 @@ static int winOpen(
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
pFile->lastErrno = lastErrno;
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
@@ -5096,6 +5204,8 @@ static int winOpen(
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
pFile->lastErrno = lastErrno;
winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
return SQLITE_CANTOPEN_BKPT;
}
}
@@ -5688,9 +5798,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
EntropyGatherer e;
UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
e.a = (unsigned char*)zBuf;
e.na = nBuf;
e.nXor = 0;
@@ -5985,6 +6092,10 @@ int sqlite3_os_init(void){
sqlite3_vfs_register(&winLongPathNolockVfs, 0);
#endif
#ifndef SQLITE_OMIT_WAL
winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
return SQLITE_OK;
}
@@ -5995,6 +6106,11 @@ int sqlite3_os_end(void){
sleepObj = NULL;
}
#endif
#ifndef SQLITE_OMIT_WAL
winBigLock = 0;
#endif
return SQLITE_OK;
}
+317 -164
View File
@@ -128,8 +128,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
** struct as its argument.
*/
#define PAGERID(p) ((int)(p->fd))
#define FILEHANDLEID(fd) ((int)fd)
#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
/*
** The Pager.eState variable stores the current 'state' of a pager. A
@@ -616,6 +616,18 @@ struct PagerSavepoint {
** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
** sub-codes.
**
** syncFlags, walSyncFlags
**
** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode
** and contains the flags used to sync the checkpoint operations in the
** lower two bits, and sync flags used for transaction commits in the WAL
** file in bits 0x04 and 0x08. In other words, to get the correct sync flags
** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note
** that with synchronous=NORMAL in WAL mode, transaction commit is not synced
** meaning that the 0x04 and 0x08 bits are both zero.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
@@ -625,9 +637,8 @@ struct Pager {
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 extraSync; /* sync directory after journal delete */
u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
u8 walSyncFlags; /* See description above */
u8 tempFile; /* zFilename is a temporary or immutable file */
u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */
@@ -688,7 +699,7 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
int aStat[3]; /* Total cache hits, misses and writes */
int aStat[4]; /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
int nRead; /* Database pages read */
#endif
@@ -716,6 +727,7 @@ struct Pager {
#define PAGER_STAT_HIT 0
#define PAGER_STAT_MISS 1
#define PAGER_STAT_WRITE 2
#define PAGER_STAT_SPILL 3
/*
** The following global variables hold counters used for
@@ -947,6 +959,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
assert( pPager->dbOrigSize<=pPager->dbHintSize );
break;
@@ -958,6 +971,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
break;
@@ -983,8 +997,12 @@ static int assert_pager_state(Pager *p){
** to "print *pPager" in gdb:
**
** (gdb) printf "%s", print_pager_state(pPager)
**
** This routine has external linkage in order to suppress compiler warnings
** about an unused function. It is enclosed within SQLITE_DEBUG and so does
** not appear in normal builds.
*/
static char *print_pager_state(Pager *p){
char *print_pager_state(Pager *p){
static char zRet[1024];
sqlite3_snprintf(1024, zRet,
@@ -1168,34 +1186,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
}
/*
** This function determines whether or not the atomic-write optimization
** can be used with this pager. The optimization can be used if:
** This function determines whether or not the atomic-write or
** atomic-batch-write optimizations can be used with this pager. The
** atomic-write optimization can be used if:
**
** (a) the value returned by OsDeviceCharacteristics() indicates that
** a database page may be written atomically, and
** (b) the value returned by OsSectorSize() is less than or equal
** to the page size.
**
** The optimization is also always enabled for temporary files. It is
** an error to call this function if pPager is opened on an in-memory
** database.
** If it can be used, then the value returned is the size of the journal
** file when it contains rollback data for exactly one page.
**
** If the optimization cannot be used, 0 is returned. If it can be used,
** then the value returned is the size of the journal file when it
** contains rollback data for exactly one page.
** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
** returned in this case.
**
** If neither optimization can be used, 0 is returned.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
static int jrnlBufferSize(Pager *pPager){
assert( !MEMDB );
if( !pPager->tempFile ){
int dc; /* Device characteristics */
int nSector; /* Sector size */
int szPage; /* Page size */
assert( isOpen(pPager->fd) );
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
nSector = pPager->sectorSize;
szPage = pPager->pageSize;
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
int dc; /* Device characteristics */
assert( isOpen(pPager->fd) );
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#else
UNUSED_PARAMETER(pPager);
#endif
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){
return -1;
}
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
{
int nSector = pPager->sectorSize;
int szPage = pPager->pageSize;
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
@@ -1205,11 +1236,11 @@ static int jrnlBufferSize(Pager *pPager){
}
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
}
#else
# define jrnlBufferSize(x) 0
#endif
return 0;
}
/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function. This is used for testing
@@ -1291,6 +1322,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
|| len>=nMaster
|| len>szJ-16
|| len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
@@ -1736,7 +1768,6 @@ static void pager_reset(Pager *pPager){
** Return the pPager->iDataVersion value
*/
u32 sqlite3PagerDataVersion(Pager *pPager){
assert( pPager->eState>PAGER_OPEN );
return pPager->iDataVersion;
}
@@ -2012,7 +2043,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}
releaseAllSavepoints(pPager);
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
assert( isOpen(pPager->jfd) || pPager->pInJournal==0
|| (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
if( isOpen(pPager->jfd) ){
assert( !pagerUseWal(pPager) );
@@ -2100,7 +2133,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc = pager_truncate(pPager, pPager->dbSize);
}
if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
if( rc==SQLITE_OK && bCommit ){
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
}
@@ -2780,6 +2813,7 @@ static int pager_playback(Pager *pPager, int isHot){
char *zMaster = 0; /* Name of master journal file if any */
int needPagerReset; /* True to reset page prior to first page rollback */
int nPlayback = 0; /* Total number of pages restored from journal */
u32 savedPageSize = pPager->pageSize;
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
@@ -2909,15 +2943,16 @@ static int pager_playback(Pager *pPager, int isHot){
assert( 0 );
end_playback:
if( rc==SQLITE_OK ){
rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
}
/* Following a rollback, the database file should be back in its original
** state prior to the start of the transaction, so invoke the
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
** assertion that the transaction counter was modified.
*/
#ifdef SQLITE_DEBUG
if( pPager->fd->pMethods ){
sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
}
sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
#endif
/* If this playback is happening automatically as a result of an IO or
@@ -2967,7 +3002,8 @@ end_playback:
/*
** Read the content for page pPg out of the database file and into
** Read the content for page pPg out of the database file (or out of
** the WAL if that is where the most recent copy if found) into
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
@@ -2977,30 +3013,33 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
static int readDbPage(PgHdr *pPg, u32 iFrame){
static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */
int pgsz = pPager->pageSize; /* Number of bytes to read */
#ifndef SQLITE_OMIT_WAL
u32 iFrame = 0; /* Frame of WAL containing pgno */
assert( pPager->eState>=PAGER_READER && !MEMDB );
assert( isOpen(pPager->fd) );
#ifndef SQLITE_OMIT_WAL
if( pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
if( rc ) return rc;
}
if( iFrame ){
/* Try to pull the page from the write-ahead log. */
rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
}else
#endif
{
i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
if( pgno==1 ){
if( pPg->pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
@@ -3020,13 +3059,13 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pgno));
IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
PAGERID(pPager), pgno, pager_pagehash(pPg)));
PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
return rc;
}
@@ -3077,11 +3116,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
u32 iFrame = 0;
rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
if( rc==SQLITE_OK ){
rc = readDbPage(pPg, iFrame);
}
rc = readDbPage(pPg);
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
@@ -3587,20 +3622,17 @@ void sqlite3PagerSetFlags(
}
if( pPager->noSync ){
pPager->syncFlags = 0;
pPager->ckptSyncFlags = 0;
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
}
pPager->walSyncFlags = pPager->syncFlags;
pPager->walSyncFlags = (pPager->syncFlags<<2);
if( pPager->fullSync ){
pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
pPager->walSyncFlags |= pPager->syncFlags;
}
if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
@@ -3673,20 +3705,18 @@ static int pagerOpentemp(
** retried. If it returns zero, then the SQLITE_BUSY error is
** returned to the caller of the pager API function.
*/
void sqlite3PagerSetBusyhandler(
void sqlite3PagerSetBusyHandler(
Pager *pPager, /* Pager object */
int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
){
void **ap;
pPager->xBusyHandler = xBusyHandler;
pPager->pBusyHandlerArg = pBusyHandlerArg;
if( isOpen(pPager->fd) ){
void **ap = (void **)&pPager->xBusyHandler;
assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
assert( ap[1]==pBusyHandlerArg );
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
}
ap = (void **)&pPager->xBusyHandler;
assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
assert( ap[1]==pBusyHandlerArg );
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
}
/*
@@ -4072,6 +4102,30 @@ static void pagerFreeMapHdrs(Pager *pPager){
}
}
/* Verify that the database file has not be deleted or renamed out from
** under the pager. Return SQLITE_OK if the database is still where it ought
** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
** code from sqlite3OsAccess()) if the database has gone missing.
*/
static int databaseIsUnmoved(Pager *pPager){
int bHasMoved = 0;
int rc;
if( pPager->tempFile ) return SQLITE_OK;
if( pPager->dbSize==0 ) return SQLITE_OK;
assert( pPager->zFilename && pPager->zFilename[0] );
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
if( rc==SQLITE_NOTFOUND ){
/* If the HAS_MOVED file-control is unimplemented, assume that the file
** has not been moved. That is the historical behavior of SQLite: prior to
** version 3.8.3, it never checked */
rc = SQLITE_OK;
}else if( rc==SQLITE_OK && bHasMoved ){
rc = SQLITE_READONLY_DBMOVED;
}
return rc;
}
/*
** Shutdown the page cache. Free all memory and close all files.
@@ -4088,8 +4142,7 @@ static void pagerFreeMapHdrs(Pager *pPager){
** to the caller.
*/
int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
u8 *pTmp = (u8 *)pPager->pTmpSpace;
u8 *pTmp = (u8*)pPager->pTmpSpace;
assert( db || pagerUseWal(pPager)==0 );
assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
@@ -4098,11 +4151,17 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
assert( db || pPager->pWal==0 );
sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize,
(db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
);
pPager->pWal = 0;
{
u8 *a = 0;
assert( db || pPager->pWal==0 );
if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
&& SQLITE_OK==databaseIsUnmoved(pPager)
){
a = pTmp;
}
sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a);
pPager->pWal = 0;
}
#endif
pager_reset(pPager);
if( MEMDB ){
@@ -4559,6 +4618,7 @@ static int pagerStress(void *p, PgHdr *pPg){
return SQLITE_OK;
}
pPager->aStat[PAGER_STAT_SPILL]++;
pPg->pDirty = 0;
if( pagerUseWal(pPager) ){
/* Write a single frame for this page to the log. */
@@ -4567,6 +4627,13 @@ static int pagerStress(void *p, PgHdr *pPg){
rc = pagerWalFrames(pPager, pPg, 0, 0);
}
}else{
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( pPager->tempFile==0 ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
}
#endif
/* Sync the journal file if required. */
if( pPg->flags&PGHDR_NEED_SYNC
@@ -4657,6 +4724,11 @@ int sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
#ifdef SQLITE_ENABLE_DESERIALIZE
int memJM = 0; /* Memory journal mode */
#else
# define memJM 0
#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -4784,7 +4856,10 @@ int sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
readOnly = (fout&SQLITE_OPEN_READONLY);
#ifdef SQLITE_ENABLE_DESERIALIZE
memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
** choose a default page size in case we have to create the
@@ -4900,13 +4975,11 @@ act_like_temp_file:
assert( pPager->extraSync==0 );
assert( pPager->syncFlags==0 );
assert( pPager->walSyncFlags==0 );
assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
pPager->extraSync = 0;
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
}
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
@@ -4917,7 +4990,7 @@ act_like_temp_file:
setSectorSize(pPager);
if( !useJournal ){
pPager->journalMode = PAGER_JOURNALMODE_OFF;
}else if( memDb ){
}else if( memDb || memJM ){
pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
}
/* pPager->xBusyHandler = 0; */
@@ -4932,30 +5005,6 @@ act_like_temp_file:
}
/* Verify that the database file has not be deleted or renamed out from
** under the pager. Return SQLITE_OK if the database is still were it ought
** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
** code from sqlite3OsAccess()) if the database has gone missing.
*/
static int databaseIsUnmoved(Pager *pPager){
int bHasMoved = 0;
int rc;
if( pPager->tempFile ) return SQLITE_OK;
if( pPager->dbSize==0 ) return SQLITE_OK;
assert( pPager->zFilename && pPager->zFilename[0] );
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
if( rc==SQLITE_NOTFOUND ){
/* If the HAS_MOVED file-control is unimplemented, assume that the file
** has not been moved. That is the historical behavior of SQLite: prior to
** version 3.8.3, it never checked */
rc = SQLITE_OK;
}else if( rc==SQLITE_OK && bHasMoved ){
rc = SQLITE_READONLY_DBMOVED;
}
return rc;
}
/*
** This function is called after transitioning from PAGER_UNLOCK to
@@ -5326,7 +5375,8 @@ int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op.
*/
static void pagerUnlockIfUnused(Pager *pPager){
if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
pagerUnlockAndRollback(pPager);
}
}
@@ -5467,14 +5517,9 @@ static int getPageNormal(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
u32 iFrame = 0; /* Frame to read from WAL file */
if( pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
rc = readDbPage(pPg, iFrame);
rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
@@ -5548,7 +5593,7 @@ static int getPageMMap(
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
}else{
}else{
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
}
if( pPg ){
@@ -5617,25 +5662,40 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
** If the number of references to the page drop to zero, then the
** page is added to the LRU list. When all references to all pages
** are released, a rollback occurs and the lock on the database is
** removed.
** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
** used if we know that the page being released is not the last page.
** The btree layer always holds page1 open until the end, so these first
** to routines can be used to release any page other than BtShared.pPage1.
**
** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
** pages reaches zero it drops the database lock.
*/
void sqlite3PagerUnrefNotNull(DbPage *pPg){
Pager *pPager;
TESTONLY( Pager *pPager = pPg->pPager; )
assert( pPg!=0 );
pPager = pPg->pPager;
if( pPg->flags & PGHDR_MMAP ){
assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
pagerUnlockIfUnused(pPager);
/* Do not use this routine to release the last reference to page1 */
assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
}
void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
}
void sqlite3PagerUnrefPageOne(DbPage *pPg){
Pager *pPager;
assert( pPg!=0 );
assert( pPg->pgno==1 );
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
pPager = pPg->pPager;
sqlite3PagerResetLockTimeout(pPager);
sqlite3PcacheRelease(pPg);
pagerUnlockIfUnused(pPager);
}
/*
** This function is called at the start of every write transaction.
@@ -6228,12 +6288,9 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
*/
int sqlite3PagerSync(Pager *pPager, const char *zMaster){
int rc = SQLITE_OK;
if( isOpen(pPager->fd) ){
void *pArg = (void*)zMaster;
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
}
void *pArg = (void*)zMaster;
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc==SQLITE_OK && !pPager->noSync ){
assert( !MEMDB );
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
@@ -6328,9 +6385,10 @@ int sqlite3PagerCommitPhaseOne(
** backup in progress needs to be restarted. */
sqlite3BackupRestart(pPager->pBackup);
}else{
PgHdr *pList;
if( pagerUseWal(pPager) ){
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
PgHdr *pPageOne = 0;
pList = sqlite3PcacheDirtyList(pPager->pPCache);
if( pList==0 ){
/* Must have at least one page for the WAL commit flag.
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
@@ -6347,6 +6405,21 @@ int sqlite3PagerCommitPhaseOne(
sqlite3PcacheCleanAll(pPager->pPCache);
}
}else{
/* The bBatch boolean is true if the batch-atomic-write commit method
** should be used. No rollback journal is created if batch-atomic-write
** is enabled.
*/
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
sqlite3_file *fd = pPager->fd;
int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
&& !pPager->noSync
&& sqlite3JournalIsInMemory(pPager->jfd);
#else
# define bBatch 0
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/* The following block updates the change-counter. Exactly how it
** does this depends on whether or not the atomic-update optimization
** was enabled at compile time, and if this transaction meets the
@@ -6370,33 +6443,41 @@ int sqlite3PagerCommitPhaseOne(
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
PgHdr *pPg;
assert( isOpen(pPager->jfd)
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
if( bBatch==0 ){
PgHdr *pPg;
assert( isOpen(pPager->jfd)
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
}
}
}
#else
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( zMaster ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
assert( bBatch==0 );
}
#endif
rc = pager_incr_changecounter(pPager, 0);
#endif
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write the master journal name into the journal file. If a master
@@ -6419,8 +6500,37 @@ int sqlite3PagerCommitPhaseOne(
*/
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
pList = sqlite3PcacheDirtyList(pPager->pPCache);
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( bBatch ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
if( rc!=SQLITE_OK ){
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
}
}
if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ){
sqlite3OsClose(pPager->jfd);
goto commit_phase_one_exit;
}
bBatch = 0;
}else{
sqlite3OsClose(pPager->jfd);
}
}
#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
if( bBatch==0 ){
rc = pager_write_pagelist(pPager, pList);
}
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
@@ -6641,8 +6751,12 @@ int *sqlite3PagerStats(Pager *pPager){
#endif
/*
** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or
** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the
** Parameter eStat must be one of SQLITE_DBSTATUS_CACHE_HIT, _MISS, _WRITE,
** or _WRITE+1. The SQLITE_DBSTATUS_CACHE_WRITE+1 case is a translation
** of SQLITE_DBSTATUS_CACHE_SPILL. The _SPILL case is not contiguous because
** it was added later.
**
** Before returning, *pnVal is incremented by the
** current cache hit or miss count, according to the value of eStat. If the
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
@@ -6652,15 +6766,18 @@ void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
|| eStat==SQLITE_DBSTATUS_CACHE_WRITE
|| eStat==SQLITE_DBSTATUS_CACHE_WRITE+1
);
assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1
&& PAGER_STAT_WRITE==2 && PAGER_STAT_SPILL==3 );
*pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
eStat -= SQLITE_DBSTATUS_CACHE_HIT;
*pnVal += pPager->aStat[eStat];
if( reset ){
pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
pPager->aStat[eStat] = 0;
}
}
@@ -6864,6 +6981,16 @@ sqlite3_file *sqlite3PagerFile(Pager *pPager){
return pPager->fd;
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** Reset the lock timeout for pager.
*/
void sqlite3PagerResetLockTimeout(Pager *pPager){
int x = 0;
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
}
#endif
/*
** Return the file handle for the journal file (if it exists).
** This will be either the rollback journal or the WAL file.
@@ -7155,13 +7282,6 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){
int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
u8 eOld = pPager->journalMode; /* Prior journalmode */
#ifdef SQLITE_DEBUG
/* The print_pager_state() routine is intended to be used by the debugger
** only. We invoke it once here to suppress a compiler warning. */
print_pager_state(pPager);
#endif
/* The eMode parameter is always valid */
assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
@@ -7321,9 +7441,10 @@ int sqlite3PagerCheckpoint(
rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
sqlite3PagerResetLockTimeout(pPager);
}
return rc;
}
@@ -7478,7 +7599,7 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
@@ -7529,6 +7650,38 @@ int sqlite3PagerSnapshotRecover(Pager *pPager){
}
return rc;
}
/*
** The caller currently has a read transaction open on the database.
** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
** this function takes a SHARED lock on the CHECKPOINTER slot and then
** checks if the snapshot passed as the second argument is still
** available. If so, SQLITE_OK is returned.
**
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
** lock is released before returning.
*/
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
int rc;
if( pPager->pWal ){
rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot);
}else{
rc = SQLITE_ERROR;
}
return rc;
}
/*
** Release a lock obtained by an earlier successful call to
** sqlite3PagerSnapshotCheck().
*/
void sqlite3PagerSnapshotUnlock(Pager *pPager){
assert( pPager->pWal );
return sqlite3WalSnapshotUnlock(pPager->pWal);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */
+9 -1
View File
@@ -126,7 +126,7 @@ int sqlite3PagerClose(Pager *pPager, sqlite3*);
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int);
#ifdef SQLITE_HAS_CODEC
void sqlite3PagerAlignReserve(Pager*,Pager*);
@@ -151,6 +151,7 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
void sqlite3PagerRef(DbPage*);
void sqlite3PagerUnref(DbPage*);
void sqlite3PagerUnrefNotNull(DbPage*);
void sqlite3PagerUnrefPageOne(DbPage*);
/* Operations on page references. */
int sqlite3PagerWrite(DbPage*);
@@ -185,6 +186,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
int sqlite3PagerSnapshotRecover(Pager *pPager);
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
void sqlite3PagerSnapshotUnlock(Pager *pPager);
# endif
#else
# define sqlite3PagerUseWal(x,y) 0
@@ -211,6 +214,11 @@ int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
void sqlite3PagerResetLockTimeout(Pager *pPager);
#else
# define sqlite3PagerResetLockTimeout(X)
#endif
/* Functions used to truncate the database file. */
void sqlite3PagerTruncateImage(Pager*,Pgno);
+488 -344
View File
File diff suppressed because it is too large Load Diff
+12 -20
View File
@@ -191,12 +191,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
p->eCreate = 2;
}
}
pPage->pDirtyNext = 0;
pPage->pDirtyPrev = 0;
}
if( addRemove & PCACHE_DIRTYLIST_ADD ){
assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
pPage->pDirtyPrev = 0;
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
@@ -434,7 +431,7 @@ int sqlite3PcacheFetchStress(
sqlite3_log(SQLITE_FULL,
"spill page %d making room for %d - cache used: %d/%d",
pPg->pgno, pgno,
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache),
numberOfCachePages(pCache));
#endif
pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
@@ -513,11 +510,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
}else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
/* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
** then page p is already at the head of the dirty list and the
** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
** tag above. */
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -573,16 +566,15 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
*/
void sqlite3PcacheMakeClean(PgHdr *p){
assert( sqlite3PcachePageSanity(p) );
if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){
assert( (p->flags & PGHDR_CLEAN)==0 );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
p->flags |= PGHDR_CLEAN;
pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
assert( sqlite3PcachePageSanity(p) );
if( p->nRef==0 ){
pcacheUnpin(p);
}
assert( (p->flags & PGHDR_DIRTY)!=0 );
assert( (p->flags & PGHDR_CLEAN)==0 );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
p->flags |= PGHDR_CLEAN;
pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
assert( sqlite3PcachePageSanity(p) );
if( p->nRef==0 ){
pcacheUnpin(p);
}
}
+2
View File
@@ -43,6 +43,8 @@ struct PgHdr {
i16 nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
** PgHdr object is not dirty */
};
/* Bit values for PgHdr.flags */
+32 -30
View File
@@ -96,7 +96,6 @@ typedef struct PGroup PGroup;
struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */
u8 isPinned; /* Page in use, not on the LRU list */
u8 isBulkLocal; /* This page from bulk local storage */
u8 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */
@@ -105,6 +104,12 @@ struct PgHdr1 {
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
};
/*
** A page is pinned if it is no on the LRU list
*/
#define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0)
/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
** of one or more PCaches that are able to recycle each other's unpinned
** pages when they are under memory pressure. A PGroup is an instance of
@@ -132,7 +137,7 @@ struct PGroup {
unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
unsigned int nCurrentPage; /* Number of purgeable pages allocated */
unsigned int nPurgeable; /* Number of purgeable pages allocated */
PgHdr1 lru; /* The beginning and end of the LRU list */
};
@@ -146,11 +151,13 @@ struct PGroup {
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
** flag (bPurgeable) are set when the cache is created. nMax may be
** flag (bPurgeable) and the pnPurgeable pointer are all set when the
** cache is created and are never changed thereafter. nMax may be
** modified at any time by a call to the pcache1Cachesize() method.
** The PGroup mutex must be held when accessing nMax.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */
int szPage; /* Size of database content section */
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */
@@ -245,6 +252,7 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
if( pBuf==0 ) sz = n = 0;
if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -437,9 +445,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
p->isBulkLocal = 0;
p->isAnchor = 0;
}
if( pCache->bPurgeable ){
pCache->pGroup->nCurrentPage++;
}
(*pCache->pnPurgeable)++;
return p;
}
@@ -460,9 +466,7 @@ static void pcache1FreePage(PgHdr1 *p){
sqlite3_free(p);
#endif
}
if( pCache->bPurgeable ){
pCache->pGroup->nCurrentPage--;
}
(*pCache->pnPurgeable)--;
}
/*
@@ -557,22 +561,18 @@ static void pcache1ResizeHash(PCache1 *p){
** The PGroup mutex must be held when this function is called.
*/
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
PCache1 *pCache;
assert( pPage!=0 );
assert( pPage->isPinned==0 );
pCache = pPage->pCache;
assert( PAGE_IS_UNPINNED(pPage) );
assert( pPage->pLruNext );
assert( pPage->pLruPrev );
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
pPage->pLruPrev->pLruNext = pPage->pLruNext;
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
pPage->pLruNext = 0;
pPage->pLruPrev = 0;
pPage->isPinned = 1;
assert( pPage->isAnchor==0 );
assert( pCache->pGroup->lru.isAnchor==1 );
pCache->nRecyclable--;
assert( pPage->pCache->pGroup->lru.isAnchor==1 );
pPage->pCache->nRecyclable--;
return pPage;
}
@@ -606,11 +606,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
PGroup *pGroup = pCache->pGroup;
PgHdr1 *p;
assert( sqlite3_mutex_held(pGroup->mutex) );
while( pGroup->nCurrentPage>pGroup->nMaxPage
while( pGroup->nPurgeable>pGroup->nMaxPage
&& (p=pGroup->lru.pLruPrev)->isAnchor==0
){
assert( p->pCache->pGroup==pGroup );
assert( p->isPinned==0 );
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -659,7 +659,7 @@ static void pcache1TruncateUnsafe(
if( pPage->iKey>=iLimit ){
pCache->nPage--;
*pp = pPage->pNext;
if( !pPage->isPinned ) pcache1PinPage(pPage);
if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
@@ -777,6 +777,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->nMin = 10;
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pCache->pnPurgeable = &pGroup->nPurgeable;
}else{
static unsigned int dummyCurrentPage;
pCache->pnPurgeable = &dummyCurrentPage;
}
pcache1LeaveMutex(pGroup);
if( pCache->nHash==0 ){
@@ -878,7 +882,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
){
PCache1 *pOther;
pPage = pGroup->lru.pLruPrev;
assert( pPage->isPinned==0 );
assert( PAGE_IS_UNPINNED(pPage) );
pcache1RemoveFromHash(pPage, 0);
pcache1PinPage(pPage);
pOther = pPage->pCache;
@@ -886,7 +890,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pcache1FreePage(pPage);
pPage = 0;
}else{
pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
@@ -905,7 +909,6 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pPage->pCache = pCache;
pPage->pLruPrev = 0;
pPage->pLruNext = 0;
pPage->isPinned = 1;
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
if( iKey>pCache->iMaxKey ){
@@ -991,7 +994,7 @@ static PgHdr1 *pcache1FetchNoMutex(
** Otherwise (page not in hash and createFlag!=0) continue with
** subsequent steps to try to create the page. */
if( pPage ){
if( !pPage->isPinned ){
if( PAGE_IS_UNPINNED(pPage) ){
return pcache1PinPage(pPage);
}else{
return pPage;
@@ -1066,9 +1069,9 @@ static void pcache1Unpin(
** part of the PGroup LRU list.
*/
assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
assert( pPage->isPinned==1 );
assert( PAGE_IS_PINNED(pPage) );
if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage, 1);
}else{
/* Add the page to the PGroup LRU list. */
@@ -1077,7 +1080,6 @@ static void pcache1Unpin(
(pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
*ppFirst = pPage;
pCache->nRecyclable++;
pPage->isPinned = 0;
}
pcache1LeaveMutex(pCache->pGroup);
@@ -1221,7 +1223,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
assert( p->isPinned==0 );
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -1245,10 +1247,10 @@ void sqlite3PcacheStats(
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
assert( p->isPinned==0 );
assert( PAGE_IS_UNPINNED(p) );
nRecyclable++;
}
*pnCurrent = pcache1.grp.nCurrentPage;
*pnCurrent = pcache1.grp.nPurgeable;
*pnMax = (int)pcache1.grp.nMaxPage;
*pnMin = (int)pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
+94 -92
View File
@@ -298,16 +298,16 @@ static const PragmaName *pragmaLocate(const char *zName){
/*
** Helper subroutine for PRAGMA integrity_check:
**
** Generate code to output a single-column result row with the result
** held in register regResult. Decrement the result count and halt if
** the maximum number of result rows have been issued.
** Generate code to output a single-column result row with a value of the
** string held in register 3. Decrement the result count in register 1
** and halt if the maximum number of result rows have been issued.
*/
static int integrityCheckResultRow(Vdbe *v, int regResult){
static int integrityCheckResultRow(Vdbe *v){
int addr;
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
sqlite3VdbeAddOp0(v, OP_Halt);
return addr;
}
@@ -1080,6 +1080,7 @@ void sqlite3Pragma(
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
** pk: Non-zero for PK fields.
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
@@ -1234,13 +1235,11 @@ void sqlite3Pragma(
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
p = (FuncDef*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
break;
@@ -1252,7 +1251,6 @@ void sqlite3Pragma(
for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
Module *pMod = (Module*)sqliteHashData(j);
sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -1262,7 +1260,6 @@ void sqlite3Pragma(
int i;
for(i=0; i<ArraySize(aPragmaName); i++){
sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
break;
@@ -1488,12 +1485,11 @@ void sqlite3Pragma(
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
int *aRoot;
int cnt = 0;
int mxIdx = 0;
int nIdx;
HashElem *x; /* For looping over tables in the schema */
Hash *pTbls; /* Set of all tables in the schema */
int *aRoot; /* Array of root page numbers of all btrees */
int cnt = 0; /* Number of entries in aRoot[] */
int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -1508,8 +1504,9 @@ void sqlite3Pragma(
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
Table *pTab = sqliteHashData(x); /* Current table */
Index *pIdx; /* An index on pTab */
int nIdx; /* Number of indexes on pTab */
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
@@ -1519,12 +1516,12 @@ void sqlite3Pragma(
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
aRoot[cnt++] = pIdx->tnum;
aRoot[++cnt] = pIdx->tnum;
}
}
aRoot[cnt] = 0;
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
@@ -1537,9 +1534,8 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
P4_DYNAMIC);
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
integrityCheckResultRow(v, 2);
sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
@@ -1553,16 +1549,12 @@ void sqlite3Pragma(
int r1 = -1;
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
if( pTab->pCheck==0
&& (pTab->tabFlags & TF_HasNotNull)==0
&& (pTab->pIndex==0 || isQuick)
){
continue; /* No additional checks needed for this table */
}
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
sqlite3ExprCacheClear(pParse);
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
** reg[8+i] counts the number of entries in the i-th index
*/
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
@@ -1571,6 +1563,11 @@ void sqlite3Pragma(
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
if( !isQuick ){
/* Sanity check on record header decoding */
sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
}
/* Verify that all NOT NULL columns really are NOT NULL */
for(j=0; j<pTab->nCol; j++){
char *zErr;
@@ -1583,7 +1580,7 @@ void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
integrityCheckResultRow(v, 3);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
}
/* Verify CHECK constraints */
@@ -1595,7 +1592,6 @@ void sqlite3Pragma(
char *zErr;
int k;
pParse->iSelfTab = iDataCur + 1;
sqlite3ExprCachePush(pParse);
for(k=pCheck->nExpr-1; k>0; k--){
sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
}
@@ -1606,57 +1602,58 @@ void sqlite3Pragma(
zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
pTab->zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
integrityCheckResultRow(v, 3);
integrityCheckResultRow(v);
sqlite3VdbeResolveLabel(v, addrCkOk);
sqlite3ExprCachePop(pParse);
}
sqlite3ExprListDelete(db, pCheck);
}
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx && !isQuick; pIdx=pIdx->pNext, j++){
int jmp2, jmp3, jmp4, jmp5;
int ckUniq = sqlite3VdbeMakeLabel(v);
if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
pPrior, r1);
pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
/* Verify that an index entry exists for the current table row */
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeLoadString(v, 3, "row ");
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
sqlite3VdbeLoadString(v, 4, " missing from index ");
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp4 = integrityCheckResultRow(v, 3);
sqlite3VdbeJumpHere(v, jmp2);
/* For UNIQUE indexes, verify that only one entry exists with the
** current key. The entry is unique if (1) any column is NULL
** or (2) the next entry has a different key */
if( IsUniqueIndex(pIdx) ){
int uniqOk = sqlite3VdbeMakeLabel(v);
int jmp6;
int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
VdbeCoverage(v);
if( !isQuick ){ /* Omit the remaining tests for quick_check */
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2, jmp3, jmp4, jmp5;
int ckUniq = sqlite3VdbeMakeLabel(v);
if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
pPrior, r1);
pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
/* Verify that an index entry exists for the current table row */
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeLoadString(v, 3, "row ");
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
sqlite3VdbeLoadString(v, 4, " missing from index ");
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp4 = integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
/* For UNIQUE indexes, verify that only one entry exists with the
** current key. The entry is unique if (1) any column is NULL
** or (2) the next entry has a different key */
if( IsUniqueIndex(pIdx) ){
int uniqOk = sqlite3VdbeMakeLabel(v);
int jmp6;
int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
VdbeCoverage(v);
}
jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
sqlite3VdbeGoto(v, uniqOk);
sqlite3VdbeJumpHere(v, jmp6);
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
pIdx->nKeyCol); VdbeCoverage(v);
sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
sqlite3VdbeGoto(v, jmp5);
sqlite3VdbeResolveLabel(v, uniqOk);
}
jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
sqlite3VdbeGoto(v, uniqOk);
sqlite3VdbeJumpHere(v, jmp6);
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
pIdx->nKeyCol); VdbeCoverage(v);
sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
sqlite3VdbeGoto(v, jmp5);
sqlite3VdbeResolveLabel(v, uniqOk);
sqlite3VdbeJumpHere(v, jmp4);
sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeJumpHere(v, jmp4);
sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
@@ -1668,9 +1665,9 @@ void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
sqlite3VdbeLoadString(v, 3, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
integrityCheckResultRow(v, 7);
sqlite3VdbeLoadString(v, 4, pIdx->zName);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -1684,6 +1681,9 @@ void sqlite3Pragma(
{ OP_IfNotZero, 1, 4, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0}, /* 3 */
{ OP_Halt, 0, 0, 0}, /* 4 */
{ OP_String8, 0, 3, 0}, /* 5 */
{ OP_Goto, 0, 3, 0}, /* 6 */
};
VdbeOp *aOp;
@@ -1692,7 +1692,10 @@ void sqlite3Pragma(
aOp[0].p2 = 1-mxErr;
aOp[2].p4type = P4_STATIC;
aOp[2].p4.z = "ok";
aOp[5].p4type = P4_STATIC;
aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
}
sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
}
}
break;
@@ -2212,26 +2215,25 @@ static int pragmaVtabConnect(
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x");
sqlite3_str_appendall(&acc, "CREATE TABLE x");
for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]);
sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]);
cSep = ',';
}
if( i==0 ){
sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName);
cSep = ',';
sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName);
i++;
}
j = 0;
if( pPragma->mPragFlg & PragFlg_Result1 ){
sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN");
sqlite3_str_appendall(&acc, ",arg HIDDEN");
j++;
}
if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN");
sqlite3_str_appendall(&acc, ",schema HIDDEN");
j++;
}
sqlite3StrAccumAppend(&acc, ")", 1);
sqlite3_str_append(&acc, ")", 1);
sqlite3StrAccumFinish(&acc);
assert( strlen(zBuf) < sizeof(zBuf)-1 );
rc = sqlite3_declare_vtab(db, zBuf);
@@ -2383,13 +2385,13 @@ static int pragmaVtabFilter(
}
}
sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
sqlite3StrAccumAppendAll(&acc, "PRAGMA ");
sqlite3_str_appendall(&acc, "PRAGMA ");
if( pCsr->azArg[1] ){
sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]);
sqlite3_str_appendf(&acc, "%Q.", pCsr->azArg[1]);
}
sqlite3StrAccumAppendAll(&acc, pTab->pName->zName);
sqlite3_str_appendall(&acc, pTab->pName->zName);
if( pCsr->azArg[0] ){
sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]);
sqlite3_str_appendf(&acc, "=%Q", pCsr->azArg[0]);
}
zSql = sqlite3StrAccumFinish(&acc);
if( zSql==0 ) return SQLITE_NOMEM;
+75 -64
View File
@@ -25,15 +25,23 @@ static void corruptSchema(
const char *zExtra /* Error information */
){
sqlite3 *db = pData->db;
if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
if( db->mallocFailed ){
pData->rc = SQLITE_NOMEM_BKPT;
}else if( pData->pzErrMsg[0]!=0 ){
/* A error message has already been generated. Do not overwrite it */
}else if( pData->mInitFlags & INITFLAG_AlterTable ){
*pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
pData->rc = SQLITE_ERROR;
}else if( db->flags & SQLITE_WriteSchema ){
pData->rc = SQLITE_CORRUPT_BKPT;
}else{
char *z;
if( zObj==0 ) zObj = "?";
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
sqlite3DbFree(db, *pData->pzErrMsg);
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
*pData->pzErrMsg = z;
pData->rc = SQLITE_CORRUPT_BKPT;
}
pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
}
/*
@@ -85,7 +93,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
/* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -132,7 +140,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
** auxiliary databases. Return one of the SQLITE_ error codes to
** indicate success or failure.
*/
static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
int rc;
int i;
#ifndef SQLITE_OMIT_DEPRECATED
@@ -145,11 +153,14 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
const char *zMasterName;
int openedTransaction = 0;
assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pSchema );
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
db->init.busy = 1;
/* Construct the in-memory representation schema tables (sqlite_master or
** sqlite_temp_master) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
@@ -158,12 +169,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
azArg[1] = "1";
azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
"rootpage integer,sql text)";
"rootpage int,sql text)";
azArg[3] = 0;
initData.db = db;
initData.iDb = iDb;
initData.rc = SQLITE_OK;
initData.pzErrMsg = pzErrMsg;
initData.mInitFlags = mFlags;
sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
if( initData.rc ){
rc = initData.rc;
@@ -174,10 +186,10 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
DbSetProperty(db, 1, DB_SchemaLoaded);
}
return SQLITE_OK;
assert( iDb==1 );
DbSetProperty(db, 1, DB_SchemaLoaded);
rc = SQLITE_OK;
goto error_out;
}
/* If there is not already a read-only (or read-write) transaction opened
@@ -185,7 +197,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** will be closed before this function returns. */
sqlite3BtreeEnter(pDb->pBt);
if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0);
if( rc!=SQLITE_OK ){
sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
goto initone_error_out;
@@ -213,6 +225,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
for(i=0; i<ArraySize(meta); i++){
sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
if( (db->flags & SQLITE_ResetDatabase)!=0 ){
memset(meta, 0, sizeof(meta));
}
pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1];
/* If opening a non-empty database, check the text encoding. For the
@@ -336,9 +351,13 @@ initone_error_out:
sqlite3BtreeLeave(pDb->pBt);
error_out:
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
if( rc ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
}
sqlite3ResetOneSchema(db, iDb);
}
db->init.busy = 0;
return rc;
}
@@ -354,42 +373,30 @@ error_out:
*/
int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
int commit_internal = !(db->flags&SQLITE_InternChanges);
int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
assert( db->init.busy==0 );
rc = SQLITE_OK;
db->init.busy = 1;
ENC(db) = SCHEMA_ENC(db);
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
rc = sqlite3InitOne(db, i, pzErrMsg);
if( rc ){
sqlite3ResetOneSchema(db, i);
assert( db->nDb>0 );
/* Do the main schema first */
if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
if( rc ) return rc;
}
/* All other schemas after the main schema. The "temp" schema must be last */
for(i=db->nDb-1; i>0; i--){
assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
rc = sqlite3InitOne(db, i, pzErrMsg, 0);
if( rc ) return rc;
}
}
/* Once all the other databases have been initialized, load the schema
** for the TEMP database. This is loaded last, as the TEMP database
** schema may contain references to objects in other databases.
*/
#ifndef SQLITE_OMIT_TEMPDB
assert( db->nDb>1 );
if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
rc = sqlite3InitOne(db, 1, pzErrMsg);
if( rc ){
sqlite3ResetOneSchema(db, 1);
}
}
#endif
db->init.busy = 0;
if( rc==SQLITE_OK && commit_internal ){
if( commit_internal ){
sqlite3CommitInternalChanges(db);
}
return rc;
return SQLITE_OK;
}
/*
@@ -402,10 +409,12 @@ int sqlite3ReadSchema(Parse *pParse){
assert( sqlite3_mutex_held(db->mutex) );
if( !db->init.busy ){
rc = sqlite3Init(db, &pParse->zErrMsg);
}
if( rc!=SQLITE_OK ){
pParse->rc = rc;
pParse->nErr++;
if( rc!=SQLITE_OK ){
pParse->rc = rc;
pParse->nErr++;
}else if( db->noSharedCache ){
db->mDbFlags |= DBFLAG_SchemaKnownOk;
}
}
return rc;
}
@@ -433,7 +442,7 @@ static void schemaIsValid(Parse *pParse){
** on the b-tree database, open one now. If a transaction is opened, it
** will be closed immediately after reading the meta-value. */
if( !sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3BtreeBeginTrans(pBt, 0);
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
}
@@ -480,7 +489,8 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
*/
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
for(i=0; ALWAYS(i<db->nDb); i++){
for(i=0; 1; i++){
assert( i<db->nDb );
if( db->aDb[i].pSchema==pSchema ){
break;
}
@@ -494,16 +504,14 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** Free all memory allocations in the pParse object
*/
void sqlite3ParserReset(Parse *pParse){
if( pParse ){
sqlite3 *db = pParse->db;
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
if( db ){
assert( db->lookaside.bDisable >= pParse->disableLookaside );
db->lookaside.bDisable -= pParse->disableLookaside;
}
pParse->disableLookaside = 0;
sqlite3 *db = pParse->db;
sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr);
if( db ){
assert( db->lookaside.bDisable >= pParse->disableLookaside );
db->lookaside.bDisable -= pParse->disableLookaside;
}
pParse->disableLookaside = 0;
}
/*
@@ -617,7 +625,7 @@ static int sqlite3Prepare(
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"selectid", "order", "from", "detail"
"id", "parent", "notused", "detail"
};
int iFirst, mx;
if( sParse.explain==2 ){
@@ -663,8 +671,6 @@ static int sqlite3Prepare(
end_prepare:
sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
}
static int sqlite3LockAndPrepare(
@@ -677,6 +683,7 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
int cnt = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
@@ -687,14 +694,18 @@ static int sqlite3LockAndPrepare(
}
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
if( rc==SQLITE_SCHEMA ){
sqlite3_finalize(*ppStmt);
do{
/* Make multiple attempts to compile the SQL, until it either succeeds
** or encounters a permanent error. A schema problem after one schema
** reset is considered a permanent error. */
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
}
assert( rc==SQLITE_OK || *ppStmt==0 );
}while( rc==SQLITE_ERROR_RETRY
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
sqlite3BtreeLeaveAll(db);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
sqlite3_mutex_leave(db->mutex);
assert( rc==SQLITE_OK || *ppStmt==0 );
return rc;
}
+203 -69
View File
@@ -134,7 +134,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG );
assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
p->accError = eError;
p->nAlloc = 0;
}
@@ -168,8 +168,8 @@ static char *getTextArg(PrintfArguments *p){
/*
** Render a string given by "fmt" into the StrAccum object.
*/
void sqlite3VXPrintf(
StrAccum *pAccum, /* Accumulate results here */
void sqlite3_str_vappendf(
sqlite3_str *pAccum, /* Accumulate results here */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
@@ -206,6 +206,11 @@ void sqlite3VXPrintf(
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
/* pAccum never starts out with an empty buffer that was obtained from
** malloc(). This precondition is required by the mprintf("%z...")
** optimization. */
assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 );
bufpt = 0;
if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){
pArgList = va_arg(ap, PrintfArguments*);
@@ -221,11 +226,11 @@ void sqlite3VXPrintf(
#else
do{ fmt++; }while( *fmt && *fmt != '%' );
#endif
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt));
if( *fmt==0 ) break;
}
if( (c=(*++fmt))==0 ){
sqlite3StrAccumAppend(pAccum, "%", 1);
sqlite3_str_append(pAccum, "%", 1);
break;
}
/* Find out what flags are present */
@@ -403,7 +408,7 @@ void sqlite3VXPrintf(
u64 n = (u64)precision + 10 + precision/3;
zOut = zExtra = sqlite3Malloc( n );
if( zOut==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
setStrAccumError(pAccum, SQLITE_NOMEM);
return;
}
nOut = (int)n;
@@ -528,7 +533,7 @@ void sqlite3VXPrintf(
bufpt = zExtra
= sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 );
if( bufpt==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
setStrAccumError(pAccum, SQLITE_NOMEM);
return;
}
}
@@ -624,22 +629,52 @@ void sqlite3VXPrintf(
case etCHARX:
if( bArgList ){
bufpt = getTextArg(pArgList);
c = bufpt ? bufpt[0] : 0;
length = 1;
if( bufpt ){
buf[0] = c = *(bufpt++);
if( (c&0xc0)==0xc0 ){
while( length<4 && (bufpt[0]&0xc0)==0x80 ){
buf[length++] = *(bufpt++);
}
}
}else{
buf[0] = 0;
}
}else{
c = va_arg(ap,int);
unsigned int ch = va_arg(ap,unsigned int);
if( ch<0x00080 ){
buf[0] = ch & 0xff;
length = 1;
}else if( ch<0x00800 ){
buf[0] = 0xc0 + (u8)((ch>>6)&0x1f);
buf[1] = 0x80 + (u8)(ch & 0x3f);
length = 2;
}else if( ch<0x10000 ){
buf[0] = 0xe0 + (u8)((ch>>12)&0x0f);
buf[1] = 0x80 + (u8)((ch>>6) & 0x3f);
buf[2] = 0x80 + (u8)(ch & 0x3f);
length = 3;
}else{
buf[0] = 0xf0 + (u8)((ch>>18) & 0x07);
buf[1] = 0x80 + (u8)((ch>>12) & 0x3f);
buf[2] = 0x80 + (u8)((ch>>6) & 0x3f);
buf[3] = 0x80 + (u8)(ch & 0x3f);
length = 4;
}
}
if( precision>1 ){
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlite3AppendChar(pAccum, width-1, ' ');
sqlite3_str_appendchar(pAccum, width-1, ' ');
width = 0;
}
sqlite3AppendChar(pAccum, precision-1, c);
while( precision-- > 1 ){
sqlite3_str_append(pAccum, buf, length);
}
}
length = 1;
buf[0] = c;
bufpt = buf;
break;
flag_altform2 = 1;
goto adjust_width_for_utf8;
case etSTRING:
case etDYNSTRING:
if( bArgList ){
@@ -651,17 +686,50 @@ void sqlite3VXPrintf(
if( bufpt==0 ){
bufpt = "";
}else if( xtype==etDYNSTRING ){
if( pAccum->nChar==0
&& pAccum->mxAlloc
&& width==0
&& precision<0
&& pAccum->accError==0
){
/* Special optimization for sqlite3_mprintf("%z..."):
** Extend an existing memory allocation rather than creating
** a new one. */
assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 );
pAccum->zText = bufpt;
pAccum->nAlloc = sqlite3DbMallocSize(pAccum->db, bufpt);
pAccum->nChar = 0x7fffffff & (int)strlen(bufpt);
pAccum->printfFlags |= SQLITE_PRINTF_MALLOCED;
length = 0;
break;
}
zExtra = bufpt;
}
if( precision>=0 ){
for(length=0; length<precision && bufpt[length]; length++){}
if( flag_altform2 ){
/* Set length to the number of bytes needed in order to display
** precision characters */
unsigned char *z = (unsigned char*)bufpt;
while( precision-- > 0 && z[0] ){
SQLITE_SKIP_UTF8(z);
}
length = (int)(z - (unsigned char*)bufpt);
}else{
for(length=0; length<precision && bufpt[length]; length++){}
}
}else{
length = sqlite3Strlen30(bufpt);
length = 0x7fffffff & (int)strlen(bufpt);
}
adjust_width_for_utf8:
if( flag_altform2 && width>0 ){
/* Adjust width to account for extra bytes in UTF-8 characters */
int ii = length - 1;
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
}
break;
case etSQLESCAPE: /* Escape ' characters */
case etSQLESCAPE2: /* Escape ' and enclose in '...' */
case etSQLESCAPE3: { /* Escape " characters */
case etSQLESCAPE: /* %q: Escape ' characters */
case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
case etSQLESCAPE3: { /* %w: Escape " characters */
int i, j, k, n, isnull;
int needQuote;
char ch;
@@ -675,16 +743,24 @@ void sqlite3VXPrintf(
}
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
/* For %q, %Q, and %w, the precision is the number of byte (or
** characters if the ! flags is present) to use from the input.
** Because of the extra quoting characters inserted, the number
** of output characters may be larger than the precision.
*/
k = precision;
for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
if( ch==q ) n++;
if( flag_altform2 && (ch&0xc0)==0xc0 ){
while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
}
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 3;
if( n>etBUFSIZE ){
bufpt = zExtra = sqlite3Malloc( n );
if( bufpt==0 ){
setStrAccumError(pAccum, STRACCUM_NOMEM);
setStrAccumError(pAccum, SQLITE_NOMEM);
return;
}
}else{
@@ -700,10 +776,7 @@ void sqlite3VXPrintf(
if( needQuote ) bufpt[j++] = q;
bufpt[j] = 0;
length = j;
/* The precision in %q and %Q means how many input characters to
** consume, not the length of the output...
** if( precision>=0 && precision<length ) length = precision; */
break;
goto adjust_width_for_utf8;
}
case etTOKEN: {
Token *pToken;
@@ -711,7 +784,7 @@ void sqlite3VXPrintf(
pToken = va_arg(ap, Token*);
assert( bArgList==0 );
if( pToken && pToken->n ){
sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
}
length = width = 0;
break;
@@ -727,10 +800,10 @@ void sqlite3VXPrintf(
assert( bArgList==0 );
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase ){
sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase);
sqlite3StrAccumAppend(pAccum, ".", 1);
sqlite3_str_appendall(pAccum, pItem->zDatabase);
sqlite3_str_append(pAccum, ".", 1);
}
sqlite3StrAccumAppendAll(pAccum, pItem->zName);
sqlite3_str_appendall(pAccum, pItem->zName);
length = width = 0;
break;
}
@@ -742,15 +815,18 @@ void sqlite3VXPrintf(
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
** the output. Both length and width are in bytes, not characters,
** at this point. If the "!" flag was present on string conversions
** indicating that width and precision should be expressed in characters,
** then the values have been translated prior to reaching this point.
*/
width -= length;
if( width>0 ){
if( !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
sqlite3StrAccumAppend(pAccum, bufpt, length);
if( flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' ');
sqlite3_str_append(pAccum, bufpt, length);
if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' ');
}else{
sqlite3StrAccumAppend(pAccum, bufpt, length);
sqlite3_str_append(pAccum, bufpt, length);
}
if( zExtra ){
@@ -771,18 +847,17 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
testcase(p->accError==SQLITE_TOOBIG);
testcase(p->accError==SQLITE_NOMEM);
return 0;
}
if( p->mxAlloc==0 ){
N = p->nAlloc - p->nChar - 1;
setStrAccumError(p, STRACCUM_TOOBIG);
setStrAccumError(p, SQLITE_TOOBIG);
return N;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
i64 szNew = p->nChar;
assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -790,8 +865,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
szNew += p->nChar;
}
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
sqlite3_str_reset(p);
setStrAccumError(p, SQLITE_TOOBIG);
return 0;
}else{
p->nAlloc = (int)szNew;
@@ -808,8 +883,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
sqlite3_str_reset(p);
setStrAccumError(p, SQLITE_NOMEM);
return 0;
}
}
@@ -819,12 +894,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
/*
** Append N copies of character c to the given string buffer.
*/
void sqlite3AppendChar(StrAccum *p, int N, char c){
void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){
testcase( p->nChar + (i64)N > 0x7fffffff );
if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
assert( (p->zText==p->zBase)==!isMalloced(p) );
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -832,9 +906,9 @@ void sqlite3AppendChar(StrAccum *p, int N, char c){
** The StrAccum "p" is not large enough to accept N new bytes of z[].
** So enlarge if first, then do the append.
**
** This is a helper routine to sqlite3StrAccumAppend() that does special-case
** This is a helper routine to sqlite3_str_append() that does special-case
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
** sqlite3_str_append() routine can use fast calling semantics.
*/
static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
@@ -842,14 +916,13 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
}
/*
** Append N bytes of text from z to the StrAccum object. Increase the
** size of the memory allocation for StrAccum if necessary.
*/
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
void sqlite3_str_append(sqlite3_str *p, const char *z, int N){
assert( z!=0 || N==0 );
assert( p->zText!=0 || p->nChar==0 || p->accError );
assert( N>=0 );
@@ -866,8 +939,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
/*
** Append the complete text of zero-terminated string z[] to the p string.
*/
void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z));
void sqlite3_str_appendall(sqlite3_str *p, const char *z){
sqlite3_str_append(p, z, sqlite3Strlen30(z));
}
@@ -877,19 +950,20 @@ void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
** pointer if any kind of error was encountered.
*/
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
char *zText;
assert( p->mxAlloc>0 && !isMalloced(p) );
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
if( zText ){
memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
setStrAccumError(p, STRACCUM_NOMEM);
setStrAccumError(p, SQLITE_NOMEM);
}
return p->zText;
p->zText = zText;
return zText;
}
char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
if( p->mxAlloc>0 && !isMalloced(p) ){
return strAccumFinishRealloc(p);
@@ -898,15 +972,56 @@ char *sqlite3StrAccumFinish(StrAccum *p){
return p->zText;
}
/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one. This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/
static sqlite3_str sqlite3OomStr = {
0, 0, 0, 0, 0, SQLITE_NOMEM, 0
};
/* Finalize a string created using sqlite3_str_new().
*/
char *sqlite3_str_finish(sqlite3_str *p){
char *z;
if( p!=0 && p!=&sqlite3OomStr ){
z = sqlite3StrAccumFinish(p);
sqlite3_free(p);
}else{
z = 0;
}
return z;
}
/* Return any error code associated with p */
int sqlite3_str_errcode(sqlite3_str *p){
return p ? p->accError : SQLITE_NOMEM;
}
/* Return the current length of p in bytes */
int sqlite3_str_length(sqlite3_str *p){
return p ? p->nChar : 0;
}
/* Return the current value for p */
char *sqlite3_str_value(sqlite3_str *p){
if( p==0 || p->nChar==0 ) return 0;
p->zText[p->nChar] = 0;
return p->zText;
}
/*
** Reset an StrAccum string. Reclaim all malloced memory.
*/
void sqlite3StrAccumReset(StrAccum *p){
assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
void sqlite3_str_reset(StrAccum *p){
if( isMalloced(p) ){
sqlite3DbFree(p->db, p->zText);
p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
}
p->nAlloc = 0;
p->nChar = 0;
p->zText = 0;
}
@@ -925,15 +1040,27 @@ void sqlite3StrAccumReset(StrAccum *p){
** allocations will ever occur.
*/
void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
p->zText = p->zBase = zBase;
p->zText = zBase;
p->db = db;
p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
p->nChar = 0;
p->accError = 0;
p->printfFlags = 0;
}
/* Allocate and initialize a new dynamic string object */
sqlite3_str *sqlite3_str_new(sqlite3 *db){
sqlite3_str *p = sqlite3_malloc64(sizeof(*p));
if( p ){
sqlite3StrAccumInit(p, 0, 0, 0,
db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
}else{
p = &sqlite3OomStr;
}
return p;
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
@@ -946,9 +1073,9 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
acc.printfFlags = SQLITE_PRINTF_INTERNAL;
sqlite3VXPrintf(&acc, zFormat, ap);
sqlite3_str_vappendf(&acc, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.accError==STRACCUM_NOMEM ){
if( acc.accError==SQLITE_NOMEM ){
sqlite3OomFault(db);
}
return z;
@@ -986,7 +1113,7 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
if( sqlite3_initialize() ) return 0;
#endif
sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
sqlite3VXPrintf(&acc, zFormat, ap);
sqlite3_str_vappendf(&acc, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
return z;
}
@@ -1031,7 +1158,7 @@ char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
}
#endif
sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
sqlite3VXPrintf(&acc, zFormat, ap);
sqlite3_str_vappendf(&acc, zFormat, ap);
zBuf[acc.nChar] = 0;
return zBuf;
}
@@ -1053,7 +1180,7 @@ char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
** allocate memory because it might be called while the memory allocator
** mutex is held.
**
** sqlite3VXPrintf() might ask for *temporary* memory allocations for
** sqlite3_str_vappendf() might ask for *temporary* memory allocations for
** certain format characters (%q) or for very large precisions or widths.
** Care must be taken that any sqlite3_log() calls that occur while the
** memory mutex is held do not use these mechanisms.
@@ -1063,7 +1190,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
sqlite3VXPrintf(&acc, zFormat, ap);
sqlite3_str_vappendf(&acc, zFormat, ap);
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
sqlite3StrAccumFinish(&acc));
}
@@ -1092,22 +1219,29 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
char zBuf[500];
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
va_start(ap,zFormat);
sqlite3VXPrintf(&acc, zFormat, ap);
sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
sqlite3StrAccumFinish(&acc);
#ifdef SQLITE_OS_TRACE_PROC
{
extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf);
SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf));
}
#else
fprintf(stdout,"%s", zBuf);
fflush(stdout);
#endif
}
#endif
/*
** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument
** variable-argument wrapper around sqlite3_str_vappendf(). The bFlags argument
** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
*/
void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
va_list ap;
va_start(ap,zFormat);
sqlite3VXPrintf(p, zFormat, ap);
sqlite3_str_vappendf(p, zFormat, ap);
va_end(ap);
}
+243 -105
View File
@@ -75,29 +75,31 @@ static void resolveAlias(
assert( pOrig!=0 );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
ExprSetProperty(pDup, EP_Alias);
if( pDup!=0 ){
if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
ExprSetProperty(pDup, EP_Alias);
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
** The pExpr->u.zToken might point into memory that will be freed by the
** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
pExpr->flags |= EP_MemToken;
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
** The pExpr->u.zToken might point into memory that will be freed by the
** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
pExpr->flags |= EP_MemToken;
}
sqlite3DbFree(db, pDup);
}
sqlite3DbFree(db, pDup);
ExprSetProperty(pExpr, EP_Alias);
}
@@ -191,7 +193,7 @@ static int lookupName(
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
int isTrigger = 0; /* True if resolved to a trigger column */
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table hold the row */
Column *pCol; /* A column of pTab */
@@ -262,6 +264,9 @@ static int lookupName(
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
continue;
}
if( IN_RENAME_OBJECT && pItem->zAlias ){
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->pTab);
}
}
if( 0==(cntTab++) ){
pMatch = pItem;
@@ -296,22 +301,35 @@ static int lookupName(
}
} /* if( pSrcList ) */
#ifndef SQLITE_OMIT_TRIGGER
#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT)
/* If we have not already resolved the name, then maybe
** it is a new.* or old.* trigger argument reference
** it is a new.* or old.* trigger argument reference. Or
** maybe it is an excluded.* from an upsert.
*/
if( zDb==0 && zTab!=0 && cntTab==0 && pParse->pTriggerTab!=0 ){
int op = pParse->eTriggerOp;
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
pExpr->iTable = 1;
pTab = pParse->pTriggerTab;
}else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
pExpr->iTable = 0;
pTab = pParse->pTriggerTab;
}else{
pTab = 0;
if( zDb==0 && zTab!=0 && cntTab==0 ){
pTab = 0;
#ifndef SQLITE_OMIT_TRIGGER
if( pParse->pTriggerTab!=0 ){
int op = pParse->eTriggerOp;
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
pExpr->iTable = 1;
pTab = pParse->pTriggerTab;
}else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
pExpr->iTable = 0;
pTab = pParse->pTriggerTab;
}
}
#endif /* SQLITE_OMIT_TRIGGER */
#ifndef SQLITE_OMIT_UPSERT
if( (pNC->ncFlags & NC_UUpsert)!=0 ){
Upsert *pUpsert = pNC->uNC.pUpsert;
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
pTab = pUpsert->pUpsertSrc->a[0].pTab;
pExpr->iTable = 2;
}
}
#endif /* SQLITE_OMIT_UPSERT */
if( pTab ){
int iCol;
@@ -331,24 +349,42 @@ static int lookupName(
}
if( iCol<pTab->nCol ){
cnt++;
if( iCol<0 ){
pExpr->affinity = SQLITE_AFF_INTEGER;
}else if( pExpr->iTable==0 ){
testcase( iCol==31 );
testcase( iCol==32 );
pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
}else{
testcase( iCol==31 );
testcase( iCol==32 );
pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
#ifndef SQLITE_OMIT_UPSERT
if( pExpr->iTable==2 ){
testcase( iCol==(-1) );
if( IN_RENAME_OBJECT ){
pExpr->iColumn = iCol;
pExpr->pTab = pTab;
eNewExprOp = TK_COLUMN;
}else{
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
eNewExprOp = TK_REGISTER;
ExprSetProperty(pExpr, EP_Alias);
}
}else
#endif /* SQLITE_OMIT_UPSERT */
{
#ifndef SQLITE_OMIT_TRIGGER
if( iCol<0 ){
pExpr->affinity = SQLITE_AFF_INTEGER;
}else if( pExpr->iTable==0 ){
testcase( iCol==31 );
testcase( iCol==32 );
pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
}else{
testcase( iCol==31 );
testcase( iCol==32 );
pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
}
pExpr->pTab = pTab;
pExpr->iColumn = (i16)iCol;
eNewExprOp = TK_TRIGGER;
#endif /* SQLITE_OMIT_TRIGGER */
}
pExpr->iColumn = (i16)iCol;
pExpr->pTab = pTab;
isTrigger = 1;
}
}
}
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
#endif /* !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) */
/*
** Perhaps the name is a reference to the ROWID
@@ -383,10 +419,12 @@ static int lookupName(
** is supported for backwards compatibility only. Hence, we issue a warning
** on sqlite3_log() whenever the capability is used.
*/
if( (pEList = pNC->pEList)!=0
&& zTab==0
if( (pNC->ncFlags & NC_UEList)!=0
&& cnt==0
&& zTab==0
){
pEList = pNC->uNC.pEList;
assert( pEList!=0 );
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@@ -407,6 +445,9 @@ static int lookupName(
cnt = 1;
pMatch = 0;
assert( zTab==0 && zDb==0 );
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
}
goto lookupname_end;
}
}
@@ -431,10 +472,16 @@ static int lookupName(
** Because no reference was made to outer contexts, the pNC->nRef
** fields are not changed in any context.
*/
if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){
pExpr->op = TK_STRING;
pExpr->pTab = 0;
return WRC_Prune;
if( cnt==0 && zTab==0 ){
assert( pExpr->op==TK_ID );
if( ExprHasProperty(pExpr,EP_DblQuoted) ){
pExpr->op = TK_STRING;
pExpr->pTab = 0;
return WRC_Prune;
}
if( sqlite3ExprIdToTrueFalse(pExpr) ){
return WRC_Prune;
}
}
/*
@@ -477,7 +524,7 @@ static int lookupName(
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN);
pExpr->op = eNewExprOp;
ExprSetProperty(pExpr, EP_Leaf);
lookupname_end:
if( cnt==1 ){
@@ -596,7 +643,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
SrcList *pSrcList = pNC->pSrcList;
struct SrcList_item *pItem;
assert( pSrcList && pSrcList->nSrc==1 );
pItem = pSrcList->a;
pItem = pSrcList->a;
assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
pExpr->op = TK_COLUMN;
pExpr->pTab = pItem->pTab;
pExpr->iTable = pItem->iCursor;
@@ -627,17 +675,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
zTable = 0;
zColumn = pExpr->u.zToken;
}else{
Expr *pLeft = pExpr->pLeft;
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
zTable = pExpr->pLeft->u.zToken;
zColumn = pRight->u.zToken;
}else{
assert( pRight->op==TK_DOT );
zDb = pExpr->pLeft->u.zToken;
zTable = pRight->pLeft->u.zToken;
zColumn = pRight->pRight->u.zToken;
zDb = pLeft->u.zToken;
pLeft = pRight->pLeft;
pRight = pRight->pRight;
}
zTable = pLeft->u.zToken;
zColumn = pRight->u.zToken;
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
}
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, (void*)&pExpr->pTab, (void*)pLeft);
}
}
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
@@ -720,40 +775,95 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
NC_IdxExpr|NC_PartIdx);
}
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
is_agg = 0;
}else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
&& pParse->explain==0
if( 0==IN_RENAME_OBJECT ){
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|| (pDef->xValue==0 && pDef->xInverse==0)
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
);
if( pDef && pDef->xValue==0 && pExpr->pWin ){
sqlite3ErrorMsg(pParse,
"%.*s() may not be used as a window function", nId, zId
);
pNC->nErr++;
}else if(
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|| (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
|| (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
){
const char *zType;
if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
zType = "window";
}else{
zType = "aggregate";
}
sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
pNC->nErr++;
is_agg = 0;
}
#else
if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId);
pNC->nErr++;
is_agg = 0;
}
#endif
){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
pNC->nErr++;
}else if( wrong_num_args ){
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
nId, zId);
pNC->nErr++;
else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
&& pParse->explain==0
#endif
){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
pNC->nErr++;
}else if( wrong_num_args ){
sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
nId, zId);
pNC->nErr++;
}
if( is_agg ){
#ifndef SQLITE_OMIT_WINDOWFUNC
pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
#else
pNC->ncFlags &= ~NC_AllowAgg;
#endif
}
}
if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
NameContext *pNC2 = pNC;
pExpr->op = TK_AGG_FUNCTION;
pExpr->op2 = 0;
while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
pExpr->op2++;
pNC2 = pNC2->pNext;
}
assert( pDef!=0 );
if( pNC2 ){
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pExpr->pWin ){
Select *pSel = pNC->pWinSelect;
sqlite3WalkExprList(pWalker, pExpr->pWin->pPartition);
sqlite3WalkExprList(pWalker, pExpr->pWin->pOrderBy);
sqlite3WalkExpr(pWalker, pExpr->pWin->pFilter);
sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef);
if( 0==pSel->pWin
|| 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin)
){
pExpr->pWin->pNextWin = pSel->pWin;
pSel->pWin = pExpr->pWin;
}
pNC->ncFlags |= NC_AllowWin;
}else
#endif /* SQLITE_OMIT_WINDOWFUNC */
{
NameContext *pNC2 = pNC;
pExpr->op = TK_AGG_FUNCTION;
pExpr->op2 = 0;
while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
pExpr->op2++;
pNC2 = pNC2->pNext;
}
assert( pDef!=0 );
if( pNC2 ){
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
}
pNC->ncFlags |= NC_AllowAgg;
}
pNC->ncFlags |= NC_AllowAgg;
}
/* FIX ME: Compute pExpr->affinity based on the expected return
** type of the function
@@ -782,15 +892,30 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
break;
}
case TK_IS:
case TK_ISNOT: {
Expr *pRight;
assert( !ExprHasProperty(pExpr, EP_Reduced) );
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
** and "x IS NOT FALSE". */
if( (pRight = pExpr->pRight)->op==TK_ID ){
int rc = resolveExprStep(pWalker, pRight);
if( rc==WRC_Abort ) return WRC_Abort;
if( pRight->op==TK_TRUEFALSE ){
pExpr->op2 = pExpr->op;
pExpr->op = TK_TRUTH;
return WRC_Continue;
}
}
/* Fall thru */
}
case TK_BETWEEN:
case TK_EQ:
case TK_NE:
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_IS:
case TK_ISNOT: {
case TK_GE: {
int nLeft, nRight;
if( pParse->db->mallocFailed ) break;
assert( pExpr->pLeft!=0 );
@@ -893,8 +1018,8 @@ static int resolveOrderByTermToExprList(
memset(&nc, 0, sizeof(nc));
nc.pParse = pParse;
nc.pSrcList = pSelect->pSrc;
nc.pEList = pEList;
nc.ncFlags = NC_AllowAgg;
nc.uNC.pEList = pEList;
nc.ncFlags = NC_AllowAgg|NC_UEList;
nc.nErr = 0;
db = pParse->db;
savedSuppErr = db->suppressErr;
@@ -959,12 +1084,10 @@ static int resolveCompoundOrderBy(
pOrderBy = pSelect->pOrderBy;
if( pOrderBy==0 ) return 0;
db = pParse->db;
#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
return 1;
}
#endif
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].done = 0;
}
@@ -1056,12 +1179,10 @@ int sqlite3ResolveOrderGroupBy(
struct ExprList_item *pItem;
if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
return 1;
}
#endif
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
@@ -1143,6 +1264,19 @@ static int resolveOrderGroupBy(
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pE->pWin ){
/* Since this window function is being changed into a reference
** to the same window function the result set, remove the instance
** of this window function from the Select.pWin list. */
Window **pp;
for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
if( *pp==pE->pWin ){
*pp = (*pp)->pNextWin;
}
}
}
#endif
pItem->u.x.iOrderByCol = j+1;
}
}
@@ -1199,8 +1333,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
if( sqlite3ResolveExprNames(&sNC, p->pLimit) ||
sqlite3ResolveExprNames(&sNC, p->pOffset) ){
sNC.pWinSelect = p;
if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
return WRC_Abort;
}
@@ -1248,12 +1382,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
*/
sNC.ncFlags = NC_AllowAgg;
sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
/* Resolve names in the result set. */
if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
sNC.ncFlags &= ~NC_AllowWin;
/* If there are no aggregate functions in the result-set, and no GROUP BY
** expression, do not allow aggregates in any of the other expressions.
@@ -1282,7 +1417,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** Minor point: If this is the case, then the expression will be
** re-evaluated for each reference to it.
*/
sNC.pEList = p->pEList;
assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert))==0 );
sNC.uNC.pEList = p->pEList;
sNC.ncFlags |= NC_UEList;
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
@@ -1300,7 +1437,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** outer queries
*/
sNC.pNext = 0;
sNC.ncFlags |= NC_AllowAgg;
sNC.ncFlags |= NC_AllowAgg|NC_AllowWin;
/* If this is a converted compound query, move the ORDER BY clause from
** the sub-query back to the parent query. At this point each term
@@ -1331,6 +1468,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( db->mallocFailed ){
return WRC_Abort;
}
sNC.ncFlags &= ~NC_AllowWin;
/* Resolve the GROUP BY clause. At the same time, make sure
** the GROUP BY clause does not contain aggregate functions.
@@ -1515,7 +1653,7 @@ void sqlite3ResolveSelfReference(
Table *pTab, /* The table being referenced */
int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NUL. */
ExprList *pList /* Expression list to resolve. May be NULL. */
){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
+28 -24
View File
@@ -124,30 +124,23 @@ struct RowSet {
#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
/*
** Turn bulk memory into a RowSet object. N bytes of memory
** are available at pSpace. The db pointer is used as a memory context
** for any subsequent allocations that need to occur.
** Return a pointer to the new RowSet object.
**
** It must be the case that N is sufficient to make a Rowset. If not
** an assertion fault occurs.
**
** If N is larger than the minimum, use the surplus as an initial
** allocation of entries available to be filled.
** Allocate a RowSet object. Return NULL if a memory allocation
** error occurs.
*/
RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
RowSet *p;
assert( N >= ROUND8(sizeof(*p)) );
p = pSpace;
p->pChunk = 0;
p->db = db;
p->pEntry = 0;
p->pLast = 0;
p->pForest = 0;
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
p->rsFlags = ROWSET_SORTED;
p->iBatch = 0;
RowSet *sqlite3RowSetInit(sqlite3 *db){
RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p));
if( p ){
int N = sqlite3DbMallocSize(db, p);
p->pChunk = 0;
p->db = db;
p->pEntry = 0;
p->pLast = 0;
p->pForest = 0;
p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
p->rsFlags = ROWSET_SORTED;
p->iBatch = 0;
}
return p;
}
@@ -156,7 +149,8 @@ RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
** the RowSet has allocated over its lifetime. This routine is
** the destructor for the RowSet.
*/
void sqlite3RowSetClear(RowSet *p){
void sqlite3RowSetClear(void *pArg){
RowSet *p = (RowSet*)pArg;
struct RowSetChunk *pChunk, *pNextChunk;
for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
pNextChunk = pChunk->pNextChunk;
@@ -170,6 +164,16 @@ void sqlite3RowSetClear(RowSet *p){
p->rsFlags = ROWSET_SORTED;
}
/*
** Deallocate all chunks from a RowSet. This frees all memory that
** the RowSet has allocated over its lifetime. This routine is
** the destructor for the RowSet.
*/
void sqlite3RowSetDelete(void *pArg){
sqlite3RowSetClear(pArg);
sqlite3DbFree(((RowSet*)pArg)->db, pArg);
}
/*
** Allocate a new RowSetEntry object that is associated with the
** given RowSet. Return a pointer to the new and completely uninitialized
+1377 -815
View File
File diff suppressed because it is too large Load Diff
-8398
View File
File diff suppressed because it is too large Load Diff
+2334 -540
View File
File diff suppressed because it is too large Load Diff
+810 -226
View File
File diff suppressed because it is too large Load Diff
+50 -5
View File
@@ -134,7 +134,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -246,7 +246,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -292,6 +292,30 @@ struct sqlite3_api_routines {
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
int (*vtab_nochange)(sqlite3_context*);
int (*value_nochange)(sqlite3_value*);
const char *(*vtab_collation)(sqlite3_index_info*,int);
/* Version 3.24.0 and later */
int (*keyword_count)(void);
int (*keyword_name)(int,const char**,int*);
int (*keyword_check)(const char*,int);
sqlite3_str *(*str_new)(sqlite3*);
char *(*str_finish)(sqlite3_str*);
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
void (*str_append)(sqlite3_str*, const char *zIn, int N);
void (*str_appendall)(sqlite3_str*, const char *zIn);
void (*str_appendchar)(sqlite3_str*, int N, char C);
void (*str_reset)(sqlite3_str*);
int (*str_errcode)(sqlite3_str*);
int (*str_length)(sqlite3_str*);
char *(*str_value)(sqlite3_str*);
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*));
};
/*
@@ -418,7 +442,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -442,7 +466,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -518,7 +542,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
@@ -558,6 +582,27 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
#define sqlite3_result_pointer sqlite3_api->result_pointer
#define sqlite3_value_pointer sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
#define sqlite3_value_nochange sqlite3_api->value_nochange
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
/* Version 3.24.0 and later */
#define sqlite3_keyword_count sqlite3_api->keyword_count
#define sqlite3_keyword_name sqlite3_api->keyword_name
#define sqlite3_keyword_check sqlite3_api->keyword_check
#define sqlite3_str_new sqlite3_api->str_new
#define sqlite3_str_finish sqlite3_api->str_finish
#define sqlite3_str_appendf sqlite3_api->str_appendf
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
#define sqlite3_str_append sqlite3_api->str_append
#define sqlite3_str_appendall sqlite3_api->str_appendall
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
#define sqlite3_str_reset sqlite3_api->str_reset
#define sqlite3_str_errcode sqlite3_api->str_errcode
#define sqlite3_str_length sqlite3_api->str_length
#define sqlite3_str_value sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+423 -222
View File
File diff suppressed because it is too large Load Diff
+33 -4
View File
@@ -122,7 +122,6 @@ void sqlite3StatusHighwater(int op, int X){
: sqlite3MallocMutex()) );
assert( op==SQLITE_STATUS_MALLOC_SIZE
|| op==SQLITE_STATUS_PAGECACHE_SIZE
|| op==SQLITE_STATUS_SCRATCH_SIZE
|| op==SQLITE_STATUS_PARSER_STACK );
if( newValue>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = newValue;
@@ -171,6 +170,28 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
return rc;
}
/*
** Return the number of LookasideSlot elements on the linked list
*/
static u32 countLookasideSlots(LookasideSlot *p){
u32 cnt = 0;
while( p ){
p = p->pNext;
cnt++;
}
return cnt;
}
/*
** Count the number of slots of lookaside memory that are outstanding
*/
int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
u32 nInit = countLookasideSlots(db->lookaside.pInit);
u32 nFree = countLookasideSlots(db->lookaside.pFree);
if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
return db->lookaside.nSlot - (nInit+nFree);
}
/*
** Query status information for a single database connection
*/
@@ -190,10 +211,15 @@ int sqlite3_db_status(
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
*pCurrent = db->lookaside.nOut;
*pHighwater = db->lookaside.mxOut;
*pCurrent = sqlite3LookasideUsed(db, pHighwater);
if( resetFlag ){
db->lookaside.mxOut = db->lookaside.nOut;
LookasideSlot *p = db->lookaside.pFree;
if( p ){
while( p->pNext ) p = p->pNext;
p->pNext = db->lookaside.pInit;
db->lookaside.pInit = db->lookaside.pFree;
db->lookaside.pFree = 0;
}
}
break;
}
@@ -311,6 +337,9 @@ int sqlite3_db_status(
** pagers the database handle is connected to. *pHighwater is always set
** to zero.
*/
case SQLITE_DBSTATUS_CACHE_SPILL:
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
/* Fall through into the next case */
case SQLITE_DBSTATUS_CACHE_HIT:
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
+265 -789
View File
File diff suppressed because it is too large Load Diff
+181 -3
View File
@@ -2256,6 +2256,27 @@ static int SQLITE_TCLAPI test_config_sqllog(
}
#endif
/*
** Usage: sqlite3_config_sorterref
**
** Set the SQLITE_CONFIG_SORTERREF_SIZE configuration option
*/
static int SQLITE_TCLAPI test_config_sorterref(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int iVal;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &iVal) ) return TCL_ERROR;
sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, iVal);
return TCL_OK;
}
/*
** Usage: vfs_current_time_int64
**
@@ -2372,6 +2393,8 @@ static int SQLITE_TCLAPI test_snapshot_open(
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}else{
Tcl_ResetResult(interp);
}
return TCL_OK;
}
@@ -2553,6 +2576,46 @@ static int SQLITE_TCLAPI test_delete_database(
return TCL_OK;
}
/*
** Usage: atomic_batch_write PATH
*/
static int SQLITE_TCLAPI test_atomic_batch_write(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char *zFile = 0; /* Path to file to test */
sqlite3 *db = 0; /* Database handle */
sqlite3_file *pFd = 0; /* SQLite fd open on zFile */
int bRes = 0; /* Integer result of this command */
int dc = 0; /* Device-characteristics mask */
int rc; /* sqlite3_open() return code */
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
return TCL_ERROR;
}
zFile = Tcl_GetString(objv[1]);
rc = sqlite3_open(zFile, &db);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
sqlite3_close(db);
return TCL_ERROR;
}
rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
dc = pFd->pMethods->xDeviceCharacteristics(pFd);
if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
bRes = 1;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
sqlite3_close(db);
return TCL_OK;
}
/*
** Usage: sqlite3_next_stmt DB STMT
**
@@ -4519,6 +4582,35 @@ static int SQLITE_TCLAPI test_complete16(
return TCL_OK;
}
/*
** Usage: sqlite3_normalize SQL
**
** Return the normalized value for an SQL statement.
*/
static int SQLITE_TCLAPI test_normalize(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char *zSql;
char *zNorm;
extern char *sqlite3_normalize(const char*);
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SQL");
return TCL_ERROR;
}
zSql = (char*)Tcl_GetString(objv[1]);
zNorm = sqlite3_normalize(zSql);
if( zNorm ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(zNorm, -1));
sqlite3_free(zNorm);
}
return TCL_OK;
}
/*
** Usage: sqlite3_step STMT
**
@@ -5594,6 +5686,44 @@ static int SQLITE_TCLAPI file_control_lasterrno_test(
return TCL_OK;
}
/*
** tclcmd: file_control_data_version DB DBNAME
**
** This TCL command runs the sqlite3_file_control with the
** SQLITE_FCNTL_DATA_VERSION opcode, returning the result.
*/
static int SQLITE_TCLAPI file_control_data_version(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
unsigned int iVers; /* data version */
char *zDb; /* Db name ("main", "temp" etc.) */
sqlite3 *db; /* Database handle */
int rc; /* file_control() return code */
char zBuf[100];
if( objc!=3 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers);
if( rc ){
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
return TCL_ERROR;
}else{
sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
return TCL_OK;
}
}
/*
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
**
@@ -6854,17 +6984,16 @@ static int SQLITE_TCLAPI optimization_control(
{ "all", SQLITE_AllOpts },
{ "none", 0 },
{ "query-flattener", SQLITE_QueryFlattener },
{ "column-cache", SQLITE_ColumnCache },
{ "groupby-order", SQLITE_GroupByOrder },
{ "factor-constants", SQLITE_FactorOutConst },
{ "distinct-opt", SQLITE_DistinctOpt },
{ "cover-idx-scan", SQLITE_CoverIdxScan },
{ "order-by-idx-join", SQLITE_OrderByIdxJoin },
{ "transitive", SQLITE_Transitive },
{ "subquery-coroutine", SQLITE_SubqCoroutine },
{ "omit-noop-join", SQLITE_OmitNoopJoin },
{ "stat3", SQLITE_Stat34 },
{ "stat4", SQLITE_Stat34 },
{ "skip-scan", SQLITE_SkipScan },
};
if( objc!=4 ){
@@ -6921,6 +7050,9 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
#ifdef SQLITE_HAVE_ZLIB
extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*);
#endif
static const struct {
const char *zExtName;
int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
@@ -6942,6 +7074,9 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
{ "totype", sqlite3_totype_init },
{ "unionvtab", sqlite3_unionvtab_init },
{ "wholenumber", sqlite3_wholenumber_init },
#ifdef SQLITE_HAVE_ZLIB
{ "zipfile", sqlite3_zipfile_init },
#endif
};
sqlite3 *db;
const char *zName;
@@ -7323,6 +7458,8 @@ static int SQLITE_TCLAPI test_sqlite3_db_config(
{ "LOAD_EXTENSION", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
{ "NO_CKPT_ON_CLOSE",SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
{ "QPSG", SQLITE_DBCONFIG_ENABLE_QPSG },
{ "TRIGGER_EQP", SQLITE_DBCONFIG_TRIGGER_EQP },
{ "RESET_DB", SQLITE_DBCONFIG_RESET_DATABASE },
};
int i;
int v;
@@ -7375,6 +7512,35 @@ static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube(
}
}
/*
** Usage: sqlite3_mmap_warm DB DBNAME
*/
static int SQLITE_TCLAPI test_mmap_warm(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
extern int sqlite3_mmap_warm(sqlite3 *db, const char *);
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB ?DBNAME?");
return TCL_ERROR;
}else{
int rc;
sqlite3 *db;
const char *zDb = 0;
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
if( objc==3 ){
zDb = Tcl_GetString(objv[2]);
}
rc = sqlite3_mmap_warm(db, zDb);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_OK;
}
}
/*
** Register commands with the TCL interpreter.
*/
@@ -7473,6 +7639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_open16", test_open16 ,0 },
{ "sqlite3_open_v2", test_open_v2 ,0 },
{ "sqlite3_complete16", test_complete16 ,0 },
{ "sqlite3_normalize", test_normalize ,0 },
{ "sqlite3_prepare", test_prepare ,0 },
{ "sqlite3_prepare16", test_prepare16 ,0 },
@@ -7572,6 +7739,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_data_version", file_control_data_version, 0 },
#if SQLITE_OS_WIN
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "file_control_win32_get_handle", file_control_win32_get_handle, 0 },
@@ -7644,7 +7812,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
#endif
{ "sqlite3_delete_database", test_delete_database, 0 },
{ "sqlite3_delete_database", test_delete_database, 0 },
{ "atomic_batch_write", test_atomic_batch_write, 0 },
{ "sqlite3_mmap_warm", test_mmap_warm, 0 },
{ "sqlite3_config_sorterref", test_config_sorterref, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
@@ -7668,6 +7839,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_FTS3
extern int sqlite3_fts3_enable_parentheses;
#endif
#endif
#if defined(SQLITE_ENABLE_SELECTTRACE)
extern int sqlite3SelectTrace;
#endif
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
@@ -7754,6 +7928,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_sync_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_fullsync_count",
(char*)&sqlite3_fullsync_count, TCL_LINK_INT);
#if defined(SQLITE_ENABLE_SELECTTRACE)
Tcl_LinkVar(interp, "sqlite3SelectTrace",
(char*)&sqlite3SelectTrace, TCL_LINK_INT);
#endif
#if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
(char*)&sqlite3_fts3_enable_parentheses, TCL_LINK_INT);
+1 -1
View File
@@ -133,7 +133,7 @@ static int SQLITE_TCLAPI btree_begin_transaction(
}
pBt = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeBeginTrans(pBt, 1);
rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
sqlite3BtreeLeave(pBt);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
+25
View File
@@ -736,6 +736,7 @@ static int processDevSymArgs(
{ "sequential", SQLITE_IOCAP_SEQUENTIAL },
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
{ "batch-atomic", SQLITE_IOCAP_BATCH_ATOMIC },
{ 0, 0 }
};
@@ -976,7 +977,30 @@ static int SQLITE_TCLAPI devSymObjCmd(
devsym_register(iDc, iSectorSize);
return TCL_OK;
}
/*
** tclcmd: sqlite3_crash_on_write N
*/
static int SQLITE_TCLAPI writeCrashObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
void devsym_crash_on_write(int);
int nWrite = 0;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
return TCL_ERROR;
}
devsym_crash_on_write(nWrite);
return TCL_OK;
}
/*
@@ -1068,6 +1092,7 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
+11 -10
View File
@@ -897,17 +897,18 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
}
if( zOp[0]=='L' ){
zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
zSep, zNewCol);
} else {
zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zNewCol, zOp);
if( zOp ){
if( zOp[0]=='L' ){
zNew = sqlite3_mprintf(" %s %s LIKE (SELECT '%%'||?||'%%')",
zSep, zNewCol);
} else {
zNew = sqlite3_mprintf(" %s %s %s ?", zSep, zNewCol, zOp);
}
string_concat(&zQuery, zNew, 1, &rc);
zSep = "AND";
pUsage->argvIndex = ++nArg;
pUsage->omit = 1;
}
string_concat(&zQuery, zNew, 1, &rc);
zSep = "AND";
pUsage->argvIndex = ++nArg;
pUsage->omit = 1;
}
}
+10
View File
@@ -414,6 +414,16 @@ static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zOp = "glob"; break;
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
case SQLITE_INDEX_CONSTRAINT_NE:
zOp = "ne"; break;
case SQLITE_INDEX_CONSTRAINT_ISNOT:
zOp = "isnot"; break;
case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
zOp = "isnotnull"; break;
case SQLITE_INDEX_CONSTRAINT_ISNULL:
zOp = "isnull"; break;
case SQLITE_INDEX_CONSTRAINT_IS:
zOp = "is"; break;
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
+42
View File
@@ -148,6 +148,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_DESERIALIZE
Tcl_SetVar2(interp, "sqlite_options", "deserialize", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_MEMSYS3
Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
#else
@@ -160,6 +166,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mem5", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","1",TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "offset_sql_func","0",TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "1", TCL_GLOBAL_ONLY);
#else
@@ -214,6 +226,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_HAS_CODEC
Tcl_SetVar2(interp, "sqlite_options", "has_codec", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
Tcl_SetVar2(interp, "sqlite_options", "like_match_blobs", "0", TCL_GLOBAL_ONLY);
#else
@@ -423,6 +441,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "icu", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_ICU_COLLATIONS
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_INCRBLOB
Tcl_SetVar2(interp, "sqlite_options", "incrblob", "0", TCL_GLOBAL_ONLY);
#else
@@ -483,6 +507,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
#ifdef SQLITE_ENABLE_NULL_TRIM
Tcl_SetVar2(interp, "sqlite_options", "null_trim", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "null_trim", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY);
#else
@@ -690,6 +720,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_FAST_SECURE_DELETE
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_SECURE_DELETE
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY);
#else
@@ -726,6 +762,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_WINDOWFUNC
Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY);
#endif
#define LINKVAR(x) { \
static const int cv_ ## x = SQLITE_ ## x; \
Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
+168 -50
View File
@@ -28,6 +28,7 @@
** Name used to identify this VFS.
*/
#define DEVSYM_VFS_NAME "devsym"
#define WRITECRASH_NAME "writecrash"
typedef struct devsym_file devsym_file;
struct devsym_file {
@@ -72,61 +73,13 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
DEVSYM_VFS_NAME, /* zName */
0, /* pAppData */
devsymOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
static sqlite3_io_methods devsym_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
struct DevsymGlobal {
sqlite3_vfs *pVfs;
int iDeviceChar;
int iSectorSize;
int nWriteCrash;
};
struct DevsymGlobal g = {0, 0, 512};
struct DevsymGlobal g = {0, 0, 512, 0};
/*
** Close an devsym-file.
@@ -271,6 +224,26 @@ static int devsymOpen(
int flags,
int *pOutFlags
){
static sqlite3_io_methods devsym_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
@@ -372,6 +345,137 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
/*
** Return the sector-size in bytes for an writecrash-file.
*/
static int writecrashSectorSize(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsSectorSize(p->pReal);
}
/*
** Return the device characteristic flags supported by an writecrash-file.
*/
static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsDeviceCharacteristics(p->pReal);
}
/*
** Write data to an writecrash-file.
*/
static int writecrashWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
devsym_file *p = (devsym_file *)pFile;
if( g.nWriteCrash>0 ){
g.nWriteCrash--;
if( g.nWriteCrash==0 ) abort();
}
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Open an writecrash file handle.
*/
static int writecrashOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
static sqlite3_io_methods writecrash_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
writecrashWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
writecrashSectorSize, /* xSectorSize */
writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
pFile->pMethods = &writecrash_io_methods;
}
return rc;
}
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
DEVSYM_VFS_NAME, /* zName */
0, /* pAppData */
devsymOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
static sqlite3_vfs writecrash_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
WRITECRASH_NAME, /* zName */
0, /* pAppData */
writecrashOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
@@ -379,10 +483,13 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** available function in this file.
*/
void devsym_register(int iDeviceChar, int iSectorSize){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
if( iDeviceChar>=0 ){
g.iDeviceChar = iDeviceChar;
@@ -403,4 +510,15 @@ void devsym_unregister(){
g.iSectorSize = 0;
}
void devsym_crash_on_write(int nWrite){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
g.nWriteCrash = nWrite;
}
#endif
+118
View File
@@ -791,6 +791,123 @@ abuse_err:
}
/*
** SQLite user defined function to use with matchinfo() to calculate the
** relevancy of an FTS match. The value returned is the relevancy score
** (a real value greater than or equal to zero). A larger value indicates
** a more relevant document.
**
** The overall relevancy returned is the sum of the relevancies of each
** column value in the FTS table. The relevancy of a column value is the
** sum of the following for each reportable phrase in the FTS query:
**
** (<hit count> / <global hit count>) * <column weight>
**
** where <hit count> is the number of instances of the phrase in the
** column value of the current row and <global hit count> is the number
** of instances of the phrase in the same column of all rows in the FTS
** table. The <column weight> is a weighting factor assigned to each
** column by the caller (see below).
**
** The first argument to this function must be the return value of the FTS
** matchinfo() function. Following this must be one argument for each column
** of the FTS table containing a numeric weight factor for the corresponding
** column. Example:
**
** CREATE VIRTUAL TABLE documents USING fts3(title, content)
**
** The following query returns the docids of documents that match the full-text
** query <query> sorted from most to least relevant. When calculating
** relevance, query term instances in the 'title' column are given twice the
** weighting of those in the 'content' column.
**
** SELECT docid FROM documents
** WHERE documents MATCH <query>
** ORDER BY rank(matchinfo(documents), 1.0, 0.5) DESC
*/
static void rankfunc(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
int *aMatchinfo; /* Return value of matchinfo() */
int nMatchinfo; /* Number of elements in aMatchinfo[] */
int nCol = 0; /* Number of columns in the table */
int nPhrase = 0; /* Number of phrases in the query */
int iPhrase; /* Current phrase */
double score = 0.0; /* Value to return */
assert( sizeof(int)==4 );
/* Check that the number of arguments passed to this function is correct.
** If not, jump to wrong_number_args. Set aMatchinfo to point to the array
** of unsigned integer values returned by FTS function matchinfo. Set
** nPhrase to contain the number of reportable phrases in the users full-text
** query, and nCol to the number of columns in the table. Then check that the
** size of the matchinfo blob is as expected. Return an error if it is not.
*/
if( nVal<1 ) goto wrong_number_args;
aMatchinfo = (int*)sqlite3_value_blob(apVal[0]);
nMatchinfo = sqlite3_value_bytes(apVal[0]) / sizeof(int);
if( nMatchinfo>=2 ){
nPhrase = aMatchinfo[0];
nCol = aMatchinfo[1];
}
if( nMatchinfo!=(2+3*nCol*nPhrase) ){
sqlite3_result_error(pCtx,
"invalid matchinfo blob passed to function rank()", -1);
return;
}
if( nVal!=(1+nCol) ) goto wrong_number_args;
/* Iterate through each phrase in the users query. */
for(iPhrase=0; iPhrase<nPhrase; iPhrase++){
int iCol; /* Current column */
/* Now iterate through each column in the users query. For each column,
** increment the relevancy score by:
**
** (<hit count> / <global hit count>) * <column weight>
**
** aPhraseinfo[] points to the start of the data for phrase iPhrase. So
** the hit count and global hit counts for each column are found in
** aPhraseinfo[iCol*3] and aPhraseinfo[iCol*3+1], respectively.
*/
int *aPhraseinfo = &aMatchinfo[2 + iPhrase*nCol*3];
for(iCol=0; iCol<nCol; iCol++){
int nHitCount = aPhraseinfo[3*iCol];
int nGlobalHitCount = aPhraseinfo[3*iCol+1];
double weight = sqlite3_value_double(apVal[iCol+1]);
if( nHitCount>0 ){
score += ((double)nHitCount / (double)nGlobalHitCount) * weight;
}
}
}
sqlite3_result_double(pCtx, score);
return;
/* Jump here if the wrong number of arguments are passed to this function */
wrong_number_args:
sqlite3_result_error(pCtx, "wrong number of arguments to function rank()", -1);
}
static int SQLITE_TCLAPI install_fts3_rank_function(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
sqlite3 *db;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
sqlite3_create_function(db, "rank", -1, SQLITE_UTF8, 0, rankfunc, 0, 0);
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
@@ -801,6 +918,7 @@ int Sqlitetest_func_Init(Tcl_Interp *interp){
} aObjCmd[] = {
{ "autoinstall_test_functions", autoinstall_test_funcs },
{ "abuse_create_function", abuse_create_function },
{ "install_fts3_rank_function", install_fts3_rank_function },
};
int i;
extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *);
+19 -41
View File
@@ -32,6 +32,8 @@ static struct MemFault {
int nRepeat; /* Number of times to repeat the failure */
int nBenign; /* Number of benign failures seen since last config */
int nFail; /* Number of failures seen since last config */
int nOkBefore; /* Successful allocations prior to the first fault */
int nOkAfter; /* Successful allocations after a fault */
u8 enable; /* True if enabled */
int isInstalled; /* True if the fault simulation layer is installed */
int isBenignMode; /* True if malloc failures are considered benign */
@@ -47,18 +49,32 @@ static void sqlite3Fault(void){
cnt++;
}
/*
** This routine exists as a place to set a breakpoint that will
** fire the first time any malloc() fails on a single test case.
** The sqlite3Fault() routine above runs on every malloc() failure.
** This routine only runs on the first such failure.
*/
static void sqlite3FirstFault(void){
static int cnt2 = 0;
cnt2++;
}
/*
** Check to see if a fault should be simulated. Return true to simulate
** the fault. Return false if the fault should not be simulated.
*/
static int faultsimStep(void){
if( likely(!memfault.enable) ){
memfault.nOkAfter++;
return 0;
}
if( memfault.iCountdown>0 ){
memfault.iCountdown--;
memfault.nOkBefore++;
return 0;
}
if( memfault.nFail==0 ) sqlite3FirstFault();
sqlite3Fault();
memfault.nFail++;
if( memfault.isBenignMode>0 ){
@@ -133,6 +149,8 @@ static void faultsimConfig(int nDelay, int nRepeat){
memfault.nRepeat = nRepeat;
memfault.nBenign = 0;
memfault.nFail = 0;
memfault.nOkBefore = 0;
memfault.nOkAfter = 0;
memfault.enable = nDelay>=0;
/* Sometimes, when running multi-threaded tests, the isBenignMode
@@ -887,46 +905,6 @@ static int SQLITE_TCLAPI test_memdebug_log(
return TCL_OK;
}
/*
** Usage: sqlite3_config_scratch SIZE N
**
** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
** The buffer is static and is of limited size. N might be
** adjusted downward as needed to accommodate the requested size.
** The revised value of N is returned.
**
** A negative SIZE causes the buffer pointer to be NULL.
*/
static int SQLITE_TCLAPI test_config_scratch(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int sz, N, rc;
Tcl_Obj *pResult;
static char *buf = 0;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "SIZE N");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &N) ) return TCL_ERROR;
free(buf);
if( sz<0 ){
buf = 0;
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, (void*)0, 0, 0);
}else{
buf = malloc( sz*N + 1 );
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, buf, sz, N);
}
pResult = Tcl_NewObj();
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(rc));
Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(N));
Tcl_SetObjResult(interp, pResult);
return TCL_OK;
}
/*
** Usage: sqlite3_config_pagecache SIZE N
**
@@ -1423,6 +1401,7 @@ static int SQLITE_TCLAPI test_db_status(
{ "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },
{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },
{ "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },
{ "CACHE_SPILL", SQLITE_DBSTATUS_CACHE_SPILL },
};
Tcl_Obj *pResult;
if( objc!=4 ){
@@ -1538,7 +1517,6 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 },
{ "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0 },
{ "sqlite3_memdebug_log", test_memdebug_log ,0 },
{ "sqlite3_config_scratch", test_config_scratch ,0 },
{ "sqlite3_config_pagecache", test_config_pagecache ,0 },
{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
{ "sqlite3_status", test_status ,0 },
+450
View File
@@ -0,0 +1,450 @@
/*
** 2017-10-13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code to implement an MD5 extension to TCL.
*/
#include "sqlite3.h"
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
/*
* If compiled on a machine that doesn't have a 32-bit integer,
* you just set "uint32" to the appropriate datatype for an
* unsigned 32-bit integer. For example:
*
* cc -Duint32='unsigned long' md5.c
*
*/
#ifndef uint32
# define uint32 unsigned int
#endif
struct MD5Context {
int isInit;
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
typedef struct MD5Context MD5Context;
/*
* Note: this code is harmless on little-endian machines.
*/
static void byteReverse (unsigned char *buf, unsigned longs){
uint32 t;
do {
t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
((unsigned)buf[1]<<8 | buf[0]);
*(uint32 *)buf = t;
buf += 4;
} while (--longs);
}
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32 buf[4], const uint32 in[16]){
register uint32 a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *ctx){
ctx->isInit = 1;
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
uint32 t;
/* Update bitcount */
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
ctx->bits[1]++; /* Carry from low to high */
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
/* Handle any leading odd-sized chunks */
if ( t ) {
unsigned char *p = (unsigned char *)ctx->in + t;
t = 64-t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
unsigned count;
unsigned char *p;
/* Compute number of bytes mod 64 */
count = (ctx->bits[0] >> 3) & 0x3F;
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count-8);
}
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
memcpy(ctx->in + 14*4, ctx->bits, 8);
MD5Transform(ctx->buf, (uint32 *)ctx->in);
byteReverse((unsigned char *)ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
}
/*
** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
*/
static void MD5DigestToBase16(unsigned char *digest, char *zBuf){
static char const zEncode[] = "0123456789abcdef";
int i, j;
for(j=i=0; i<16; i++){
int a = digest[i];
zBuf[j++] = zEncode[(a>>4)&0xf];
zBuf[j++] = zEncode[a & 0xf];
}
zBuf[j] = 0;
}
/*
** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
** each representing 16 bits of the digest and separated from each
** other by a "-" character.
*/
static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
int i, j;
unsigned int x;
for(i=j=0; i<16; i+=2){
x = digest[i]*256 + digest[i+1];
if( i>0 ) zDigest[j++] = '-';
sqlite3_snprintf(50-j, &zDigest[j], "%05u", x);
j += 5;
}
zDigest[j] = 0;
}
/*
** A TCL command for md5. The argument is the text to be hashed. The
** Result is the hash in base64.
*/
static int SQLITE_TCLAPI md5_cmd(
void*cd,
Tcl_Interp *interp,
int argc,
const char **argv
){
MD5Context ctx;
unsigned char digest[16];
char zBuf[50];
void (*converter)(unsigned char*, char*);
if( argc!=2 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" TEXT\"", (char*)0);
return TCL_ERROR;
}
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
MD5Final(digest, &ctx);
converter = (void(*)(unsigned char*,char*))cd;
converter(digest, zBuf);
Tcl_AppendResult(interp, zBuf, (char*)0);
return TCL_OK;
}
/*
** A TCL command to take the md5 hash of a file. The argument is the
** name of the file.
*/
static int SQLITE_TCLAPI md5file_cmd(
void*cd,
Tcl_Interp *interp,
int argc,
const char **argv
){
FILE *in;
int ofst;
int amt;
MD5Context ctx;
void (*converter)(unsigned char*, char*);
unsigned char digest[16];
char zBuf[10240];
if( argc!=2 && argc!=4 ){
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" FILENAME [OFFSET AMT]\"", (char*)0);
return TCL_ERROR;
}
if( argc==4 ){
ofst = atoi(argv[2]);
amt = atoi(argv[3]);
}else{
ofst = 0;
amt = 2147483647;
}
in = fopen(argv[1],"rb");
if( in==0 ){
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
"\" for reading", (char*)0);
return TCL_ERROR;
}
fseek(in, ofst, SEEK_SET);
MD5Init(&ctx);
while( amt>0 ){
int n;
n = (int)fread(zBuf, 1, sizeof(zBuf)<=amt ? sizeof(zBuf) : amt, in);
if( n<=0 ) break;
MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
amt -= n;
}
fclose(in);
MD5Final(digest, &ctx);
converter = (void(*)(unsigned char*,char*))cd;
converter(digest, zBuf);
Tcl_AppendResult(interp, zBuf, (char*)0);
return TCL_OK;
}
/*
** Register the four new TCL commands for generating MD5 checksums
** with the TCL interpreter.
*/
int Md5_Init(Tcl_Interp *interp){
Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd,
MD5DigestToBase16, 0);
Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd,
MD5DigestToBase10x8, 0);
Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd,
MD5DigestToBase16, 0);
Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd,
MD5DigestToBase10x8, 0);
return TCL_OK;
}
/*
** During testing, the special md5sum() aggregate function is available.
** inside SQLite. The following routines implement that function.
*/
static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
MD5Context *p;
int i;
if( argc<1 ) return;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return;
if( !p->isInit ){
MD5Init(p);
}
for(i=0; i<argc; i++){
const char *zData = (char*)sqlite3_value_text(argv[i]);
if( zData ){
MD5Update(p, (unsigned char*)zData, (int)strlen(zData));
}
}
}
static void md5finalize(sqlite3_context *context){
MD5Context *p;
unsigned char digest[16];
char zBuf[33];
p = sqlite3_aggregate_context(context, sizeof(*p));
MD5Final(digest,p);
MD5DigestToBase16(digest, zBuf);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
int Md5_Register(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pThunk
){
int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
md5step, md5finalize);
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
return rc;
}
+203
View File
@@ -0,0 +1,203 @@
/*
** 2017-10-13
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains extensions to the the "tclsqlite.c" module used for
** testing. Basically, all of the other "test_*.c" modules are linked
** into the enhanced tclsh used for testing (and named "testfixture" or
** "testfixture.exe") using logic encoded by this file.
**
** The code in this file used to be found in tclsqlite3.c, contained within
** #if SQLITE_TEST ... #endif. It is factored out into this separate module
** in an effort to keep the tclsqlite.c file pure.
*/
#include "sqlite3.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
/* Needed for the setrlimit() system call on unix */
#if defined(unix)
#include <sys/resource.h>
#endif
/* Forward declaration */
static int SQLITE_TCLAPI load_testfixture_extensions(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
);
/*
** This routine is the primary export of this file.
**
** Configure the interpreter passed as the first argument to have access
** to the commands and linked variables that make up:
**
** * the [sqlite3] extension itself,
**
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
**
** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
** test suite.
*/
const char *sqlite3TestInit(Tcl_Interp *interp){
extern int Sqlite3_Init(Tcl_Interp*);
extern int Sqliteconfig_Init(Tcl_Interp*);
extern int Sqlitetest1_Init(Tcl_Interp*);
extern int Sqlitetest2_Init(Tcl_Interp*);
extern int Sqlitetest3_Init(Tcl_Interp*);
extern int Sqlitetest4_Init(Tcl_Interp*);
extern int Sqlitetest5_Init(Tcl_Interp*);
extern int Sqlitetest6_Init(Tcl_Interp*);
extern int Sqlitetest7_Init(Tcl_Interp*);
extern int Sqlitetest8_Init(Tcl_Interp*);
extern int Sqlitetest9_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
extern int Sqlitetest_blob_Init(Tcl_Interp*);
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
extern int Sqlitetest_func_Init(Tcl_Interp*);
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
extern int Sqlitetest_init_Init(Tcl_Interp*);
extern int Sqlitetest_malloc_Init(Tcl_Interp*);
extern int Sqlitetest_mutex_Init(Tcl_Interp*);
extern int Sqlitetestschema_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*);
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
extern int Sqlitetestfs_Init(Tcl_Interp*);
extern int SqlitetestThread_Init(Tcl_Interp*);
extern int SqlitetestOnefile_Init();
extern int SqlitetestOsinst_Init(Tcl_Interp*);
extern int Sqlitetestbackup_Init(Tcl_Interp*);
extern int Sqlitetestintarray_Init(Tcl_Interp*);
extern int Sqlitetestvfs_Init(Tcl_Interp *);
extern int Sqlitetestrtree_Init(Tcl_Interp*);
extern int Sqlitequota_Init(Tcl_Interp*);
extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*);
extern int SqlitetestSyscall_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
extern int TestSession_Init(Tcl_Interp*);
#endif
extern int Md5_Init(Tcl_Interp*);
extern int Fts5tcl_Init(Tcl_Interp *);
extern int SqliteRbu_Init(Tcl_Interp*);
extern int Sqlitetesttcl_Init(Tcl_Interp*);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
extern int Zipvfs_Init(Tcl_Interp*);
#endif
extern int TestExpert_Init(Tcl_Interp*);
extern int Sqlitetest_window_Init(Tcl_Interp *);
Tcl_CmdInfo cmdInfo;
/* Since the primary use case for this binary is testing of SQLite,
** be sure to generate core files if we crash */
#if defined(unix)
{ struct rlimit x;
getrlimit(RLIMIT_CORE, &x);
x.rlim_cur = x.rlim_max;
setrlimit(RLIMIT_CORE, &x);
}
#endif /* unix */
if( Tcl_GetCommandInfo(interp, "sqlite3", &cmdInfo)==0 ){
Sqlite3_Init(interp);
}
#ifdef SQLITE_ENABLE_ZIPVFS
Zipvfs_Init(interp);
#endif
Md5_Init(interp);
Sqliteconfig_Init(interp);
Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp);
Sqlitetest3_Init(interp);
Sqlitetest4_Init(interp);
Sqlitetest5_Init(interp);
Sqlitetest6_Init(interp);
Sqlitetest7_Init(interp);
Sqlitetest8_Init(interp);
Sqlitetest9_Init(interp);
Sqlitetestasync_Init(interp);
Sqlitetest_autoext_Init(interp);
Sqlitetest_blob_Init(interp);
Sqlitetest_demovfs_Init(interp);
Sqlitetest_func_Init(interp);
Sqlitetest_hexio_Init(interp);
Sqlitetest_init_Init(interp);
Sqlitetest_malloc_Init(interp);
Sqlitetest_mutex_Init(interp);
Sqlitetestschema_Init(interp);
Sqlitetesttclvar_Init(interp);
Sqlitetestfs_Init(interp);
SqlitetestThread_Init(interp);
SqlitetestOnefile_Init();
SqlitetestOsinst_Init(interp);
Sqlitetestbackup_Init(interp);
Sqlitetestintarray_Init(interp);
Sqlitetestvfs_Init(interp);
Sqlitetestrtree_Init(interp);
Sqlitequota_Init(interp);
Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp);
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
TestSession_Init(interp);
#endif
Fts5tcl_Init(interp);
SqliteRbu_Init(interp);
Sqlitetesttcl_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp);
#endif
TestExpert_Init(interp);
Sqlitetest_window_Init(interp);
Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
);
return 0;
}
/* tclcmd: load_testfixture_extensions
*/
static int SQLITE_TCLAPI load_testfixture_extensions(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
Tcl_Interp *slave;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SLAVE");
return TCL_ERROR;
}
slave = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
if( !slave ){
return TCL_ERROR;
}
(void)sqlite3TestInit(slave);
return TCL_OK;
}
+88 -2
View File
@@ -15,6 +15,25 @@
**
** The emphasis of this file is a virtual table that provides
** access to TCL variables.
**
** The TCLVAR eponymous virtual table has a schema like this:
**
** CREATE TABLE tclvar(
** name TEXT, -- base name of the variable: "x" in "$x(y)"
** arrayname TEXT, -- array index name: "y" in "$x(y)"
** value TEXT, -- the value of the variable
** fullname TEXT, -- the full name of the variable
** PRIMARY KEY(fullname)
** ) WITHOUT ROWID;
**
** DELETE, INSERT, and UPDATE operations use the "fullname" field to
** determine the variable to be modified. Changing "value" to NULL
** deletes the variable.
**
** For SELECT operations, the "name" and "arrayname" fields will always
** match the "fullname" field. For DELETE, INSERT, and UPDATE, the
** "name" and "arrayname" fields are ignored and the variable is modified
** according to "fullname" and "value" only.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
@@ -67,7 +86,12 @@ static int tclvarConnect(
){
tclvar_vtab *pVtab;
static const char zSchema[] =
"CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
"CREATE TABLE x("
" name TEXT," /* Base name */
" arrayname TEXT," /* Array index */
" value TEXT," /* Value */
" fullname TEXT PRIMARY KEY" /* base(index) name */
") WITHOUT ROWID";
pVtab = sqlite3MallocZero( sizeof(*pVtab) );
if( pVtab==0 ) return SQLITE_NOMEM;
*ppVtab = &pVtab->base;
@@ -251,6 +275,16 @@ static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
break;
}
case 3: {
char *z3;
if( p2 ){
z3 = sqlite3_mprintf("%s(%s)", z1, z2);
sqlite3_result_text(ctx, z3, -1, sqlite3_free);
}else{
sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
}
break;
}
}
return SQLITE_OK;
}
@@ -376,6 +410,58 @@ static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_OK;
}
/*
** Invoked for any UPDATE, INSERT, or DELETE against a tclvar table
*/
static int tclvarUpdate(
sqlite3_vtab *tab,
int argc,
sqlite3_value **argv,
sqlite_int64 *pRowid
){
tclvar_vtab *pTab = (tclvar_vtab*)tab;
if( argc==1 ){
/* A DELETE operation. The variable to be deleted is stored in argv[0] */
const char *zVar = (const char*)sqlite3_value_text(argv[0]);
Tcl_UnsetVar(pTab->interp, zVar, TCL_GLOBAL_ONLY);
return SQLITE_OK;
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
/* An INSERT operation */
const char *zValue = (const char*)sqlite3_value_text(argv[4]);
const char *zName;
if( sqlite3_value_type(argv[5])!=SQLITE_TEXT ){
tab->zErrMsg = sqlite3_mprintf("the 'fullname' column must be TEXT");
return SQLITE_ERROR;
}
zName = (const char*)sqlite3_value_text(argv[5]);
if( zValue ){
Tcl_SetVar(pTab->interp, zName, zValue, TCL_GLOBAL_ONLY);
}else{
Tcl_UnsetVar(pTab->interp, zName, TCL_GLOBAL_ONLY);
}
return SQLITE_OK;
}
if( sqlite3_value_type(argv[0])==SQLITE_TEXT
&& sqlite3_value_type(argv[1])==SQLITE_TEXT
){
/* An UPDATE operation */
const char *zOldName = (const char*)sqlite3_value_text(argv[0]);
const char *zNewName = (const char*)sqlite3_value_text(argv[1]);
const char *zValue = (const char*)sqlite3_value_text(argv[4]);
if( strcmp(zOldName, zNewName)!=0 || zValue==0 ){
Tcl_UnsetVar(pTab->interp, zOldName, TCL_GLOBAL_ONLY);
}
if( zValue!=0 ){
Tcl_SetVar(pTab->interp, zNewName, zValue, TCL_GLOBAL_ONLY);
}
return SQLITE_OK;
}
tab->zErrMsg = sqlite3_mprintf("prohibited TCL variable change");
return SQLITE_ERROR;
}
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
@@ -394,7 +480,7 @@ static sqlite3_module tclvarModule = {
tclvarEof, /* xEof - check for end of scan */
tclvarColumn, /* xColumn - read data */
tclvarRowid, /* xRowid - read data */
0, /* xUpdate */
tclvarUpdate, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
+30 -4
View File
@@ -133,8 +133,9 @@ struct Testvfs {
#define TESTVFS_UNLOCK_MASK 0x00020000
#define TESTVFS_LOCK_MASK 0x00040000
#define TESTVFS_CKLOCK_MASK 0x00080000
#define TESTVFS_FCNTL_MASK 0x00100000
#define TESTVFS_ALL_MASK 0x000FFFFF
#define TESTVFS_ALL_MASK 0x001FFFFF
#define TESTVFS_MAX_PAGES 1024
@@ -517,7 +518,8 @@ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
** File control method. For custom operations on an tvfs-file.
*/
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
TestvfsFd *p = tvfsGetFd(pFile);
TestvfsFd *pFd = tvfsGetFd(pFile);
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
if( op==SQLITE_FCNTL_PRAGMA ){
char **argv = (char**)pArg;
if( sqlite3_stricmp(argv[1],"error")==0 ){
@@ -535,11 +537,34 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
return rc;
}
if( sqlite3_stricmp(argv[1], "filename")==0 ){
argv[0] = sqlite3_mprintf("%s", p->zFilename);
argv[0] = sqlite3_mprintf("%s", pFd->zFilename);
return SQLITE_OK;
}
}
return sqlite3OsFileControl(p->pReal, op, pArg);
if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){
struct Fcntl {
int iFnctl;
const char *zFnctl;
} aF[] = {
{ SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" },
{ SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" },
};
int i;
for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){
if( op==aF[i].iFnctl ) break;
}
if( i<sizeof(aF)/sizeof(aF[0]) ){
int rc = 0;
tvfsExecTcl(p, "xFileControl",
Tcl_NewStringObj(pFd->zFilename, -1),
Tcl_NewStringObj(aF[i].zFnctl, -1),
0, 0
);
tvfsResultCode(p, &rc);
if( rc ) return rc;
}
}
return sqlite3OsFileControl(pFd->pReal, op, pArg);
}
/*
@@ -1160,6 +1185,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
{ "xUnlock", TESTVFS_UNLOCK_MASK },
{ "xLock", TESTVFS_LOCK_MASK },
{ "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
{ "xFileControl", TESTVFS_FCNTL_MASK },
};
Tcl_Obj **apElem = 0;
int nElem = 0;
-1
View File
@@ -14,7 +14,6 @@
*/
#if defined(_WIN32) && defined(_MSC_VER)
#include "test_windirent.h"
/*
+40 -4
View File
@@ -13,13 +13,17 @@
** POSIX functions on Win32 using the MSVCRT.
*/
#if defined(_WIN32) && defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
#define SQLITE_WINDIRENT_H
/*
** We need several data types from the Windows SDK header.
*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "windows.h"
/*
@@ -37,6 +41,33 @@
#include <errno.h>
#include <io.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
** We may need several defines that should have been in "sys/stat.h".
*/
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (0)
#endif
/*
** We may need to provide the "mode_t" type.
*/
#ifndef MODE_T_DEFINED
#define MODE_T_DEFINED
typedef unsigned short mode_t;
#endif
/*
** We may need to provide the "ino_t" type.
@@ -75,22 +106,27 @@
** We need to provide the necessary structures and related types.
*/
#ifndef DIRENT_DEFINED
#define DIRENT_DEFINED
typedef struct DIRENT DIRENT;
typedef struct DIR DIR;
typedef DIRENT *LPDIRENT;
typedef DIR *LPDIR;
struct DIRENT {
ino_t d_ino; /* Sequence number, do not use. */
unsigned d_attributes; /* Win32 file attributes. */
char d_name[NAME_MAX + 1]; /* Name within the directory. */
};
#endif
#ifndef DIR_DEFINED
#define DIR_DEFINED
typedef struct DIR DIR;
typedef DIR *LPDIR;
struct DIR {
intptr_t d_handle; /* Value returned by "_findfirst". */
DIRENT d_first; /* DIRENT constructed based on "_findfirst". */
DIRENT d_next; /* DIRENT constructed based on "_findnext". */
};
#endif
/*
** Provide a macro, for use by the implementation, to determine if a
+349
View File
@@ -0,0 +1,349 @@
/*
** 2018 June 17
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
*/
#include "sqlite3.h"
#ifdef SQLITE_TEST
#include "sqliteInt.h"
#include <tcl.h>
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
extern const char *sqlite3ErrName(int);
typedef struct TestWindow TestWindow;
struct TestWindow {
Tcl_Obj *xStep;
Tcl_Obj *xFinal;
Tcl_Obj *xValue;
Tcl_Obj *xInverse;
Tcl_Interp *interp;
};
typedef struct TestWindowCtx TestWindowCtx;
struct TestWindowCtx {
Tcl_Obj *pVal;
};
static void doTestWindowStep(
int bInverse,
sqlite3_context *ctx,
int nArg,
sqlite3_value **apArg
){
int i;
TestWindow *p = (TestWindow*)sqlite3_user_data(ctx);
Tcl_Obj *pEval = Tcl_DuplicateObj(bInverse ? p->xInverse : p->xStep);
TestWindowCtx *pCtx = sqlite3_aggregate_context(ctx, sizeof(TestWindowCtx));
Tcl_IncrRefCount(pEval);
if( pCtx ){
const char *zResult;
int rc;
if( pCtx->pVal ){
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));
}else{
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));
}
for(i=0; i<nArg; i++){
Tcl_Obj *pArg;
pArg = Tcl_NewStringObj((const char*)sqlite3_value_text(apArg[i]), -1);
Tcl_ListObjAppendElement(p->interp, pEval, pArg);
}
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
zResult = Tcl_GetStringResult(p->interp);
sqlite3_result_error(ctx, zResult, -1);
}else{
if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);
pCtx->pVal = Tcl_DuplicateObj(Tcl_GetObjResult(p->interp));
Tcl_IncrRefCount(pCtx->pVal);
}
}
Tcl_DecrRefCount(pEval);
}
static void doTestWindowFinalize(int bValue, sqlite3_context *ctx){
TestWindow *p = (TestWindow*)sqlite3_user_data(ctx);
Tcl_Obj *pEval = Tcl_DuplicateObj(bValue ? p->xValue : p->xFinal);
TestWindowCtx *pCtx = sqlite3_aggregate_context(ctx, sizeof(TestWindowCtx));
Tcl_IncrRefCount(pEval);
if( pCtx ){
const char *zResult;
int rc;
if( pCtx->pVal ){
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_DuplicateObj(pCtx->pVal));
}else{
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj("", -1));
}
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
zResult = Tcl_GetStringResult(p->interp);
if( rc!=TCL_OK ){
sqlite3_result_error(ctx, zResult, -1);
}else{
sqlite3_result_text(ctx, zResult, -1, SQLITE_TRANSIENT);
}
if( bValue==0 ){
if( pCtx->pVal ) Tcl_DecrRefCount(pCtx->pVal);
pCtx->pVal = 0;
}
}
Tcl_DecrRefCount(pEval);
}
static void testWindowStep(
sqlite3_context *ctx,
int nArg,
sqlite3_value **apArg
){
doTestWindowStep(0, ctx, nArg, apArg);
}
static void testWindowInverse(
sqlite3_context *ctx,
int nArg,
sqlite3_value **apArg
){
doTestWindowStep(1, ctx, nArg, apArg);
}
static void testWindowFinal(sqlite3_context *ctx){
doTestWindowFinalize(0, ctx);
}
static void testWindowValue(sqlite3_context *ctx){
doTestWindowFinalize(1, ctx);
}
static void testWindowDestroy(void *pCtx){
ckfree(pCtx);
}
/*
** Usage: sqlite3_create_window_function DB NAME XSTEP XFINAL XVALUE XINVERSE
*/
static int SQLITE_TCLAPI test_create_window(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
TestWindow *pNew;
sqlite3 *db;
const char *zName;
int rc;
if( objc!=7 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB NAME XSTEP XFINAL XVALUE XINVERSE");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zName = Tcl_GetString(objv[2]);
pNew = (TestWindow*)ckalloc(sizeof(TestWindow));
memset(pNew, 0, sizeof(TestWindow));
pNew->xStep = Tcl_DuplicateObj(objv[3]);
pNew->xFinal = Tcl_DuplicateObj(objv[4]);
pNew->xValue = Tcl_DuplicateObj(objv[5]);
pNew->xInverse = Tcl_DuplicateObj(objv[6]);
pNew->interp = interp;
Tcl_IncrRefCount(pNew->xStep);
Tcl_IncrRefCount(pNew->xFinal);
Tcl_IncrRefCount(pNew->xValue);
Tcl_IncrRefCount(pNew->xInverse);
rc = sqlite3_create_window_function(db, zName, -1, SQLITE_UTF8, (void*)pNew,
testWindowStep, testWindowFinal, testWindowValue, testWindowInverse,
testWindowDestroy
);
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}
return TCL_OK;
}
static int SQLITE_TCLAPI test_create_window_misuse(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
0, testWindowFinal, testWindowValue, testWindowInverse,
0
);
if( rc!=SQLITE_MISUSE ) goto error;
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
testWindowStep, 0, testWindowValue, testWindowInverse,
0
);
if( rc!=SQLITE_MISUSE ) goto error;
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
testWindowStep, testWindowFinal, 0, testWindowInverse,
0
);
if( rc!=SQLITE_MISUSE ) goto error;
rc = sqlite3_create_window_function(db, "fff", -1, SQLITE_UTF8, 0,
testWindowStep, testWindowFinal, testWindowValue, 0,
0
);
if( rc!=SQLITE_MISUSE ) goto error;
return TCL_OK;
error:
Tcl_SetObjResult(interp, Tcl_NewStringObj("misuse test error", -1));
return TCL_ERROR;
}
/*
** xStep for sumint().
*/
static void sumintStep(
sqlite3_context *ctx,
int nArg,
sqlite3_value *apArg[]
){
sqlite3_int64 *pInt;
assert( nArg==1 );
if( sqlite3_value_type(apArg[0])!=SQLITE_INTEGER ){
sqlite3_result_error(ctx, "invalid argument", -1);
return;
}
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
if( pInt ){
*pInt += sqlite3_value_int64(apArg[0]);
}
}
/*
** xInverse for sumint().
*/
static void sumintInverse(
sqlite3_context *ctx,
int nArg,
sqlite3_value *apArg[]
){
sqlite3_int64 *pInt;
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, sizeof(sqlite3_int64));
*pInt -= sqlite3_value_int64(apArg[0]);
}
/*
** xFinal for sumint().
*/
static void sumintFinal(sqlite3_context *ctx){
sqlite3_int64 res = 0;
sqlite3_int64 *pInt;
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
if( pInt ) res = *pInt;
sqlite3_result_int64(ctx, res);
}
/*
** xValue for sumint().
*/
static void sumintValue(sqlite3_context *ctx){
sqlite3_int64 res = 0;
sqlite3_int64 *pInt;
pInt = (sqlite3_int64*)sqlite3_aggregate_context(ctx, 0);
if( pInt ) res = *pInt;
sqlite3_result_int64(ctx, res);
}
static int SQLITE_TCLAPI test_create_sumint(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_window_function(db, "sumint", 1, SQLITE_UTF8, 0,
sumintStep, sumintFinal, sumintValue, sumintInverse,
0
);
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}
return TCL_OK;
}
static int SQLITE_TCLAPI test_override_sum(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "sum", -1, SQLITE_UTF8, 0,
0, sumintStep, sumintFinal
);
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}
return TCL_OK;
}
int Sqlitetest_window_Init(Tcl_Interp *interp){
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
int clientData;
} aObjCmd[] = {
{ "sqlite3_create_window_function", test_create_window, 0 },
{ "test_create_window_function_misuse", test_create_window_misuse, 0 },
{ "test_create_sumint", test_create_sumint, 0 },
{ "test_override_sum", test_override_sum, 0 },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
ClientData c = (ClientData)SQLITE_INT_TO_PTR(aObjCmd[i].clientData);
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0);
}
return TCL_OK;
}
#endif
+137 -37
View File
@@ -54,11 +54,12 @@
#define CC_TILDA 25 /* '~' */
#define CC_DOT 26 /* '.' */
#define CC_ILLEGAL 27 /* Illegal character */
#define CC_NUL 28 /* 0x00 */
static const unsigned char aiClass[] = {
#ifdef SQLITE_ASCII
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
/* 0x */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
@@ -183,11 +184,85 @@ const char sqlite3IsEbcdicIdChar[] = {
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
/* Make the IdChar function accessible from ctime.c */
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
/* Make the IdChar function accessible from ctime.c and alter.c */
int sqlite3IsIdChar(u8 c){ return IdChar(c); }
#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Return the id of the next token in string (*pz). Before returning, set
** (*pz) to point to the byte following the parsed token.
*/
static int getToken(const unsigned char **pz){
const unsigned char *z = *pz;
int t; /* Token type to return */
do {
z += sqlite3GetToken(z, &t);
}while( t==TK_SPACE );
if( t==TK_ID
|| t==TK_STRING
|| t==TK_JOIN_KW
|| t==TK_WINDOW
|| t==TK_OVER
|| sqlite3ParserFallback(t)==TK_ID
){
t = TK_ID;
}
*pz = z;
return t;
}
/*
** The following three functions are called immediately after the tokenizer
** reads the keywords WINDOW, OVER and FILTER, respectively, to determine
** whether the token should be treated as a keyword or an SQL identifier.
** This cannot be handled by the usual lemon %fallback method, due to
** the ambiguity in some constructions. e.g.
**
** SELECT sum(x) OVER ...
**
** In the above, "OVER" might be a keyword, or it might be an alias for the
** sum(x) expression. If a "%fallback ID OVER" directive were added to
** grammar, then SQLite would always treat "OVER" as an alias, making it
** impossible to call a window-function without a FILTER clause.
**
** WINDOW is treated as a keyword if:
**
** * the following token is an identifier, or a keyword that can fallback
** to being an identifier, and
** * the token after than one is TK_AS.
**
** OVER is a keyword if:
**
** * the previous token was TK_RP, and
** * the next token is either TK_LP or an identifier.
**
** FILTER is a keyword if:
**
** * the previous token was TK_RP, and
** * the next token is TK_LP.
*/
static int analyzeWindowKeyword(const unsigned char *z){
int t;
t = getToken(&z);
if( t!=TK_ID ) return TK_ID;
t = getToken(&z);
if( t!=TK_AS ) return TK_ID;
return TK_WINDOW;
}
static int analyzeOverKeyword(const unsigned char *z, int lastToken){
if( lastToken==TK_RP ){
int t = getToken(&z);
if( t==TK_LP || t==TK_ID ) return TK_OVER;
}
return TK_ID;
}
static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
if( lastToken==TK_RP && getToken(&z)==TK_LP ){
return TK_FILTER;
}
return TK_ID;
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Return the length (in bytes) of the token that begins at z[0].
@@ -456,6 +531,10 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
i = 1;
break;
}
case CC_NUL: {
*tokenType = TK_ILLEGAL;
return 0;
}
default: {
*tokenType = TK_ILLEGAL;
return 1;
@@ -496,9 +575,9 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
/* sqlite3ParserTrace(stdout, "parser: "); */
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
pEngine = &sEngine;
sqlite3ParserInit(pEngine);
sqlite3ParserInit(pEngine, pParse);
#else
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse);
if( pEngine==0 ){
sqlite3OomFault(db);
return SQLITE_NOMEM_BKPT;
@@ -509,47 +588,64 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pParse->nVar==0 );
assert( pParse->pVList==0 );
while( 1 ){
if( zSql[0]!=0 ){
n = sqlite3GetToken((u8*)zSql, &tokenType);
mxSqlLen -= n;
if( mxSqlLen<0 ){
pParse->rc = SQLITE_TOOBIG;
break;
}
}else{
/* Upon reaching the end of input, call the parser two more times
** with tokens TK_SEMI and 0, in that order. */
if( lastTokenParsed==TK_SEMI ){
tokenType = 0;
}else if( lastTokenParsed==0 ){
break;
}else{
tokenType = TK_SEMI;
}
zSql -= n;
n = sqlite3GetToken((u8*)zSql, &tokenType);
mxSqlLen -= n;
if( mxSqlLen<0 ){
pParse->rc = SQLITE_TOOBIG;
break;
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( tokenType>=TK_WINDOW ){
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|| tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
);
#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( db->u1.isInterrupted ){
pParse->rc = SQLITE_INTERRUPT;
break;
}
if( tokenType==TK_ILLEGAL ){
if( tokenType==TK_SPACE ){
zSql += n;
continue;
}
if( zSql[0]==0 ){
/* Upon reaching the end of input, call the parser two more times
** with tokens TK_SEMI and 0, in that order. */
if( lastTokenParsed==TK_SEMI ){
tokenType = 0;
}else if( lastTokenParsed==0 ){
break;
}else{
tokenType = TK_SEMI;
}
n = 0;
#ifndef SQLITE_OMIT_WINDOWFUNC
}else if( tokenType==TK_WINDOW ){
assert( n==6 );
tokenType = analyzeWindowKeyword((const u8*)&zSql[6]);
}else if( tokenType==TK_OVER ){
assert( n==4 );
tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
}else if( tokenType==TK_FILTER ){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
}else{
sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
break;
}
zSql += n;
}else{
pParse->sLastToken.z = zSql;
pParse->sLastToken.n = n;
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
lastTokenParsed = tokenType;
zSql += n;
if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
}
pParse->sLastToken.z = zSql;
pParse->sLastToken.n = n;
sqlite3Parser(pEngine, tokenType, pParse->sLastToken);
lastTokenParsed = tokenType;
zSql += n;
if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
}
assert( nErr==0 );
pParse->zTail = zSql;
#ifdef YYTRACKMAXSTACKDEPTH
sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
@@ -571,10 +667,12 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
assert( pzErrMsg!=0 );
if( pParse->zErrMsg ){
*pzErrMsg = pParse->zErrMsg;
sqlite3_log(pParse->rc, "%s", *pzErrMsg);
sqlite3_log(pParse->rc, "%s in \"%s\"",
*pzErrMsg, pParse->zTail);
pParse->zErrMsg = 0;
nErr++;
}
pParse->zTail = zSql;
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
@@ -590,16 +688,18 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
sqlite3_free(pParse->apVtabLock);
#endif
if( !IN_DECLARE_VTAB ){
if( !IN_SPECIAL_PARSE ){
/* If the pParse->declareVtab flag is set, do not delete any table
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
if( !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
sqlite3DbFree(db, pParse->pVList);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
+183 -32
View File
@@ -58,15 +58,17 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
if( p ){
for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4);
}
sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
}
if( zFormat!=0 ){
va_start(ap, zFormat);
sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
assert( acc.nChar>0 );
sqlite3_str_append(&acc, "\n", 1);
}
va_start(ap, zFormat);
sqlite3VXPrintf(&acc, zFormat, ap);
va_end(ap);
assert( acc.nChar>0 );
if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
fflush(stdout);
@@ -99,17 +101,17 @@ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){
char zLine[1000];
const struct Cte *pCte = &pWith->a[i];
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
sqlite3XPrintf(&x, "%s", pCte->zName);
sqlite3_str_appendf(&x, "%s", pCte->zName);
if( pCte->pCols && pCte->pCols->nExpr>0 ){
char cSep = '(';
int j;
for(j=0; j<pCte->pCols->nExpr; j++){
sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
cSep = ',';
}
sqlite3XPrintf(&x, ")");
sqlite3_str_appendf(&x, ")");
}
sqlite3XPrintf(&x, " AS");
sqlite3_str_appendf(&x, " AS");
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
@@ -137,9 +139,11 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewPush(pView, 1);
}
do{
sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
sqlite3TreeViewLine(pView,
"SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
p->selId, p, p->selFlags,
(int)p->nSelectRow
);
if( cnt++ ) sqlite3TreeViewPop(pView);
@@ -153,9 +157,23 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
if( p->pHaving ) n++;
if( p->pOrderBy ) n++;
if( p->pLimit ) n++;
if( p->pOffset ) n++;
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWin ) n++;
if( p->pWinDefn ) n++;
#endif
}
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWin ){
Window *pX;
pView = sqlite3TreeViewPush(pView, (n--)>0);
sqlite3TreeViewLine(pView, "window-functions");
for(pX=p->pWin; pX; pX=pX->pNextWin){
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
}
#endif
if( p->pSrc && p->pSrc->nSrc ){
int i;
pView = sqlite3TreeViewPush(pView, (n--)>0);
@@ -165,20 +183,20 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
StrAccum x;
char zLine[100];
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor);
sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor);
if( pItem->zDatabase ){
sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
}else if( pItem->zName ){
sqlite3XPrintf(&x, " %s", pItem->zName);
sqlite3_str_appendf(&x, " %s", pItem->zName);
}
if( pItem->pTab ){
sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName);
sqlite3_str_appendf(&x, " tabname=%Q", pItem->pTab->zName);
}
if( pItem->zAlias ){
sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias);
sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias);
}
if( pItem->fg.jointype & JT_LEFT ){
sqlite3XPrintf(&x, " LEFT-JOIN");
sqlite3_str_appendf(&x, " LEFT-JOIN");
}
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
@@ -205,17 +223,27 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewExpr(pView, p->pHaving, 0);
sqlite3TreeViewPop(pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWinDefn ){
Window *pX;
sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
}
#endif
if( p->pOrderBy ){
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
}
if( p->pLimit ){
sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
sqlite3TreeViewExpr(pView, p->pLimit, 0);
sqlite3TreeViewPop(pView);
}
if( p->pOffset ){
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
sqlite3TreeViewExpr(pView, p->pOffset, 0);
sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
if( p->pLimit->pRight ){
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
sqlite3TreeViewPop(pView);
}
sqlite3TreeViewPop(pView);
}
if( p->pPrior ){
@@ -232,6 +260,83 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewPop(pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a description of starting or stopping bounds
*/
void sqlite3TreeViewBound(
TreeView *pView, /* View context */
u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */
Expr *pExpr, /* Value for PRECEDING or FOLLOWING */
u8 moreToFollow /* True if more to follow */
){
switch( eBound ){
case TK_UNBOUNDED: {
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
sqlite3TreeViewPop(pView);
break;
}
case TK_CURRENT: {
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
sqlite3TreeViewPop(pView);
break;
}
case TK_PRECEDING: {
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
break;
}
case TK_FOLLOWING: {
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
break;
}
}
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a human-readable explanation for a Window object
*/
void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
pView = sqlite3TreeViewPush(pView, more);
if( pWin->zName ){
sqlite3TreeViewLine(pView, "OVER %s", pWin->zName);
}else{
sqlite3TreeViewLine(pView, "OVER");
}
if( pWin->pPartition ){
sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY");
}
if( pWin->pOrderBy ){
sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY");
}
if( pWin->eType ){
sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0);
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
sqlite3TreeViewPop(pView);
}
sqlite3TreeViewPop(pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a human-readable explanation for a Window Function object
*/
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
pView = sqlite3TreeViewPush(pView, more);
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
pWin->pFunc->zName, pWin->pFunc->nArg);
sqlite3TreeViewWindow(pView, pWin, 0);
sqlite3TreeViewPop(pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Generate a human-readable explanation of an expression tree.
*/
@@ -269,6 +374,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView, "{%d:%d}%s",
pExpr->iTable, pExpr->iColumn, zFlgs);
}
if( ExprHasProperty(pExpr, EP_FixedCol) ){
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
}
break;
}
case TK_INTEGER: {
@@ -293,6 +401,11 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView,"NULL");
break;
}
case TK_TRUEFALSE: {
sqlite3TreeViewLine(pView,
sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE");
break;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
@@ -349,6 +462,19 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
case TK_ISNULL: zUniOp = "ISNULL"; break;
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
case TK_TRUTH: {
int x;
const char *azOp[] = {
"IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE"
};
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
assert( pExpr->pRight );
assert( pExpr->pRight->op==TK_TRUEFALSE );
x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight);
zUniOp = azOp[x];
break;
}
case TK_SPAN: {
sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
@@ -364,10 +490,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
case TK_AGG_FUNCTION:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
Window *pWin;
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
pWin = 0;
}else{
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
pWin = pExpr->pWin;
#else
pWin = 0;
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
@@ -376,8 +509,13 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
}
if( pFarg ){
sqlite3TreeViewExprList(pView, pFarg, 0, 0);
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
sqlite3TreeViewWindow(pView, pWin, 0);
}
#endif
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -508,12 +646,25 @@ void sqlite3TreeViewBareExprList(
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
if( j ){
sqlite3TreeViewPush(pView, 0);
sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
char *zName = pList->a[i].zName;
int moreToFollow = i<pList->nExpr - 1;
if( j || zName ){
sqlite3TreeViewPush(pView, moreToFollow);
moreToFollow = 0;
sqlite3TreeViewLine(pView, 0);
if( zName ){
fprintf(stdout, "AS %s ", zName);
}
if( j ){
fprintf(stdout, "iOrderByCol=%d", j);
}
fprintf(stdout, "\n");
fflush(stdout);
}
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
if( j || zName ){
sqlite3TreeViewPop(pView);
}
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
if( j ) sqlite3TreeViewPop(pView);
}
}
}
+120 -35
View File
@@ -25,6 +25,8 @@ void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerStep){
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
sqlite3UpsertDelete(db, pTmp->pUpsert);
sqlite3DbFree(db, pTmp->zSpan);
sqlite3DbFree(db, pTmp);
}
@@ -179,14 +181,16 @@ void sqlite3BeginTrigger(
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
if( !IN_RENAME_OBJECT ){
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
if( !noErr ){
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
}
goto trigger_cleanup;
}
goto trigger_cleanup;
}
/* Do not create a trigger on a system table */
@@ -210,7 +214,7 @@ void sqlite3BeginTrigger(
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
if( !IN_RENAME_OBJECT ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zDbSName;
@@ -244,8 +248,15 @@ void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
pTrigger->pWhen = pWhen;
pWhen = 0;
}else{
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
}
pTrigger->pColumns = pColumns;
pColumns = 0;
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
@@ -294,6 +305,14 @@ void sqlite3FinishTrigger(
goto triggerfinish_cleanup;
}
#ifndef SQLITE_OMIT_ALTERTABLE
if( IN_RENAME_OBJECT ){
assert( !db->init.busy );
pParse->pNewTrigger = pTrig;
pTrig = 0;
}else
#endif
/* if we are not initializing,
** build the sqlite_master entry
*/
@@ -335,10 +354,21 @@ void sqlite3FinishTrigger(
triggerfinish_cleanup:
sqlite3DeleteTrigger(db, pTrig);
assert( !pParse->pNewTrigger );
assert( IN_RENAME_OBJECT || !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(db, pStepList);
}
/*
** Duplicate a range of text from an SQL statement, then convert all
** whitespace characters into ordinary space characters.
*/
static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
char *z = sqlite3DbSpanDup(db, zStart, zEnd);
int i;
if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
return z;
}
/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
@@ -346,7 +376,12 @@ triggerfinish_cleanup:
** The parser calls this routine when it finds a SELECT statement in
** body of a TRIGGER.
*/
TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
TriggerStep *sqlite3TriggerSelectStep(
sqlite3 *db, /* Database connection */
Select *pSelect, /* The SELECT statement */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(db, pSelect);
@@ -355,6 +390,7 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
return pTriggerStep;
}
@@ -365,10 +401,13 @@ TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
*/
static TriggerStep *triggerStepAllocate(
sqlite3 *db, /* Database connection */
Parse *pParse, /* Parser context */
u8 op, /* Trigger opcode */
Token *pName /* The target name */
Token *pName, /* The target name */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
@@ -378,6 +417,10 @@ static TriggerStep *triggerStepAllocate(
sqlite3Dequote(z);
pTriggerStep->zTarget = z;
pTriggerStep->op = op;
pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
if( IN_RENAME_OBJECT ){
sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
}
}
return pTriggerStep;
}
@@ -390,23 +433,36 @@ static TriggerStep *triggerStepAllocate(
** body of a trigger.
*/
TriggerStep *sqlite3TriggerInsertStep(
sqlite3 *db, /* The database connection */
Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
Select *pSelect, /* A SELECT statement that supplies values */
u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
Upsert *pUpsert, /* ON CONFLICT clauses for upsert */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
assert(pSelect != 0 || db->mallocFailed);
pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
if( pTriggerStep ){
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
if( IN_RENAME_OBJECT ){
pTriggerStep->pSelect = pSelect;
pSelect = 0;
}else{
pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
}
pTriggerStep->pIdList = pColumn;
pTriggerStep->pUpsert = pUpsert;
pTriggerStep->orconf = orconf;
}else{
testcase( pColumn );
sqlite3IdListDelete(db, pColumn);
testcase( pUpsert );
sqlite3UpsertDelete(db, pUpsert);
}
sqlite3SelectDelete(db, pSelect);
@@ -419,18 +475,28 @@ TriggerStep *sqlite3TriggerInsertStep(
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerUpdateStep(
sqlite3 *db, /* The database connection */
Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table to be updated */
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
if( pTriggerStep ){
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
if( IN_RENAME_OBJECT ){
pTriggerStep->pExprList = pEList;
pTriggerStep->pWhere = pWhere;
pEList = 0;
pWhere = 0;
}else{
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
}
pTriggerStep->orconf = orconf;
}
sqlite3ExprListDelete(db, pEList);
@@ -444,15 +510,23 @@ TriggerStep *sqlite3TriggerUpdateStep(
** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/
TriggerStep *sqlite3TriggerDeleteStep(
sqlite3 *db, /* Database connection */
Parse *pParse, /* Parser */
Token *pTableName, /* The table from which rows are deleted */
Expr *pWhere /* The WHERE clause */
Expr *pWhere, /* The WHERE clause */
const char *zStart, /* Start of SQL text */
const char *zEnd /* End of SQL text */
){
sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
if( pTriggerStep ){
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
if( IN_RENAME_OBJECT ){
pTriggerStep->pWhere = pWhere;
pWhere = 0;
}else{
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
}
pTriggerStep->orconf = OE_Default;
}
sqlite3ExprDelete(db, pWhere);
@@ -585,7 +659,7 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
*pp = (*pp)->pNext;
}
sqlite3DeleteTrigger(db, pTrigger);
db->flags |= SQLITE_InternChanges;
db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -705,13 +779,21 @@ static int codeTriggerProgram(
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
assert( pParse->okConstFactor==0 );
#ifndef SQLITE_OMIT_TRACE
if( pStep->zSpan ){
sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
sqlite3MPrintf(db, "-- %s", pStep->zSpan),
P4_DYNAMIC);
}
#endif
switch( pStep->op ){
case TK_UPDATE: {
sqlite3Update(pParse,
targetSrcList(pParse, pStep),
sqlite3ExprListDup(db, pStep->pExprList, 0),
sqlite3ExprDup(db, pStep->pWhere, 0),
pParse->eOrconf
pParse->eOrconf, 0, 0, 0
);
break;
}
@@ -720,14 +802,15 @@ static int codeTriggerProgram(
targetSrcList(pParse, pStep),
sqlite3SelectDup(db, pStep->pSelect, 0),
sqlite3IdListDup(db, pStep->pIdList),
pParse->eOrconf
pParse->eOrconf,
sqlite3UpsertDup(db, pStep->pUpsert)
);
break;
}
case TK_DELETE: {
sqlite3DeleteFrom(pParse,
targetSrcList(pParse, pStep),
sqlite3ExprDup(db, pStep->pWhere, 0)
sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
);
break;
}
@@ -845,9 +928,11 @@ static TriggerPrg *codeRowTrigger(
pTab->zName
));
#ifndef SQLITE_OMIT_TRACE
sqlite3VdbeChangeP4(v, -1,
sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
);
if( pTrigger->zName ){
sqlite3VdbeChangeP4(v, -1,
sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
);
}
#endif
/* If one was specified, code the WHEN clause. If it evaluates to false
@@ -875,7 +960,7 @@ static TriggerPrg *codeRowTrigger(
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
transferParseError(pParse, pSubParse);
if( db->mallocFailed==0 ){
if( db->mallocFailed==0 && pParse->nErr==0 ){
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
}
pProgram->nMem = pSubParse->nMem;
+198 -125
View File
@@ -91,7 +91,10 @@ void sqlite3Update(
SrcList *pTabList, /* The table in which we should change things */
ExprList *pChanges, /* Things to be changed */
Expr *pWhere, /* The WHERE clause. May be null */
int onError /* How to handle constraint errors */
int onError, /* How to handle constraint errors */
ExprList *pOrderBy, /* ORDER BY clause. May be null */
Expr *pLimit, /* LIMIT clause. May be null */
Upsert *pUpsert /* ON CONFLICT clause, or null */
){
int i, j; /* Loop counters */
Table *pTab; /* The table to be updated */
@@ -176,6 +179,16 @@ void sqlite3Update(
# define isView 0
#endif
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
if( !isView ){
pWhere = sqlite3LimitWhere(
pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
);
pOrderBy = 0;
pLimit = 0;
}
#endif
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
@@ -188,16 +201,23 @@ void sqlite3Update(
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++;
iBaseCur = iDataCur = pParse->nTab++;
iIdxCur = iDataCur+1;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
testcase( pPk!=0 && pPk!=pTab->pIndex );
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){
if( pPk==pIdx ){
iDataCur = pParse->nTab;
pTabList->a[0].iCursor = iDataCur;
}
pParse->nTab++;
}
if( pUpsert ){
/* On an UPSERT, reuse the same cursors already opened by INSERT */
iDataCur = pUpsert->iDataCur;
iIdxCur = pUpsert->iIdxCur;
pParse->nTab = iBaseCur;
}
pTabList->a[0].iCursor = iDataCur;
/* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
** Initialize aXRef[] and aToOpen[] to their default values.
@@ -214,6 +234,8 @@ void sqlite3Update(
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
@@ -317,7 +339,7 @@ void sqlite3Update(
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb);
/* Allocate required registers. */
if( !IsVirtual(pTab) ){
@@ -344,7 +366,11 @@ void sqlite3Update(
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
sqlite3MaterializeView(pParse, pTab,
pWhere, pOrderBy, pLimit, iDataCur
);
pOrderBy = 0;
pLimit = 0;
}
#endif
@@ -364,8 +390,16 @@ void sqlite3Update(
}
#endif
/* Initialize the count of updated rows */
if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
/* Jump to labelBreak to abandon further processing of this UPDATE */
labelContinue = labelBreak = sqlite3VdbeMakeLabel(v);
/* Not an UPSERT. Normal processing. Begin by
** initialize the count of updated rows */
if( (db->flags&SQLITE_CountRows)!=0
&& !pParse->pTriggerTab
&& !pParse->nested
&& pUpsert==0
){
regRowCount = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
@@ -378,46 +412,61 @@ void sqlite3Update(
iPk = pParse->nMem+1;
pParse->nMem += nPk;
regKey = ++pParse->nMem;
iEph = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_Null, 0, iPk);
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
** there are any triggers or foreign keys to process, or rows may
** be deleted as a result of REPLACE conflict handling. Any of these
** things might disturb a cursor being used to scan through the table
** or index, causing a single-pass approach to malfunction. */
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
if( pWInfo==0 ) goto update_cleanup;
/* A one-pass strategy that might update more than one row may not
** be used if any column of the index used for the scan is being
** updated. Otherwise, if there is an index on "b", statements like
** the following could create an infinite loop:
**
** UPDATE t1 SET b=b+1 WHERE b>?
**
** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
** strategy that uses an index for which one or more columns are being
** updated. */
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
if( eOnePass==ONEPASS_MULTI ){
int iCur = aiCurOnePass[1];
if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
eOnePass = ONEPASS_OFF;
if( pUpsert==0 ){
iEph = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
assert( iCur!=iDataCur || !HasRowid(pTab) );
}
if( pUpsert ){
/* If this is an UPSERT, then all cursors have already been opened by
** the outer INSERT and the data cursor should be pointing at the row
** that is to be updated. So bypass the code that searches for the
** row(s) to be updated.
*/
pWInfo = 0;
eOnePass = ONEPASS_SINGLE;
sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
}else{
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
** there are any triggers or foreign keys to process, or rows may
** be deleted as a result of REPLACE conflict handling. Any of these
** things might disturb a cursor being used to scan through the table
** or index, causing a single-pass approach to malfunction. */
flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
if( pWInfo==0 ) goto update_cleanup;
/* A one-pass strategy that might update more than one row may not
** be used if any column of the index used for the scan is being
** updated. Otherwise, if there is an index on "b", statements like
** the following could create an infinite loop:
**
** UPDATE t1 SET b=b+1 WHERE b>?
**
** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
** strategy that uses an index for which one or more columns are being
** updated. */
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
if( eOnePass!=ONEPASS_SINGLE ){
sqlite3MultiWrite(pParse);
if( eOnePass==ONEPASS_MULTI ){
int iCur = aiCurOnePass[1];
if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
eOnePass = ONEPASS_OFF;
}
assert( iCur!=iDataCur || !HasRowid(pTab) );
}
}
}
if( HasRowid(pTab) ){
/* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
** mode, write the rowid into the FIFO. In either of the one-pass modes,
@@ -437,7 +486,7 @@ void sqlite3Update(
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i);
}
if( eOnePass ){
sqlite3VdbeChangeToNoop(v, addrOpen);
if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
nKey = nPk;
regKey = iPk;
}else{
@@ -447,59 +496,58 @@ void sqlite3Update(
}
}
if( eOnePass!=ONEPASS_MULTI ){
sqlite3WhereEnd(pWInfo);
}
labelBreak = sqlite3VdbeMakeLabel(v);
if( !isView ){
int addrOnce = 0;
/* Open every index that needs updating. */
if( pUpsert==0 ){
if( eOnePass!=ONEPASS_MULTI ){
sqlite3WhereEnd(pWInfo);
}
if( !isView ){
int addrOnce = 0;
/* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
}
if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
aToOpen, 0, 0);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
}
/* Top of the update loop */
if( eOnePass!=ONEPASS_OFF ){
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
}
if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
0, 0);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
}
/* Top of the update loop */
if( eOnePass!=ONEPASS_OFF ){
if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
assert( pPk );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
VdbeCoverageNeverTaken(v);
}
if( eOnePass==ONEPASS_SINGLE ){
labelContinue = labelBreak;
}else{
if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
assert( pPk );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
VdbeCoverage(v);
}
if( eOnePass!=ONEPASS_SINGLE ){
labelContinue = sqlite3VdbeMakeLabel(v);
}
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
VdbeCoverageIf(v, pPk==0);
VdbeCoverageIf(v, pPk!=0);
}else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
VdbeCoverage(v);
}else{
labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
regOldRowid);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
VdbeCoverageIf(v, pPk==0);
VdbeCoverageIf(v, pPk!=0);
}else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
VdbeCoverage(v);
}else{
labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak,
regOldRowid);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
VdbeCoverage(v);
}
/* If the record number will change, set register regNewRowid to
** contain the new value. If the record number is not being modified,
/* If the rowid value will change, set register regNewRowid to
** contain the new value. If the rowid is not being modified,
** then regNewRowid is the same register as regOldRowid, which is
** already populated. */
assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
@@ -562,7 +610,7 @@ void sqlite3Update(
*/
testcase( i==31 );
testcase( i==32 );
sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
}
@@ -591,10 +639,14 @@ void sqlite3Update(
VdbeCoverage(v);
}
/* If it did not delete it, the row-trigger may still have modified
/* After-BEFORE-trigger-reload-loop:
** If it did not delete it, the BEFORE trigger may still have modified
** some of the columns of the row being updated. Load the values for
** all columns not modified by the update statement into their
** registers in case this has happened.
** all columns not modified by the update statement into their registers
** in case this has happened. Only unmodified columns are reloaded.
** The values computed for modified columns use the values before the
** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
** for an example.
*/
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]<0 && i!=pTab->iPKey ){
@@ -610,7 +662,7 @@ void sqlite3Update(
assert( regOldRowid>0 );
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
aXRef);
aXRef, 0);
/* Do FK constraint checks. */
if( hasFK ){
@@ -680,7 +732,7 @@ void sqlite3Update(
/* Increment the row counter
*/
if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){
if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
@@ -707,16 +759,15 @@ void sqlite3Update(
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
if( pParse->nested==0 && pParse->pTriggerTab==0 ){
if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){
sqlite3AutoincrementEnd(pParse);
}
/*
** Return the number of rows that were changed. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
** Return the number of rows that were changed, if we are tracking
** that information.
*/
if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){
if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
@@ -728,6 +779,10 @@ update_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(db, pWhere);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
#endif
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -784,10 +839,10 @@ static void updateVirtualTable(
int regRowid; /* Register for ephem table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
int bOnePass; /* True to use onepass strategy */
int eOnePass; /* True to use onepass strategy */
int addr; /* Address of OP_OpenEphemeral */
/* Allocate nArg registers to martial the arguments to VUpdate. Then
/* Allocate nArg registers in which to gather the arguments for VUpdate. Then
** create and open the ephemeral table in which the records created from
** these arguments will be temporarily stored. */
assert( v );
@@ -803,40 +858,58 @@ static void updateVirtualTable(
if( pWInfo==0 ) return;
/* Populate the argument registers. */
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
if( pRowid ){
sqlite3ExprCode(pParse, pRowid, regArg+1);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
}
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
}else{
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
sqlite3VdbeChangeP5(v, 1); /* Enable sqlite3_vtab_nochange() */
}
}
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
if( bOnePass ){
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
** above. Also, if this is a top-level parse (not a trigger), clear the
** multi-write flag so that the VM does not open a statement journal */
sqlite3VdbeChangeToNoop(v, addr);
if( sqlite3IsToplevel(pParse) ){
pParse->isMultiWrite = 0;
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
if( pRowid ){
sqlite3ExprCode(pParse, pRowid, regArg+1);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
}
}else{
Index *pPk; /* PRIMARY KEY index */
i16 iPk; /* PRIMARY KEY column */
pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
assert( pPk->nKeyCol==1 );
iPk = pPk->aiColumn[0];
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
}
eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
/* There is no ONEPASS_MULTI on virtual tables */
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
if( eOnePass ){
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
** above. */
sqlite3VdbeChangeToNoop(v, addr);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}else{
/* Create a record from the argument register contents and insert it into
** the ephemeral table. */
sqlite3MultiWrite(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
#ifdef SQLITE_DEBUG
/* Signal an assert() within OP_MakeRecord that it is allowed to
** accept no-change records with serial_type 10 */
sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
#endif
sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
}
if( bOnePass==0 ){
if( eOnePass==ONEPASS_OFF ){
/* End the virtual table scan */
sqlite3WhereEnd(pWInfo);
@@ -856,7 +929,7 @@ static void updateVirtualTable(
/* End of the ephemeral table scan. Or, if using the onepass strategy,
** jump to here if the scan visited zero rows. */
if( bOnePass==0 ){
if( eOnePass==ONEPASS_OFF ){
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
+252
View File
@@ -0,0 +1,252 @@
/*
** 2018-04-12
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement various aspects of UPSERT
** processing and handling of the Upsert object.
*/
#include "sqliteInt.h"
#ifndef SQLITE_OMIT_UPSERT
/*
** Free a list of Upsert objects
*/
void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
if( p ){
sqlite3ExprListDelete(db, p->pUpsertTarget);
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
sqlite3ExprListDelete(db, p->pUpsertSet);
sqlite3ExprDelete(db, p->pUpsertWhere);
sqlite3DbFree(db, p);
}
}
/*
** Duplicate an Upsert object.
*/
Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
if( p==0 ) return 0;
return sqlite3UpsertNew(db,
sqlite3ExprListDup(db, p->pUpsertTarget, 0),
sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
sqlite3ExprListDup(db, p->pUpsertSet, 0),
sqlite3ExprDup(db, p->pUpsertWhere, 0)
);
}
/*
** Create a new Upsert object.
*/
Upsert *sqlite3UpsertNew(
sqlite3 *db, /* Determines which memory allocator to use */
ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
Expr *pTargetWhere, /* Optional WHERE clause on the target */
ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
){
Upsert *pNew;
pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
if( pNew==0 ){
sqlite3ExprListDelete(db, pTarget);
sqlite3ExprDelete(db, pTargetWhere);
sqlite3ExprListDelete(db, pSet);
sqlite3ExprDelete(db, pWhere);
return 0;
}else{
pNew->pUpsertTarget = pTarget;
pNew->pUpsertTargetWhere = pTargetWhere;
pNew->pUpsertSet = pSet;
pNew->pUpsertWhere = pWhere;
pNew->pUpsertIdx = 0;
}
return pNew;
}
/*
** Analyze the ON CONFLICT clause described by pUpsert. Resolve all
** symbols in the conflict-target.
**
** Return SQLITE_OK if everything works, or an error code is something
** is wrong.
*/
int sqlite3UpsertAnalyzeTarget(
Parse *pParse, /* The parsing context */
SrcList *pTabList, /* Table into which we are inserting */
Upsert *pUpsert /* The ON CONFLICT clauses */
){
Table *pTab; /* That table into which we are inserting */
int rc; /* Result code */
int iCursor; /* Cursor used by pTab */
Index *pIdx; /* One of the indexes of pTab */
ExprList *pTarget; /* The conflict-target clause */
Expr *pTerm; /* One term of the conflict-target clause */
NameContext sNC; /* Context for resolving symbolic names */
Expr sCol[2]; /* Index column converted into an Expr */
assert( pTabList->nSrc==1 );
assert( pTabList->a[0].pTab!=0 );
assert( pUpsert!=0 );
assert( pUpsert->pUpsertTarget!=0 );
/* Resolve all symbolic names in the conflict-target clause, which
** includes both the list of columns and the optional partial-index
** WHERE clause.
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
if( rc ) return rc;
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
if( rc ) return rc;
/* Check to see if the conflict target matches the rowid. */
pTab = pTabList->a[0].pTab;
pTarget = pUpsert->pUpsertTarget;
iCursor = pTabList->a[0].iCursor;
if( HasRowid(pTab)
&& pTarget->nExpr==1
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
&& pTerm->iColumn==XN_ROWID
){
/* The conflict-target is the rowid of the primary table */
assert( pUpsert->pUpsertIdx==0 );
return SQLITE_OK;
}
/* Initialize sCol[0..1] to be an expression parse tree for a
** single column of an index. The sCol[0] node will be the TK_COLLATE
** operator and sCol[1] will be the TK_COLUMN operator. Code below
** will populate the specific collation and column number values
** prior to comparing against the conflict-target expression.
*/
memset(sCol, 0, sizeof(sCol));
sCol[0].op = TK_COLLATE;
sCol[0].pLeft = &sCol[1];
sCol[1].op = TK_COLUMN;
sCol[1].iTable = pTabList->a[0].iCursor;
/* Check for matches against other indexes */
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int ii, jj, nn;
if( !IsUniqueIndex(pIdx) ) continue;
if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
if( pIdx->pPartIdxWhere ){
if( pUpsert->pUpsertTargetWhere==0 ) continue;
if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
pIdx->pPartIdxWhere, iCursor)!=0 ){
continue;
}
}
nn = pIdx->nKeyCol;
for(ii=0; ii<nn; ii++){
Expr *pExpr;
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
pExpr = &sCol[0];
}
}else{
sCol[0].pLeft = &sCol[1];
sCol[1].iColumn = pIdx->aiColumn[ii];
pExpr = &sCol[0];
}
for(jj=0; jj<nn; jj++){
if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){
break; /* Column ii of the index matches column jj of target */
}
}
if( jj>=nn ){
/* The target contains no match for column jj of the index */
break;
}
}
if( ii<nn ){
/* Column ii of the index did not match any term of the conflict target.
** Continue the search with the next index. */
continue;
}
pUpsert->pUpsertIdx = pIdx;
return SQLITE_OK;
}
sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any "
"PRIMARY KEY or UNIQUE constraint");
return SQLITE_ERROR;
}
/*
** Generate bytecode that does an UPDATE as part of an upsert.
**
** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
** In this case parameter iCur is a cursor open on the table b-tree that
** currently points to the conflicting table row. Otherwise, if pIdx
** is not NULL, then pIdx is the constraint that failed and iCur is a
** cursor points to the conflicting row.
*/
void sqlite3UpsertDoUpdate(
Parse *pParse, /* The parsing and code-generating context */
Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */
Table *pTab, /* The table being updated */
Index *pIdx, /* The UNIQUE constraint that failed */
int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */
){
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
SrcList *pSrc; /* FROM clause for the UPDATE */
int iDataCur;
assert( v!=0 );
assert( pUpsert!=0 );
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
iDataCur = pUpsert->iDataCur;
if( pIdx && iCur!=iDataCur ){
if( HasRowid(pTab) ){
int regRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regRowid);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
int nPk = pPk->nKeyCol;
int iPk = pParse->nMem+1;
int i;
pParse->nMem += nPk;
for(i=0; i<nPk; i++){
int k;
assert( pPk->aiColumn[i]>=0 );
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
VdbeComment((v, "%s.%s", pIdx->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
}
sqlite3VdbeVerifyAbortable(v, OE_Abort);
i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
"corrupt database", P4_STATIC);
sqlite3VdbeJumpHere(v, i);
}
}
/* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
** we have to make a copy before passing it down into sqlite3Update() */
pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
}
#endif /* SQLITE_OMIT_UPSERT */
+101 -44
View File
@@ -320,6 +320,45 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
}
/*
** Compute 10 to the E-th power. Examples: E==1 results in 10.
** E==2 results in 100. E==50 results in 1.0e50.
**
** This routine only works for values of E between 1 and 341.
*/
static LONGDOUBLE_TYPE sqlite3Pow10(int E){
#if defined(_MSC_VER)
static const LONGDOUBLE_TYPE x[] = {
1.0e+001,
1.0e+002,
1.0e+004,
1.0e+008,
1.0e+016,
1.0e+032,
1.0e+064,
1.0e+128,
1.0e+256
};
LONGDOUBLE_TYPE r = 1.0;
int i;
assert( E>=0 && E<=307 );
for(i=0; E!=0; i++, E >>=1){
if( E & 1 ) r *= x[i];
}
return r;
#else
LONGDOUBLE_TYPE x = 10.0;
LONGDOUBLE_TYPE r = 1.0;
while(1){
if( E & 1 ) r *= x;
E >>= 1;
if( E==0 ) break;
x *= x;
}
return r;
#endif
}
/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
@@ -387,12 +426,12 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
/* copy max significant digits to significand */
while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
z+=incr, nDigits++;
z+=incr; nDigits++;
}
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; nDigits++; d++; }
if( z>=zEnd ) goto do_atof_calc;
/* if decimal point is present */
@@ -405,7 +444,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
s = s*10 + (*z - '0');
d--;
}
z+=incr, nDigits++;
z+=incr; nDigits++;
}
}
if( z>=zEnd ) goto do_atof_calc;
@@ -475,11 +514,10 @@ do_atof_calc:
if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
result = (double)s;
}else{
LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
while( e%308 ) { scale *= 1.0e+1; e -= 1; }
LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
if( esign<0 ){
result = s / scale;
result /= 1.0e+308;
@@ -491,14 +529,15 @@ do_atof_calc:
if( esign<0 ){
result = 0.0*s;
}else{
#ifdef INFINITY
result = INFINITY*s;
#else
result = 1e308*1e308*s; /* Infinity */
#endif
}
}
}else{
/* 1.0e+22 is the largest power of 10 than can be
** represented exactly. */
while( e%22 ) { scale *= 1.0e+1; e -= 1; }
while( e>0 ) { scale *= 1.0e+22; e -= 22; }
LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
if( esign<0 ){
result = s / scale;
}else{
@@ -553,16 +592,12 @@ static int compare2pow63(const char *zNum, int incr){
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
** routine does *not* accept hexadecimal notation.
**
** If the zNum value is representable as a 64-bit twos-complement
** integer, then write that value into *pNum and return 0.
** Returns:
**
** If zNum is exactly 9223372036854775808, return 2. This special
** case is broken out because while 9223372036854775808 cannot be a
** signed 64-bit integer, its negative -9223372036854775808 can be.
**
** If zNum is too big for a 64-bit integer and is not
** 9223372036854775808 or if zNum contains any non-numeric text,
** then return 1.
** 0 Successful transformation. Fits in a 64-bit signed integer.
** 1 Excess non-space text after the integer value
** 2 Integer too large for a 64-bit signed integer or is malformed
** 3 Special case of 9223372036854775808
**
** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated. The encoding is
@@ -575,6 +610,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
int i;
int c = 0;
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
int rc; /* Baseline return code */
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -602,43 +638,57 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
u = u*10 + c - '0';
}
testcase( i==18*incr );
testcase( i==19*incr );
testcase( i==20*incr );
if( u>LARGEST_INT64 ){
/* This test and assignment is needed only to suppress UB warnings
** from clang and -fsanitize=undefined. This test and assignment make
** the code a little larger and slower, and no harm comes from omitting
** them, but we must appaise the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
}else{
*pNum = (i64)u;
}
testcase( i==18 );
testcase( i==19 );
testcase( i==20 );
if( &zNum[i]<zEnd /* Extra bytes at the end */
|| (i==0 && zStart==zNum) /* No digits */
|| i>19*incr /* Too many digits */
rc = 0;
if( (i==0 && zStart==zNum) /* No digits */
|| nonNum /* UTF16 with high-order bytes non-zero */
){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
return 1;
}else if( i<19*incr ){
rc = 1;
}else if( &zNum[i]<zEnd ){ /* Extra bytes at the end */
int jj = i;
do{
if( !sqlite3Isspace(zNum[jj]) ){
rc = 1; /* Extra non-space text after the integer */
break;
}
jj += incr;
}while( &zNum[jj]<zEnd );
}
if( i<19*incr ){
/* Less than 19 digits, so we know that it fits in 64 bits */
assert( u<=LARGEST_INT64 );
return 0;
return rc;
}else{
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
c = compare2pow63(zNum, incr);
c = i>19*incr ? 1 : compare2pow63(zNum, incr);
if( c<0 ){
/* zNum is less than 9223372036854775808 so it fits */
assert( u<=LARGEST_INT64 );
return 0;
}else if( c>0 ){
/* zNum is greater than 9223372036854775808 so it overflows */
return 1;
return rc;
}else{
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
return neg ? 0 : 2;
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
if( c>0 ){
/* zNum is greater than 9223372036854775808 so it overflows */
return 2;
}else{
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
return neg ? rc : 3;
}
}
}
}
@@ -651,8 +701,9 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
** Returns:
**
** 0 Successful transformation. Fits in a 64-bit signed integer.
** 1 Integer too large for a 64-bit signed integer or is malformed
** 2 Special case of 9223372036854775808
** 1 Excess text after the integer value
** 2 Integer too large for a 64-bit signed integer or is malformed
** 3 Special case of 9223372036854775808
*/
int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
@@ -666,7 +717,7 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
return (z[k]==0 && k-i<=16) ? 0 : 1;
return (z[k]==0 && k-i<=16) ? 0 : 2;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
@@ -1276,7 +1327,7 @@ int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
** overflow, leave *pA unchanged and return 1.
*/
int sqlite3AddInt64(i64 *pA, i64 iB){
#if GCC_VERSION>=5004000
#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_add_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -1296,7 +1347,7 @@ int sqlite3AddInt64(i64 *pA, i64 iB){
#endif
}
int sqlite3SubInt64(i64 *pA, i64 iB){
#if GCC_VERSION>=5004000
#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_sub_overflow(*pA, iB, pA);
#else
testcase( iB==SMALLEST_INT64+1 );
@@ -1311,7 +1362,7 @@ int sqlite3SubInt64(i64 *pA, i64 iB){
#endif
}
int sqlite3MulInt64(i64 *pA, i64 iB){
#if GCC_VERSION>=5004000
#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
return __builtin_mul_overflow(*pA, iB, pA);
#else
i64 iA = *pA;
@@ -1413,8 +1464,14 @@ LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
#if GCC_VERSION>=5004000
int i = 60 - __builtin_clzll(x);
y += i*10;
x >>= i;
#else
while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
while( x>15 ){ y += 10; x >>= 1; }
#endif
}
return a[x&7] + y - 10;
}
+18 -9
View File
@@ -39,8 +39,14 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
if( zSubSql ){
assert( zSubSql[0]!='S' );
/* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
** or INSERT. Historically there have been attacks that first
** corrupt the sqlite_master.sql field with other kinds of statements
** then run VACUUM to get those statements to execute at inappropriate
** times. */
if( zSubSql
&& (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0)
){
rc = execSql(db, pzErrMsg, zSubSql);
if( rc!=SQLITE_OK ) break;
}
@@ -130,7 +136,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
int saved_flags; /* Saved value of the db->flags */
u16 saved_mDbFlags; /* Saved value of db->mDbFlags */
u32 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
u8 saved_mTrace; /* Saved trace settings */
@@ -153,11 +160,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
| SQLITE_PreferBuiltin | SQLITE_Vacuum);
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
db->mTrace = 0;
@@ -216,7 +224,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
*/
rc = execSql(db, pzErrMsg, "BEGIN");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeBeginTrans(pMain, 2);
rc = sqlite3BtreeBeginTrans(pMain, 2, 0);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Do not attempt to change the page size for a WAL database */
@@ -251,7 +259,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execSqlF(db, pzErrMsg,
"SELECT sql FROM \"%w\".sqlite_master"
" WHERE type='index' AND length(sql)>10",
" WHERE type='index'",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@@ -268,8 +276,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
assert( (db->flags & SQLITE_Vacuum)!=0 );
db->flags &= ~SQLITE_Vacuum;
assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
db->mDbFlags &= ~DBFLAG_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers, views, and virtual tables from the main database
@@ -337,6 +345,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
end_of_vacuum:
/* Restore the original value of db->flags */
db->init.iDb = 0;
db->mDbFlags = saved_mDbFlags;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
+675 -328
View File
File diff suppressed because it is too large Load Diff
+57 -4
View File
@@ -73,7 +73,8 @@ struct VdbeOp {
u64 cycles; /* Total time spent executing this instruction */
#endif
#ifdef SQLITE_VDBE_COVERAGE
int iSrcLine; /* Source-code line that generated this opcode */
u32 iSrcLine; /* Source-code line that generated this opcode
** with flags in the upper 8 bits */
#endif
};
typedef struct VdbeOp VdbeOp;
@@ -127,6 +128,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
#define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -196,7 +198,24 @@ void sqlite3VdbeEndCoroutine(Vdbe*,int);
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
# define sqlite3VdbeVerifyNoResultRow(A)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
#if defined(SQLITE_DEBUG)
void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
#else
# define sqlite3VdbeVerifyAbortable(A,B)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#ifndef SQLITE_OMIT_EXPLAIN
void sqlite3VdbeExplain(Parse*,u8,const char*,...);
void sqlite3VdbeExplainPop(Parse*);
int sqlite3VdbeExplainParent(Parse*);
# define ExplainQueryPlan(P) sqlite3VdbeExplain P
# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P)
#else
# define ExplainQueryPlan(P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
@@ -240,6 +259,7 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
char *sqlite3VdbeExpandSql(Vdbe*, const char*);
#endif
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3BlobCompare(const Mem*, const Mem*);
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
@@ -295,23 +315,52 @@ int sqlite3NotPureFunc(sqlite3_context*);
**
** VdbeCoverageNeverTaken(v) // Previous branch is never taken
**
** VdbeCoverageNeverNull(v) // Previous three-way branch is only
** // taken on the first two ways. The
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
** // in distingishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
** routine in vdbe.c, alerting the developer to the missed tag.
**
** During testing, the test application will invoke
** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
** contains the sqlite3.c source line number ov the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
**
** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the
** vdbe.c source file for additional information.
*/
#ifdef SQLITE_VDBE_COVERAGE
void sqlite3VdbeSetLineNumber(Vdbe*,int);
# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
# define VdbeCoverageAlwaysTaken(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000);
# define VdbeCoverageNeverTaken(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000);
# define VdbeCoverageNeverNull(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
# define VdbeCoverageNeverNullIf(v,x) \
if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
# define VdbeCoverageEqNe(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000);
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
#else
# define VdbeCoverage(v)
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
# define VdbeCoverageNeverNull(v)
# define VdbeCoverageNeverNullIf(v,x)
# define VdbeCoverageEqNe(v)
# define VDBE_OFFSET_LINENO(x) 0
#endif
@@ -321,4 +370,8 @@ void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
# define sqlite3VdbeScanStatus(a,b,c,d,e)
#endif
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
#endif /* SQLITE_VDBE_H */
+45 -20
View File
@@ -85,6 +85,7 @@ struct VdbeCursor {
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
Btree *pBtx; /* Separate file holding temporary table */
i64 seqCount; /* Sequence counter */
int *aAltMap; /* Mapping from table to index column numbers */
@@ -96,18 +97,18 @@ struct VdbeCursor {
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
** if there have been no prior seeks on the cursor. */
/* NB: seekResult does not distinguish between "no seeks have ever occurred
** on this cursor" and "the most recent seek was an exact match". */
/* seekResult does not distinguish between "no seeks have ever occurred
** on this cursor" and "the most recent seek was an exact match".
** For CURTYPE_PSEUDO, seekResult is the register holding the record */
/* When a new VdbeCursor is allocated, only the fields above are zeroed.
** The fields that follow are uninitialized, and must be individually
** initialized prior to first use. */
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
union {
BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */
sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
@@ -168,6 +169,9 @@ struct VdbeFrame {
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#if SQLITE_DEBUG
u32 iFrameMagic; /* magic number for sanity checking */
#endif
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
@@ -178,6 +182,13 @@ struct VdbeFrame {
int nDbChange; /* Value of db->nChange */
};
/* Magic number for sanity checking on VdbeFrame objects */
#define SQLITE_FRAME_MAGIC 0x879fb71e
/*
** Return a pointer to the array of registers allocated for use
** by a VdbeFrame.
*/
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
/*
@@ -192,8 +203,6 @@ struct sqlite3_value {
int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
@@ -208,7 +217,7 @@ struct sqlite3_value {
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
u16 mScopyFlags; /* flags value immediately after the shallow copy */
#endif
};
@@ -237,8 +246,8 @@ struct sqlite3_value {
#define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_AffMask 0x001f /* Mask of affinity bits */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
/* Available 0x0020 */
/* Available 0x0040 */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
#define MEM_TypeMask 0xc1ff /* Mask of type bits */
@@ -265,7 +274,7 @@ struct sqlite3_value {
** that needs to be deallocated to avoid a leak.
*/
#define VdbeMemDynamic(X) \
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
(((X)->flags&(MEM_Agg|MEM_Dyn))!=0)
/*
** Clear any existing type flags from a Mem and replace them with f
@@ -317,7 +326,6 @@ struct sqlite3_context {
int iOp; /* Instruction number of OP_Function */
int isError; /* Error code returned by the function. */
u8 skipFlag; /* Skip accumulator loading if true */
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
u8 argc; /* Number of arguments */
sqlite3_value *argv[1]; /* Argument set */
};
@@ -380,14 +388,15 @@ struct Vdbe {
int nOp; /* Number of instructions in the program */
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
bft expired:1; /* True if the VM needs to be recompiled */
bft doingRerun:1; /* True if rerunning after an auto-reprepare */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft doingRerun:1; /* True if rerunning after an auto-reprepare */
bft changeCntOn:1; /* True to update the change-counter */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
@@ -448,9 +457,6 @@ void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
int sqlite3VdbeCursorRestore(VdbeCursor*);
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
u32 sqlite3VdbeSerialTypeLen(u32);
u8 sqlite3VdbeOneByteSerialTypeLen(u8);
u32 sqlite3VdbeSerialType(Mem*, int, u32*);
@@ -481,12 +487,16 @@ void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
void sqlite3VdbeMemSetRowSet(Mem*);
#ifdef SQLITE_DEBUG
int sqlite3VdbeMemIsRowSet(const Mem*);
#endif
int sqlite3VdbeMemSetRowSet(Mem*);
int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemStringify(Mem*, u8, u8);
i64 sqlite3VdbeIntValue(Mem*);
int sqlite3VdbeMemIntegerify(Mem*);
double sqlite3VdbeRealValue(Mem*);
int sqlite3VdbeBooleanValue(Mem*, int ifNull);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*);
@@ -494,11 +504,18 @@ void sqlite3VdbeMemCast(Mem*,u8,u8);
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
#ifndef SQLITE_OMIT_WINDOWFUNC
int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
#endif
const char *sqlite3OpcodeName(int);
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
int sqlite3VdbeCloseStatement(Vdbe *, int);
void sqlite3VdbeFrameDelete(VdbeFrame*);
#ifdef SQLITE_DEBUG
int sqlite3VdbeFrameIsValid(VdbeFrame*);
#endif
void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */
void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */
int sqlite3VdbeFrameRestore(VdbeFrame *);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
@@ -514,6 +531,14 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#ifdef SQLITE_DEBUG
void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
void sqlite3VdbeAssertAbortable(Vdbe*);
#else
# define sqlite3VdbeIncrWriteCounter(V,C)
# define sqlite3VdbeAssertAbortable(V)
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE)
void sqlite3VdbeEnter(Vdbe*);
#else
+55 -61
View File
@@ -268,6 +268,11 @@ int sqlite3_value_type(sqlite3_value* pVal){
return aType[pVal->flags&MEM_AffMask];
}
/* Return true if a parameter to xUpdate represents an unchanged column */
int sqlite3_value_nochange(sqlite3_value *pVal){
return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
}
/* Make a copy of an sqlite3_value object
*/
sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
@@ -367,14 +372,12 @@ void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
@@ -480,8 +483,7 @@ int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
return SQLITE_OK;
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
@@ -495,7 +497,6 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
SQLITE_UTF8, SQLITE_STATIC);
}
@@ -505,7 +506,6 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
pCtx->fErrorOrAux = 1;
sqlite3OomFault(pCtx->pOut->db);
}
@@ -524,7 +524,7 @@ static int doWalCallbacks(sqlite3 *db){
sqlite3BtreeEnter(pBt);
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
}
}
@@ -634,7 +634,7 @@ static int sqlite3Step(Vdbe *p){
if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
#endif
if( rc==SQLITE_DONE ){
if( rc==SQLITE_DONE && db->autoCommit ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
if( p->rc!=SQLITE_OK ){
@@ -678,7 +678,6 @@ end_of_step:
*/
int sqlite3_step(sqlite3_stmt *pStmt){
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 */
@@ -692,32 +691,31 @@ int sqlite3_step(sqlite3_stmt *pStmt){
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
int savedPc = v->pc;
rc2 = rc = sqlite3Reprepare(v);
if( rc!=SQLITE_OK) break;
rc = sqlite3Reprepare(v);
if( rc!=SQLITE_OK ){
/* 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 = rc = sqlite3ApiExit(db, rc);
} else {
v->zErrMsg = 0;
v->rc = rc = SQLITE_NOMEM_BKPT;
}
break;
}
sqlite3_reset(pStmt);
if( savedPc>=0 ) v->doingRerun = 1;
assert( v->expired==0 );
}
if( rc2!=SQLITE_OK ){
/* 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_BKPT;
}
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -747,6 +745,25 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
return p->pOut->db;
}
/*
** If this routine is invoked from within an xColumn method of a virtual
** table, then it returns true if and only if the the call is during an
** UPDATE operation and the value of the column will not be modified
** by the UPDATE.
**
** If this routine is called from any context other than within the
** xColumn method of a virtual table, then the return value is meaningless
** and arbitrary.
**
** Virtual table implements might use this routine to optimize their
** performance by substituting a NULL result, or some other light-weight
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
int sqlite3_vtab_nochange(sqlite3_context *p){
assert( p );
return sqlite3_value_nochange(p->pOut);
}
/*
** Return the current time for a statement. If the current time
** is requested more than once within the same run of a single prepared
@@ -770,28 +787,6 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
return *piTime;
}
/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context. The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
** for name resolution but are actually overloaded by the xFindFunction
** method of virtual tables.
*/
void sqlite3InvalidFunction(
sqlite3_context *context, /* The function calling context */
int NotUsed, /* Number of arguments to the function */
sqlite3_value **NotUsed2 /* Value of each argument */
){
const char *zName = context->pFunc->zName;
char *zErr;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
zErr = sqlite3_mprintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
}
/*
** Create a new aggregate context for p and return a pointer to
** its pMem->z element.
@@ -895,10 +890,7 @@ void sqlite3_set_auxdata(
pAuxData->iAuxArg = iArg;
pAuxData->pNextAux = pVdbe->pAuxData;
pVdbe->pAuxData = pAuxData;
if( pCtx->fErrorOrAux==0 ){
pCtx->isError = 0;
pCtx->fErrorOrAux = 1;
}
if( pCtx->isError==0 ) pCtx->isError = -1;
}else if( pAuxData->xDeleteAux ){
pAuxData->xDeleteAux(pAuxData->pAux);
}
@@ -978,7 +970,7 @@ static const Mem *columnNullValue(void){
/* .xDel = */ (void(*)(void*))0,
#ifdef SQLITE_DEBUG
/* .pScopyFrom = */ (Mem*)0,
/* .pFiller = */ (void*)0,
/* .mScopyFlags= */ 0,
#endif
};
return &nullMem;
@@ -1654,7 +1646,9 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
u32 v;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !pStmt ){
if( !pStmt
|| (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
@@ -1723,7 +1717,7 @@ static UnpackedRecord *vdbeUnpackRecord(
pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pRet ){
memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
}
return pRet;
@@ -1796,7 +1790,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
*/
int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p = db->pPreUpdate;
return (p ? p->keyinfo.nField : 0);
return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+370 -219
View File
File diff suppressed because it is too large Load Diff
+24 -26
View File
@@ -63,11 +63,12 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
v->aMem[1].u.i = iRow;
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_SeekRowid. This could
** then back it up to the point where it does the OP_NotExists. This could
** have been down with an extra OP_Goto, but simply setting the program
** counter is faster. */
if( v->pc>3 ){
v->pc = 3;
if( v->pc>4 ){
v->pc = 4;
assert( v->aOp[v->pc].opcode==OP_NotExists );
rc = sqlite3VdbeExec(v);
}else{
rc = sqlite3_step(p->pStmt);
@@ -129,8 +130,8 @@ int sqlite3_blob_open(
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
Parse *pParse = 0;
Incrblob *pBlob = 0;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
@@ -148,37 +149,34 @@ int sqlite3_blob_open(
sqlite3_mutex_enter(db->mutex);
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
if( !pBlob ) goto blob_open_out;
pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
if( !pParse ) goto blob_open_out;
do {
memset(pParse, 0, sizeof(Parse));
pParse->db = db;
memset(&sParse, 0, sizeof(Parse));
if( !pBlob ) goto blob_open_out;
sParse.db = db;
sqlite3DbFree(db, zErr);
zErr = 0;
sqlite3BtreeEnterAll(db);
pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
}
if( pTab && !HasRowid(pTab) ){
pTab = 0;
sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){
if( pParse->zErrMsg ){
if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
zErr = pParse->zErrMsg;
pParse->zErrMsg = 0;
zErr = sParse.zErrMsg;
sParse.zErrMsg = 0;
}
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
@@ -242,7 +240,7 @@ int sqlite3_blob_open(
}
}
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
@@ -278,7 +276,8 @@ int sqlite3_blob_open(
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP5(v, 1);
assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
@@ -293,7 +292,7 @@ int sqlite3_blob_open(
aOp[0].p1 = iDb;
aOp[0].p2 = pTab->tnum;
aOp[0].p3 = wrFlag;
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
}
if( db->mallocFailed==0 ){
#endif
@@ -315,10 +314,10 @@ int sqlite3_blob_open(
aOp[1].p4.i = pTab->nCol+1;
aOp[3].p2 = pTab->nCol;
pParse->nVar = 0;
pParse->nMem = 1;
pParse->nTab = 1;
sqlite3VdbeMakeReady(v, pParse);
sParse.nVar = 0;
sParse.nMem = 1;
sParse.nTab = 1;
sqlite3VdbeMakeReady(v, &sParse);
}
}
@@ -340,8 +339,7 @@ blob_open_out:
}
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
+220 -94
View File
@@ -42,8 +42,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
if( p->flags & MEM_Null ){
/* Cannot be both MEM_Null and some other type */
assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
|MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 );
assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 );
/* If MEM_Null is set, then either the value is a pure NULL (the usual
** case) or it is a pointer set using sqlite3_bind_pointer() or
@@ -93,6 +92,51 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
}
#endif
#ifdef SQLITE_DEBUG
/*
** Check that string value of pMem agrees with its integer or real value.
**
** A single int or real value always converts to the same strings. But
** many different strings can be converted into the same int or real.
** If a table contains a numeric value and an index is based on the
** corresponding string value, then it is important that the string be
** derived from the numeric value, not the other way around, to ensure
** that the index and table are consistent. See ticket
** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for
** an example.
**
** This routine looks at pMem to verify that if it has both a numeric
** representation and a string representation then the string rep has
** been derived from the numeric and not the other way around. It returns
** true if everything is ok and false if there is a problem.
**
** This routine is for use inside of assert() statements only.
*/
int sqlite3VdbeMemConsistentDualRep(Mem *p){
char zBuf[100];
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1;
if( p->flags & MEM_Int ){
sqlite3_snprintf(sizeof(zBuf),zBuf,"%lld",p->u.i);
}else{
sqlite3_snprintf(sizeof(zBuf),zBuf,"%!.15g",p->u.r);
}
z = p->z;
i = j = 0;
incr = 1;
if( p->enc!=SQLITE_UTF8 ){
incr = 2;
if( p->enc==SQLITE_UTF16BE ) z++;
}
while( zBuf[j] ){
if( zBuf[j++]!=z[i] ) return 0;
i += incr;
}
return 1;
}
#endif /* SQLITE_DEBUG */
/*
** If pMem is an object with a valid string representation, this routine
@@ -111,7 +155,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16
int rc;
#endif
assert( (pMem->flags&MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|| desiredEnc==SQLITE_UTF16BE );
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
@@ -144,7 +188,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
*/
SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
testcase( pMem->db==0 );
/* If the bPreserve flag is set to true, then the memory cell must already
@@ -155,7 +199,7 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( pMem->szMalloc==0
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
if( n<32 ) n = 32;
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
@@ -171,7 +215,8 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
if( bPreserve && pMem->z ){
assert( pMem->z!=pMem->zMalloc );
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
@@ -209,6 +254,20 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
return SQLITE_OK;
}
/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
*/
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
return SQLITE_NOMEM_BKPT;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
return SQLITE_OK;
}
/*
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
** MEM.zMalloc, where it can be safely written.
@@ -217,16 +276,12 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
*/
int sqlite3VdbeMemMakeWriteable(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
return SQLITE_NOMEM_BKPT;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
int rc = vdbeMemAddTerminator(pMem);
if( rc ) return rc;
}
}
pMem->flags &= ~MEM_Ephem;
@@ -246,7 +301,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
int nByte;
assert( pMem->flags & MEM_Zero );
assert( pMem->flags&MEM_Blob );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
/* Set nByte to the number of bytes required to store the expanded blob. */
@@ -265,20 +320,6 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){
}
#endif
/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
*/
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
return SQLITE_NOMEM_BKPT;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
return SQLITE_OK;
}
/*
** Make sure the given Mem is \u0000 terminated.
*/
@@ -315,7 +356,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
assert( !(fg&MEM_Zero) );
assert( !(fg&(MEM_Str|MEM_Blob)) );
assert( fg&(MEM_Int|MEM_Real) );
assert( (pMem->flags&MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@@ -353,28 +394,55 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
** otherwise.
*/
int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
int rc = SQLITE_OK;
if( ALWAYS(pFunc && pFunc->xFinalize) ){
sqlite3_context ctx;
Mem t;
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
t.db = pMem->db;
ctx.pOut = &t;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
assert( (pMem->flags & MEM_Dyn)==0 );
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
memcpy(pMem, &t, sizeof(t));
rc = ctx.isError;
}
return rc;
sqlite3_context ctx;
Mem t;
assert( pFunc!=0 );
assert( pFunc->xFinalize!=0 );
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
t.db = pMem->db;
ctx.pOut = &t;
ctx.pMem = pMem;
ctx.pFunc = pFunc;
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
assert( (pMem->flags & MEM_Dyn)==0 );
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
memcpy(pMem, &t, sizeof(t));
return ctx.isError;
}
/*
** Memory cell pAccum contains the context of an aggregate function.
** This routine calls the xValue method for that function and stores
** the results in memory cell pMem.
**
** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK
** otherwise.
*/
#ifndef SQLITE_OMIT_WINDOWFUNC
int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
sqlite3_context ctx;
Mem t;
assert( pFunc!=0 );
assert( pFunc->xValue!=0 );
assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
memset(&ctx, 0, sizeof(ctx));
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
t.db = pAccum->db;
sqlite3VdbeMemSetNull(pOut);
ctx.pOut = pOut;
ctx.pMem = pAccum;
ctx.pFunc = pFunc;
pFunc->xValue(&ctx);
return ctx.isError;
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** If the memory cell contains a value that must be freed by
** invoking the external callback in Mem.xDel, then this routine
@@ -393,15 +461,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
testcase( p->flags & MEM_Dyn );
}
if( p->flags&MEM_Dyn ){
assert( (p->flags&MEM_RowSet)==0 );
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
p->xDel((void *)p->z);
}else if( p->flags&MEM_RowSet ){
sqlite3RowSetClear(p->u.pRowSet);
}else if( p->flags&MEM_Frame ){
VdbeFrame *pFrame = p->u.pFrame;
pFrame->pParent = pFrame->v->pDelFrame;
pFrame->v->pDelFrame = pFrame;
}
p->flags = MEM_Null;
}
@@ -532,6 +593,16 @@ double sqlite3VdbeRealValue(Mem *pMem){
}
}
/*
** Return 1 if pMem represents true, and return 0 if pMem represents false.
** Return the value ifNull if pMem is NULL.
*/
int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
if( pMem->flags & MEM_Int ) return pMem->u.i!=0;
if( pMem->flags & MEM_Null ) return ifNull;
return sqlite3VdbeRealValue(pMem)!=0.0;
}
/*
** The MEM structure is already a MEM_Real. Try to also make it a
** MEM_Int if we can.
@@ -539,7 +610,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
void sqlite3VdbeIntegerAffinity(Mem *pMem){
i64 ix;
assert( pMem->flags & MEM_Real );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@@ -566,7 +637,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
*/
int sqlite3VdbeMemIntegerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = sqlite3VdbeIntValue(pMem);
@@ -587,6 +658,18 @@ int sqlite3VdbeMemRealify(Mem *pMem){
return SQLITE_OK;
}
/* Compare a floating point value to an integer. Return true if the two
** values are the same within the precision of the floating point value.
**
** For some versions of GCC on 32-bit machines, if you do the more obvious
** comparison of "r1==(double)i" you sometimes get an answer of false even
** though the r1 and (double)i values are bit-for-bit the same.
*/
static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
double r2 = (double)i;
return memcmp(&r1, &r2, sizeof(r1))==0;
}
/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** Invalidate any prior representations.
@@ -597,14 +680,21 @@ int sqlite3VdbeMemRealify(Mem *pMem){
*/
int sqlite3VdbeMemNumerify(Mem *pMem){
if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
int rc;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc);
if( rc==0 ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
pMem->u.r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
sqlite3VdbeIntegerAffinity(pMem);
i64 i = pMem->u.i;
sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( rc==1 && sqlite3RealSameAsInt(pMem->u.r, i) ){
pMem->u.i = i;
MemSetTypeFlag(pMem, MEM_Int);
}else{
MemSetTypeFlag(pMem, MEM_Real);
}
}
}
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
@@ -731,7 +821,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
/* A no-op destructor */
static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
/*
** Set the value stored in *pMem should already be a NULL.
@@ -765,26 +855,36 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
}
#endif
#ifdef SQLITE_DEBUG
/*
** Return true if the Mem holds a RowSet object. This routine is intended
** for use inside of assert() statements.
*/
int sqlite3VdbeMemIsRowSet(const Mem *pMem){
return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn)
&& pMem->xDel==sqlite3RowSetDelete;
}
#endif
/*
** Delete any previous value and set the value of pMem to be an
** empty boolean index.
**
** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation
** error occurs.
*/
void sqlite3VdbeMemSetRowSet(Mem *pMem){
int sqlite3VdbeMemSetRowSet(Mem *pMem){
sqlite3 *db = pMem->db;
RowSet *p;
assert( db!=0 );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
sqlite3VdbeMemRelease(pMem);
pMem->zMalloc = sqlite3DbMallocRawNN(db, 64);
if( db->mallocFailed ){
pMem->flags = MEM_Null;
pMem->szMalloc = 0;
}else{
assert( pMem->zMalloc );
pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc);
pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc);
assert( pMem->u.pRowSet!=0 );
pMem->flags = MEM_RowSet;
}
p = sqlite3RowSetInit(db);
if( p==0 ) return SQLITE_NOMEM;
pMem->z = (char*)p;
pMem->flags = MEM_Blob|MEM_Dyn;
pMem->xDel = sqlite3RowSetDelete;
return SQLITE_OK;
}
/*
@@ -817,7 +917,21 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
Mem *pX;
for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
pX->flags |= MEM_Undefined;
/* If pX is marked as a shallow copy of pMem, then verify that
** no significant changes have been made to pX since the OP_SCopy.
** A significant change would indicated a missed call to this
** function for pX. Minor changes, such as adding or removing a
** dual type, are allowed, as long as the underlying value is the
** same. */
u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i );
assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r );
assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) );
assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 );
/* pMem is the register that is changing. But also mark pX as
** undefined so that we can quickly detect the shallow-copy error */
pX->flags = MEM_Undefined;
pX->pScopyFrom = 0;
}
}
@@ -838,7 +952,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
}
void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
assert( (pFrom->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pFrom) );
assert( pTo->db==pFrom->db );
if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
memcpy(pTo, pFrom, MEMCELLSIZE);
@@ -856,7 +970,7 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
assert( (pFrom->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pFrom) );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
@@ -914,7 +1028,7 @@ int sqlite3VdbeMemSetStr(
u16 flags = 0; /* New value for pMem->flags */
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
if( !z ){
@@ -931,7 +1045,7 @@ int sqlite3VdbeMemSetStr(
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
nByte = sqlite3Strlen30(z);
nByte = 0x7fffffff & (int)strlen(z);
if( nByte>iLimit ) nByte = iLimit+1;
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
@@ -1009,12 +1123,11 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
){
int rc;
pMem->flags = MEM_Null;
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
if( rc==SQLITE_OK ){
pMem->z[amt] = 0;
pMem->z[amt+1] = 0;
pMem->flags = MEM_Blob|MEM_Term;
pMem->z[amt] = 0; /* Overrun area used when reading malformed records */
pMem->flags = MEM_Blob;
pMem->n = (int)amt;
}else{
sqlite3VdbeMemRelease(pMem);
@@ -1037,7 +1150,7 @@ int sqlite3VdbeMemFromBtree(
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
assert( (pMem->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
assert( zData!=0 );
@@ -1061,7 +1174,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert( pVal!=0 );
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
assert( (pVal->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pVal) );
assert( (pVal->flags & (MEM_Null))==0 );
if( pVal->flags & (MEM_Blob|MEM_Str) ){
if( ExpandBlob(pVal) ) return 0;
@@ -1083,6 +1196,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0
|| pVal->db->mallocFailed );
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
assert( sqlite3VdbeMemConsistentDualRep(pVal) );
return pVal->z;
}else{
return 0;
@@ -1103,8 +1217,9 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0;
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
assert( (pVal->flags & MEM_RowSet)==0 );
assert( !sqlite3VdbeMemIsRowSet(pVal) );
if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){
assert( sqlite3VdbeMemConsistentDualRep(pVal) );
return pVal->z;
}
if( pVal->flags&MEM_Null ){
@@ -1163,7 +1278,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
if( pRec ){
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
if( pRec->pKeyInfo ){
assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
assert( pRec->pKeyInfo->nAllField==nCol );
assert( pRec->pKeyInfo->enc==ENC(db) );
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
for(i=0; i<nCol; i++){
@@ -1320,7 +1435,11 @@ static int valueFromExpr(
assert( pExpr!=0 );
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
if( op==TK_REGISTER ) op = pExpr->op2;
#else
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif
/* Compressed expressions only appear when parsing the DEFAULT clause
** on a table column definition, and hence only when pCtx==0. This
@@ -1404,18 +1523,25 @@ static int valueFromExpr(
0, SQLITE_DYNAMIC);
}
#endif
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
else if( op==TK_FUNCTION && pCtx!=0 ){
rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
}
#endif
else if( op==TK_TRUEFALSE ){
pVal = valueNew(db, pCtx);
pVal->flags = MEM_Int;
pVal->u.i = pExpr->u.zToken[4]==0;
}
*ppVal = pVal;
return rc;
no_mem:
sqlite3OomFault(db);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( pCtx==0 || pCtx->pParse->nErr==0 )
#endif
sqlite3OomFault(db);
sqlite3DbFree(db, zVal);
assert( *ppVal==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -1658,11 +1784,11 @@ int sqlite3Stat4Column(
int iCol, /* Column to extract */
sqlite3_value **ppVal /* OUT: Extracted value */
){
u32 t; /* a column type code */
u32 t = 0; /* a column type code */
int nHdr; /* Size of the header in the record */
int iHdr; /* Next unread header byte */
int iField; /* Next unread data byte */
int szField; /* Size of the current data field */
int szField = 0; /* Size of the current data field */
int i; /* Column index */
u8 *a = (u8*)pRec; /* Typecast byte array */
Mem *pMem = *ppVal; /* Write result into this Mem object */
@@ -1699,7 +1825,7 @@ int sqlite3Stat4Column(
void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
if( pRec ){
int i;
int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
int nCol = pRec->pKeyInfo->nAllField;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
+16 -14
View File
@@ -823,7 +823,7 @@ static int vdbeSorterCompareText(
}
if( res==0 ){
if( pTask->pSorter->pKeyInfo->nField>1 ){
if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -892,7 +892,7 @@ static int vdbeSorterCompareInt(
}
if( res==0 ){
if( pTask->pSorter->pKeyInfo->nField>1 ){
if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
@@ -907,7 +907,7 @@ static int vdbeSorterCompareInt(
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
**
** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
** to determine the number of fields that should be compared from the
** records being sorted. However, if the value passed as argument nField
** is non-zero and the sorter is able to guarantee a stable sort, nField
@@ -960,7 +960,7 @@ int sqlite3VdbeSorterInit(
assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
@@ -972,8 +972,7 @@ int sqlite3VdbeSorterInit(
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
pKeyInfo->nXField += (pKeyInfo->nField - nField);
pKeyInfo->nField = nField;
pKeyInfo->nKeyField = nField;
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->nTask = nWorker + 1;
@@ -1001,11 +1000,9 @@ int sqlite3VdbeSorterInit(
mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
/* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
** large heap allocations.
*/
if( sqlite3GlobalConfig.pScratch==0 ){
/* Avoid large memory allocations if the application has requested
** SQLITE_CONFIG_SMALL_MALLOC. */
if( sqlite3GlobalConfig.bSmallMalloc==0 ){
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
@@ -1013,7 +1010,7 @@ int sqlite3VdbeSorterInit(
}
}
if( (pKeyInfo->nField+pKeyInfo->nXField)<13
if( pKeyInfo->nAllField<13
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
){
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
@@ -1328,7 +1325,7 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
if( pTask->pUnpacked==0 ){
pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
pTask->pUnpacked->errCode = 0;
}
return SQLITE_OK;
@@ -2110,7 +2107,11 @@ static int vdbeMergeEngineInit(
){
int rc = SQLITE_OK; /* Return code */
int i; /* For looping over PmaReader objects */
int nTree = pMerger->nTree;
int nTree; /* Number of subtrees to merge */
/* Failure to allocate the merge would have been detected prior to
** invoking this routine */
assert( pMerger!=0 );
/* eMode is always INCRINIT_NORMAL in single-threaded mode */
assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
@@ -2119,6 +2120,7 @@ static int vdbeMergeEngineInit(
assert( pMerger->pTask==0 );
pMerger->pTask = pTask;
nTree = pMerger->nTree;
for(i=0; i<nTree; i++){
if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){
/* PmaReaders should be normally initialized in order, as if they are
+17 -17
View File
@@ -82,7 +82,7 @@ char *sqlite3VdbeExpandSql(
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
Mem utf8; /* Used to convert UTF16 into UTF8 for display */
#endif
char zBase[100]; /* Initial working space */
@@ -93,17 +93,17 @@ char *sqlite3VdbeExpandSql(
while( *zRawSql ){
const char *zStart = zRawSql;
while( *(zRawSql++)!='\n' && *zRawSql );
sqlite3StrAccumAppend(&out, "-- ", 3);
sqlite3_str_append(&out, "-- ", 3);
assert( (zRawSql - zStart) > 0 );
sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart));
}
}else if( p->nVar==0 ){
sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql));
sqlite3_str_append(&out, zRawSql, sqlite3Strlen30(zRawSql));
}else{
while( zRawSql[0] ){
n = findNextHostParameter(zRawSql, &nToken);
assert( n>0 );
sqlite3StrAccumAppend(&out, zRawSql, n);
sqlite3_str_append(&out, zRawSql, n);
zRawSql += n;
assert( zRawSql[0] || nToken==0 );
if( nToken==0 ) break;
@@ -129,11 +129,11 @@ char *sqlite3VdbeExpandSql(
assert( idx>0 && idx<=p->nVar );
pVar = &p->aVar[idx-1];
if( pVar->flags & MEM_Null ){
sqlite3StrAccumAppend(&out, "NULL", 4);
sqlite3_str_append(&out, "NULL", 4);
}else if( pVar->flags & MEM_Int ){
sqlite3XPrintf(&out, "%lld", pVar->u.i);
sqlite3_str_appendf(&out, "%lld", pVar->u.i);
}else if( pVar->flags & MEM_Real ){
sqlite3XPrintf(&out, "%!.15g", pVar->u.r);
sqlite3_str_appendf(&out, "%!.15g", pVar->u.r);
}else if( pVar->flags & MEM_Str ){
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
@@ -143,7 +143,7 @@ char *sqlite3VdbeExpandSql(
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
out.accError = STRACCUM_NOMEM;
out.accError = SQLITE_NOMEM;
out.nAlloc = 0;
}
pVar = &utf8;
@@ -156,38 +156,38 @@ char *sqlite3VdbeExpandSql(
while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
}
#endif
sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
#ifndef SQLITE_OMIT_UTF16
if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
#endif
}else if( pVar->flags & MEM_Zero ){
sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
sqlite3_str_appendf(&out, "zeroblob(%d)", pVar->u.nZero);
}else{
int nOut; /* Number of bytes of the blob to include in output */
assert( pVar->flags & MEM_Blob );
sqlite3StrAccumAppend(&out, "x'", 2);
sqlite3_str_append(&out, "x'", 2);
nOut = pVar->n;
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
#endif
for(i=0; i<nOut; i++){
sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
sqlite3_str_appendf(&out, "%02x", pVar->z[i]&0xff);
}
sqlite3StrAccumAppend(&out, "'", 1);
sqlite3_str_append(&out, "'", 1);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
}
}
}
if( out.accError ) sqlite3StrAccumReset(&out);
if( out.accError ) sqlite3_str_reset(&out);
return sqlite3StrAccumFinish(&out);
}
+69 -62
View File
@@ -42,8 +42,10 @@ Module *sqlite3VtabCreateModule(
){
Module *pMod;
int nName = sqlite3Strlen30(zName);
pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
if( pMod ){
pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
if( pMod==0 ){
sqlite3OomFault(db);
}else{
Module *pDel;
char *zCopy = (char *)(&pMod[1]);
memcpy(zCopy, zName, nName+1);
@@ -260,7 +262,7 @@ void sqlite3VtabUnlockList(sqlite3 *db){
assert( sqlite3_mutex_held(db->mutex) );
if( p ){
sqlite3ExpirePreparedStatements(db);
sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
sqlite3VtabUnlock(p);
@@ -518,13 +520,14 @@ static int vtabCallConstructor(
}
}
zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
zModuleName = sqlite3DbStrDup(db, pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM_BKPT;
}
pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
pVTable = sqlite3MallocZero(sizeof(VTable));
if( !pVTable ){
sqlite3OomFault(db);
sqlite3DbFree(db, zModuleName);
return SQLITE_NOMEM_BKPT;
}
@@ -644,6 +647,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
pParse->rc = rc;
}
sqlite3DbFree(db, zErr);
}
@@ -733,10 +737,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
*/
int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
@@ -753,55 +757,55 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pTab = pCtx->pTab;
assert( IsVirtual(pTab) );
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
pParse->declareVtab = 1;
pParse->db = db;
pParse->nQueryLoop = 1;
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
&& pParse->pNewTable
&& !db->mallocFailed
&& !pParse->pNewTable->pSelect
&& !IsVirtual(pParse->pNewTable)
){
if( !pTab->aCol ){
Table *pNew = pParse->pNewTable;
Index *pIdx;
pTab->aCol = pNew->aCol;
pTab->nCol = pNew->nCol;
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
pNew->nCol = 0;
pNew->aCol = 0;
assert( pTab->pIndex==0 );
if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
rc = SQLITE_ERROR;
}
pIdx = pNew->pIndex;
if( pIdx ){
assert( pIdx->pNext==0 );
pTab->pIndex = pIdx;
pNew->pIndex = 0;
pIdx->pTable = pTab;
}
memset(&sParse, 0, sizeof(sParse));
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
sParse.db = db;
sParse.nQueryLoop = 1;
if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
&& sParse.pNewTable
&& !db->mallocFailed
&& !sParse.pNewTable->pSelect
&& !IsVirtual(sParse.pNewTable)
){
if( !pTab->aCol ){
Table *pNew = sParse.pNewTable;
Index *pIdx;
pTab->aCol = pNew->aCol;
pTab->nCol = pNew->nCol;
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
pNew->nCol = 0;
pNew->aCol = 0;
assert( pTab->pIndex==0 );
assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
if( !HasRowid(pNew)
&& pCtx->pVTable->pMod->pModule->xUpdate!=0
&& sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
){
/* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
** or else must have a single-column PRIMARY KEY */
rc = SQLITE_ERROR;
}
pIdx = pNew->pIndex;
if( pIdx ){
assert( pIdx->pNext==0 );
pTab->pIndex = pIdx;
pNew->pIndex = 0;
pIdx->pTable = pTab;
}
pCtx->bDeclared = 1;
}else{
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
pParse->declareVtab = 0;
if( pParse->pVdbe ){
sqlite3VdbeFinalize(pParse->pVdbe);
}
sqlite3DeleteTable(db, pParse->pNewTable);
sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
pCtx->bDeclared = 1;
}else{
sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
rc = SQLITE_ERROR;
}
sParse.eParseMode = PARSE_MODE_NORMAL;
if( sParse.pVdbe ){
sqlite3VdbeFinalize(sParse.pVdbe);
}
sqlite3DeleteTable(db, sParse.pNewTable);
sqlite3ParserReset(&sParse);
assert( (rc&0xff)==rc );
rc = sqlite3ApiExit(db, rc);
@@ -1045,9 +1049,6 @@ FuncDef *sqlite3VtabOverloadFunction(
void *pArg = 0;
FuncDef *pNew;
int rc = 0;
char *zLowerName;
unsigned char *z;
/* Check to see the left operand is a column in a virtual table */
if( NEVER(pExpr==0) ) return pDef;
@@ -1062,16 +1063,22 @@ FuncDef *sqlite3VtabOverloadFunction(
if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFindFunction method on the virtual table implementation
** to see if the implementation wants to overload this function
** to see if the implementation wants to overload this function.
**
** Though undocumented, we have historically always invoked xFindFunction
** with an all lower-case function name. Continue in this tradition to
** avoid any chance of an incompatibility.
*/
zLowerName = sqlite3DbStrDup(db, pDef->zName);
if( zLowerName ){
for(z=(unsigned char*)zLowerName; *z; z++){
*z = sqlite3UpperToLower[*z];
#ifdef SQLITE_DEBUG
{
int i;
for(i=0; pDef->zName[i]; i++){
unsigned char x = (unsigned char)pDef->zName[i];
assert( x==sqlite3UpperToLower[x] );
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
sqlite3DbFree(db, zLowerName);
}
#endif
rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg);
if( rc==0 ){
return pDef;
}
+450 -147
View File
File diff suppressed because it is too large Load Diff
+6 -4
View File
@@ -19,11 +19,11 @@
#include "sqliteInt.h"
/* Additional values that can be added to the sync_flags argument of
** sqlite3WalFrames():
/* Macros for extracting appropriate sync flags for either transaction
** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
*/
#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
#define WAL_SYNC_FLAGS(X) ((X)&0x03)
#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03)
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
@@ -132,6 +132,8 @@ int sqlite3WalHeapMemory(Wal *pWal);
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
int sqlite3WalSnapshotRecover(Wal *pWal);
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
void sqlite3WalSnapshotUnlock(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
+32 -22
View File
@@ -40,18 +40,30 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pRight ){
if( walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else if( pExpr->x.pList ){
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
while(1){
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
if( pExpr->pRight ){
pExpr = pExpr->pRight;
continue;
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
}else if( pExpr->x.pList ){
if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( !ExprHasProperty(pExpr, EP_Reduced) && pExpr->pWin ){
Window *pWin = pExpr->pWin;
if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort;
if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort;
}
#endif
}
break;
}
return WRC_Continue;
}
@@ -87,7 +99,6 @@ int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort;
if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort;
return WRC_Continue;
}
@@ -104,16 +115,15 @@ int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
struct SrcList_item *pItem;
pSrc = p->pSrc;
if( ALWAYS(pSrc) ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
&& sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
){
return WRC_Abort;
}
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
&& sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
){
return WRC_Abort;
}
}
return WRC_Continue;
+411 -183
View File
File diff suppressed because it is too large Load Diff
+8 -6
View File
@@ -19,7 +19,7 @@
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/***/ int sqlite3WhereTrace;
/***/ extern int sqlite3WhereTrace;
#endif
#if defined(SQLITE_DEBUG) \
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
@@ -82,6 +82,8 @@ struct WhereLevel {
struct InLoop {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
int iBase; /* Base register of multi-key index record */
int nPrefix; /* Number of prior entires in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -320,6 +322,7 @@ struct WhereClause {
WhereInfo *pWInfo; /* WHERE clause processing context */
WhereClause *pOuter; /* Outer conjunction */
u8 op; /* Split operator. TK_AND or TK_OR */
u8 hasOr; /* True if any a[].eOperator is WO_OR */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@@ -467,12 +470,10 @@ int sqlite3WhereExplainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
int iLevel, /* Value for "level" column of output */
int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
);
#else
# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0
# define sqlite3WhereExplainOneScan(u,v,w,x) 0
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
void sqlite3WhereAddScanStatus(
@@ -495,6 +496,7 @@ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
void sqlite3WhereClauseClear(WhereClause*);
void sqlite3WhereSplit(WhereClause*,Expr*,u8);
Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
@@ -515,7 +517,6 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
#define WO_IN 0x0001
#define WO_EQ 0x0002
@@ -523,7 +524,7 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 0x0040
#define WO_AUX 0x0040 /* Op useful to virtual tables only */
#define WO_IS 0x0080
#define WO_ISNULL 0x0100
#define WO_OR 0x0200 /* Two or more OR-connected terms */
@@ -558,3 +559,4 @@ void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */
+200 -119
View File
@@ -51,23 +51,23 @@ static void explainAppendTerm(
int i;
assert( nTerm>=1 );
if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5);
if( bAnd ) sqlite3_str_append(pStr, " AND ", 5);
if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i));
if( i ) sqlite3_str_append(pStr, ",", 1);
sqlite3_str_appendall(pStr, explainIndexColumnName(pIdx, iTerm+i));
}
if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
sqlite3StrAccumAppend(pStr, zOp, 1);
sqlite3_str_append(pStr, zOp, 1);
if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
sqlite3StrAccumAppend(pStr, "?", 1);
if( i ) sqlite3_str_append(pStr, ",", 1);
sqlite3_str_append(pStr, "?", 1);
}
if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
}
/*
@@ -91,11 +91,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
int i, j;
if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
sqlite3StrAccumAppend(pStr, " (", 2);
sqlite3_str_append(pStr, " (", 2);
for(i=0; i<nEq; i++){
const char *z = explainIndexColumnName(pIndex, i);
if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
if( i ) sqlite3_str_append(pStr, " AND ", 5);
sqlite3_str_appendf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
}
j = i;
@@ -106,7 +106,7 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
}
sqlite3StrAccumAppend(pStr, ")", 1);
sqlite3_str_append(pStr, ")", 1);
}
/*
@@ -122,19 +122,16 @@ int sqlite3WhereExplainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
int iLevel, /* Value for "level" column of output */
int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
int ret = 0;
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
if( pParse->explain==2 )
if( sqlite3ParseToplevel(pParse)->explain==2 )
#endif
{
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe; /* VM being constructed */
sqlite3 *db = pParse->db; /* Database handle */
int iId = pParse->iSelectId; /* Select id (left-most output column) */
int isSearch; /* True for a SEARCH. False for SCAN. */
WhereLoop *pLoop; /* The controlling WhereLoop object */
u32 flags; /* Flags that describe this loop */
@@ -151,15 +148,15 @@ int sqlite3WhereExplainOneScan(
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
if( pItem->pSelect ){
sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
}else{
sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
}
if( pItem->zAlias ){
sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
sqlite3_str_appendf(&str, " AS %s", pItem->zAlias);
}
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
const char *zFmt = 0;
@@ -182,8 +179,8 @@ int sqlite3WhereExplainOneScan(
zFmt = "INDEX %s";
}
if( zFmt ){
sqlite3StrAccumAppend(&str, " USING ", 7);
sqlite3XPrintf(&str, zFmt, pIdx->zName);
sqlite3_str_append(&str, " USING ", 7);
sqlite3_str_appendf(&str, zFmt, pIdx->zName);
explainIndexRange(&str, pLoop);
}
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
@@ -198,23 +195,26 @@ int sqlite3WhereExplainOneScan(
assert( flags&WHERE_TOP_LIMIT);
zRangeOp = "<";
}
sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
sqlite3_str_appendf(&str,
" USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
if( pLoop->nOut>=10 ){
sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
sqlite3_str_appendf(&str, " (~%llu rows)",
sqlite3LogEstToInt(pLoop->nOut));
}else{
sqlite3StrAccumAppend(&str, " (~1 row)", 9);
sqlite3_str_append(&str, " (~1 row)", 9);
}
#endif
zMsg = sqlite3StrAccumFinish(&str);
ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
}
return ret;
}
@@ -294,8 +294,8 @@ void sqlite3WhereAddScanStatus(
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
int nLoop = 0;
while( ALWAYS(pTerm!=0)
&& (pTerm->wtFlags & TERM_CODED)==0
assert( pTerm!=0 );
while( (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
@@ -306,6 +306,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
}
if( pTerm->iParent<0 ) break;
pTerm = &pTerm->pWC->a[pTerm->iParent];
assert( pTerm!=0 );
pTerm->nChild--;
if( pTerm->nChild!=0 ) break;
nLoop++;
@@ -346,7 +347,6 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
/* Code the OP_Affinity opcode if there is anything left to do. */
if( n>0 ){
sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
sqlite3ExprCacheAffinityChange(pParse, base, n);
}
}
@@ -376,6 +376,102 @@ static void updateRangeAffinityStr(
}
}
/*
** pX is an expression of the form: (vector) IN (SELECT ...)
** In other words, it is a vector IN operator with a SELECT clause on the
** LHS. But not all terms in the vector are indexable and the terms might
** not be in the correct order for indexing.
**
** This routine makes a copy of the input pX expression and then adjusts
** the vector on the LHS with corresponding changes to the SELECT so that
** the vector contains only index terms and those terms are in the correct
** order. The modified IN expression is returned. The caller is responsible
** for deleting the returned expression.
**
** Example:
**
** CREATE TABLE t1(a,b,c,d,e,f);
** CREATE INDEX t1x1 ON t1(e,c);
** SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
** \_______________________________________/
** The pX expression
**
** Since only columns e and c can be used with the index, in that order,
** the modified IN expression that is returned will be:
**
** (e,c) IN (SELECT z,x FROM t2)
**
** The reduced pX is different from the original (obviously) and thus is
** only used for indexing, to improve performance. The original unaltered
** IN expression must also be run on each output row for correctness.
*/
static Expr *removeUnindexableInClauseTerms(
Parse *pParse, /* The parsing context */
int iEq, /* Look at loop terms starting here */
WhereLoop *pLoop, /* The current loop */
Expr *pX /* The IN expression to be reduced */
){
sqlite3 *db = pParse->db;
Expr *pNew = sqlite3ExprDup(db, pX, 0);
if( db->mallocFailed==0 ){
ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */
ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */
ExprList *pRhs = 0; /* New RHS after modifications */
ExprList *pLhs = 0; /* New LHS after mods */
int i; /* Loop counter */
Select *pSelect; /* Pointer to the SELECT on the RHS */
for(i=iEq; i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i]->pExpr==pX ){
int iField = pLoop->aLTerm[i]->iField - 1;
assert( pOrigRhs->a[iField].pExpr!=0 );
pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
pOrigRhs->a[iField].pExpr = 0;
assert( pOrigLhs->a[iField].pExpr!=0 );
pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
pOrigLhs->a[iField].pExpr = 0;
}
}
sqlite3ExprListDelete(db, pOrigRhs);
sqlite3ExprListDelete(db, pOrigLhs);
pNew->pLeft->x.pList = pLhs;
pNew->x.pSelect->pEList = pRhs;
if( pLhs && pLhs->nExpr==1 ){
/* Take care here not to generate a TK_VECTOR containing only a
** single value. Since the parser never creates such a vector, some
** of the subroutines do not handle this case. */
Expr *p = pLhs->a[0].pExpr;
pLhs->a[0].pExpr = 0;
sqlite3ExprDelete(db, pNew->pLeft);
pNew->pLeft = p;
}
pSelect = pNew->x.pSelect;
if( pSelect->pOrderBy ){
/* If the SELECT statement has an ORDER BY clause, zero the
** iOrderByCol variables. These are set to non-zero when an
** ORDER BY term exactly matches one of the terms of the
** result-set. Since the result-set of the SELECT statement may
** have been modified or reordered, these variables are no longer
** set correctly. Since setting them is just an optimization,
** it's easiest just to zero them here. */
ExprList *pOrderBy = pSelect->pOrderBy;
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].u.x.iOrderByCol = 0;
}
}
#if 0
printf("For indexing, change the IN expr:\n");
sqlite3TreeViewExpr(0, pX, 0);
printf("Into:\n");
sqlite3TreeViewExpr(0, pNew, 0);
#endif
}
return pNew;
}
/*
** Generate code for a single equality term of the WHERE clause. An equality
** term can be either X=expr or X IN (...). pTerm is the term to be
@@ -438,68 +534,23 @@ static int codeEqualityTerm(
}
}
for(i=iEq;i<pLoop->nLTerm; i++){
if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
assert( pLoop->aLTerm[i]!=0 );
if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
}
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
}else{
Select *pSelect = pX->x.pSelect;
sqlite3 *db = pParse->db;
u16 savedDbOptFlags = db->dbOptFlags;
ExprList *pOrigRhs = pSelect->pEList;
ExprList *pOrigLhs = pX->pLeft->x.pList;
ExprList *pRhs = 0; /* New Select.pEList for RHS */
ExprList *pLhs = 0; /* New pX->pLeft vector */
pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
for(i=iEq;i<pLoop->nLTerm; i++){
if( pLoop->aLTerm[i]->pExpr==pX ){
int iField = pLoop->aLTerm[i]->iField - 1;
Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
}
}
if( !db->mallocFailed ){
Expr *pLeft = pX->pLeft;
if( pSelect->pOrderBy ){
/* If the SELECT statement has an ORDER BY clause, zero the
** iOrderByCol variables. These are set to non-zero when an
** ORDER BY term exactly matches one of the terms of the
** result-set. Since the result-set of the SELECT statement may
** have been modified or reordered, these variables are no longer
** set correctly. Since setting them is just an optimization,
** it's easiest just to zero them here. */
ExprList *pOrderBy = pSelect->pOrderBy;
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].u.x.iOrderByCol = 0;
}
}
/* Take care here not to generate a TK_VECTOR containing only a
** single value. Since the parser never creates such a vector, some
** of the subroutines do not handle this case. */
if( pLhs->nExpr==1 ){
pX->pLeft = pLhs->a[0].pExpr;
}else{
pLeft->x.pList = pLhs;
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
testcase( aiMap==0 );
}
pSelect->pEList = pRhs;
db->dbOptFlags |= SQLITE_QueryFlattener;
aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
db->dbOptFlags = savedDbOptFlags;
testcase( aiMap!=0 && aiMap[0]!=0 );
pSelect->pEList = pOrigRhs;
pLeft->x.pList = pOrigLhs;
pX->pLeft = pLeft;
pTerm->pExpr->iTable = pX->iTable;
}
sqlite3ExprListDelete(pParse->db, pLhs);
sqlite3ExprListDelete(pParse->db, pRhs);
sqlite3ExprDelete(db, pX);
pX = pTerm->pExpr;
}
if( eType==IN_INDEX_INDEX_DESC ){
@@ -539,7 +590,14 @@ static int codeEqualityTerm(
sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
if( i==iEq ){
pIn->iCur = iTab;
pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
pIn->iBase = iReg - i;
pIn->nPrefix = i;
pLoop->wsFlags |= WHERE_IN_EARLYOUT;
}else{
pIn->nPrefix = 0;
}
}else{
pIn->eEndLoopOp = OP_Noop;
}
@@ -794,7 +852,7 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
char d2[3];
char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
@@ -826,11 +884,8 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
Vdbe *v = pWalker->pParse->pVdbe;
int reg = ++pWalker->pParse->nMem; /* Register for column value */
sqlite3ExprCodeGetColumnOfTable(
v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
);
sqlite3ExprCode(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -1017,7 +1072,7 @@ static void codeDeferredSeek(
*/
static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
assert( nReg>0 );
if( sqlite3ExprIsVector(p) ){
if( p && sqlite3ExprIsVector(p) ){
#ifndef SQLITE_OMIT_SUBQUERY
if( (p->flags & EP_xIsSelect) ){
Vdbe *v = pParse->pVdbe;
@@ -1070,9 +1125,9 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
}
/*
** For an indexes on expression X, locate every instance of expression X in pExpr
** and change that subexpression into a reference to the appropriate column of
** the index.
** For an indexes on expression X, locate every instance of expression X
** in pExpr and change that subexpression into a reference to the appropriate
** column of the index.
*/
static void whereIndexExprTrans(
Index *pIdx, /* The Index */
@@ -1163,6 +1218,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|| pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
);
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
pLevel->iLeftJoin = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
@@ -1180,7 +1238,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v);
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
pLevel->op = OP_Goto;
}else
@@ -1194,7 +1252,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
int nConstraint = pLoop->nLTerm;
int iIn; /* Counter for IN constraints */
sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
for(j=0; j<nConstraint; j++){
@@ -1267,7 +1324,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
**
** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
*/
sqlite3ExprCachePop(pParse);
}else
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -1291,9 +1347,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
}else if( (pLoop->wsFlags & WHERE_IPK)!=0
&& (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
@@ -1343,7 +1396,15 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( sqlite3ExprIsVector(pX->pRight) ){
r1 = rTemp = sqlite3GetTempReg(pParse);
codeExprOrVector(pParse, pX->pRight, r1, 1);
op = aMoveOp[(pX->op - TK_GT) | 0x0001];
testcase( pX->op==TK_GT );
testcase( pX->op==TK_GE );
testcase( pX->op==TK_LT );
testcase( pX->op==TK_LE );
op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1];
assert( pX->op!=TK_GT || op==OP_SeekGE );
assert( pX->op!=TK_GE || op==OP_SeekGE );
assert( pX->op!=TK_LT || op==OP_SeekLE );
assert( pX->op!=TK_LE || op==OP_SeekLE );
}else{
r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
disableTerm(pLevel, pStart);
@@ -1355,7 +1416,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, pX->op==TK_LE);
VdbeCoverageIf(v, pX->op==TK_LT);
VdbeCoverageIf(v, pX->op==TK_GE);
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
sqlite3ReleaseTempReg(pParse, rTemp);
}else{
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
@@ -1390,7 +1450,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( testOp!=OP_Noop ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
VdbeCoverageIf(v, testOp==OP_Le);
VdbeCoverageIf(v, testOp==OP_Lt);
@@ -1595,6 +1654,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** above has already left the cursor sitting on the correct row,
** so no further seeking is needed */
}else{
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
}
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -1613,7 +1675,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
nConstraint = nEq;
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -1657,6 +1718,10 @@ Bitmask sqlite3WhereCodeOneLoopStart(
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
}
/* Seek the table cursor, if required */
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
@@ -1667,7 +1732,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
)){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
VdbeCoverage(v);
}else{
@@ -1687,9 +1751,16 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* If pIdx is an index on one or more expressions, then look through
** all the expressions in pWInfo and try to transform matching expressions
** into reference to index columns.
**
** Do not do this for the RHS of a LEFT JOIN. This is because the
** expression may be evaluated after OP_NullRow has been executed on
** the cursor. In this case it is important to do the full evaluation,
** as the result of the expression may not be NULL, even if all table
** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
*/
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
if( pLevel->iLeftJoin==0 ){
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
}
/* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
@@ -1845,7 +1916,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
@@ -1864,13 +1934,17 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int jmp1 = 0; /* Address of jump operation */
if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
assert( (pTabItem[0].fg.jointype & JT_LEFT)==0
|| ExprHasProperty(pOrExpr, EP_FromJoin)
);
if( pAndExpr ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
@@ -1882,7 +1956,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
if( pSubWInfo ){
WhereLoop *pSubLoop;
int addrExplain = sqlite3WhereExplainOneScan(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
pParse, pOrTab, &pSubWInfo->a[0], 0
);
sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
@@ -1892,23 +1966,23 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** row will be skipped in subsequent sub-WHERE clauses.
*/
if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int r;
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
if( HasRowid(pTab) ){
r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid);
jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
r,iSet);
regRowid, iSet);
VdbeCoverage(v);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
int nPk = pPk->nKeyCol;
int iPk;
int r;
/* Read the PK into an array of temp registers. */
r = sqlite3GetTempRange(pParse, nPk);
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk);
}
/* Check if the temp table already contains this key. If so,
@@ -1981,6 +2055,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
}
}
ExplainQueryPlanPop(pParse);
pLevel->u.pCovidx = pCov;
if( pCov ) pLevel->iIdxCur = iCovCur;
if( pAndExpr ){
@@ -2053,7 +2128,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
pE = pTerm->pExpr;
assert( pE!=0 );
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){
continue;
}
@@ -2066,7 +2141,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
continue;
}
if( pTerm->wtFlags & TERM_LIKECOND ){
if( (pTerm->wtFlags & TERM_LIKECOND)!=0 ){
/* If the TERM_LIKECOND flag is set, that means that the range search
** is sufficient to guarantee that the LIKE operator is true, so we
** can skip the call to the like(A,B) function. But this only works
@@ -2076,8 +2151,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
continue;
#else
u32 x = pLevel->iLikeRepCntr;
assert( x>0 );
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If, (int)(x>>1));
if( x>0 ){
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1));
}
VdbeCoverage(v);
#endif
}
@@ -2117,6 +2193,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
WO_EQ|WO_IN|WO_IS, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
if( (pAlt->eOperator & WO_IN)
&& (pAlt->pExpr->flags & EP_xIsSelect)
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
){
continue;
}
testcase( pAlt->eOperator & WO_EQ );
testcase( pAlt->eOperator & WO_IS );
testcase( pAlt->eOperator & WO_IN );
@@ -2133,7 +2215,6 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit"));
sqlite3ExprCacheClear(pParse);
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
+233 -109
View File
@@ -194,18 +194,18 @@ static int isLikeOrGlob(
int *pisComplete, /* True if the only wildcard is % in the last character */
int *pnoCase /* True if uppercase is equivalent to lowercase */
){
const char *z = 0; /* String on RHS of LIKE operator */
const u8 *z = 0; /* String on RHS of LIKE operator */
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
ExprList *pList; /* List of operands to the LIKE operator */
int c; /* One character in z[] */
u8 c; /* One character in z[] */
int cnt; /* Number of non-wildcard prefix characters */
char wc[3]; /* Wildcard characters */
u8 wc[4]; /* Wildcard characters */
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
int rc; /* Result code to return */
if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){
return 0;
}
#ifdef SQLITE_EBCDIC
@@ -221,41 +221,78 @@ static int isLikeOrGlob(
int iCol = pRight->iColumn;
pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
z = (char *)sqlite3_value_text(pVal);
z = sqlite3_value_text(pVal);
}
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
}else if( op==TK_STRING ){
z = pRight->u.zToken;
z = (u8*)pRight->u.zToken;
}
if( z ){
/* If the RHS begins with a digit or a minus sign, then the LHS must
** be an ordinary column (not a virtual table column) with TEXT affinity.
** Otherwise the LHS might be numeric and "lhs >= rhs" would be false
** even though "lhs LIKE rhs" is true. But if the RHS does not start
** with a digit or '-', then "lhs LIKE rhs" will always be false if
** the LHS is numeric and so the optimization still works.
*/
if( sqlite3Isdigit(z[0]) || z[0]=='-' ){
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| IsVirtual(pLeft->pTab) /* Value might be numeric */
){
sqlite3ValueFree(pVal);
return 0;
}
}
/* Count the number of prefix characters prior to the first wildcard */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
if( c==wc[3] && z[cnt]!=0 ) cnt++;
}
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
/* The optimization is possible only if (1) the pattern does not begin
** with a wildcard and if (2) the non-wildcard prefix does not end with
** an (illegal 0xff) character, or (3) the pattern does not consist of
** a single escape character. The second condition is necessary so
** that we can increment the prefix key to find an upper bound for the
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
*pisComplete = c==wc[0] && z[cnt+1]==0;
pPrefix = sqlite3Expr(db, TK_STRING, z);
if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
/* Get the pattern prefix. Remove all escapes from the prefix. */
pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
if( pPrefix ){
int iFrom, iTo;
char *zNew = pPrefix->u.zToken;
zNew[cnt] = 0;
for(iFrom=iTo=0; iFrom<cnt; iFrom++){
if( zNew[iFrom]==wc[3] ) iFrom++;
zNew[iTo++] = zNew[iFrom];
}
zNew[iTo] = 0;
/* If the RHS begins with a digit or a minus sign, then the LHS must be
** an ordinary column (not a virtual table column) with TEXT affinity.
** Otherwise the LHS might be numeric and "lhs >= rhs" would be false
** even though "lhs LIKE rhs" is true. But if the RHS does not start
** with a digit or '-', then "lhs LIKE rhs" will always be false if
** the LHS is numeric and so the optimization still works.
**
** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033
** The RHS pattern must not be '/%' because the termination condition
** will then become "x<'0'" and if the affinity is numeric, will then
** be converted into "x<0", which is incorrect.
*/
if( sqlite3Isdigit(zNew[0])
|| zNew[0]=='-'
|| (zNew[0]+1=='0' && iTo==1)
){
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| IsVirtual(pLeft->pTab) /* Value might be numeric */
){
sqlite3ExprDelete(db, pPrefix);
sqlite3ValueFree(pVal);
return 0;
}
}
}
*ppPrefix = pPrefix;
/* If the RHS pattern is a bound parameter, make arrangements to
** reprepare the statement when that parameter is rebound */
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
sqlite3VdbeSetVarmask(v, pRight->iColumn);
@@ -286,48 +323,123 @@ static int isLikeOrGlob(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Check to see if the given expression is of the form
** Check to see if the pExpr expression is a form that needs to be passed
** to the xBestIndex method of virtual tables. Forms of interest include:
**
** column OP expr
** Expression Virtual Table Operator
** ----------------------- ---------------------------------
** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH
** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB
** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE
** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP
** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE
** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE
** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT
** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT
** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL
**
** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a
** column of a virtual table.
** In every case, "column" must be a column of a virtual table. If there
** is a match, set *ppLeft to the "column" expression, set *ppRight to the
** "expr" expression (even though in forms (6) and (8) the column is on the
** right and the expression is on the left). Also set *peOp2 to the
** appropriate virtual table operator. The return value is 1 or 2 if there
** is a match. The usual return is 1, but if the RHS is also a column
** of virtual table in forms (5) or (7) then return 2.
**
** If it is then return TRUE. If not, return FALSE.
** If the expression matches none of the patterns above, return 0.
*/
static int isMatchOfColumn(
static int isAuxiliaryVtabOperator(
sqlite3 *db, /* Parsing context */
Expr *pExpr, /* Test this expression */
unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */
Expr **ppLeft, /* Column expression to left of MATCH/op2 */
Expr **ppRight /* Expression to left of MATCH/op2 */
){
static const struct Op2 {
const char *zOp;
unsigned char eOp2;
} aOp[] = {
{ "match", SQLITE_INDEX_CONSTRAINT_MATCH },
{ "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
{ "like", SQLITE_INDEX_CONSTRAINT_LIKE },
{ "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
};
ExprList *pList;
Expr *pCol; /* Column reference */
int i;
if( pExpr->op==TK_FUNCTION ){
static const struct Op2 {
const char *zOp;
unsigned char eOp2;
} aOp[] = {
{ "match", SQLITE_INDEX_CONSTRAINT_MATCH },
{ "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
{ "like", SQLITE_INDEX_CONSTRAINT_LIKE },
{ "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
};
ExprList *pList;
Expr *pCol; /* Column reference */
int i;
if( pExpr->op!=TK_FUNCTION ){
return 0;
}
pList = pExpr->x.pList;
if( pList==0 || pList->nExpr!=2 ){
return 0;
}
pCol = pList->a[1].pExpr;
if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
return 0;
}
for(i=0; i<ArraySize(aOp); i++){
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
*peOp2 = aOp[i].eOp2;
return 1;
pList = pExpr->x.pList;
if( pList==0 || pList->nExpr!=2 ){
return 0;
}
/* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a
** virtual table on their second argument, which is the same as
** the left-hand side operand in their in-fix form.
**
** vtab_column MATCH expression
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){
for(i=0; i<ArraySize(aOp); i++){
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
*peOp2 = aOp[i].eOp2;
*ppRight = pList->a[0].pExpr;
*ppLeft = pCol;
return 1;
}
}
}
/* We can also match against the first column of overloaded
** functions where xFindFunction returns a value of at least
** SQLITE_INDEX_CONSTRAINT_FUNCTION.
**
** OVERLOADED(vtab_column,expression)
**
** Historically, xFindFunction expected to see lower-case function
** names. But for this use case, xFindFunction is expected to deal
** with function names in an arbitrary case.
*/
pCol = pList->a[0].pExpr;
if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
void *pNotUsed;
pVtab = sqlite3GetVTable(db, pCol->pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
if( pMod->xFindFunction!=0 ){
i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed);
if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
*peOp2 = i;
*ppRight = pList->a[1].pExpr;
*ppLeft = pCol;
return 1;
}
}
}
}else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->pTab) ){
res++;
}
if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->pTab) ){
res++;
SWAP(Expr*, pLeft, pRight);
}
*ppLeft = pLeft;
*ppRight = pRight;
if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
return res;
}
return 0;
}
@@ -578,7 +690,7 @@ static void exprAnalyzeOrTerm(
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
if( allowedOp(pAndTerm->pExpr->op)
|| pAndTerm->eOperator==WO_MATCH
|| pAndTerm->eOperator==WO_AUX
){
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
@@ -610,7 +722,12 @@ static void exprAnalyzeOrTerm(
** empty.
*/
pOrInfo->indexable = indexable;
pTerm->eOperator = indexable==0 ? 0 : WO_OR;
if( indexable ){
pTerm->eOperator = WO_OR;
pWC->hasOr = 1;
}else{
pTerm->eOperator = WO_OR;
}
/* For a two-way OR, attempt to implementation case 2.
*/
@@ -751,12 +868,11 @@ static void exprAnalyzeOrTerm(
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
/* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */
markTermAsChild(pWC, idxNew, idxTerm);
}else{
sqlite3ExprListDelete(db, pList);
}
pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
}
}
}
@@ -780,7 +896,6 @@ static void exprAnalyzeOrTerm(
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
char aff1, aff2;
CollSeq *pColl;
const char *zColl1, *zColl2;
if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
@@ -792,12 +907,8 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
return 0;
}
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
zColl1 = pColl ? pColl->zName : 0;
pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
zColl2 = pColl ? pColl->zName : 0;
return sqlite3_stricmp(zColl1, zColl2)==0;
if( sqlite3IsBinary(pColl) ) return 1;
return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
}
/*
@@ -819,6 +930,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
for(i=0; i<pSrc->nSrc; i++){
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
if( pSrc->a[i].fg.isTabFunc ){
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
}
}
}
pS = pS->pPrior;
@@ -926,7 +1040,7 @@ static void exprAnalyze(
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */
unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */
int nLeft; /* Number of elements on left side vector */
if( db->mallocFailed ){
@@ -952,7 +1066,7 @@ static void exprAnalyze(
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
}
pMaskSet->bVarSelect = 0;
prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
if( ExprHasProperty(pExpr, EP_FromJoin) ){
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
@@ -1134,7 +1248,7 @@ static void exprAnalyze(
}
*pC = c + 1;
}
zCollSeqName = noCase ? "NOCASE" : "BINARY";
zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
@@ -1160,41 +1274,46 @@ static void exprAnalyze(
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Add a WO_MATCH auxiliary term to the constraint set if the
** current expression is of the form: column MATCH expr.
/* Add a WO_AUX auxiliary term to the constraint set if the
** current expression is of the form "column OP expr" where OP
** is an operator that gets passed into virtual tables but which is
** not normally optimized for ordinary tables. In other words, OP
** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
** This information is used by the xBestIndex methods of
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){
int idxNew;
Expr *pRight, *pLeft;
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
if( pWC->op==TK_AND ){
Expr *pRight = 0, *pLeft = 0;
int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight);
while( res-- > 0 ){
int idxNew;
WhereTerm *pNewTerm;
Bitmask prereqColumn, prereqExpr;
pRight = pExpr->x.pList->a[0].pExpr;
pLeft = pExpr->x.pList->a[1].pExpr;
prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
0, sqlite3ExprDup(db, pRight, 0));
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
ExprSetProperty(pNewExpr, EP_FromJoin);
prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
0, sqlite3ExprDup(db, pRight, 0));
if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
ExprSetProperty(pNewExpr, EP_FromJoin);
}
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
pNewTerm->prereqRight = prereqExpr;
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_AUX;
pNewTerm->eMatchOp = eOp2;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
}
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
pNewTerm->prereqRight = prereqExpr;
pNewTerm->leftCursor = pLeft->iTable;
pNewTerm->u.leftColumn = pLeft->iColumn;
pNewTerm->eOperator = WO_MATCH;
pNewTerm->eMatchOp = eOp2;
markTermAsChild(pWC, idxNew, idxTerm);
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags |= TERM_COPIED;
pNewTerm->prereqAll = pTerm->prereqAll;
SWAP(Expr*, pLeft, pRight);
}
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -1226,7 +1345,7 @@ static void exprAnalyze(
exprAnalyze(pSrc, pWC, idxNew);
}
pTerm = &pWC->a[idxTerm];
pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */
pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */
pTerm->eOperator = 0;
}
@@ -1340,6 +1459,7 @@ void sqlite3WhereClauseInit(
WhereInfo *pWInfo /* The WHERE processing context */
){
pWC->pWInfo = pWInfo;
pWC->hasOr = 0;
pWC->pOuter = 0;
pWC->nTerm = 0;
pWC->nSlot = ArraySize(pWC->aStatic);
@@ -1376,17 +1496,18 @@ void sqlite3WhereClauseClear(WhereClause *pWC){
** a bitmask indicating which tables are used in that expression
** tree.
*/
Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
Bitmask mask;
if( p==0 ) return 0;
if( p->op==TK_COLUMN ){
if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
return sqlite3WhereGetMask(pMaskSet, p->iTable);
}else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
assert( p->op!=TK_IF_NULL_ROW );
return 0;
}
mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
assert( !ExprHasProperty(p, EP_TokenOnly) );
if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
if( p->pRight ){
mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
assert( p->x.pList==0 );
}else if( ExprHasProperty(p, EP_xIsSelect) ){
if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
@@ -1396,6 +1517,9 @@ Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
}
return mask;
}
Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
}
Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
int i;
Bitmask mask = 0;
+2252
View File
File diff suppressed because it is too large Load Diff