Merge sqlite-release(3.15.2) into prerelease-integration

This commit is contained in:
Nick Parker
2016-12-06 13:10:27 -06:00
471 changed files with 45126 additions and 8286 deletions
+18 -22
View File
@@ -229,7 +229,7 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(void){
static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
static FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
@@ -238,13 +238,7 @@ void sqlite3AlterFunctions(void){
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
for(i=0; i<ArraySize(aAlterTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
/*
@@ -419,7 +413,7 @@ void sqlite3AlterRenameTable(
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
zDb = db->aDb[iDb].zDbSName;
db->flags |= SQLITE_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
@@ -607,6 +601,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
int r1; /* Temporary registers */
db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
@@ -616,7 +611,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
assert( sqlite3BtreeHoldsAllMutexes(db) );
iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
zDb = db->aDb[iDb].zName;
zDb = db->aDb[iDb].zDbSName;
zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
pCol = &pNew->aCol[pNew->nCol-1];
pDflt = pCol->pDflt;
@@ -634,7 +629,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** literal NULL, then set pDflt to 0. This simplifies checking
** for an SQL NULL default below.
*/
if( pDflt && pDflt->op==TK_NULL ){
assert( pDflt==0 || pDflt->op==TK_SPAN );
if( pDflt && pDflt->pLeft->op==TK_NULL ){
pDflt = 0;
}
@@ -700,16 +696,18 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
db->flags = savedDbFlags;
}
/* If the default value of the new column is NULL, then the file
** format to 2. If the default value of the new column is not NULL,
** the file format be 3. Back when this feature was first added
** in 2006, we went to the trouble to upgrade the file format to the
** minimum support values. But 10-years on, we can assume that all
** extent versions of SQLite support file-format 4, so we always and
** unconditionally upgrade to 4.
/* Make sure the schema version is at least 3. But do not upgrade
** from less than 3 to 4, as that will corrupt any preexisting DESC
** index.
*/
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT,
SQLITE_MAX_FILE_FORMAT);
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
sqlite3VdbeUsesBtree(v, iDb);
sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
sqlite3ReleaseTempReg(pParse, r1);
/* Reload the schema of the modified table. */
reloadTableSchema(pParse, pTab, pTab->zName);
@@ -791,9 +789,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0;
pCol->zType = 0;
pCol->pDflt = 0;
pCol->zDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
+31 -31
View File
@@ -210,14 +210,14 @@ static void openStatTable(
for(i=0; i<ArraySize(aTable); i++){
const char *zTab = aTable[i].zName;
Table *pStat;
if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
if( aTable[i].zCols ){
/* The sqlite_statN table does not exist. Create it. Note that a
** side-effect of the CREATE TABLE statement is to leave the rootpage
** of the new table in register pParse->regRoot. This is important
** because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
aRoot[i] = pParse->regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
@@ -232,7 +232,7 @@ static void openStatTable(
if( zWhere ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE %s=%Q",
pDb->zName, zTab, zWhereType, zWhere
pDb->zDbSName, zTab, zWhereType, zWhere
);
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
@@ -481,8 +481,7 @@ static const FuncDef statInitFuncdef = {
statInit, /* xSFunc */
0, /* xFinalize */
"stat_init", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
#ifdef SQLITE_ENABLE_STAT4
@@ -781,8 +780,7 @@ static const FuncDef statPushFuncdef = {
statPush, /* xSFunc */
0, /* xFinalize */
"stat_push", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
@@ -927,8 +925,7 @@ static const FuncDef statGetFuncdef = {
statGet, /* xSFunc */
0, /* xFinalize */
"stat_get", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
@@ -997,7 +994,7 @@ static void analyzeOneTable(
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
db->aDb[iDb].zName ) ){
db->aDb[iDb].zDbSName ) ){
return;
}
#endif
@@ -1387,7 +1384,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
/* Form 3: Analyze the fully qualified table name */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){
zDb = db->aDb[iDb].zName;
zDb = db->aDb[iDb].zDbSName;
z = sqlite3NameFromToken(db, pTableName);
if( z ){
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
@@ -1673,7 +1670,7 @@ static int loadStatTbl(
assert( db->lookaside.bDisable );
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -1713,7 +1710,7 @@ static int loadStatTbl(
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
@@ -1729,7 +1726,7 @@ static int loadStatTbl(
zSql = sqlite3MPrintf(db, zSql2, zDb);
if( !zSql ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -1767,7 +1764,7 @@ static int loadStatTbl(
pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
pIdx->nSample++;
@@ -1829,7 +1826,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
HashElem *i;
char *zSql;
int rc;
int rc = SQLITE_OK;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
@@ -1838,30 +1835,33 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx);
pIdx->aiRowLogEst[0] = 0;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3DeleteIndexSamples(db, pIdx);
pIdx->aSample = 0;
#endif
}
/* Check to make sure the sqlite_stat1 table exists */
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
return SQLITE_ERROR;
}
/* Load new statistics out of the sqlite_stat1 table */
zSql = sqlite3MPrintf(db,
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
sqlite3DbFree(db, zSql);
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zDbSName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
zSql = sqlite3MPrintf(db,
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
sqlite3DbFree(db, zSql);
}
}
/* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx);
}
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+13 -14
View File
@@ -97,7 +97,7 @@ static void attachFunc(
goto attach_error;
}
for(i=0; i<db->nDb; i++){
char *z = db->aDb[i].zName;
char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
@@ -144,7 +144,7 @@ static void attachFunc(
Pager *pPager;
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
@@ -161,10 +161,10 @@ static void attachFunc(
#endif
sqlite3BtreeLeave(aNew->pBt);
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && aNew->zName==0 ){
rc = SQLITE_NOMEM;
aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
aNew->zDbSName = sqlite3DbStrDup(db, zName);
if( rc==SQLITE_OK && aNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT;
}
@@ -192,7 +192,7 @@ static void attachFunc(
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
break;
@@ -275,7 +275,7 @@ static void detachFunc(
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
}
if( i>=db->nDb ){
@@ -325,6 +325,7 @@ static void codeAttach(
sqlite3* db = pParse->db;
int regArgs;
if( pParse->nErr ) goto attach_end;
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
@@ -392,8 +393,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
detachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_detach", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@@ -412,8 +412,7 @@ void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
attachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_attach", /* zName */
0, /* pHash */
0 /* pDestructor */
{0}
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}
@@ -435,7 +434,7 @@ void sqlite3FixInit(
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
pFix->zDb = db->aDb[iDb].zName;
pFix->zDb = db->aDb[iDb].zDbSName;
pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
@@ -532,7 +531,7 @@ int sqlite3FixExpr(
return 1;
}
}
if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
+4 -3
View File
@@ -107,10 +107,11 @@ int sqlite3AuthReadCol(
const char *zCol, /* Column name */
int iDb /* Index of containing database. */
){
sqlite3 *db = pParse->db; /* Database handle */
char *zDb = db->aDb[iDb].zName; /* Name of attached database */
int rc; /* Auth callback return code */
sqlite3 *db = pParse->db; /* Database handle */
char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
int rc; /* Auth callback return code */
if( db->init.busy ) return SQLITE_OK;
rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
#ifdef SQLITE_USER_AUTHENTICATION
,db->auth.zAuthUser
+30 -27
View File
@@ -83,22 +83,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
int i = sqlite3FindDbName(pDb, zDb);
if( i==1 ){
Parse *pParse;
Parse sParse;
int rc = 0;
pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
if( pParse==0 ){
sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
rc = SQLITE_NOMEM;
}else{
pParse->db = pDb;
if( sqlite3OpenTempDatabase(pParse) ){
sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
rc = SQLITE_ERROR;
}
sqlite3DbFree(pErrorDb, pParse->zErrMsg);
sqlite3ParserReset(pParse);
sqlite3StackFree(pErrorDb, pParse);
memset(&sParse, 0, sizeof(sParse));
sParse.db = pDb;
if( sqlite3OpenTempDatabase(&sParse) ){
sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
rc = SQLITE_ERROR;
}
sqlite3DbFree(pErrorDb, sParse.zErrMsg);
sqlite3ParserReset(&sParse);
if( rc ){
return 0;
}
@@ -182,7 +176,7 @@ sqlite3_backup *sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
sqlite3Error(pDestDb, SQLITE_NOMEM);
sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
}
}
@@ -196,7 +190,6 @@ sqlite3_backup *sqlite3_backup_init(
p->isAttached = 0;
if( 0==p->pSrc || 0==p->pDest
|| setDestPgsz(p)==SQLITE_NOMEM
|| checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
){
/* One (or both) of the named databases did not exist or an OOM
@@ -384,14 +377,6 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = SQLITE_OK;
}
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
){
p->bDestLocked = 1;
sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
}
/* If there is no open read-transaction on the source database, open
** one now. If a transaction is opened here, then it will be closed
** before this function exits.
@@ -401,6 +386,24 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
bCloseTrans = 1;
}
/* If the destination database has not yet been locked (i.e. if this
** is the first call to backup_step() for the current backup operation),
** try to set its page size to the same as the source database. This
** is especially important on ZipVFS systems, as in that case it is
** not possible to create a database file that uses one page size by
** writing to it with another. */
if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
rc = SQLITE_NOMEM;
}
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
){
p->bDestLocked = 1;
sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
}
/* Do not allow backup if the destination database is in WAL mode
** and the page sizes are different between source and destination */
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
@@ -581,7 +584,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
}
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
p->rc = rc;
}
@@ -777,10 +780,10 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
** sqlite3_backup_step(), we can guarantee that the copy finishes
** within a single call (unless an error occurs). The assert() statement
** checks this assumption - (p->rc) should be set to either SQLITE_DONE
** or an error code.
*/
** or an error code. */
sqlite3_backup_step(&b, 0x7FFFFFFF);
assert( b.rc!=SQLITE_OK );
rc = sqlite3_backup_finish(&b);
if( rc==SQLITE_OK ){
pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
+2 -2
View File
@@ -177,7 +177,7 @@ int sqlite3BitvecSet(Bitvec *p, u32 i){
i = i%p->iDivisor;
if( p->u.apSub[bin]==0 ){
p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
}
p = p->u.apSub[bin];
}
@@ -212,7 +212,7 @@ bitvec_set_rehash:
int rc;
u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
if( aiValues==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
+183 -171
View File
@@ -350,7 +350,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
if( !pLock ){
pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
if( !pLock ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
pLock->iTable = iTable;
pLock->pBtree = p;
@@ -450,6 +450,15 @@ static void releasePage(MemPage *pPage); /* Forward reference */
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
/* Verify that the cursor and the BtShared agree about what is the current
** database connetion. This is important in shared-cache mode. If the database
** connection pointers get out-of-sync, it is possible for routines like
** btreeInitPage() to reference an stale connection pointer that references a
** a connection that has already closed. This routine is used inside assert()
** statements only and for the purpose of double-checking that the btree code
** does keep the database connection pointers up-to-date.
*/
static int cursorOwnsBtShared(BtCursor *p){
assert( cursorHoldsMutex(p) );
return (p->pBtree->db==p->pBt->db);
@@ -553,7 +562,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
assert( pgno<=pBt->nPage );
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
}
if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
@@ -609,21 +618,19 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
** the key.
*/
static int saveCursorKey(BtCursor *pCur){
int rc;
int rc = SQLITE_OK;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data. */
if( 0==pCur->curIntKey ){
void *pKey = sqlite3Malloc( pCur->nKey );
if( pCur->curIntKey ){
/* Only the rowid is required for a table btree */
pCur->nKey = sqlite3BtreeIntegerKey(pCur);
}else{
/* For an index btree, save the complete key content */
void *pKey;
pCur->nKey = sqlite3BtreePayloadSize(pCur);
pKey = sqlite3Malloc( pCur->nKey );
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
@@ -632,7 +639,7 @@ static int saveCursorKey(BtCursor *pCur){
sqlite3_free(pKey);
}
}else{
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
}
assert( !pCur->curIntKey || !pCur->pKey );
@@ -756,7 +763,7 @@ static int btreeMoveto(
){
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
char aSpace[200]; /* Temp space for pIdxKey - to avoid a malloc */
char aSpace[384]; /* Temp space for pIdxKey - to avoid a malloc */
char *pFree = 0;
if( pKey ){
@@ -764,7 +771,7 @@ static int btreeMoveto(
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
);
if( pIdxKey==0 ) return SQLITE_NOMEM;
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
sqlite3DbFree(pCur->pKeyInfo->db, pFree);
@@ -1598,8 +1605,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( data[iPtr+1]==0 && data[iPtr]==0 ){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlk<iStart ){
if( iFreeBlk<iPtr+4 ) return SQLITE_CORRUPT_BKPT;
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
if( iFreeBlk<iPtr+4 ){
if( iFreeBlk==0 ) break;
return SQLITE_CORRUPT_BKPT;
}
iPtr = iFreeBlk;
}
if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
@@ -1676,11 +1686,11 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->xCellSize = cellSizePtr;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
/* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
** table b-tree page. */
/* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
** interior table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
/* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
** table b-tree page. */
/* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
** leaf table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
if( pPage->leaf ){
@@ -1694,11 +1704,11 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
/* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
** index b-tree page. */
/* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
** interior index b-tree page. */
assert( (PTF_ZERODATA)==2 );
/* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
** index b-tree page. */
/* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
** leaf index b-tree page. */
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
@@ -2176,7 +2186,7 @@ int sqlite3BtreeOpen(
}
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
p->inTrans = TRANS_NONE;
p->db = db;
@@ -2200,7 +2210,7 @@ int sqlite3BtreeOpen(
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
if( isMemdb ){
memcpy(zFullPathname, zFilename, nFilename);
@@ -2268,7 +2278,7 @@ int sqlite3BtreeOpen(
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
@@ -2330,14 +2340,14 @@ int sqlite3BtreeOpen(
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new BtShared object to the linked list sharable BtShareds.
*/
pBt->nRef = 1;
if( p->sharable ){
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
pBt->nRef = 1;
MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
}
@@ -2360,12 +2370,12 @@ int sqlite3BtreeOpen(
for(i=0; i<db->nDb; i++){
if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
while( pSib->pPrev ){ pSib = pSib->pPrev; }
if( p->pBt<pSib->pBt ){
if( (uptr)p->pBt<(uptr)pSib->pBt ){
p->pNext = pSib;
p->pPrev = 0;
pSib->pPrev = p;
}else{
while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
pSib = pSib->pNext;
}
p->pNext = pSib->pNext;
@@ -2403,6 +2413,7 @@ btree_open_out:
assert( sqlite3_mutex_held(mutexOpen) );
sqlite3_mutex_leave(mutexOpen);
}
assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
return rc;
}
@@ -2619,21 +2630,6 @@ int sqlite3BtreeSetPagerFlags(
}
#endif
/*
** Return TRUE if the given btree is set to safety level 1. In other
** words, return TRUE if no sync() occurs on the disk files.
*/
int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt;
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
assert( pBt && pBt->pPager );
rc = sqlite3PagerNosync(pBt->pPager);
sqlite3BtreeLeave(p);
return rc;
}
/*
** Change the default pages size and the number of reserved bytes per page.
** Or, if the page size has already been fixed, return SQLITE_READONLY
@@ -2879,9 +2875,25 @@ static int lockBtree(BtShared *pBt){
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}else{
#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
sqlite3 *db;
Db *pDb;
if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
if( pDb->bSyncSet==0
&& pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
){
pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
sqlite3PagerSetFlags(pBt->pPager,
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
}
}
#endif
if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
}
rc = SQLITE_NOTADB;
}
@@ -4114,7 +4126,7 @@ static int btreeCursor(
if( wrFlag ){
allocateTempSpace(pBt);
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
}
if( iTable==1 && btreePagecount(pBt)==0 ){
assert( wrFlag==0 );
@@ -4261,46 +4273,33 @@ int sqlite3BtreeCursorIsValid(BtCursor *pCur){
#endif /* NDEBUG */
/*
** Set *pSize to the size of the buffer needed to hold the value of
** the key for the current entry. If the cursor is not pointing
** to a valid entry, *pSize is set to 0.
**
** For a table with the INTKEY flag set, this routine returns the key
** itself, not the number of bytes in the key.
**
** The caller must position the cursor prior to invoking this routine.
**
** This routine cannot fail. It always returns SQLITE_OK.
** Return the value of the integer key or "rowid" for a table btree.
** This routine is only valid for a cursor that is pointing into a
** ordinary table btree. If the cursor points to an index btree or
** is invalid, the result of this routine is undefined.
*/
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->curIntKey );
getCellInfo(pCur);
*pSize = pCur->info.nKey;
return SQLITE_OK;
return pCur->info.nKey;
}
/*
** Set *pSize to the number of bytes of data in the entry the
** cursor currently points to.
** Return the number of bytes of payload for the entry that pCur is
** currently pointing to. For table btrees, this will be the amount
** of data. For index btrees, this will be the size of the key.
**
** The caller must guarantee that the cursor is pointing to a non-NULL
** valid entry. In other words, the calling procedure must guarantee
** that the cursor has Cursor.eState==CURSOR_VALID.
**
** Failure is not possible. This function always returns SQLITE_OK.
** It might just as well be a procedure (returning void) but we continue
** to return an integer result code for historical reasons.
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
assert( cursorOwnsBtShared(pCur) );
u32 sqlite3BtreePayloadSize(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
getCellInfo(pCur);
*pSize = pCur->info.nPayload;
return SQLITE_OK;
return pCur->info.nPayload;
}
/*
@@ -4471,8 +4470,13 @@ static int accessPayload(
#endif
assert( offset+amt <= pCur->info.nPayload );
if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
/* Trying to read or write past the end of the data is an error */
assert( aPayload > pPage->aData );
if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
/* Trying to read or write past the end of the data is an error. The
** conditional above is really:
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
return SQLITE_CORRUPT_BKPT;
}
@@ -4512,7 +4516,7 @@ static int accessPayload(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
@@ -4597,7 +4601,7 @@ static int accessPayload(
&& (bEnd || a==ovflSize) /* (6) */
&& pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
&& pBt->pPage1->aData[19]==0x01 /* (5) */
&& 0==sqlite3PagerUseWal(pBt->pPager) /* (5) */
&& &pBuf[-4]>=pBufStart /* (7) */
){
u8 aSave[4];
@@ -4737,10 +4741,7 @@ static const void *fetchPayload(
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
return fetchPayload(pCur, pAmt);
}
const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
return fetchPayload(pCur, pAmt);
}
@@ -5073,11 +5074,12 @@ int sqlite3BtreeMovetoUnpacked(
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( pRes );
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
&& pCur->curIntKey
if( pIdxKey==0
&& pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
@@ -5217,7 +5219,7 @@ int sqlite3BtreeMovetoUnpacked(
}
pCellKey = sqlite3Malloc( nCell+18 );
if( pCellKey==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
@@ -6066,9 +6068,7 @@ static int clearCell(
static int fillInCell(
MemPage *pPage, /* The page that contains the cell */
unsigned char *pCell, /* Complete text of the cell */
const void *pKey, i64 nKey, /* The key */
const void *pData,int nData, /* The data */
int nZero, /* Extra zero bytes to append to pData */
const BtreePayload *pX, /* Payload with which to construct the cell */
int *pnSize /* Write cell size here */
){
int nPayload;
@@ -6092,26 +6092,21 @@ static int fillInCell(
/* Fill in the header. */
nHeader = pPage->childPtrSize;
nPayload = nData + nZero;
if( pPage->intKeyLeaf ){
nHeader += putVarint32(&pCell[nHeader], nPayload);
}else{
assert( nData==0 );
assert( nZero==0 );
}
nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
/* Fill in the payload size */
if( pPage->intKey ){
pSrc = pData;
nSrc = nData;
nData = 0;
}else{
assert( nKey<=0x7fffffff && pKey!=0 );
nPayload = (int)nKey;
pSrc = pKey;
nSrc = (int)nKey;
nPayload = pX->nData + pX->nZero;
pSrc = pX->pData;
nSrc = pX->nData;
assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */
nHeader += putVarint32(&pCell[nHeader], nPayload);
nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey);
}else{
assert( pX->nKey<=0x7fffffff && pX->pKey!=0 );
nSrc = nPayload = (int)pX->nKey;
pSrc = pX->pKey;
nHeader += putVarint32(&pCell[nHeader], nPayload);
}
/* Fill in the payload */
if( nPayload<=pPage->maxLocal ){
n = nHeader + nPayload;
testcase( n==3 );
@@ -6149,7 +6144,7 @@ static int fillInCell(
CellInfo info;
pPage->xParseCell(pPage, pCell, &info);
assert( nHeader==(int)(info.pPayload - pCell) );
assert( info.nKey==nKey );
assert( info.nKey==pX->nKey );
assert( *pnSize == info.nSize );
assert( spaceLeft == info.nLocal );
}
@@ -6234,10 +6229,6 @@ static int fillInCell(
pSrc += n;
nSrc -= n;
spaceLeft -= n;
if( nSrc==0 ){
nSrc = nData;
pSrc = pData;
}
}
releasePage(pToRelease);
return SQLITE_OK;
@@ -6304,6 +6295,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
**
** *pRC must be SQLITE_OK when this routine is called.
*/
static void insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -6319,8 +6312,7 @@ static void insertCell(
u8 *data; /* The content of the whole page */
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
if( *pRC ) return;
assert( *pRC==SQLITE_OK );
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
@@ -6394,7 +6386,7 @@ static void insertCell(
/*
** A CellArray object contains a cache of pointers and sizes for a
** consecutive sequence of cells that might be held multiple pages.
** consecutive sequence of cells that might be held on multiple pages.
*/
typedef struct CellArray CellArray;
struct CellArray {
@@ -6539,8 +6531,8 @@ static int pageInsertArray(
u8 *pSlot;
sz = cachedCellSize(pCArray, i);
if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
if( (pData - pBegin)<sz ) return 1;
pData -= sz;
if( pData<pBegin ) return 1;
pSlot = pData;
}
/* pSlot and pCArray->apCell[i] will never overlap on a well-formed
@@ -6702,7 +6694,7 @@ static int editPage(
for(i=0; i<nNew && !CORRUPT_DB; i++){
u8 *pCell = pCArray->apCell[i+iNew];
int iOff = get2byteAligned(&pPg->aCellIdx[i*2]);
if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){
pCell = &pTmp[pCell - aData];
}
assert( 0==memcmp(pCell, &aData[iOff],
@@ -6826,8 +6818,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop );
/* Insert the new divider cell into pParent. */
insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
0, pPage->pgno, &rc);
if( rc==SQLITE_OK ){
insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
0, pPage->pgno, &rc);
}
/* Set the right-child pointer of pParent to point to the new page. */
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
@@ -7036,7 +7030,7 @@ static int balance_nonroot(
assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
/* Find the sibling pages to balance. Also locate the cells in pParent
@@ -7136,7 +7130,7 @@ static int balance_nonroot(
assert( szScratch<=6*(int)pBt->pageSize );
b.apCell = sqlite3ScratchMalloc( szScratch );
if( b.apCell==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto balance_cleanup;
}
b.szCell = (u16*)&b.apCell[nMaxCells];
@@ -7347,7 +7341,7 @@ static int balance_nonroot(
assert( r<nMaxCells );
(void)cachedCellSize(&b, r);
if( szRight!=0
&& (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+2)) ){
&& (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
break;
}
szRight += b.szCell[d] + 2;
@@ -7571,9 +7565,9 @@ static int balance_nonroot(
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
** Note that this can never happen in an SQLite data file, as all
** cells are at least 4 bytes. It only happens in b-trees used
** to evaluate "IN (SELECT ...)" and similar clauses.
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
** and WITHOUT ROWID tables with exactly one column which is the
** primary key.
*/
if( b.szCell[j]==4 ){
assert(leafCorrection==4);
@@ -7919,13 +7913,19 @@ static int balance(BtCursor *pCur){
/*
** Insert a new record into the BTree. The key is given by (pKey,nKey)
** and the data is given by (pData,nData). The cursor is used only to
** define what table the record should be inserted into. The cursor
** is left pointing at a random location.
** Insert a new record into the BTree. The content of the new record
** is described by the pX object. The pCur cursor is used only to
** define what table the record should be inserted into, and is left
** pointing at a random location.
**
** For an INTKEY table, only the nKey value of the key is used. pKey is
** ignored. For a ZERODATA table, the pData and nData are both ignored.
** For a table btree (used for rowid tables), only the pX.nKey value of
** the key is used. The pX.pKey value must be NULL. The pX.nKey is the
** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields
** hold the content of the row.
**
** For an index btree (used for indexes and WITHOUT ROWID tables), the
** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
** pX.pData,nData,nZero fields must be zero.
**
** If the seekResult parameter is non-zero, then a successful call to
** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
@@ -7942,9 +7942,7 @@ static int balance(BtCursor *pCur){
*/
int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, i64 nKey, /* The key of the new record */
const void *pData, int nData, /* The data of the new record */
int nZero, /* Number of extra 0 bytes to append to data */
const BtreePayload *pX, /* Content of the row to be inserted */
int appendBias, /* True if this is likely an append */
int seekResult /* Result of prior MovetoUnpacked() call */
){
@@ -7974,7 +7972,7 @@ int sqlite3BtreeInsert(
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
assert( (pKey==0)==(pCur->pKeyInfo==0) );
assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
/* Save the positions of any other cursors open on this table.
**
@@ -7993,38 +7991,38 @@ int sqlite3BtreeInsert(
}
if( pCur->pKeyInfo==0 ){
assert( pKey==0 );
assert( pX->pKey==0 );
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
invalidateIncrblobCursors(p, nKey, 0);
invalidateIncrblobCursors(p, pX->nKey, 0);
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary
** btreeMoveto() call */
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0
&& pCur->info.nKey==nKey-1 ){
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
&& pCur->info.nKey==pX->nKey-1 ){
loc = -1;
}else if( loc==0 ){
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc);
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc);
if( rc ) return rc;
}
}else if( loc==0 ){
rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc);
if( rc ) return rc;
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->apPage[pCur->iPage];
assert( pPage->intKey || nKey>=0 );
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
pCur->pgnoRoot, nKey, nData, pPage->pgno,
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit );
newCell = pBt->pTmpSpace;
assert( newCell!=0 );
rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
rc = fillInCell(pPage, newCell, pX, &szNew);
if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
@@ -8050,6 +8048,7 @@ int sqlite3BtreeInsert(
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
/* If no error has occurred and pPage has an overflow cell, call balance()
@@ -8073,7 +8072,8 @@ int sqlite3BtreeInsert(
** row without seeking the cursor. This can be a big performance boost.
*/
pCur->info.nSize = 0;
if( rc==SQLITE_OK && pPage->nOverflow ){
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
pCur->curFlags &= ~(BTCF_ValidNKey);
rc = balance(pCur);
@@ -8134,6 +8134,28 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
** the entry being deleted. This cell will replace the cell being deleted
@@ -8160,28 +8182,6 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
** key and leaving the cursor in CURSOR_REQUIRESEEK state before
** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
rc = saveCursorKey(pCur);
if( rc ) return rc;
}else{
bSkipnext = 1;
}
}
/* Make the page containing the entry to be deleted writable. Then free any
** overflow pages associated with the entry and finally remove the cell
** itself from within the page. */
@@ -8209,7 +8209,9 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pTmp = pBt->pTmpSpace;
assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
if( rc==SQLITE_OK ){
insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
}
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;
}
@@ -9698,4 +9700,14 @@ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
int sqlite3BtreeSharable(Btree *p){
return p->sharable;
}
/*
** Return the number of connections to the BtShared object accessed by
** the Btree handle passed as the only argument. For private caches
** this is always 1. For shared caches it may be 1 or greater.
*/
int sqlite3BtreeConnectionCount(Btree *p){
testcase( p->sharable );
return p->pBt->nRef;
}
#endif
+41 -11
View File
@@ -13,8 +13,8 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
*/
#ifndef _BTREE_H_
#define _BTREE_H_
#ifndef SQLITE_BTREE_H
#define SQLITE_BTREE_H
/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
@@ -39,6 +39,7 @@
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
typedef struct BtreePayload BtreePayload;
int sqlite3BtreeOpen(
@@ -68,7 +69,6 @@ int sqlite3BtreeSetSpillSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#endif
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -90,7 +90,9 @@ int sqlite3BtreeIsInReadTrans(Btree*);
int sqlite3BtreeIsInBackup(Btree*);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *pBtree);
#ifndef SQLITE_OMIT_SHARED_CACHE
int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
#endif
int sqlite3BtreeSavepoint(Btree *, int, int);
const char *sqlite3BtreeGetFilename(Btree *);
@@ -251,26 +253,52 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
const void *pData, int nData,
int nZero, int bias, int seekResult);
/* An instance of the BtreePayload object describes the content of a single
** 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.
**
** 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.
**
** This object is used to pass information into sqlite3BtreeInsert(). The
** same information used to be passed as five separate parameters. But placing
** the information into this object helps to keep the interface more
** organized and understandable, and it also helps the resulting code to
** run a little faster by using fewer registers for parameter passing.
*/
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 */
int nData; /* Size of pData. 0 if none. */
int nZero; /* Extra zero data appended after pData,nData */
};
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int bias, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
i64 sqlite3BtreeIntegerKey(BtCursor*);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
u32 sqlite3BtreePayloadSize(BtCursor*);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
#ifndef SQLITE_OMIT_INCRBLOB
int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeIncrblobCursor(BtCursor *);
#endif
void sqlite3BtreeClearCursor(BtCursor *);
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
@@ -304,11 +332,13 @@ void sqlite3BtreeCursorList(Btree*);
void sqlite3BtreeEnterAll(sqlite3*);
int sqlite3BtreeSharable(Btree*);
void sqlite3BtreeEnterCursor(BtCursor*);
int sqlite3BtreeConnectionCount(Btree*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
# define sqlite3BtreeSharable(X) 0
# define sqlite3BtreeEnterCursor(X)
# define sqlite3BtreeConnectionCount(X) 1
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
@@ -333,4 +363,4 @@ void sqlite3BtreeCursorList(Btree*);
#endif
#endif /* _BTREE_H_ */
#endif /* SQLITE_BTREE_H */
+218 -197
View File
@@ -146,15 +146,14 @@ void sqlite3FinishCoding(Parse *pParse){
assert( !pParse->isMultiWrite
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
sqlite3VdbeAddOp0(v, OP_Halt);
#if SQLITE_USER_AUTHENTICATION
if( pParse->nTableLock>0 && db->init.busy==0 ){
sqlite3UserAuthInit(db);
if( db->auth.authLevel<UAUTH_User ){
pParse->rc = SQLITE_AUTH_USER;
sqlite3ErrorMsg(pParse, "user not authenticated");
pParse->rc = SQLITE_AUTH_USER;
return;
}
}
@@ -173,14 +172,16 @@ void sqlite3FinishCoding(Parse *pParse){
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
for(iDb=0; iDb<db->nDb; iDb++){
Schema *pSchema;
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
pSchema = db->aDb[iDb].pSchema;
sqlite3VdbeAddOp4Int(v,
OP_Transaction, /* Opcode */
iDb, /* P1 */
DbMaskTest(pParse->writeMask,iDb), /* P2 */
pParse->cookieValue[iDb], /* P3 */
db->aDb[iDb].pSchema->iGeneration /* P4 */
pSchema->schema_cookie, /* P3 */
pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
VdbeComment((v,
@@ -231,16 +232,6 @@ void sqlite3FinishCoding(Parse *pParse){
}else{
pParse->rc = SQLITE_ERROR;
}
/* We are done with this Parse object. There is no need to de-initialize it */
#if 0
pParse->colNamesSet = 0;
pParse->nTab = 0;
pParse->nMem = 0;
pParse->nSet = 0;
pParse->nVar = 0;
DbMaskZero(pParse->cookieMask);
#endif
}
/*
@@ -260,8 +251,7 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
char *zSql;
char *zErrMsg = 0;
sqlite3 *db = pParse->db;
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
char saveBuf[SAVE_SZ];
char saveBuf[PARSE_TAIL_SZ];
if( pParse->nErr ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
@@ -272,12 +262,12 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
return; /* A malloc must have failed */
}
pParse->nested++;
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
memset(&pParse->nVar, 0, SAVE_SZ);
memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
sqlite3RunParser(pParse, zSql, &zErrMsg);
sqlite3DbFree(db, zErrMsg);
sqlite3DbFree(db, zSql);
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
pParse->nested--;
}
@@ -318,10 +308,11 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
#endif
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
if( p ) break;
if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
if( p ) break;
}
}
return p;
}
@@ -338,7 +329,7 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
*/
Table *sqlite3LocateTable(
Parse *pParse, /* context in which to report errors */
int isView, /* True if looking for a VIEW rather than a TABLE */
u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */
const char *zName, /* Name of the table we are looking for */
const char *zDbase /* Name of the database. Might be NULL */
){
@@ -352,7 +343,7 @@ Table *sqlite3LocateTable(
p = sqlite3FindTable(pParse->db, zName, zDbase);
if( p==0 ){
const char *zMsg = isView ? "no such view" : "no such table";
const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
/* If zName is the not the name of a table in the schema created using
@@ -364,12 +355,14 @@ Table *sqlite3LocateTable(
}
}
#endif
if( zDbase ){
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
}else{
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
if( (flags & LOCATE_NOERR)==0 ){
if( zDbase ){
sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
}else{
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
}
pParse->checkSchema = 1;
}
pParse->checkSchema = 1;
}
return p;
@@ -386,18 +379,18 @@ Table *sqlite3LocateTable(
*/
Table *sqlite3LocateTableItem(
Parse *pParse,
int isView,
u32 flags,
struct SrcList_item *p
){
const char *zDb;
assert( p->pSchema==0 || p->zDatabase==0 );
if( p->pSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
zDb = pParse->db->aDb[iDb].zName;
zDb = pParse->db->aDb[iDb].zDbSName;
}else{
zDb = p->zDatabase;
}
return sqlite3LocateTable(pParse, isView, p->zName, zDb);
return sqlite3LocateTable(pParse, flags, p->zName, zDb);
}
/*
@@ -421,7 +414,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
Schema *pSchema = db->aDb[j].pSchema;
assert( pSchema );
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&pSchema->idxHash, zName);
if( p ) break;
@@ -490,8 +483,8 @@ void sqlite3CollapseDatabaseArray(sqlite3 *db){
for(i=j=2; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
sqlite3DbFree(db, pDb->zName);
pDb->zName = 0;
sqlite3DbFree(db, pDb->zDbSName);
pDb->zDbSName = 0;
continue;
}
if( j<i ){
@@ -571,8 +564,6 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
for(i=0; i<pTable->nCol; i++, pCol++){
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
sqlite3DbFree(db, pCol->zDflt);
sqlite3DbFree(db, pCol->zType);
sqlite3DbFree(db, pCol->zColl);
}
sqlite3DbFree(db, pTable->aCol);
@@ -594,16 +585,10 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
** db parameter can be used with db->pnBytesFreed to measure the memory
** used by the Table object.
*/
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
assert( !pTable || pTable->nRef>0 );
/* Do not delete the table until the reference count reaches zero. */
if( !pTable ) return;
if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
/* Record the number of outstanding lookaside allocations in schema Tables
** prior to doing any free() operations. Since schema Tables do not use
** lookaside, this number should not change. */
@@ -613,8 +598,9 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema );
if( !db || db->pnBytesFreed==0 ){
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
@@ -643,6 +629,13 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Verify that no lookaside memory was used by schema tables */
assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
}
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
if( !pTable ) return;
if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
deleteTable(db, pTable);
}
/*
** Unlink the given table from the hash tables and the delete the
@@ -710,12 +703,8 @@ int sqlite3FindDbName(sqlite3 *db, const char *zName){
int i = -1; /* Database number */
if( zName ){
Db *pDb;
int n = sqlite3Strlen30(zName);
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) &&
0==sqlite3StrICmp(pDb->zName, zName) ){
break;
}
if( 0==sqlite3StrICmp(pDb->zDbSName, zName) ) break;
}
}
return i;
@@ -774,7 +763,7 @@ int sqlite3TwoPartName(
return -1;
}
}else{
assert( db->init.iDb==0 || db->init.busy );
assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -885,7 +874,7 @@ void sqlite3StartTable(
SQLITE_CREATE_VIEW,
SQLITE_CREATE_TEMP_VIEW
};
char *zDb = db->aDb[iDb].zName;
char *zDb = db->aDb[iDb].zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto begin_table_error;
}
@@ -904,7 +893,7 @@ void sqlite3StartTable(
** collisions.
*/
if( !IN_DECLARE_VTAB ){
char *zDb = db->aDb[iDb].zName;
char *zDb = db->aDb[iDb].zDbSName;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error;
}
@@ -927,7 +916,7 @@ void sqlite3StartTable(
pTable = sqlite3DbMallocZero(db, sizeof(Table));
if( pTable==0 ){
assert( db->mallocFailed );
pParse->rc = SQLITE_NOMEM;
pParse->rc = SQLITE_NOMEM_BKPT;
pParse->nErr++;
goto begin_table_error;
}
@@ -1043,10 +1032,11 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
** first to get things going. Then this routine is called for each
** column.
*/
void sqlite3AddColumn(Parse *pParse, Token *pName){
void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
Table *p;
int i;
char *z;
char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
@@ -1056,8 +1046,11 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
return;
}
#endif
z = sqlite3NameFromToken(db, pName);
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
memcpy(z, pName->z, pName->n);
z[pName->n] = 0;
sqlite3Dequote(z);
for(i=0; i<p->nCol; i++){
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
@@ -1079,13 +1072,21 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
pCol->zName = z;
sqlite3ColumnPropertiesFromName(p, pCol);
/* If there is no type specified, columns have the default affinity
** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
** be called next to set pCol->affinity correctly.
*/
pCol->affinity = SQLITE_AFF_BLOB;
pCol->szEst = 1;
if( pType->n==0 ){
/* If there is no type specified, columns have the default affinity
** 'BLOB'. */
pCol->affinity = SQLITE_AFF_BLOB;
pCol->szEst = 1;
}else{
zType = z + sqlite3Strlen30(z) + 1;
memcpy(zType, pType->z, pType->n);
zType[pType->n] = 0;
sqlite3Dequote(zType);
pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
pCol->colFlags |= COLFLAG_HASTYPE;
}
p->nCol++;
pParse->constraintName.n = 0;
}
/*
@@ -1131,7 +1132,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
if( zIn==0 ) return aff;
assert( zIn!=0 );
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
@@ -1188,28 +1189,6 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
return aff;
}
/*
** This routine is called by the parser while in the middle of
** parsing a CREATE TABLE statement. The pFirst token is the first
** token in the sequence of tokens that describe the type of the
** column currently under construction. pLast is the last token
** in the sequence. Use this information to construct a string
** that contains the typename of the column and store that string
** in zType.
*/
void sqlite3AddColumnType(Parse *pParse, Token *pType){
Table *p;
Column *pCol;
p = pParse->pNewTable;
if( p==0 || NEVER(p->nCol<1) ) return;
pCol = &p->aCol[p->nCol-1];
assert( pCol->zType==0 || CORRUPT_DB );
sqlite3DbFree(pParse->db, pCol->zType);
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
}
/*
** The expression is the default value for the most recently added column
** of the table currently under construction.
@@ -1235,11 +1214,16 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
sqlite3DbFree(db, pCol->zDflt);
pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
(int)(pSpan->zEnd - pSpan->zStart));
memset(&x, 0, sizeof(x));
x.op = TK_SPAN;
x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
(int)(pSpan->zEnd - pSpan->zStart));
x.pLeft = pSpan->pExpr;
x.flags = EP_Skip;
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
sqlite3DbFree(db, x.u.zToken);
}
}
sqlite3ExprDelete(db, pSpan->pExpr);
@@ -1295,10 +1279,10 @@ void sqlite3AddPrimaryKey(
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
char *zType = 0;
Column *pCol = 0;
int iCol = -1, i;
int nTerm;
if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
if( pTab==0 ) goto primary_key_exit;
if( pTab->tabFlags & TF_HasPrimaryKey ){
sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
@@ -1307,8 +1291,8 @@ void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
zType = pTab->aCol[iCol].zType;
pCol = &pTab->aCol[iCol];
pCol->colFlags |= COLFLAG_PRIMKEY;
nTerm = 1;
}else{
nTerm = pList->nExpr;
@@ -1320,8 +1304,8 @@ void sqlite3AddPrimaryKey(
const char *zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
zType = pTab->aCol[iCol].zType;
pCol = &pTab->aCol[iCol];
pCol->colFlags |= COLFLAG_PRIMKEY;
break;
}
}
@@ -1329,7 +1313,8 @@ void sqlite3AddPrimaryKey(
}
}
if( nTerm==1
&& zType && sqlite3StrICmp(zType, "INTEGER")==0
&& pCol
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
&& sortOrder!=SQLITE_SO_DESC
){
pTab->iPKey = iCol;
@@ -1343,12 +1328,8 @@ void sqlite3AddPrimaryKey(
"INTEGER PRIMARY KEY");
#endif
}else{
Index *p;
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
0, sortOrder, 0);
if( p ){
p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
}
sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY);
pList = 0;
}
@@ -1467,6 +1448,9 @@ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
** set back to prior value. But schema changes are infrequent
** and the probability of hitting the same cookie value is only
** 1 chance in 2^32. So we're safe enough.
**
** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments
** the schema-version whenever the schema changes.
*/
void sqlite3ChangeCookie(Parse *pParse, int iDb){
sqlite3 *db = pParse->db;
@@ -1608,7 +1592,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
zExtra = sqlite3DbMallocZero(db, nByte);
if( zExtra==0 ) return SQLITE_NOMEM;
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
pIdx->azColl = (const char**)zExtra;
zExtra += sizeof(char*)*N;
@@ -1665,21 +1649,23 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** are appropriate for a WITHOUT ROWID table instead of a rowid table.
** Changes include:
**
** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is
** no rowid btree for a WITHOUT ROWID. Instead, the canonical
** data storage is a covering index btree.
** (2) Bypass the creation of the sqlite_master table entry
** (3) Bypass the creation of the sqlite_master table entry
** for the PRIMARY KEY as the primary key index is now
** identified by the sqlite_master table entry of the table itself.
** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
** (5) Add all table columns to the PRIMARY KEY Index object
** so that the PRIMARY KEY is a covering index. The surplus
** columns are part of KeyInfo.nXField and are not used for
** sorting or lookup or uniqueness checks.
** (6) Replace the rowid tail on all automatically generated UNIQUE
** indices with the PRIMARY KEY columns.
**
** For virtual tables, only (1) is performed.
*/
static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
Index *pIdx;
@@ -1689,6 +1675,20 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
/* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
*/
if( !db->init.imposterTable ){
for(i=0; i<pTab->nCol; i++){
if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){
pTab->aCol[i].notNull = OE_Abort;
}
}
}
/* The remaining transformations only apply to b-tree tables, not to
** virtual tables */
if( IN_DECLARE_VTAB ) return;
/* Convert the OP_CreateTable opcode that would normally create the
** root-page for the table into an OP_CreateIndex opcode. The index
** created will become the PRIMARY KEY index.
@@ -1710,9 +1710,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( pList==0 ) return;
pList->a[0].sortOrder = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab );
pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
if( pPk==0 ) return;
pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
SQLITE_IDXTYPE_PRIMARYKEY);
if( db->mallocFailed ) return;
pPk = sqlite3PrimaryKeyIndex(pTab);
pTab->iPKey = -1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -1740,19 +1741,11 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}
pPk->nKeyCol = j;
}
pPk->isCovering = 1;
assert( pPk!=0 );
pPk->isCovering = 1;
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
nPk = pPk->nKeyCol;
/* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
** do not enforce this for imposter tables.) */
if( !db->init.imposterTable ){
for(i=0; i<nPk; i++){
pTab->aCol[pPk->aiColumn[i]].notNull = OE_Abort;
}
pPk->uniqNotNull = 1;
}
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -1996,7 +1989,7 @@ void sqlite3EndTable(
"UPDATE %Q.%s "
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
"WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb),
zType,
p->zName,
p->zName,
@@ -2011,13 +2004,13 @@ void sqlite3EndTable(
/* Check to see if we need to create an sqlite_sequence table for
** keeping track of autoincrement keys.
*/
if( p->tabFlags & TF_Autoincrement ){
if( (p->tabFlags & TF_Autoincrement)!=0 ){
Db *pDb = &db->aDb[iDb];
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_sequence(name,seq)",
pDb->zName
pDb->zDbSName
);
}
}
@@ -2141,7 +2134,9 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth; /* Saved xAuth pointer */
#endif
assert( pTable );
@@ -2187,44 +2182,55 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
if( pTable->pCheck ){
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bDisable++;
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
db->lookaside.bDisable--;
}else{
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
db->lookaside.bDisable++;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
db->xAuth = xAuth;
xAuth = db->xAuth;
db->xAuth = 0;
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
db->xAuth = xAuth;
#else
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
#endif
db->lookaside.bDisable--;
pParse->nTab = n;
if( pSelTab ){
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
}else{
pTable->nCol = 0;
nErr++;
pParse->nTab = n;
if( pTable->pCheck ){
/* CREATE VIEW name(arglist) AS ...
** The names of the columns in the table are taken from
** arglist which is stored in pTable->pCheck. The pCheck field
** normally holds CHECK constraints on an ordinary table, but for
** a VIEW it holds the list of column names.
*/
sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
if( db->mallocFailed==0
&& pParse->nErr==0
&& pTable->nCol==pSel->pEList->nExpr
){
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
}
sqlite3SelectDelete(db, pSel);
} else {
}else if( pSelTab ){
/* CREATE VIEW name AS... without an argument list. Construct
** the column names from the SELECT statement that defines the view.
*/
assert( pTable->aCol==0 );
pTable->nCol = pSelTab->nCol;
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
}else{
pTable->nCol = 0;
nErr++;
}
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
db->lookaside.bDisable--;
} else {
nErr++;
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
#endif /* SQLITE_OMIT_VIEW */
@@ -2320,7 +2326,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
pParse->db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
@@ -2396,7 +2402,7 @@ static void sqlite3ClearStatTables(
const char *zName /* Name of index or table */
){
int i;
const char *zDbName = pParse->db->aDb[iDb].zName;
const char *zDbName = pParse->db->aDb[iDb].zDbSName;
for(i=1; i<=4; i++){
char zTab[24];
sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
@@ -2449,7 +2455,7 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
if( pTab->tabFlags & TF_Autoincrement ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
pDb->zName, pTab->zName
pDb->zDbSName, pTab->zName
);
}
#endif
@@ -2463,7 +2469,7 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
*/
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
pDb->zDbSName, SCHEMA_TABLE(iDb), pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
@@ -2496,6 +2502,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
assert( pName->nSrc==1 );
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
assert( isView==0 || isView==LOCATE_VIEW );
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
@@ -2516,7 +2523,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
{
int code;
const char *zTab = SCHEMA_TABLE(iDb);
const char *zDb = db->aDb[iDb].zName;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
@@ -2757,7 +2764,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
db->aDb[iDb].zName ) ){
db->aDb[iDb].zDbSName ) ){
return;
}
#endif
@@ -2773,6 +2780,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
tnum = pIndex->tnum;
}
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
@@ -2796,8 +2804,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
if( IsUniqueIndex(pIndex) && pKey!=0 ){
if( IsUniqueIndex(pIndex) ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeGoto(v, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
@@ -2866,12 +2873,8 @@ Index *sqlite3AllocateIndexObject(
** pList is a list of columns to be indexed. pList will be NULL if this
** is a primary key or unique-constraint on the most recent column added
** to the table currently under construction.
**
** If the index is created successfully, return a pointer to the new Index
** structure. This is used by sqlite3AddPrimaryKey() to mark the index
** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
*/
Index *sqlite3CreateIndex(
void sqlite3CreateIndex(
Parse *pParse, /* All information about this parse */
Token *pName1, /* First part of index name. May be NULL */
Token *pName2, /* Second part of index name. May be NULL */
@@ -2881,9 +2884,9 @@ Index *sqlite3CreateIndex(
Token *pStart, /* The CREATE token that begins this statement */
Expr *pPIWhere, /* WHERE clause for partial indices */
int sortOrder, /* Sort order of primary key when pList==NULL */
int ifNotExist /* Omit error if index already exists */
int ifNotExist, /* Omit error if index already exists */
u8 idxType /* The index type */
){
Index *pRet = 0; /* Pointer to return */
Table *pTab = 0; /* Table to be indexed */
Index *pIndex = 0; /* The index to be created */
char *zName = 0; /* Name of the index */
@@ -2901,7 +2904,10 @@ Index *sqlite3CreateIndex(
char *zExtra = 0; /* Extra space after the Index object */
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
if( db->mallocFailed || pParse->nErr>0 ){
goto exit_create_index;
}
if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
goto exit_create_index;
}
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
@@ -3010,7 +3016,7 @@ Index *sqlite3CreateIndex(
goto exit_create_index;
}
}
if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
if( !ifNotExist ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
}else{
@@ -3027,13 +3033,20 @@ Index *sqlite3CreateIndex(
if( zName==0 ){
goto exit_create_index;
}
/* Automatic index names generated from within sqlite3_declare_vtab()
** must have names that are distinct from normal automatic index names.
** The following statement converts "sqlite3_autoindex..." into
** "sqlite3_butoindex..." in order to make the names distinct.
** The "vtab_err.test" test demonstrates the need of this statement. */
if( IN_DECLARE_VTAB ) zName[7]++;
}
/* Check for authorization to create an index.
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
{
const char *zDb = pDb->zName;
const char *zDb = pDb->zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
}
@@ -3090,7 +3103,7 @@ Index *sqlite3CreateIndex(
pIndex->pTable = pTab;
pIndex->onError = (u8)onError;
pIndex->uniqNotNull = onError!=OE_None;
pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
pIndex->idxType = idxType;
pIndex->pSchema = db->aDb[iDb].pSchema;
pIndex->nKeyCol = pList->nExpr;
if( pPIWhere ){
@@ -3200,6 +3213,20 @@ Index *sqlite3CreateIndex(
sqlite3DefaultRowEst(pIndex);
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
/* If this index contains every column of its table, then mark
** it as a covering index */
assert( HasRowid(pTab)
|| pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
pIndex->isCovering = 1;
for(j=0; j<pTab->nCol; j++){
if( j==pTab->iPKey ) continue;
if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
pIndex->isCovering = 0;
break;
}
}
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
@@ -3237,7 +3264,7 @@ Index *sqlite3CreateIndex(
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k];
if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
if( sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nKeyCol ){
if( pIdx->onError!=pIndex->onError ){
@@ -3256,7 +3283,7 @@ Index *sqlite3CreateIndex(
pIdx->onError = pIndex->onError;
}
}
pRet = pIdx;
if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
goto exit_create_index;
}
}
@@ -3268,6 +3295,7 @@ Index *sqlite3CreateIndex(
assert( pParse->nErr==0 );
if( db->init.busy ){
Index *p;
assert( !IN_DECLARE_VTAB );
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, pIndex);
@@ -3333,7 +3361,7 @@ Index *sqlite3CreateIndex(
*/
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb),
pIndex->zName,
pTab->zName,
iMem,
@@ -3349,7 +3377,7 @@ Index *sqlite3CreateIndex(
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
sqlite3VdbeAddOp1(v, OP_Expire, 0);
sqlite3VdbeAddOp0(v, OP_Expire);
}
sqlite3VdbeJumpHere(v, pIndex->tnum);
@@ -3374,7 +3402,6 @@ Index *sqlite3CreateIndex(
pIndex->pNext = pOther->pNext;
pOther->pNext = pIndex;
}
pRet = pIndex;
pIndex = 0;
}
@@ -3385,7 +3412,6 @@ exit_create_index:
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);
sqlite3DbFree(db, zName);
return pRet;
}
/*
@@ -3414,10 +3440,11 @@ void sqlite3DefaultRowEst(Index *pIdx){
int i;
/* Set the first entry (number of rows in the index) to the estimated
** number of rows in the table. Or 10, if the estimated number of rows
** in the table is less than that. */
** number of rows in the table, or half the number of rows in the table
** for a partial index. But do not let the estimate drop below 10. */
a[0] = pIdx->pTable->nRowLogEst;
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
@@ -3468,7 +3495,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
const char *zDb = db->aDb[iDb].zName;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
goto exit_drop_index;
@@ -3486,7 +3513,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
sqlite3ChangeCookie(pParse, iDb);
@@ -4007,15 +4034,13 @@ int sqlite3OpenTempDatabase(Parse *pParse){
*/
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
sqlite3 *db = pToplevel->db;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb>=0 && iDb<pParse->db->nDb );
assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb<SQLITE_MAX_ATTACHED+2 );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
DbMaskSet(pToplevel->cookieMask, iDb);
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pToplevel);
}
@@ -4031,7 +4056,7 @@ void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
int i;
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){
sqlite3CodeVerifySchema(pParse, i);
}
}
@@ -4278,7 +4303,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
if( iDb<0 ) return;
z = sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
zDb = db->aDb[iDb].zName;
zDb = db->aDb[iDb].zDbSName;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
@@ -4299,10 +4324,6 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
/*
** Return a KeyInfo structure that is appropriate for the given Index.
**
** The KeyInfo structure for an index is cached in the Index object.
** So there might be multiple references to the returned pointer. The
** caller should not try to modify the KeyInfo object.
**
** The caller should invoke sqlite3KeyInfoUnref() on the returned object
** when it has finished using it.
*/
+39 -31
View File
@@ -284,14 +284,12 @@ static int matchQuality(
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
const char *zFunc, /* Name of function */
int nFunc /* Number of bytes in zFunc */
const char *zFunc /* Name of function */
){
FuncDef *p;
for(p=pHash->a[h]; p; p=p->pHash){
if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
if( sqlite3StrICmp(p->zName, zFunc)==0 ){
return p;
}
}
@@ -301,23 +299,26 @@ static FuncDef *functionSearch(
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
void sqlite3FuncDefInsert(
FuncDefHash *pHash, /* The hash table into which to insert */
FuncDef *pDef /* The function definition to insert */
void sqlite3InsertBuiltinFuncs(
FuncDef *aDef, /* List of global functions to be inserted */
int nDef /* Length of the apDef[] list */
){
FuncDef *pOther;
int nName = sqlite3Strlen30(pDef->zName);
u8 c1 = (u8)pDef->zName[0];
int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
pOther = functionSearch(pHash, h, pDef->zName, nName);
if( pOther ){
assert( pOther!=pDef && pOther->pNext!=pDef );
pDef->pNext = pOther->pNext;
pOther->pNext = pDef;
}else{
pDef->pNext = 0;
pDef->pHash = pHash->a[h];
pHash->a[h] = pDef;
int i;
for(i=0; i<nDef; i++){
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
pOther = functionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
aDef[i].pNext = pOther->pNext;
pOther->pNext = &aDef[i];
}else{
aDef[i].pNext = 0;
aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
sqlite3BuiltinFunctions.a[h] = &aDef[i];
}
}
}
@@ -344,8 +345,7 @@ void sqlite3FuncDefInsert(
*/
FuncDef *sqlite3FindFunction(
sqlite3 *db, /* An open database */
const char *zName, /* Name of the function. Not null-terminated */
int nName, /* Number of characters in the name */
const char *zName, /* Name of the function. zero-terminated */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
u8 createFlag /* Create new entry if true and does not otherwise exist */
@@ -354,14 +354,15 @@ FuncDef *sqlite3FindFunction(
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
int nName; /* Length of the name */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
nName = sqlite3Strlen30(zName);
/* First search for a match amongst the application-defined functions.
*/
p = functionSearch(&db->aFunc, h, zName, nName);
p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -384,9 +385,9 @@ FuncDef *sqlite3FindFunction(
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
p = functionSearch(pHash, h, zName, nName);
h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
p = functionSearch(h, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -403,12 +404,19 @@ FuncDef *sqlite3FindFunction(
*/
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
pBest->zName = (char *)&pBest[1];
FuncDef *pOther;
pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;
sqlite3FuncDefInsert(&db->aFunc, pBest);
memcpy((char*)&pBest[1], zName, nName+1);
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
sqlite3OomFault(db);
return 0;
}else{
pBest->pNext = pOther;
}
}
if( pBest && (pBest->xSFunc || createFlag) ){
+1 -1
View File
@@ -281,7 +281,7 @@ int sqlite3_complete16(const void *zSql){
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}else{
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
sqlite3ValueFree(pVal);
return rc & 0xff;
+2 -2
View File
@@ -402,7 +402,7 @@ static int sqlcipher_find_db_index(sqlite3 *db, const char *zDb) {
}
for(db_index = 0; db_index < db->nDb; db_index++) {
struct Db *pDb = &db->aDb[db_index];
if(strcmp(pDb->zName, zDb) == 0) {
if(strcmp(pDb->zDbSName, zDb) == 0) {
return db_index;
}
}
@@ -610,7 +610,7 @@ void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **ar
int saved_flags; /* Saved value of the db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
int (*saved_xTrace)(u32,void*,void*,void*); /* Saved db->xTrace */
int rc = SQLITE_OK; /* Return code from service routines */
char *zSql = NULL; /* SQL statements */
char *pzErrMsg = NULL;
+1 -1
View File
@@ -1022,7 +1022,7 @@ int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
int saved_flags;
int saved_nChange;
int saved_nTotalChange;
void (*saved_xTrace)(void*,const char*);
int (*saved_xTrace)(u32,void*,void*,void*); /* Saved db->xTrace */
Db *pDb = 0;
sqlite3 *db = ctx->pBt->db;
const char *db_filename = sqlite3_db_filename(db, "main");
+10 -1
View File
@@ -45,6 +45,15 @@ static const char * const azCompileOpt[] = {
#if SQLITE_CHECK_PAGES
"CHECK_PAGES",
#endif
#if defined(__clang__) && defined(__clang_major__)
"COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
CTIMEOPT_VAL(__clang_minor__) "."
CTIMEOPT_VAL(__clang_patchlevel__),
#elif defined(_MSC_VER)
"COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
#elif defined(__GNUC__) && defined(__VERSION__)
"COMPILER=gcc-" __VERSION__,
#endif
#if SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
@@ -64,7 +73,7 @@ static const char * const azCompileOpt[] = {
"DISABLE_LFS",
#endif
#if SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES",
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
#if SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR",
+12 -10
View File
@@ -50,6 +50,15 @@
#ifndef SQLITE_OMIT_DATETIME_FUNCS
/*
** The MSVC CRT on Windows CE may not have a localtime() function.
** So declare a substitute. The substitute function itself is
** defined in "os_win.c".
*/
#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
(!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
struct tm *__cdecl localtime(const time_t *);
#endif
/*
** A structure for holding a single date and time.
@@ -418,6 +427,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
p->validTZ = 0;
}
#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to
@@ -436,7 +446,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
#define HAVE_LOCALTIME_S 1
#endif
#ifndef SQLITE_OMIT_LOCALTIME
/*
** The following routine implements the rough equivalent of localtime_r()
** using whatever operating-system specific localtime facility that
@@ -1103,7 +1112,6 @@ static void currentTimeFunc(
){
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
sqlite3 *db;
sqlite3_int64 iT;
struct tm *pTm;
struct tm sNow;
@@ -1136,7 +1144,7 @@ static void currentTimeFunc(
** external linkage.
*/
void sqlite3RegisterDateTimeFunctions(void){
static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
DFUNCTION(date, -1, 0, 0, dateFunc ),
@@ -1152,11 +1160,5 @@ void sqlite3RegisterDateTimeFunctions(void){
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
for(i=0; i<ArraySize(aDateTimeFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}
+15 -15
View File
@@ -58,10 +58,10 @@
*/
#define VTAB_SCHEMA \
"CREATE TABLE xx( " \
" name STRING, /* Name of table or index */" \
" path INTEGER, /* Path to page from root */" \
" name TEXT, /* Name of table or index */" \
" path TEXT, /* Path to page from root */" \
" pageno INTEGER, /* Page number */" \
" pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
" pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
" payload INTEGER, /* Bytes of payload on this page */" \
" unused INTEGER, /* Bytes of unused space on this page */" \
@@ -162,7 +162,7 @@ static int statConnect(
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
if( pTab==0 ) rc = SQLITE_NOMEM;
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
}
assert( rc==SQLITE_OK || pTab==0 );
@@ -243,7 +243,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
if( pCsr==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}else{
memset(pCsr, 0, sizeof(StatCursor));
pCsr->base.pVtab = pVTab;
@@ -349,7 +349,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
if( p->aCell==0 ) return SQLITE_NOMEM;
if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
for(i=0; i<p->nCell; i++){
@@ -382,7 +382,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
for(j=1; j<nOvfl; j++){
int rc;
@@ -461,7 +461,7 @@ statNextRestart:
pCsr->aPage[0].iCell = 0;
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
pCsr->iPage = 0;
if( z==0 ) rc = SQLITE_NOMEM;
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
@@ -496,7 +496,7 @@ statNextRestart:
}
pCell->iOvfl++;
statSizeAndOffset(pCsr);
return z==0 ? SQLITE_NOMEM : SQLITE_OK;
return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -520,7 +520,7 @@ statNextRestart:
p[1].iCell = 0;
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
p->iCell++;
if( z==0 ) rc = SQLITE_NOMEM;
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}
@@ -554,7 +554,7 @@ statNextRestart:
pCsr->nUnused = p->nUnused;
pCsr->nMxPayload = p->nMxPayload;
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
if( z==0 ) rc = SQLITE_NOMEM;
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
nPayload = 0;
for(i=0; i<p->nCell; i++){
nPayload += p->aCell[i].nLocal;
@@ -588,7 +588,7 @@ static int statFilter(
if( pCsr->iDb<0 ){
sqlite3_free(pCursor->pVtab->zErrMsg);
pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
}
}else{
pCsr->iDb = pTab->iDb;
@@ -602,9 +602,9 @@ static int statFilter(
" UNION ALL "
"SELECT name, rootpage, type"
" FROM \"%w\".%s WHERE rootpage!=0"
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
if( zSql==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}else{
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
@@ -656,7 +656,7 @@ static int statColumn(
default: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
int iDb = pCsr->iDb;
sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
break;
}
}
+27 -29
View File
@@ -102,7 +102,7 @@ void sqlite3MaterializeView(
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}
@@ -143,7 +143,7 @@ Expr *sqlite3LimitWhere(
*/
if( pOrderBy && (pLimit == 0) ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
goto limit_where_cleanup_2;
goto limit_where_cleanup;
}
/* We only need to generate a select expression if there
@@ -165,16 +165,16 @@ Expr *sqlite3LimitWhere(
*/
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
if( pSelectRowid == 0 ) goto limit_where_cleanup;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
if( pEList == 0 ) goto limit_where_cleanup_2;
if( pEList == 0 ) goto limit_where_cleanup;
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
goto limit_where_cleanup_2;
goto limit_where_cleanup;
}
/* generate the SELECT expression tree. */
@@ -184,21 +184,11 @@ Expr *sqlite3LimitWhere(
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
if( pInClause == 0 ) goto limit_where_cleanup_1;
pInClause->x.pSelect = pSelect;
pInClause->flags |= EP_xIsSelect;
sqlite3ExprSetHeightAndFlags(pParse, pInClause);
pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0) : 0;
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
/* something went wrong. clean up anything allocated. */
limit_where_cleanup_1:
sqlite3SelectDelete(pParse->db, pSelect);
return 0;
limit_where_cleanup_2:
limit_where_cleanup:
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
sqlite3ExprDelete(pParse->db, pLimit);
@@ -222,7 +212,6 @@ void sqlite3DeleteFrom(
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
const char *zDb; /* Name of database holding pTab */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
@@ -249,11 +238,12 @@ void sqlite3DeleteFrom(
int addrBypass = 0; /* Address of jump over the delete logic */
int addrLoop = 0; /* Top of the delete loop */
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
int bComplex; /* True if there are triggers or FKs or
** subqueries in the WHERE clause */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
Trigger *pTrigger; /* List of table triggers, if required */
int bComplex; /* True if there are either triggers or FKs */
#endif
memset(&sContext, 0, sizeof(sContext));
@@ -281,7 +271,6 @@ void sqlite3DeleteFrom(
#else
# define pTrigger 0
# define isView 0
# define bComplex 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
@@ -299,8 +288,8 @@ void sqlite3DeleteFrom(
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
zDb = db->aDb[iDb].zName;
rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
db->aDb[iDb].zDbSName);
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
if( rcauth==SQLITE_DENY ){
goto delete_from_cleanup;
@@ -366,6 +355,9 @@ void sqlite3DeleteFrom(
&& pWhere==0
&& !bComplex
&& !IsVirtual(pTab)
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
&& db->xPreUpdateCallback==0
#endif
){
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
@@ -380,7 +372,8 @@ void sqlite3DeleteFrom(
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
@@ -480,7 +473,7 @@ void sqlite3DeleteFrom(
if( !isView ){
int iAddrOnce = 0;
if( eOnePass==ONEPASS_MULTI ){
iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
testcase( IsVirtual(pTab) );
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
@@ -715,14 +708,19 @@ void sqlite3GenerateRowDelete(
/* Delete the index and table entries. Skip this step if pTab is really
** a view (in which case the only effect of the DELETE statement is to
** fire the INSTEAD OF triggers). */
** fire the INSTEAD OF triggers).
**
** If variable 'count' is non-zero, then this OP_Delete instruction should
** invoke the update-hook. The pre-update-hook, on the other hand should
** be invoked unless table pTab is a system table. The difference is that
** the update-hook is not invoked for rows removed by REPLACE, but the
** pre-update-hook is.
*/
if( pTab->pSelect==0 ){
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
if( count ){
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
}
sqlite3VdbeChangeP4(v, -1, (char*)pTab, P4_TABLE);
if( eMode!=ONEPASS_OFF ){
sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
}
+1285 -528
View File
File diff suppressed because it is too large Load Diff
+8 -4
View File
@@ -871,7 +871,7 @@ void sqlite3FkCheck(
if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
zDb = db->aDb[iDb].zDbSName;
/* Loop through all the foreign key constraints for which pTab is the
** child table (the table that the foreign key definition is part of). */
@@ -1162,6 +1162,9 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
pTrigger = pFKey->apTrigger[iAction];
if( action!=OE_None && !pTrigger ){
@@ -1239,10 +1242,10 @@ static Trigger *fkActionTrigger(
if( pDflt ){
pNew = sqlite3ExprDup(db, pDflt, 0);
}else{
pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
}
}else{
pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
}
pList = sqlite3ExprListAppend(pParse, pList, pNew);
sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
@@ -1369,7 +1372,8 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
assert( db==0 || IsVirtual(pTab)
|| sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
/* Remove the FK from the fkeyHash hash table. */
+84 -43
View File
@@ -208,6 +208,8 @@ static void instrFunc(
zHaystack = sqlite3_value_text(argv[0]);
zNeedle = sqlite3_value_text(argv[1]);
isText = 1;
if( zNeedle==0 ) return;
assert( zHaystack );
}
while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
N++;
@@ -740,7 +742,7 @@ static int patternCompare(
}
c2 = Utf8Read(zString);
if( c==c2 ) continue;
if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){
continue;
}
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
@@ -1316,6 +1318,26 @@ static void trimFunc(
}
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
** When the "sqlite3" command-line shell is built using this functionality,
** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
** involving application-defined functions to be examined in a generic
** sqlite3 shell.
*/
static void unknownFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
/* no-op */
}
#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
/* IMP: R-25361-16150 This function is omitted from SQLite by default. It
** is only available if the SQLITE_SOUNDEX compile-time option is used
** when SQLite is built.
@@ -1386,6 +1408,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3 *db = sqlite3_context_db_handle(context);
char *zErrMsg = 0;
/* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc
** flag is set. See the sqlite3_enable_load_extension() API.
*/
if( (db->flags & SQLITE_LoadExtFunc)==0 ){
sqlite3_result_error(context, "not authorized", -1);
return;
}
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
}else{
@@ -1611,7 +1641,7 @@ static void groupConcatFinalize(sqlite3_context *context){
** of the built-in functions above are part of the global function set.
** This routine only deals with those that are not global.
*/
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
/* BEGIN SQLCIPHER */
#ifdef SQLITE_HAS_CODEC
@@ -1638,8 +1668,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
*/
static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef;
pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
2, SQLITE_UTF8, 0);
pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
if( ALWAYS(pDef) ){
pDef->funcFlags |= flagVal;
}
@@ -1687,9 +1716,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pDef = sqlite3FindFunction(db, pExpr->u.zToken,
sqlite3Strlen30(pExpr->u.zToken),
2, SQLITE_UTF8, 0);
pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -1713,7 +1740,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
**
** After this routine runs
*/
void sqlite3RegisterGlobalFunctions(void){
void sqlite3RegisterBuiltinFunctions(void){
/*
** The following array holds FuncDef structures for all of the functions
** defined in this file.
@@ -1721,8 +1748,27 @@ void sqlite3RegisterGlobalFunctions(void){
** The array cannot be constant since changes are made to the
** FuncDef.pHash elements at start-time. The elements of this array
** are read-only after initialization is complete.
**
** For peak efficiency, put the most frequently used function last.
*/
static SQLITE_WSD FuncDef aBuiltinFunc[] = {
static FuncDef aBuiltinFunc[] = {
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
VFUNCTION(load_extension, 1, 0, 0, loadExt ),
VFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@@ -1740,8 +1786,6 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
@@ -1752,40 +1796,22 @@ void sqlite3RegisterGlobalFunctions(void){
#endif
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
VFUNCTION(load_extension, 1, 0, 0, loadExt ),
VFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
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 ),
@@ -1796,27 +1822,42 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
#ifdef SQLITE_CASE_SENSITIVE_LIKE
LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#else
#else
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
#endif
#endif
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
FUNCTION(unknown, -1, 0, 0, unknownFunc ),
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
for(i=0; i<ArraySize(aBuiltinFunc); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
sqlite3RegisterDateTimeFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
#if 0 /* Enable to print out how the built-in functions are hashed */
{
int i;
FuncDef *p;
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
printf("FUNC-HASH %02d:", i);
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
int n = sqlite3Strlen30(p->zName);
int h = p->zName[0] + n;
printf(" %s(%d)", p->zName, h);
}
printf("\n");
}
}
#endif
}
+23 -11
View File
@@ -70,6 +70,7 @@ const unsigned char sqlite3UpperToLower[] = {
** isxdigit() 0x08
** toupper() 0x20
** SQLite identifier character 0x40
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
** case. i.e. if the character is a lower-case ASCII character.
@@ -78,16 +79,13 @@ const unsigned char sqlite3UpperToLower[] = {
**
** (x & ~(map[x]&0x20))
**
** Standard function tolower() is implemented using the sqlite3UpperToLower[]
** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
** array. tolower() is used more often than toupper() by SQLite.
**
** Bit 0x40 is set if the character non-alphanumeric and can be used in an
** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
**
** SQLite's versions are identical to the standard versions assuming a
** locale of "C". They are implemented as macros in sqliteInt.h.
*/
#ifdef SQLITE_ASCII
const unsigned char sqlite3CtypeMap[256] = {
@@ -95,7 +93,7 @@ const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
@@ -103,8 +101,8 @@ const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
@@ -159,6 +157,18 @@ const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_SORTER_PMASZ 250
#endif
/* Statement journals spill to disk when their size exceeds the following
** threshold (in bytes). 0 means that statement journals are created and
** written to disk immediately (the default behavior for SQLite versions
** before 3.12.0). -1 means always keep the entire statement journal in
** memory. (The statement journal is also always held entirely in memory
** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
** setting.)
*/
#ifndef SQLITE_STMTJRNL_SPILL
# define SQLITE_STMTJRNL_SPILL (64*1024)
#endif
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -173,6 +183,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* neverCorrupt */
128, /* szLookaside */
500, /* nLookaside */
SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
@@ -211,7 +222,8 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
#ifndef SQLITE_OMIT_BUILTIN_TEST
0, /* xTestCallback */
#endif
0 /* bLocaltimeFault */
0, /* bLocaltimeFault */
0x7ffffffe /* iOnceResetThreshold */
};
/*
@@ -219,7 +231,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
** database connections. After initialization, this table is
** read-only.
*/
SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
FuncDefHash sqlite3BuiltinFunctions;
/*
** Constant tokens for values 0 and 1.
@@ -234,7 +246,7 @@ const Token sqlite3IntTokens[] = {
** The value of the "pending" byte must be 0x40000000 (1 byte past the
** 1-gibabyte boundary) in a compatible database. SQLite never uses
** the database page that contains the pending byte. It never attempts
** to read or write that page. The pending byte page is set assign
** to read or write that page. The pending byte page is set aside
** for use by the VFS layers as space for managing file locks.
**
** During testing, it is often desirable to move the pending byte to
+7 -3
View File
@@ -55,8 +55,12 @@ void sqlite3HashClear(Hash *pH){
static unsigned int strHash(const char *z){
unsigned int h = 0;
unsigned char c;
while( (c = (unsigned char)*z++)!=0 ){
h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
** 0x9e3779b1 is 2654435761 which is the closest prime number to
** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
h += sqlite3UpperToLower[c];
h *= 0x9e3779b1;
}
return h;
}
@@ -148,7 +152,7 @@ static HashElem *findElementWithHash(
int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
if( pH->ht ){
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
h = strHash(pKey) % pH->htsize;
pEntry = &pH->ht[h];
+3 -3
View File
@@ -12,8 +12,8 @@
** This is the header file for the generic hash-table implementation
** used in SQLite.
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_
#ifndef SQLITE_HASH_H
#define SQLITE_HASH_H
/* Forward declarations of structures. */
typedef struct Hash Hash;
@@ -93,4 +93,4 @@ void sqlite3HashClear(Hash*);
*/
/* #define sqliteHashCount(H) ((H)->count) // NOT USED */
#endif /* _SQLITE_HASH_H_ */
#endif /* SQLITE_HASH_H */
+3 -3
View File
@@ -13,8 +13,8 @@
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
#ifndef _HWTIME_H_
#define _HWTIME_H_
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
/*
** The following routine only works on pentium-class (or newer) processors.
@@ -82,4 +82,4 @@
#endif
#endif /* !defined(_HWTIME_H_) */
#endif /* !defined(SQLITE_HWTIME_H) */
+107
View File
@@ -0,0 +1,107 @@
IN-Operator Implementation Notes
================================
## Definitions:
An IN operator has one of the following formats:
>
x IN (y1,y2,y3,...,yN)
x IN (subquery)
The "x" is referred to as the LHS (left-hand side). The list or subquery
on the right is called the RHS (right-hand side). If the RHS is a list
it must be a non-empty list. But if the RHS is a subquery, it can be an
empty set.
The LHS can be a scalar (a single quantity) or a vector (a list of
two or or more values) or a subquery that returns one or more columns.
We use the term "vector" to mean an actually list of values or a
subquery that returns two or more columns. An isolated value or
a subquery that returns a single columns is called a scalar.
The RHS can be a subquery that returns a single column, a subquery
that returns two or more columns, or a list of scalars. It is not
currently support for the RHS to be a list of vectors.
The number of columns for LHS must match the number of columns for
the RHS. If the RHS is a list of values, then the LHS must be a
scalar. If the RHS is a subquery returning N columns, then the LHS
must be a vector of size N.
NULL values can occur in either or both of the LHS and RHS.
If the LHS contains only
NULL values then we say that it is a "total-NULL". If the LHS contains
some NULL values and some non-NULL values, then it is a "partial-NULL".
For a scalar, there is no difference between a partial-NULL and a total-NULL.
The RHS is a partial-NULL if any row contains a NULL value. The RHS is
a total-NULL if it contains one or more rows that contain only NULL values.
The LHS is called "non-NULL" if it contains no NULL values. The RHS is
called "non-NULL" if it contains no NULL values in any row.
The result of an IN operator is one of TRUE, FALSE, or NULL. A NULL result
means that it cannot be determined if the LHS is contained in the RHS due
to the presence of NULL values. In some contexts (for example, when the IN
operator occurs in a WHERE clause)
the system only needs a binary result: TRUE or NOT-TRUE. One can also
to define a binary result of FALSE and NOT-FALSE, but
it turns out that no extra optimizations are possible in that case, so if
the FALSE/NOT-FALSE binary is needed, we have to compute the three-state
TRUE/FALSE/NULL result and then combine the TRUE and NULL values into
NOT-FALSE.
A "NOT IN" operator is computed by first computing the equivalent IN
operator, then interchanging the TRUE and FALSE results.
## Simple Full-Scan Algorithm
The following algorithm always compute the correct answer. However, this
algorithm is suboptimal, especially if there are many rows on the RHS.
1. Set the null-flag to false
2. For each row in the RHS:
<ol type='a'>
<li> Compare the LHS against the RHS
<li> If the LHS exactly matches the RHS, immediately return TRUE
<li> If the comparison result is NULL, set the null-flag to true
</ol>
3. If the null-flag is true, return NULL.
4. Return FALSE
## Optimized Algorithm
The following procedure computes the same answer as the simple full-scan
algorithm, though it does so with less work in the common case. This
is the algorithm that is implemented in SQLite.
1. If the RHS is a constant list of length 1 or 2, then rewrite the
IN operator as a simple expression. Implement
x IN (y1,y2)
as if it were
x=y1 OR x=y2
This is the INDEX_NOOP optimization and is only undertaken if the
IN operator is used for membership testing. If the IN operator is
driving a loop, then skip this step entirely.
2. Check the LHS to see if it is a partial-NULL and if it is, jump
ahead to step 5.
3. Do a binary search of the RHS using the LHS as a probe. If
an exact match is found, return TRUE.
4. If the RHS is non-NULL then return FALSE.
5. If we do not need to distinguish between FALSE and NULL,
then return FALSE.
6. For each row in the RHS, compare that row against the LHS and
if the result is NULL, immediately return NULL. In the case
of a scalar IN operator, we only need to look at the very first
row the RHS because for a scalar RHS, all NULLs will always come
first. If the RHS is empty, this step is a no-op.
7. Return FALSE.
+36 -21
View File
@@ -200,7 +200,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
/*
** Locate or create an AutoincInfo structure associated with table pTab
** which is in database iDb. Return the register number for the register
** that holds the maximum rowid.
** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT
** table. (Also return zero when doing a VACUUM since we do not want to
** update the AUTOINCREMENT counters during a VACUUM.)
**
** There is at most one AutoincInfo structure per table even if the
** same table is autoincremented multiple times due to inserts within
@@ -223,7 +225,9 @@ static int autoIncBegin(
Table *pTab /* The table we are writing to */
){
int memId = 0; /* Register holding maximum rowid */
if( pTab->tabFlags & TF_Autoincrement ){
if( (pTab->tabFlags & TF_Autoincrement)!=0
&& (pParse->db->flags & SQLITE_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
@@ -481,7 +485,6 @@ void sqlite3Insert(
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 */
const char *zDb; /* Name of the database holding this table */
int i, j, idx; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
@@ -496,7 +499,6 @@ void sqlite3Insert(
int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
SelectDest dest; /* Destination for SELECT on rhs of INSERT */
int iDb; /* Index of database holding TABLE */
Db *pDb; /* The database containing table being inserted into */
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
u8 appendFlag = 0; /* True if the insert is likely to be an append */
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
@@ -546,9 +548,8 @@ void sqlite3Insert(
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
pDb = &db->aDb[iDb];
zDb = pDb->zName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
db->aDb[iDb].zDbSName) ){
goto insert_cleanup;
}
withoutRowid = !HasRowid(pTab);
@@ -1431,9 +1432,18 @@ void sqlite3GenerateConstraintChecks(
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regNewData, 1, 0, OE_Replace,
ONEPASS_SINGLE, -1);
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);
sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
if( pTab->pIndex ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
@@ -1703,7 +1713,7 @@ void sqlite3CompleteInsertion(
}
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
if( !pParse->nested ){
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
@@ -1768,15 +1778,15 @@ int sqlite3OpenTableAndIndices(
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
if( piDataCur ) *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
}
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
if( piDataCur ) *piDataCur = iIdxCur;
}else{
sqlite3VdbeChangeP5(v, p5);
VdbeComment((v, "%s", pIdx->zName));
}
}
if( iBase>pParse->nTab ) pParse->nTab = iBase;
@@ -1999,11 +2009,15 @@ static int xferOptimization(
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
if( i>0
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
){
return 0; /* Default values must be the same for all columns */
if( i>0 ){
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|| (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
pSrcCol->pDflt->u.zToken)!=0)
){
return 0; /* Default values must be the same for all columns */
}
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
@@ -2099,7 +2113,7 @@ static int xferOptimization(
}
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
pDest->zName, 0);
(char*)pDest, P4_TABLE);
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
@@ -2163,6 +2177,7 @@ static int xferOptimization(
sqlite3ReleaseTempReg(pParse, regRowid);
sqlite3ReleaseTempReg(pParse, regData);
if( emptyDestTest ){
sqlite3AutoincrementEnd(pParse);
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
sqlite3VdbeJumpHere(v, emptyDestTest);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
-256
View File
@@ -1,256 +0,0 @@
/*
** 2007 August 22
**
** 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 a special kind of sqlite3_file object used
** by SQLite to create journal files if the atomic-write optimization
** is enabled.
**
** The distinctive characteristic of this sqlite3_file is that the
** actual on disk file is created lazily. When the file is created,
** the caller specifies a buffer size for an in-memory buffer to
** be used to service read() and write() requests. The actual file
** on disk is not created or populated until either:
**
** 1) The in-memory representation grows too large for the allocated
** buffer, or
** 2) The sqlite3JournalCreate() function is called.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#include "sqliteInt.h"
/*
** A JournalFile object is a subclass of sqlite3_file used by
** as an open file handle for journal files.
*/
struct JournalFile {
sqlite3_io_methods *pMethod; /* I/O methods on journal files */
int nBuf; /* Size of zBuf[] in bytes */
char *zBuf; /* Space to buffer journal writes */
int iSize; /* Amount of zBuf[] currently used */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
sqlite3_file *pReal; /* The "real" underlying file descriptor */
const char *zJournal; /* Name of the journal file */
};
typedef struct JournalFile JournalFile;
/*
** If it does not already exists, create and populate the on-disk file
** for JournalFile p.
*/
static int createFile(JournalFile *p){
int rc = SQLITE_OK;
if( !p->pReal ){
sqlite3_file *pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
if( rc==SQLITE_OK ){
p->pReal = pReal;
if( p->iSize>0 ){
assert(p->iSize<=p->nBuf);
rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
}
if( rc!=SQLITE_OK ){
/* If an error occurred while writing to the file, close it before
** returning. This way, SQLite uses the in-memory journal data to
** roll back changes made to the internal page-cache before this
** function was called. */
sqlite3OsClose(pReal);
p->pReal = 0;
}
}
}
return rc;
}
/*
** Close the file.
*/
static int jrnlClose(sqlite3_file *pJfd){
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
sqlite3OsClose(p->pReal);
}
sqlite3_free(p->zBuf);
return SQLITE_OK;
}
/*
** Read data from the file.
*/
static int jrnlRead(
sqlite3_file *pJfd, /* The journal file from which to read */
void *zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite_int64 iOfst /* Begin reading at this offset */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}else if( (iAmt+iOfst)>p->iSize ){
rc = SQLITE_IOERR_SHORT_READ;
}else{
memcpy(zBuf, &p->zBuf[iOfst], iAmt);
}
return rc;
}
/*
** Write data to the file.
*/
static int jrnlWrite(
sqlite3_file *pJfd, /* The journal file into which to write */
const void *zBuf, /* Take data to be written from here */
int iAmt, /* Number of bytes to write */
sqlite_int64 iOfst /* Begin writing at this offset into the file */
){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
rc = createFile(p);
}
if( rc==SQLITE_OK ){
if( p->pReal ){
rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}else{
memcpy(&p->zBuf[iOfst], zBuf, iAmt);
if( p->iSize<(iOfst+iAmt) ){
p->iSize = (iOfst+iAmt);
}
}
}
return rc;
}
/*
** Truncate the file.
*/
static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsTruncate(p->pReal, size);
}else if( size<p->iSize ){
p->iSize = size;
}
return rc;
}
/*
** Sync the file.
*/
static int jrnlSync(sqlite3_file *pJfd, int flags){
int rc;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsSync(p->pReal, flags);
}else{
rc = SQLITE_OK;
}
return rc;
}
/*
** Query the size of the file in bytes.
*/
static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
int rc = SQLITE_OK;
JournalFile *p = (JournalFile *)pJfd;
if( p->pReal ){
rc = sqlite3OsFileSize(p->pReal, pSize);
}else{
*pSize = (sqlite_int64) p->iSize;
}
return rc;
}
/*
** Table of methods for JournalFile sqlite3_file object.
*/
static struct sqlite3_io_methods JournalFileMethods = {
1, /* iVersion */
jrnlClose, /* xClose */
jrnlRead, /* xRead */
jrnlWrite, /* xWrite */
jrnlTruncate, /* xTruncate */
jrnlSync, /* xSync */
jrnlFileSize, /* xFileSize */
0, /* xLock */
0, /* xUnlock */
0, /* xCheckReservedLock */
0, /* xFileControl */
0, /* xSectorSize */
0, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0 /* xShmUnmap */
};
/*
** Open a journal file.
*/
int sqlite3JournalOpen(
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nBuf /* Bytes buffered before opening the file */
){
JournalFile *p = (JournalFile *)pJfd;
memset(p, 0, sqlite3JournalSize(pVfs));
if( nBuf>0 ){
p->zBuf = sqlite3MallocZero(nBuf);
if( !p->zBuf ){
return SQLITE_NOMEM;
}
}else{
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
p->pMethod = &JournalFileMethods;
p->nBuf = nBuf;
p->flags = flags;
p->zJournal = zName;
p->pVfs = pVfs;
return SQLITE_OK;
}
/*
** If the argument p points to a JournalFile structure, and the underlying
** file has not yet been created, create it now.
*/
int sqlite3JournalCreate(sqlite3_file *p){
if( p->pMethods!=&JournalFileMethods ){
return SQLITE_OK;
}
return createFile((JournalFile *)p);
}
/*
** The file-handle passed as the only argument is guaranteed to be an open
** file. It may or may not be of class JournalFile. If the file is a
** JournalFile, and the underlying file on disk has not yet been opened,
** return 0. Otherwise, return 1.
*/
int sqlite3JournalExists(sqlite3_file *p){
return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
}
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
*/
int sqlite3JournalSize(sqlite3_vfs *pVfs){
return (pVfs->szOsFile+sizeof(JournalFile));
}
#endif
+1 -1
View File
@@ -131,7 +131,7 @@ exec_out:
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
+42 -35
View File
@@ -21,7 +21,6 @@
#include <string.h>
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Some API routines are omitted when various features are
** excluded from a build of SQLite. Substitute a NULL pointer
@@ -91,7 +90,7 @@
# define sqlite3_enable_shared_cache 0
#endif
#ifdef SQLITE_OMIT_TRACE
#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
# define sqlite3_profile 0
# define sqlite3_trace 0
#endif
@@ -111,6 +110,10 @@
#define sqlite3_blob_reopen 0
#endif
#if defined(SQLITE_OMIT_TRACE)
# define sqlite3_trace_v2 0
#endif
/*
** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are
@@ -414,7 +417,12 @@ static const sqlite3_api_routines sqlite3Apis = {
/* Version 3.10.0 and later */
sqlite3_status64,
sqlite3_strlike,
sqlite3_db_cacheflush
sqlite3_db_cacheflush,
/* Version 3.12.0 and later */
sqlite3_system_errno,
/* Version 3.14.0 and later */
sqlite3_trace_v2,
sqlite3_expanded_sql
};
/*
@@ -437,13 +445,14 @@ static int sqlite3LoadExtension(
){
sqlite3_vfs *pVfs = db->pVfs;
void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
sqlite3_loadext_entry xInit;
char *zErrmsg = 0;
const char *zEntry;
char *zAltEntry = 0;
void **aHandle;
u64 nMsg = 300 + sqlite3Strlen30(zFile);
int ii;
int rc;
/* Shared library endings to try if zFile cannot be loaded as written */
static const char *azEndings[] = {
@@ -462,8 +471,9 @@ static int sqlite3LoadExtension(
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
** ability to run load_extension is turned off by default. One
** must call sqlite3_enable_load_extension() to turn on extension
** loading. Otherwise you get the following error.
** must call either sqlite3_enable_load_extension(db) or
** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0)
** to turn on extension loading.
*/
if( (db->flags & SQLITE_LoadExtension)==0 ){
if( pzErrMsg ){
@@ -478,7 +488,7 @@ static int sqlite3LoadExtension(
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM;
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
@@ -494,8 +504,7 @@ static int sqlite3LoadExtension(
}
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlSym(pVfs, handle, zEntry);
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
/* If no entry point was specified and the default legacy
** entry point name "sqlite3_extension_init" was not found, then
@@ -514,7 +523,7 @@ static int sqlite3LoadExtension(
zAltEntry = sqlite3_malloc64(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memcpy(zAltEntry, "sqlite3_", 8);
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
@@ -527,8 +536,7 @@ static int sqlite3LoadExtension(
}
memcpy(zAltEntry+iEntry, "_init", 6);
zEntry = zAltEntry;
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
sqlite3OsDlSym(pVfs, handle, zEntry);
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
}
if( xInit==0 ){
if( pzErrMsg ){
@@ -545,7 +553,9 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
sqlite3_free(zAltEntry);
if( xInit(db, &zErrmsg, &sqlite3Apis) ){
rc = xInit(db, &zErrmsg, &sqlite3Apis);
if( rc ){
if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK;
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
@@ -557,7 +567,7 @@ static int sqlite3LoadExtension(
/* Append the new shared library handle to the db->aExtension array. */
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
if( aHandle==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
@@ -602,26 +612,15 @@ void sqlite3CloseExtensions(sqlite3 *db){
int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension;
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
}else{
db->flags &= ~SQLITE_LoadExtension;
db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
}
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
/*
** The auto-extension code added regardless of whether or not extension
** loading is supported. We need a dummy sqlite3Apis pointer for that
** code if regular extension loading is not available. This is that
** dummy pointer.
*/
#ifdef SQLITE_OMIT_LOAD_EXTENSION
static const sqlite3_api_routines sqlite3Apis = { 0 };
#endif
#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */
/*
** The following object holds the list of automatically loaded
@@ -656,7 +655,9 @@ static SQLITE_WSD struct sqlite3AutoExtList {
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
int sqlite3_auto_extension(void (*xInit)(void)){
int sqlite3_auto_extension(
void (*xInit)(void)
){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -679,7 +680,7 @@ int sqlite3_auto_extension(void (*xInit)(void)){
void (**aNew)(void);
aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else{
wsdAutoext.aExt = aNew;
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
@@ -701,7 +702,9 @@ int sqlite3_auto_extension(void (*xInit)(void)){
** Return 1 if xInit was found on the list and removed. Return 0 if xInit
** was not on the list.
*/
int sqlite3_cancel_auto_extension(void (*xInit)(void)){
int sqlite3_cancel_auto_extension(
void (*xInit)(void)
){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -750,7 +753,7 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
u32 i;
int go = 1;
int rc;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
sqlite3_loadext_entry xInit;
wsdAutoextInit;
if( wsdAutoext.nExt==0 ){
@@ -761,18 +764,22 @@ void sqlite3AutoLoadExtensions(sqlite3 *db){
char *zErrmsg;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
const sqlite3_api_routines *pThunk = 0;
#else
const sqlite3_api_routines *pThunk = &sqlite3Apis;
#endif
sqlite3_mutex_enter(mutex);
if( i>=wsdAutoext.nExt ){
xInit = 0;
go = 0;
}else{
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
wsdAutoext.aExt[i];
xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i];
}
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){
sqlite3ErrorWithMsg(db, rc,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
+152 -67
View File
@@ -187,7 +187,7 @@ int sqlite3_initialize(void){
sqlite3GlobalConfig.pInitMutex =
sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
}
}
@@ -218,7 +218,6 @@ int sqlite3_initialize(void){
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
sqlite3GlobalConfig.inProgress = 1;
#ifdef SQLITE_ENABLE_SQLLOG
{
@@ -226,8 +225,8 @@ int sqlite3_initialize(void){
sqlite3_init_sqllog();
}
#endif
memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
sqlite3RegisterGlobalFunctions();
memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
sqlite3RegisterBuiltinFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
@@ -634,6 +633,11 @@ int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_STMTJRNL_SPILL: {
sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
break;
}
default: {
rc = SQLITE_ERROR;
break;
@@ -785,6 +789,11 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
int rc;
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
db->aDb[0].zDbSName = va_arg(ap,char*);
rc = SQLITE_OK;
break;
}
case SQLITE_DBCONFIG_LOOKASIDE: {
void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
int sz = va_arg(ap, int); /* IMP: R-47871-25994 */
@@ -797,8 +806,10 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
int op; /* The opcode */
u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -958,7 +969,7 @@ void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding.
*/
static void functionDestroy(sqlite3 *db, FuncDef *p){
FuncDestructor *pDestructor = p->pDestructor;
FuncDestructor *pDestructor = p->u.pDestructor;
if( pDestructor ){
pDestructor->nRef--;
if( pDestructor->nRef==0 ){
@@ -1027,6 +1038,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
if( db->mTrace & SQLITE_TRACE_CLOSE ){
db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
}
/* Force xDisconnect calls on all virtual tables */
disconnectAllVtab(db);
@@ -1140,18 +1154,17 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
*/
sqlite3ConnectionClosed(db);
for(j=0; j<ArraySize(db->aFunc.a); j++){
FuncDef *pNext, *pHash, *p;
for(p=db->aFunc.a[j]; p; p=pHash){
pHash = p->pHash;
while( p ){
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}
}
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
FuncDef *pNext, *p;
p = sqliteHashData(i);
do{
functionDestroy(db, p);
pNext = p->pNext;
sqlite3DbFree(db, p);
p = pNext;
}while( p );
}
sqlite3HashClear(&db->aFunc);
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* Invoke any destructors registered for collation sequence user data. */
@@ -1630,7 +1643,7 @@ int sqlite3CreateFunc(
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
@@ -1642,10 +1655,10 @@ int sqlite3CreateFunc(
}
}
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
assert(p || db->mallocFailed);
if( !p ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
/* If an older version of the function with a configured destructor is
@@ -1655,7 +1668,7 @@ int sqlite3CreateFunc(
if( pDestructor ){
pDestructor->nRef++;
}
p->pDestructor = pDestructor;
p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xSFunc = xSFunc ? xSFunc : xStep;
@@ -1770,7 +1783,6 @@ int sqlite3_overload_function(
const char *zName,
int nArg
){
int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -1779,7 +1791,7 @@ int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
@@ -1797,7 +1809,8 @@ int sqlite3_overload_function(
** trace is a pointer to a function that is invoked at the start of each
** SQL statement.
*/
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
#ifndef SQLITE_OMIT_DEPRECATED
void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -1808,11 +1821,38 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->xTrace = xTrace;
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
}
#endif /* SQLITE_OMIT_DEPRECATED */
/* Register a trace callback using the version-2 interface.
*/
int sqlite3_trace_v2(
sqlite3 *db, /* Trace this connection */
unsigned mTrace, /* Mask of events to be traced */
int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */
void *pArg /* Context */
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( mTrace==0 ) xTrace = 0;
if( xTrace==0 ) mTrace = 0;
db->mTrace = mTrace;
db->xTrace = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_DEPRECATED
/*
** Register a profile function. The pArg from the previously registered
** profile function is returned.
@@ -1841,6 +1881,7 @@ void *sqlite3_profile(
sqlite3_mutex_leave(db->mutex);
return pOld;
}
#endif /* SQLITE_OMIT_DEPRECATED */
#endif /* SQLITE_OMIT_TRACE */
/*
@@ -1919,6 +1960,27 @@ void *sqlite3_rollback_hook(
return pRet;
}
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
** Register a callback to be invoked each time a row is updated,
** inserted or deleted using this database connection.
*/
void *sqlite3_preupdate_hook(
sqlite3 *db, /* Attach the hook to this database */
void(*xCallback)( /* Callback function */
void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
void *pArg /* First callback argument */
){
void *pRet;
sqlite3_mutex_enter(db->mutex);
pRet = db->pPreUpdateArg;
db->xPreUpdateCallback = xCallback;
db->pPreUpdateArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pRet;
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifndef SQLITE_OMIT_WAL
/*
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
@@ -2149,14 +2211,14 @@ int sqlite3TempInMemory(const sqlite3 *db){
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
}
sqlite3_mutex_enter(db->mutex);
if( db->mallocFailed ){
z = sqlite3ErrStr(SQLITE_NOMEM);
z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}else{
testcase( db->pErr==0 );
z = (char*)sqlite3_value_text(db->pErr);
@@ -2224,7 +2286,7 @@ int sqlite3_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
return db->errCode & db->errMask;
}
@@ -2233,10 +2295,13 @@ int sqlite3_extended_errcode(sqlite3 *db){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
return db->errCode;
}
int sqlite3_system_errno(sqlite3 *db){
return db ? db->iSysErrno : 0;
}
/*
** Return a string that describes the kind of error specified in the
@@ -2313,7 +2378,7 @@ static int createCollation(
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
if( pColl==0 ) return SQLITE_NOMEM;
if( pColl==0 ) return SQLITE_NOMEM_BKPT;
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
pColl->xDel = xDel;
@@ -2361,8 +2426,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@@ -2492,7 +2557,7 @@ int sqlite3ParseUri(
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
zFile = sqlite3_malloc64(nByte);
if( !zFile ) return SQLITE_NOMEM;
if( !zFile ) return SQLITE_NOMEM_BKPT;
iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
@@ -2658,7 +2723,7 @@ int sqlite3ParseUri(
}else{
zFile = sqlite3_malloc64(nUri+2);
if( !zFile ) return SQLITE_NOMEM;
if( !zFile ) return SQLITE_NOMEM_BKPT;
memcpy(zFile, zUri, nUri);
zFile[nUri] = '\0';
zFile[nUri+1] = '\0';
@@ -2814,6 +2879,9 @@ static int openDatabase(
#endif
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
| SQLITE_CellSizeCk
#endif
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
| SQLITE_Fts3Tokenizer
#endif
;
sqlite3HashInit(&db->aCollSeq);
@@ -2857,7 +2925,7 @@ static int openDatabase(
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
sqlite3Error(db, rc);
goto opendb_out;
@@ -2868,13 +2936,13 @@ static int openDatabase(
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is 'full'; for the temp
** database it is 'NONE'. This matches the pager layer defaults.
/* The default safety_level for the main database is FULL; for the temp
** database it is OFF. This matches the pager layer defaults.
*/
db->aDb[0].zName = "main";
db->aDb[0].safety_level = 3;
db->aDb[1].zName = "temp";
db->aDb[1].safety_level = 1;
db->aDb[0].zDbSName = "main";
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
db->aDb[1].zDbSName = "temp";
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
@@ -2886,12 +2954,21 @@ static int openDatabase(
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
sqlite3RegisterBuiltinFunctions(db);
sqlite3RegisterPerConnectionBuiltinFunctions(db);
rc = sqlite3_errcode(db);
#ifdef SQLITE_ENABLE_FTS5
/* Register any built-in FTS5 module before loading the automatic
** extensions. This allows automatic extensions to register FTS5
** tokenizers and auxiliary functions. */
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts5Init(db);
}
#endif
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
rc = sqlite3_errcode(db);
if( rc==SQLITE_OK ){
sqlite3AutoLoadExtensions(db);
rc = sqlite3_errcode(db);
@@ -2920,12 +2997,6 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_FTS5
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3Fts5Init(db);
}
#endif
#ifdef SQLITE_ENABLE_ICU
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
@@ -3060,7 +3131,7 @@ int sqlite3_open16(
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
sqlite3ValueFree(pVal);
@@ -3205,7 +3276,7 @@ int sqlite3_get_autocommit(sqlite3 *db){
/*
** The following routines are substitutes for constants SQLITE_CORRUPT,
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
** constants. They serve two purposes:
**
** 1. Serve as a convenient place to set a breakpoint in a debugger
@@ -3214,28 +3285,33 @@ 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){
sqlite3_log(iErr, "%s at line %d of [%.10s]",
zType, lineno, 20+sqlite3_sourceid());
return iErr;
}
int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_CORRUPT,
"database corruption at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_CORRUPT;
return reportError(SQLITE_CORRUPT, lineno, "database corruption");
}
int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_MISUSE,
"misuse at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_MISUSE;
return reportError(SQLITE_MISUSE, lineno, "misuse");
}
int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_CANTOPEN,
"cannot open file at line %d of [%.10s]",
lineno, 20+sqlite3_sourceid());
return SQLITE_CANTOPEN;
return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
}
#ifdef SQLITE_DEBUG
int sqlite3NomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_NOMEM, lineno, "OOM");
}
int sqlite3IoerrnomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
}
#endif
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -3329,7 +3405,7 @@ int sqlite3_table_column_metadata(
** explicitly declared column. Copy meta information from *pCol.
*/
if( pCol ){
zDataType = pCol->zType;
zDataType = sqlite3ColumnType(pCol,0);
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
@@ -3708,6 +3784,15 @@ int sqlite3_test_control(int op, ...){
break;
}
/* Set the threshold at which OP_Once counters reset back to zero.
** By default this is 0x7ffffffe (over 2 billion), but that value is
** too big to test in a reasonable amount of time, so this control is
** provided to set a small and easily reachable reset value.
*/
case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
**
@@ -3829,7 +3914,7 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
int i;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt
&& (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
&& (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zDbSName)==0)
){
return db->aDb[i].pBt;
}
+1 -1
View File
@@ -795,7 +795,7 @@ void sqlite3OomClear(sqlite3 *db){
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
sqlite3OomClear(db);
sqlite3Error(db, SQLITE_NOMEM);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
/*
+245 -82
View File
@@ -13,6 +13,15 @@
** This file contains code use to implement an in-memory rollback journal.
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
**
** Update: The in-memory journal is also used to temporarily cache
** smaller journals that are not critical for power-loss recovery.
** For example, statement journals that are not too big will be held
** entirely in memory, thus reducing the number of file I/O calls, and
** more importantly, reducing temporary file creation events. If these
** journals become too large for memory, they are spilled to disk. But
** in the common case, they are usually small and no file I/O needs to
** occur.
*/
#include "sqliteInt.h"
@@ -21,24 +30,28 @@ typedef struct MemJournal MemJournal;
typedef struct FilePoint FilePoint;
typedef struct FileChunk FileChunk;
/* Space to hold the rollback journal is allocated in increments of
** this many bytes.
**
** The size chosen is a little less than a power of two. That way,
** the FileChunk object will have a size that almost exactly fills
** a power-of-two allocation. This minimizes wasted space in power-of-two
** memory allocators.
*/
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
/*
** The rollback journal is composed of a linked list of these structures.
**
** The zChunk array is always at least 8 bytes in size - usually much more.
** Its actual size is stored in the MemJournal.nChunkSize variable.
*/
struct FileChunk {
FileChunk *pNext; /* Next chunk in the journal */
u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
u8 zChunk[8]; /* Content of this chunk */
};
/*
** By default, allocate this many bytes of memory for each FileChunk object.
*/
#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
/*
** For chunk size nChunkSize, return the number of bytes that should
** be allocated for each FileChunk structure.
*/
#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
@@ -49,14 +62,22 @@ struct FilePoint {
};
/*
** This subclass is a subclass of sqlite3_file. Each open memory-journal
** This structure is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
int nChunkSize; /* In-memory chunk-size */
int nSpill; /* Bytes of data before flushing */
int nSize; /* Bytes of data currently in memory */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
int flags; /* xOpen flags */
sqlite3_vfs *pVfs; /* The "real" underlying VFS */
const char *zJournal; /* Name of the journal file */
};
/*
@@ -75,36 +96,94 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
/* SQLite never tries to read past the end of a rollback journal file */
assert( iOfst+iAmt<=p->endpoint.iOffset );
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
#endif
assert( (iAmt+iOfst)<=p->endpoint.iOffset );
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
pChunk=pChunk->pNext
){
iOff += JOURNAL_CHUNKSIZE;
iOff += p->nChunkSize;
}
}else{
pChunk = p->readpoint.pChunk;
assert( pChunk!=0 );
}
iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
iChunkOffset = (int)(iOfst%p->nChunkSize);
do {
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
int iSpace = p->nChunkSize - iChunkOffset;
int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
p->readpoint.iOffset = iOfst+iAmt;
p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
p->readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
** Free the list of FileChunk structures headed at MemJournal.pFirst.
*/
static void memjrnlFreeChunks(MemJournal *p){
FileChunk *pIter;
FileChunk *pNext;
for(pIter=p->pFirst; pIter; pIter=pNext){
pNext = pIter->pNext;
sqlite3_free(pIter);
}
p->pFirst = 0;
}
/*
** Flush the contents of memory to a real file on disk.
*/
static int memjrnlCreateFile(MemJournal *p){
int rc;
sqlite3_file *pReal = (sqlite3_file*)p;
MemJournal copy = *p;
memset(p, 0, sizeof(MemJournal));
rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
if( rc==SQLITE_OK ){
int nChunk = copy.nChunkSize;
i64 iOff = 0;
FileChunk *pIter;
for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
if( iOff + nChunk > copy.endpoint.iOffset ){
nChunk = copy.endpoint.iOffset - iOff;
}
rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
if( rc ) break;
iOff += nChunk;
}
if( rc==SQLITE_OK ){
/* No error has occurred. Free the in-memory buffers. */
memjrnlFreeChunks(&copy);
}
}
if( rc!=SQLITE_OK ){
/* If an error occurred while creating or writing to the file, restore
** the original before returning. This way, SQLite uses the in-memory
** journal data to roll back changes made to the internal page-cache
** before this function was called. */
sqlite3OsClose(pReal);
*p = copy;
}
return rc;
}
/*
** Write data to the file.
*/
@@ -118,38 +197,62 @@ static int memjrnlWrite(
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required by sqlite.
*/
assert( iOfst==p->endpoint.iOffset );
UNUSED_PARAMETER(iOfst);
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
if( !pNew ){
return SQLITE_IOERR_NOMEM;
}
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
p->endpoint.pChunk = pNew;
/* If the file should be created now, create it and write the new data
** into the file on disk. */
if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
int rc = memjrnlCreateFile(p);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
}
return rc;
}
memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
/* If the contents of this write should be stored in memory */
else{
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required. The only exception to this is when
** the in-memory journal is being used by a connection using the
** 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( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
}else
#else
assert( iOfst>0 || p->pFirst==0 );
#endif
{
while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
if( !pNew ){
return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->pNext = 0;
if( pChunk ){
assert( p->pFirst );
pChunk->pNext = pNew;
}else{
assert( !p->pFirst );
p->pFirst = pNew;
}
p->endpoint.pChunk = pNew;
}
memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
zWrite += iSpace;
nWrite -= iSpace;
p->endpoint.iOffset += iSpace;
}
p->nSize = iAmt + iOfst;
}
}
return SQLITE_OK;
@@ -157,19 +260,21 @@ static int memjrnlWrite(
/*
** Truncate the file.
**
** If the journal file is already on disk, truncate it there. Or, if it
** is still in main memory but is being truncated to zero bytes in size,
** ignore
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
FileChunk *pChunk;
assert(size==0);
UNUSED_PARAMETER(size);
pChunk = p->pFirst;
while( pChunk ){
FileChunk *pTmp = pChunk;
pChunk = pChunk->pNext;
sqlite3_free(pTmp);
if( ALWAYS(size==0) ){
memjrnlFreeChunks(p);
p->nSize = 0;
p->endpoint.pChunk = 0;
p->endpoint.iOffset = 0;
p->readpoint.pChunk = 0;
p->readpoint.iOffset = 0;
}
sqlite3MemJournalOpen(pJfd);
return SQLITE_OK;
}
@@ -177,21 +282,19 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
memjrnlTruncate(pJfd, 0);
MemJournal *p = (MemJournal *)pJfd;
memjrnlFreeChunks(p);
return SQLITE_OK;
}
/*
** Sync the file.
**
** Syncing an in-memory journal is a no-op. And, in fact, this routine
** is never called in a working implementation. This implementation
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
** If the real file has been created, call its xSync method. Otherwise,
** syncing an in-memory journal is a no-op.
*/
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
static int memjrnlSync(sqlite3_file *pJfd, int flags){
UNUSED_PARAMETER2(pJfd, flags);
return SQLITE_OK;
}
@@ -230,26 +333,86 @@ static const struct sqlite3_io_methods MemJournalMethods = {
};
/*
** Open a journal file.
** Open a journal file.
**
** The behaviour of the journal file depends on the value of parameter
** nSpill. If nSpill is 0, then the journal file is always create and
** accessed using the underlying VFS. If nSpill is less than zero, then
** all content is always stored in main-memory. Finally, if nSpill is a
** positive value, then the journal file is initially created in-memory
** but may be flushed to disk later on. In this case the journal file is
** flushed to disk either when it grows larger than nSpill bytes in size,
** or when sqlite3JournalCreate() is called.
*/
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
MemJournal *p = (MemJournal *)pJfd;
assert( EIGHT_BYTE_ALIGNMENT(p) );
memset(p, 0, sqlite3MemJournalSize());
p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
int sqlite3JournalOpen(
sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
const char *zName, /* Name of the journal file */
sqlite3_file *pJfd, /* Preallocated, blank file handle */
int flags, /* Opening flags */
int nSpill /* Bytes buffered before opening the file */
){
MemJournal *p = (MemJournal*)pJfd;
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
** made on the journal file-handle. */
memset(p, 0, sizeof(MemJournal));
if( nSpill==0 ){
return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
}
if( nSpill>0 ){
p->nChunkSize = nSpill;
}else{
p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
}
p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
p->nSpill = nSpill;
p->flags = flags;
p->zJournal = zName;
p->pVfs = pVfs;
return SQLITE_OK;
}
/*
** Return true if the file-handle passed as an argument is
** an in-memory journal
** Open an in-memory journal file.
*/
int sqlite3IsMemJournal(sqlite3_file *pJfd){
return pJfd->pMethods==&MemJournalMethods;
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
#ifdef SQLITE_ENABLE_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.
*/
int sqlite3JournalCreate(sqlite3_file *p){
int rc = SQLITE_OK;
if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
rc = memjrnlCreateFile((MemJournal*)p);
}
return rc;
}
#endif
/*
** The file-handle passed as the only argument is open on a journal file.
** Return true if this "journal file" is currently stored in heap memory,
** or false otherwise.
*/
int sqlite3JournalIsInMemory(sqlite3_file *p){
return p->pMethods==&MemJournalMethods;
}
/*
** Return the number of bytes required to store a MemJournal file descriptor.
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
*/
int sqlite3MemJournalSize(void){
return sizeof(MemJournal);
int sqlite3JournalSize(sqlite3_vfs *pVfs){
return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
}
+3 -3
View File
@@ -12,8 +12,8 @@
**
** This file contains code that is specific to MSVC.
*/
#ifndef _MSVC_H_
#define _MSVC_H_
#ifndef SQLITE_MSVC_H
#define SQLITE_MSVC_H
#if defined(_MSC_VER)
#pragma warning(disable : 4054)
@@ -33,4 +33,4 @@
#pragma warning(disable : 4706)
#endif /* defined(_MSC_VER) */
#endif /* _MSVC_H_ */
#endif /* SQLITE_MSVC_H */
+13 -14
View File
@@ -13,9 +13,7 @@
** This file contains OS interface code that is common to all
** architectures.
*/
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
#undef _SQLITE_OS_C_
/*
** If we compile with the SQLITE_TEST macro set, then the following block
@@ -66,9 +64,9 @@ int sqlite3_open_file_count = 0;
#if defined(SQLITE_TEST)
int sqlite3_memdebug_vfs_oom_test = 1;
#define DO_OS_MALLOC_TEST(x) \
if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \
sqlite3_free(pTstAlloc); \
}
#else
@@ -81,13 +79,11 @@ int sqlite3_memdebug_vfs_oom_test = 1;
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
int sqlite3OsClose(sqlite3_file *pId){
int rc = SQLITE_OK;
void sqlite3OsClose(sqlite3_file *pId){
if( pId->pMethods ){
rc = pId->pMethods->xClose(pId);
pId->pMethods->xClose(pId);
pId->pMethods = 0;
}
return rc;
}
int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
DO_OS_MALLOC_TEST(id);
@@ -262,6 +258,9 @@ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
}
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
@@ -287,7 +286,7 @@ int sqlite3OsOpenMalloc(
int flags,
int *pOutFlags
){
int rc = SQLITE_NOMEM;
int rc;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
@@ -297,15 +296,15 @@ int sqlite3OsOpenMalloc(
}else{
*ppFile = pFile;
}
}else{
rc = SQLITE_NOMEM_BKPT;
}
return rc;
}
int sqlite3OsCloseFree(sqlite3_file *pFile){
int rc = SQLITE_OK;
void sqlite3OsCloseFree(sqlite3_file *pFile){
assert( pFile );
rc = sqlite3OsClose(pFile);
sqlite3OsClose(pFile);
sqlite3_free(pFile);
return rc;
}
/*
@@ -316,7 +315,7 @@ int sqlite3OsCloseFree(sqlite3_file *pFile){
*/
int sqlite3OsInit(void){
void *p = sqlite3_malloc(10);
if( p==0 ) return SQLITE_NOMEM;
if( p==0 ) return SQLITE_NOMEM_BKPT;
sqlite3_free(p);
return sqlite3_os_init();
}
+3 -2
View File
@@ -160,7 +160,7 @@ int sqlite3OsInit(void);
/*
** Functions for accessing sqlite3_file methods
*/
int sqlite3OsClose(sqlite3_file*);
void sqlite3OsClose(sqlite3_file*);
int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
int sqlite3OsTruncate(sqlite3_file*, i64 size);
@@ -197,6 +197,7 @@ void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
int sqlite3OsSleep(sqlite3_vfs *, int);
int sqlite3OsGetLastError(sqlite3_vfs*);
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
@@ -204,6 +205,6 @@ int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
int sqlite3OsCloseFree(sqlite3_file *);
void sqlite3OsCloseFree(sqlite3_file *);
#endif /* _SQLITE_OS_H_ */
+3 -3
View File
@@ -13,8 +13,8 @@
** This file contains pre-processor directives related to operating system
** detection and/or setup.
*/
#ifndef _OS_SETUP_H_
#define _OS_SETUP_H_
#ifndef SQLITE_OS_SETUP_H
#define SQLITE_OS_SETUP_H
/*
** Figure out if we are dealing with Unix, Windows, or some other operating
@@ -54,4 +54,4 @@
# endif
#endif
#endif /* _OS_SETUP_H_ */
#endif /* SQLITE_OS_SETUP_H */
+104 -62
View File
@@ -71,6 +71,19 @@
# endif
#endif
/* Use pread() and pwrite() if they are available */
#if defined(__APPLE__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
# undef USE_PREAD
# define USE_PREAD64 1
#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
# undef USE_PREAD64
# define USE_PREAD 1
#endif
/*
** standard include files.
*/
@@ -392,7 +405,7 @@ static struct unix_syscall {
#else
{ "pread64", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
@@ -410,7 +423,7 @@ static struct unix_syscall {
#else
{ "pwrite64", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
aSyscall[13].pCurrent)
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
@@ -1302,7 +1315,7 @@ static int findInodeInfo(
if( pInode==0 ){
pInode = sqlite3_malloc64( sizeof(*pInode) );
if( pInode==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memset(pInode, 0, sizeof(*pInode));
memcpy(&pInode->fileId, &fileId, sizeof(fileId));
@@ -1344,12 +1357,16 @@ static int fileHasMoved(unixFile *pFile){
static void verifyDbFile(unixFile *pFile){
struct stat buf;
int rc;
/* These verifications occurs for the main database only */
if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
rc = osFstat(pFile->h, &buf);
if( rc!=0 ){
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
return;
}
if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
if( buf.st_nlink==0 ){
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
return;
}
@@ -1485,7 +1502,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
** confusion with SQLite lock names). The algorithms are complicated
** slightly in order to be compatible with windows systems simultaneously
** slightly in order to be compatible with Windows95 systems simultaneously
** accessing the same database file, in case that is ever required.
**
** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
@@ -1493,8 +1510,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range', a range of 510 bytes at a well known offset.
**
** To obtain a SHARED lock, a read-lock is obtained on the 'pending
** byte'. If this is successful, a random byte from the 'shared byte
** range' is read-locked and the lock on the 'pending byte' released.
** byte'. If this is successful, 'shared byte range' is read-locked
** and the lock on the 'pending byte' released. (Legacy note: When
** SQLite was first developed, Windows95 systems were still very common,
** and Widnows95 lacks a shared-lock capability. So on Windows95, a
** single randomly selected by from the 'shared byte range' is locked.
** Windows95 is now pretty much extinct, but this work-around for the
** lack of shared-locks on Windows95 lives on, for backwards
** compatibility.)
**
** A process may only obtain a RESERVED lock after it has a SHARED lock.
** A RESERVED lock is implemented by grabbing a write-lock on the
@@ -1513,11 +1536,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range'. Since all other locks require a read-lock on one of the bytes
** within this range, this ensures that no other locks are held on the
** database.
**
** The reason a single byte cannot be used instead of the 'shared byte
** range' is that some versions of windows do not support read-locks. By
** locking a random byte from a range, concurrent SHARED locks may exist
** even if the locking primitive used is always a write-lock.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -4222,7 +4240,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
/* Allocate space for the new unixShm object. */
p = sqlite3_malloc64( sizeof(*p) );
if( p==0 ) return SQLITE_NOMEM;
if( p==0 ) return SQLITE_NOMEM_BKPT;
memset(p, 0, sizeof(*p));
assert( pDbFd->pShm==0 );
@@ -4254,7 +4272,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
#endif
pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
@@ -4270,10 +4288,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode->h = -1;
pDbFd->pInode->pShmNode = pShmNode;
pShmNode->pInode = pDbFd->pInode;
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->mutex==0 ){
rc = SQLITE_NOMEM;
goto shm_open_err;
if( sqlite3GlobalConfig.bCoreMutex ){
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->mutex==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
}
if( pInode->bProcessLock==0 ){
@@ -4445,7 +4465,7 @@ static int unixShmMap(
pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM;
rc = SQLITE_IOERR_NOMEM_BKPT;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
@@ -4465,7 +4485,7 @@ static int unixShmMap(
}else{
pMem = sqlite3_malloc64(szRegion);
if( pMem==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto shmpage_out;
}
memset(pMem, 0, szRegion);
@@ -5243,7 +5263,7 @@ static int fillInUnixFile(
pNew->pId = vxworksFindFileId(zFilename);
if( pNew->pId==0 ){
ctrlFlags |= UNIXFILE_NOLOCK;
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
#endif
@@ -5299,7 +5319,7 @@ static int fillInUnixFile(
afpLockingContext *pCtx;
pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else{
/* NB: zFilename exists and remains valid until the file is closed
** according to requirement F11141. So we do not need to make a
@@ -5329,7 +5349,7 @@ static int fillInUnixFile(
nFilename = (int)strlen(zFilename) + 6;
zLockFile = (char *)sqlite3_malloc64(nFilename);
if( zLockFile==0 ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else{
sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
}
@@ -5352,7 +5372,7 @@ static int fillInUnixFile(
if( zSemName[n]=='/' ) zSemName[n] = '_';
pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
if( pNew->pInode->pSem == SEM_FAILED ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
pNew->pInode->aSemName[0] = '\0';
}
}
@@ -5392,20 +5412,24 @@ static const char *unixTempFileDir(void){
"/tmp",
"."
};
unsigned int i;
unsigned int i = 0;
struct stat buf;
const char *zDir = sqlite3_temp_directory;
if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
if( zDir==0 ) continue;
if( osStat(zDir, &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
if( osAccess(zDir, 07) ) continue;
break;
while(1){
if( zDir!=0
&& osStat(zDir, &buf)==0
&& S_ISDIR(buf.st_mode)
&& osAccess(zDir, 03)==0
){
return zDir;
}
if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
zDir = azDirs[i++];
}
return zDir;
return 0;
}
/*
@@ -5421,9 +5445,11 @@ static int unixGetTempname(int nBuf, char *zBuf){
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
zDir = unixTempFileDir();
if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
do{
u64 r;
sqlite3_randomness(sizeof(r), &r);
@@ -5503,6 +5529,27 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
return pUnused;
}
/*
** Find the mode, uid and gid of file zFile.
*/
static int getFileMode(
const char *zFile, /* File name */
mode_t *pMode, /* OUT: Permissions of zFile */
uid_t *pUid, /* OUT: uid of zFile. */
gid_t *pGid /* OUT: gid of zFile. */
){
struct stat sStat; /* Output of stat() on database file */
int rc = SQLITE_OK;
if( 0==osStat(zFile, &sStat) ){
*pMode = sStat.st_mode & 0777;
*pUid = sStat.st_uid;
*pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
return rc;
}
/*
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
@@ -5538,7 +5585,6 @@ static int findCreateFileMode(
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
char zDb[MAX_PATHNAME+1]; /* Database file path */
int nDb; /* Number of valid bytes in zDb */
struct stat sStat; /* Output of stat() on database file */
/* zPath is a path to a WAL or journal file. The following block derives
** the path to the associated database file from zPath. This block handles
@@ -5569,15 +5615,18 @@ static int findCreateFileMode(
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
if( 0==osStat(zDb, &sStat) ){
*pMode = sStat.st_mode & 0777;
*pUid = sStat.st_uid;
*pGid = sStat.st_gid;
}else{
rc = SQLITE_IOERR_FSTAT;
}
rc = getFileMode(zDb, pMode, pUid, pGid);
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
}else if( flags & SQLITE_OPEN_URI ){
/* If this is a main database file and the file was opened using a URI
** filename, check for the "modeof" parameter. If present, interpret
** its value as a filename and try to copy the mode, uid and gid from
** that file. */
const char *z = sqlite3_uri_parameter(zPath, "modeof");
if( z ){
rc = getFileMode(z, pMode, pUid, pGid);
}
}
return rc;
}
@@ -5693,7 +5742,7 @@ static int unixOpen(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
}
p->pUnused = pUnused;
@@ -5779,7 +5828,7 @@ static int unixOpen(
zPath = sqlite3_mprintf("%s", zName);
if( zPath==0 ){
robust_close(p, fd, __LINE__);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
#else
osUnlink(zName);
@@ -5790,9 +5839,6 @@ static int unixOpen(
p->openFlags = openFlags;
}
#endif
noLock = eType!=SQLITE_OPEN_MAIN_DB;
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
@@ -5811,6 +5857,7 @@ static int unixOpen(
/* Set up appropriate ctrlFlags */
if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
noLock = eType!=SQLITE_OPEN_MAIN_DB;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
@@ -6011,7 +6058,7 @@ static int unixFullPathname(
if( bLink ){
if( zDel==0 ){
zDel = sqlite3_malloc(nOut);
if( zDel==0 ) rc = SQLITE_NOMEM;
if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
}else if( ++nLink>SQLITE_MAX_SYMLINKS ){
rc = SQLITE_CANTOPEN_BKPT;
}
@@ -6249,23 +6296,18 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
# define unixCurrentTime 0
#endif
#ifndef SQLITE_OMIT_DEPRECATED
/*
** We added the xGetLastError() method with the intention of providing
** better low-level error messages when operating-system problems come up
** during SQLite operation. But so far, none of that has been implemented
** in the core. So this routine is never called. For now, it is merely
** a place-holder.
** The xGetLastError() method is designed to return a better
** low-level error message when operating-system problems come up
** during SQLite operation. Only the integer return code is currently
** used.
*/
static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
UNUSED_PARAMETER(NotUsed);
UNUSED_PARAMETER(NotUsed2);
UNUSED_PARAMETER(NotUsed3);
return 0;
return errno;
}
#else
# define unixGetLastError 0
#endif
/*
@@ -6555,7 +6597,7 @@ static int proxyCreateUnixFile(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
}
if( fd<0 ){
@@ -6588,7 +6630,7 @@ static int proxyCreateUnixFile(
pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
if( pNew==NULL ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto end_create_proxy;
}
memset(pNew, 0, sizeof(unixFile));
@@ -7001,7 +7043,7 @@ static int proxyTakeConch(unixFile *pFile){
if( tempLockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
if( !pCtx->lockProxyPath ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
}
}
@@ -7066,7 +7108,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
** the name of the original database file. */
*pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
if( conchPath==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memcpy(conchPath, dbPath, len+1);
@@ -7182,7 +7224,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memset(pCtx, 0, sizeof(*pCtx));
@@ -7218,7 +7260,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
if( rc==SQLITE_OK ){
pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
if( pCtx->dbPath==NULL ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}
}
if( rc==SQLITE_OK ){
+528 -224
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -12,8 +12,8 @@
**
** This file contains code that is specific to Windows.
*/
#ifndef _OS_WIN_H_
#define _OS_WIN_H_
#ifndef SQLITE_OS_WIN_H
#define SQLITE_OS_WIN_H
/*
** Include the primary Windows SDK header file.
@@ -85,4 +85,4 @@
# define SQLITE_OS_WIN_THREADS 0
#endif
#endif /* _OS_WIN_H_ */
#endif /* SQLITE_OS_WIN_H */
+171 -144
View File
@@ -428,19 +428,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/
#define MAX_SECTOR_SIZE 0x10000
/*
** If the option SQLITE_EXTRA_DURABLE option is set at compile-time, then
** SQLite will do extra fsync() operations when synchronous==FULL to help
** ensure that transactions are durable across a power failure. Most
** applications are happy as long as transactions are consistent across
** a power failure, and are perfectly willing to lose the last transaction
** in exchange for the extra performance of avoiding directory syncs.
** And so the default SQLITE_EXTRA_DURABLE setting is off.
*/
#ifndef SQLITE_EXTRA_DURABLE
# define SQLITE_EXTRA_DURABLE 0
#endif
/*
** An instance of the following structure is allocated for each active
@@ -830,9 +817,10 @@ static const unsigned char aJournalMagic[] = {
** rollback journal. Otherwise false.
*/
#ifndef SQLITE_OMIT_WAL
static int pagerUseWal(Pager *pPager){
int sqlite3PagerUseWal(Pager *pPager){
return (pPager->pWal!=0);
}
# define pagerUseWal(x) sqlite3PagerUseWal(x)
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
@@ -885,6 +873,7 @@ static int assert_pager_state(Pager *p){
** state.
*/
if( MEMDB ){
assert( !isOpen(p->fd) );
assert( p->noSync );
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
@@ -971,7 +960,7 @@ static int assert_pager_state(Pager *p){
** back to OPEN state.
*/
assert( pPager->errCode!=SQLITE_OK );
assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
break;
}
@@ -1183,6 +1172,8 @@ static int jrnlBufferSize(Pager *pPager){
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
}
#else
# define jrnlBufferSize(x) 0
#endif
/*
@@ -1343,6 +1334,7 @@ static i64 journalHdrOffset(Pager *pPager){
static int zeroJournalHdr(Pager *pPager, int doTruncate){
int rc = SQLITE_OK; /* Return code */
assert( isOpen(pPager->jfd) );
assert( !sqlite3JournalIsInMemory(pPager->jfd) );
if( pPager->journalOff ){
const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */
@@ -1724,7 +1716,7 @@ static void releaseAllSavepoints(Pager *pPager){
for(ii=0; ii<pPager->nSavepoint; ii++){
sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
}
if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){
sqlite3OsClose(pPager->sjfd);
}
sqlite3_free(pPager->aSavepoint);
@@ -1830,13 +1822,17 @@ static void pager_unlock(Pager *pPager){
** it can safely move back to PAGER_OPEN state. This happens in both
** normal and exclusive-locking mode.
*/
assert( pPager->errCode==SQLITE_OK || !MEMDB );
if( pPager->errCode ){
assert( !MEMDB );
pager_reset(pPager);
pPager->changeCountDone = pPager->tempFile;
pPager->eState = PAGER_OPEN;
pPager->errCode = SQLITE_OK;
if( pPager->tempFile==0 ){
pager_reset(pPager);
pPager->changeCountDone = 0;
pPager->eState = PAGER_OPEN;
}else{
pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
}
if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
pPager->errCode = SQLITE_OK;
}
pPager->journalOff = 0;
@@ -1880,6 +1876,29 @@ static int pager_error(Pager *pPager, int rc){
static int pager_truncate(Pager *pPager, Pgno nPage);
/*
** The write transaction open on pPager is being committed (bCommit==1)
** or rolled back (bCommit==0).
**
** Return TRUE if and only if all dirty pages should be flushed to disk.
**
** Rules:
**
** * For non-TEMP databases, always sync to disk. This is necessary
** for transactions to be durable.
**
** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
** file has been created already (via a spill on pagerStress()) and
** when the number of dirty pages in memory exceeds 25% of the total
** cache size.
*/
static int pagerFlushOnCommit(Pager *pPager, int bCommit){
if( pPager->tempFile==0 ) return 1;
if( !bCommit ) return 0;
if( !isOpen(pPager->fd) ) return 0;
return (sqlite3PCachePercentDirty(pPager->pPCache)>=25);
}
/*
** This routine ends a transaction. A transaction is usually ended by
** either a COMMIT or a ROLLBACK operation. This routine may be called
@@ -1962,8 +1981,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
if( sqlite3IsMemJournal(pPager->jfd) ){
assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
if( sqlite3JournalIsInMemory(pPager->jfd) ){
/* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
sqlite3OsClose(pPager->jfd);
}else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
if( pPager->journalOff==0 ){
@@ -1983,15 +2002,16 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
rc = zeroJournalHdr(pPager, hasMaster);
rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to
** the database file, it will do so using an in-memory journal.
** the database file, it will do so using an in-memory journal.
*/
int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
int bDelete = !pPager->tempFile;
assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
@@ -2017,8 +2037,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
pPager->nRec = 0;
sqlite3PcacheCleanAll(pPager->pPCache);
sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
if( rc==SQLITE_OK ){
if( pagerFlushOnCommit(pPager, bCommit) ){
sqlite3PcacheCleanAll(pPager->pPCache);
}else{
sqlite3PcacheClearWritable(pPager->pPCache);
}
sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
}
if( pagerUseWal(pPager) ){
/* Drop the WAL write-lock, if any. Also, if the connection was in
@@ -2302,7 +2328,7 @@ static int pager_playback_one_page(
pPg = sqlite3PagerLookup(pPager, pgno);
}
assert( pPg || !MEMDB );
assert( pPager->eState!=PAGER_OPEN || pPg==0 );
assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
(isMainJrnl?"main-journal":"sub-journal")
@@ -2324,9 +2350,9 @@ static int pager_playback_one_page(
pPager->dbFileSize = pgno;
}
if( pPager->pBackup ){
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
}
}else if( !isMainJrnl && pPg==0 ){
/* If this is a rollback of a savepoint and data was not written to
@@ -2352,7 +2378,6 @@ static int pager_playback_one_page(
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
if( rc!=SQLITE_OK ) return rc;
pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
}
if( pPg ){
@@ -2366,29 +2391,10 @@ static int pager_playback_one_page(
pData = pPg->pData;
memcpy(pData, (u8*)aData, pPager->pageSize);
pPager->xReiniter(pPg);
if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
/* If the contents of this page were just restored from the main
** journal file, then its content must be as they were when the
** transaction was first opened. In this case we can mark the page
** as clean, since there will be no need to write it out to the
** database.
**
** There is one exception to this rule. If the page is being rolled
** back as part of a savepoint (or statement) rollback from an
** unsynced portion of the main journal file, then it is not safe
** to mark the page as clean. This is because marking the page as
** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
** already in the journal file (recorded in Pager.pInJournal) and
** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
** again within this transaction, it will be marked as dirty but
** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
** be written out into the database file before its journal file
** segment is synced. If a crash occurs during or following this,
** database corruption may ensue.
*/
assert( !pagerUseWal(pPager) );
sqlite3PcacheMakeClean(pPg);
}
/* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But
** that call was dangerous and had no detectable benefit since the cache
** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so
** has been removed. */
pager_set_pagehash(pPg);
/* If this was page 1, then restore the value of Pager.dbFileVers.
@@ -2398,7 +2404,7 @@ static int pager_playback_one_page(
}
/* Decode the page just read from disk */
CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3PcacheRelease(pPg);
}
return rc;
@@ -2464,7 +2470,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
if( !pMaster ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
}else{
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
@@ -2481,7 +2487,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
nMasterPtr = pVfs->mxPathname+1;
zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
if( !zMasterJournal ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto delmaster_out;
}
zMasterPtr = &zMasterJournal[nMasterJournal+1];
@@ -2729,7 +2735,7 @@ static int pager_playback(Pager *pPager, int isHot){
** TODO: Technically the following is an error because it assumes that
** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
** mxPathname is 512, which is the same as the minimum allowable value
** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
zMaster = pPager->pTmpSpace;
@@ -2951,7 +2957,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
@@ -3179,6 +3185,8 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
*/
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
assert( isOpen(pPager->fd) );
assert( pPager->tempFile==0 );
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the number of pages in the database is not available from the
@@ -3186,14 +3194,11 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
** the database file. If the size of the database file is not an
** integer multiple of the page-size, round up the result.
*/
if( nPage==0 ){
if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
i64 n = 0; /* Size of db file in bytes */
assert( isOpen(pPager->fd) || pPager->tempFile );
if( isOpen(pPager->fd) ){
int rc = sqlite3OsFileSize(pPager->fd, &n);
if( rc!=SQLITE_OK ){
return rc;
}
int rc = sqlite3OsFileSize(pPager->fd, &n);
if( rc!=SQLITE_OK ){
return rc;
}
nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
}
@@ -3311,7 +3316,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( pSavepoint ){
pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
if( !pDone ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
}
@@ -3458,7 +3463,7 @@ void sqlite3PagerShrink(Pager *pPager){
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
** of the database to damage due to OS crashes or power failures by
** changing the number of syncs()s when writing the journals.
** There are three levels:
** There are four levels:
**
** OFF sqlite3OsSync() is never called. This is the default
** for temporary and transient files.
@@ -3478,6 +3483,10 @@ void sqlite3PagerShrink(Pager *pPager){
** assurance that the journal will not be corrupted to the
** point of causing damage to the database during rollback.
**
** EXTRA This is like FULL except that is also syncs the directory
** that contains the rollback journal after the rollback
** journal is unlinked.
**
** The above is for a rollback-journal mode. For WAL mode, OFF continues
** to mean that no syncs ever occur. NORMAL means that the WAL is synced
** prior to the start of checkpoint and that the database file is synced
@@ -3485,7 +3494,8 @@ void sqlite3PagerShrink(Pager *pPager){
** was written back into the database. But no sync operations occur for
** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL
** file is synced following each commit operation, in addition to the
** syncs associated with NORMAL.
** syncs associated with NORMAL. There is no difference between FULL
** and EXTRA for WAL mode.
**
** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The
** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
@@ -3674,7 +3684,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
}
if( rc==SQLITE_OK ){
pNew = (char *)sqlite3PageMalloc(pageSize);
if( !pNew ) rc = SQLITE_NOMEM;
if( !pNew ) rc = SQLITE_NOMEM_BKPT;
}
if( rc==SQLITE_OK ){
@@ -3950,7 +3960,7 @@ static int pagerAcquireMapPage(
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
p->pExtra = (void *)&p[1];
p->flags = PGHDR_MMAP;
@@ -4264,8 +4274,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
/* This function is only called for rollback pagers in WRITER_DBMOD state. */
assert( !pagerUseWal(pPager) );
assert( pPager->eState==PAGER_WRITER_DBMOD );
assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
assert( pPager->eLock==EXCLUSIVE_LOCK );
assert( isOpen(pPager->fd) || pList->pDirty==0 );
/* If the file is a temp-file has not yet been opened, open it now. It
** is not possible for rc to be other than SQLITE_OK if this branch
@@ -4308,7 +4319,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
if( pList->pgno==1 ) pager_write_changecounter(pList);
/* Encode the database */
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
/* Write out the page data. */
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
@@ -4353,11 +4364,14 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
static int openSubJournal(Pager *pPager){
int rc = SQLITE_OK;
if( !isOpen(pPager->sjfd) ){
const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
| SQLITE_OPEN_DELETEONCLOSE;
int nStmtSpill = sqlite3Config.nStmtSpill;
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
sqlite3MemJournalOpen(pPager->sjfd);
}else{
rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
nStmtSpill = -1;
}
rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill);
}
return rc;
}
@@ -4395,7 +4409,7 @@ static int subjournalPage(PgHdr *pPg){
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
@@ -4578,18 +4592,8 @@ int sqlite3PagerOpen(
int nUri = 0; /* Number of bytes of URI args at *zUri */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). This
** is the maximum space required for an in-memory journal file handle
** and a regular journal file-handle. Note that a "regular journal-handle"
** may be a wrapper capable of caching the first portion of the journal
** file in memory to implement the atomic-write optimization (see
** source file journal.c).
*/
if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
}else{
journalFileSize = ROUND8(sqlite3MemJournalSize());
}
** (there are two of them, the main journal and the sub-journal). */
journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
/* Set the output variable to NULL in case an error occurs. */
*ppPager = 0;
@@ -4599,7 +4603,7 @@ int sqlite3PagerOpen(
memDb = 1;
if( zFilename && zFilename[0] ){
zPathname = sqlite3DbStrDup(0, zFilename);
if( zPathname==0 ) return SQLITE_NOMEM;
if( zPathname==0 ) return SQLITE_NOMEM_BKPT;
nPathname = sqlite3Strlen30(zPathname);
zFilename = 0;
}
@@ -4615,7 +4619,7 @@ int sqlite3PagerOpen(
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3DbMallocRaw(0, nPathname*2);
if( zPathname==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
@@ -4668,7 +4672,7 @@ int sqlite3PagerOpen(
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
sqlite3DbFree(0, zPathname);
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
pPager = (Pager*)(pPtr);
pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
@@ -4823,11 +4827,7 @@ act_like_temp_file:
assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
#if SQLITE_EXTRA_DURABLE
pPager->extraSync = 1;
#else
pPager->extraSync = 0;
#endif
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
@@ -4944,6 +4944,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
if( rc==SQLITE_OK && !locked ){
Pgno nPage; /* Number of pages in database file */
assert( pPager->tempFile==0 );
rc = pagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
/* If the database is zero pages in size, that means that either (1) the
@@ -5036,17 +5037,17 @@ int sqlite3PagerSharedLock(Pager *pPager){
/* This routine is only called from b-tree and only when there are no
** outstanding pages. This implies that the pager state should either
** be OPEN or READER. READER is only possible if the pager is or was in
** exclusive access mode.
*/
** exclusive access mode. */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( assert_pager_state(pPager) );
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
assert( pPager->errCode==SQLITE_OK );
if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
@@ -5132,7 +5133,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
assert( rc==SQLITE_OK );
rc = pagerSyncHotJournal(pPager);
if( rc==SQLITE_OK ){
rc = pager_playback(pPager, 1);
rc = pager_playback(pPager, !pPager->tempFile);
pPager->eState = PAGER_OPEN;
}
}else if( !pPager->exclusiveMode ){
@@ -5228,7 +5229,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerBeginReadTransaction(pPager);
}
if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
rc = pagerPagecount(pPager, &pPager->dbSize);
}
@@ -5361,7 +5362,7 @@ int sqlite3PagerGet(
);
if( rc==SQLITE_OK && pData ){
if( pPager->eState>PAGER_READER ){
if( pPager->eState>PAGER_READER || pPager->tempFile ){
pPg = sqlite3PagerLookup(pPager, pgno);
}
if( pPg==0 ){
@@ -5388,7 +5389,7 @@ int sqlite3PagerGet(
if( rc!=SQLITE_OK ) goto pager_acquire_err;
if( pBase==0 ){
pPg = *ppPage = 0;
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto pager_acquire_err;
}
}
@@ -5428,7 +5429,8 @@ int sqlite3PagerGet(
goto pager_acquire_err;
}
if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
assert( !isOpen(pPager->fd) || !MEMDB );
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
goto pager_acquire_err;
@@ -5562,7 +5564,7 @@ static int pager_open_journal(Pager *pPager){
if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
if( pPager->pInJournal==0 ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
/* Open the journal file if it is not already open. */
@@ -5570,24 +5572,24 @@ static int pager_open_journal(Pager *pPager){
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3MemJournalOpen(pPager->jfd);
}else{
const int flags = /* VFS flags to open journal file */
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
(pPager->tempFile ?
(SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
(SQLITE_OPEN_MAIN_JOURNAL)
);
int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
int nSpill;
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
nSpill = sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
nSpill = jrnlBufferSize(pPager);
}
/* Verify that the database still has the same name as it did when
** it was originally opened. */
rc = databaseIsUnmoved(pPager);
if( rc==SQLITE_OK ){
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
rc = sqlite3JournalOpen(
pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
rc = sqlite3JournalOpen (
pVfs, pPager->zJournal, pPager->jfd, flags, nSpill
);
#else
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
#endif
}
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
@@ -5717,7 +5719,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff );
CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
cksum = pager_cksum(pPager, (u8*)pData2);
/* Even if an IO or diskfull error occurs while journalling the
@@ -5958,6 +5960,7 @@ int sqlite3PagerWrite(PgHdr *pPg){
if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
return SQLITE_OK;
}else if( pPager->sectorSize > (u32)pPager->pageSize ){
assert( pPager->tempFile==0 );
return pagerWriteLargeSector(pPg);
}else{
return pager_write(pPg);
@@ -5988,14 +5991,21 @@ int sqlite3PagerIswriteable(DbPage *pPg){
**
** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
**
** This optimization cannot be used with a temp-file, as the page may
** have been dirty at the start of the transaction. In that case, if
** memory pressure forces page pPg out of the cache, the data does need
** to be written out to disk so that it may be read back in if the
** current transaction is rolled back.
*/
void sqlite3PagerDontWrite(PgHdr *pPg){
Pager *pPager = pPg->pPager;
if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
pPg->flags |= PGHDR_DONT_WRITE;
pPg->flags &= ~PGHDR_WRITEABLE;
testcase( pPg->flags & PGHDR_NEED_SYNC );
pager_set_pagehash(pPg);
}
}
@@ -6074,7 +6084,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++;
@@ -6190,17 +6200,21 @@ int sqlite3PagerCommitPhaseOne(
/* If a prior error occurred, report that error again. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
/* Provide the ability to easily simulate an I/O error during testing */
if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
if( MEMDB ){
assert( MEMDB==0 || pPager->tempFile );
assert( isOpen(pPager->fd) || pPager->tempFile );
if( 0==pagerFlushOnCommit(pPager, 1) ){
/* If this is an in-memory db, or no pages have been written to, or this
** function has already been called, it is mostly a no-op. However, any
** backup in progress needs to be restarted.
*/
** backup in progress needs to be restarted. */
sqlite3BackupRestart(pPager->pBackup);
}else{
if( pagerUseWal(pPager) ){
@@ -6539,10 +6553,10 @@ void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
}
/*
** Return true if this is an in-memory pager.
** Return true if this is an in-memory or temp-file backed pager.
*/
int sqlite3PagerIsMemdb(Pager *pPager){
return MEMDB;
return pPager->tempFile;
}
/*
@@ -6573,7 +6587,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
);
if( !aNew ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
pPager->aSavepoint = aNew;
@@ -6589,7 +6603,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
aNew[ii].iSubRec = pPager->nSubRec;
aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
if( !aNew[ii].pInSavepoint ){
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
if( pagerUseWal(pPager) ){
sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
@@ -6643,7 +6657,11 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** savepoint. If no errors occur, SQLITE_OK is returned.
*/
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
int rc = pPager->errCode; /* Return code */
int rc = pPager->errCode;
#ifdef SQLITE_ENABLE_ZIPVFS
if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
#endif
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
@@ -6667,7 +6685,7 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
if( op==SAVEPOINT_RELEASE ){
if( nNew==0 && isOpen(pPager->sjfd) ){
/* Only truncate if it is an in-memory sub-journal. */
if( sqlite3IsMemJournal(pPager->sjfd) ){
if( sqlite3JournalIsInMemory(pPager->sjfd) ){
rc = sqlite3OsTruncate(pPager->sjfd, 0);
assert( rc==SQLITE_OK );
}
@@ -6684,6 +6702,20 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
}
#ifdef SQLITE_ENABLE_ZIPVFS
/* If the cache has been modified but the savepoint cannot be rolled
** back journal_mode=off, put the pager in the error state. This way,
** if the VFS used by this pager includes ZipVFS, the entire transaction
** can be rolled back at the ZipVFS level. */
else if(
pPager->journalMode==PAGER_JOURNALMODE_OFF
&& pPager->eState>=PAGER_WRITER_CACHEMOD
){
pPager->errCode = SQLITE_ABORT;
pPager->eState = PAGER_ERROR;
}
#endif
}
return rc;
@@ -6738,14 +6770,6 @@ const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal;
}
/*
** Return true if fsync() calls are disabled for this pager. Return FALSE
** if fsync()s are executed normally.
*/
int sqlite3PagerNosync(Pager *pPager){
return pPager->noSync;
}
#ifdef SQLITE_HAS_CODEC
/*
** Set or retrieve the codec for this pager
@@ -6830,7 +6854,8 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
/* In order to be able to rollback, an in-memory database must journal
** the page we are moving from.
*/
if( MEMDB ){
assert( pPager->tempFile || !MEMDB );
if( pPager->tempFile ){
rc = sqlite3PagerWrite(pPg);
if( rc ) return rc;
}
@@ -6887,7 +6912,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
if( MEMDB ){
if( pPager->tempFile ){
/* Do not discard pages from an in-memory database since we might
** need to rollback later. Just move the page out of the way. */
sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
@@ -6904,8 +6929,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
** to exist, in case the transaction needs to roll back. Use pPgOld
** as the original page since it has already been allocated.
*/
if( MEMDB ){
assert( pPgOld );
if( pPager->tempFile && pPgOld ){
sqlite3PcacheMove(pPgOld, origPgno);
sqlite3PagerUnrefNotNull(pPgOld);
}
@@ -7157,10 +7181,12 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** Unless this is an in-memory or temporary database, clear the pager cache.
*/
void sqlite3PagerClearCache(Pager *pPager){
if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
assert( MEMDB==0 || pPager->tempFile );
if( pPager->tempFile==0 ) pager_reset(pPager);
}
#endif
#ifndef SQLITE_OMIT_WAL
/*
** This function is called when the user invokes "PRAGMA wal_checkpoint",
@@ -7192,6 +7218,7 @@ int sqlite3PagerWalCallback(Pager *pPager){
*/
int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
if( pPager->noLock ) return 0;
return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
}
@@ -7335,6 +7362,7 @@ int sqlite3PagerCloseWal(Pager *pPager){
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
}
return rc;
@@ -7384,7 +7412,6 @@ int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
#endif /* SQLITE_OMIT_DISKIO */
/* BEGIN SQLCIPHER */
+17 -6
View File
@@ -14,8 +14,8 @@
** at a time and provides a journal for rollback.
*/
#ifndef _PAGER_H_
#define _PAGER_H_
#ifndef SQLITE_PAGER_H
#define SQLITE_PAGER_H
/*
** Default maximum size for persistent journal files. A negative
@@ -68,7 +68,11 @@ typedef struct PgHdr DbPage;
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
** Numeric constants that encode the journalmode.
** Numeric constants that encode the journalmode.
**
** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
** are exposed in the API via the "PRAGMA journal_mode" command and
** therefore cannot be changed without a compatibility break.
*/
#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
@@ -86,6 +90,11 @@ typedef struct PgHdr DbPage;
/*
** Flags for sqlite3PagerSetFlags()
**
** Value constraints (enforced via assert()):
** PAGER_FULLFSYNC == SQLITE_FullFSync
** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
** PAGER_CACHE_SPILL == SQLITE_CacheSpill
*/
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
@@ -169,10 +178,13 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerWalCallback(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
int sqlite3PagerCloseWal(Pager *pPager);
int sqlite3PagerUseWal(Pager *pPager);
# ifdef SQLITE_ENABLE_SNAPSHOT
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
# endif
#else
# define sqlite3PagerUseWal(x) 0
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -191,11 +203,10 @@ sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
sqlite3_file *sqlite3PagerJrnlFile(Pager*);
const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager *);
void sqlite3PagerClearCache(Pager*);
int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
@@ -222,4 +233,4 @@ void *sqlite3PagerCodec(DbPage *);
# define enable_simulated_io_errors()
#endif
#endif /* _PAGER_H_ */
#endif /* SQLITE_PAGER_H */
+303 -306
View File
File diff suppressed because it is too large Load Diff
+212 -30
View File
@@ -14,7 +14,29 @@
#include "sqliteInt.h"
/*
** A complete page cache is an instance of this structure.
** A complete page cache is an instance of this structure. Every
** entry in the cache holds a single page of the database file. The
** btree layer only operates on the cached copy of the database pages.
**
** A page cache entry is "clean" if it exactly matches what is currently
** on disk. A page is "dirty" if it has been modified and needs to be
** persisted to disk.
**
** pDirty, pDirtyTail, pSynced:
** All dirty pages are linked into the doubly linked list using
** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
** such that p was added to the list more recently than p->pDirtyNext.
** PCache.pDirty points to the first (newest) element in the list and
** pDirtyTail to the last (oldest).
**
** The PCache.pSynced variable is used to optimize searching for a dirty
** page to eject from the cache mid-transaction. It is better to eject
** a page that does not require a journal sync than one that does.
** Therefore, pSynced is maintained to that it *almost* always points
** to either the oldest page in the pDirty/pDirtyTail list that has a
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
** (so that the right page to eject can be found by following pDirtyPrev
** pointers).
*/
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
@@ -31,6 +53,95 @@ struct PCache {
sqlite3_pcache *pCache; /* Pluggable cache module */
};
/********************************** Test and Debug Logic **********************/
/*
** Debug tracing macros. Enable by by changing the "0" to "1" and
** recompiling.
**
** When sqlite3PcacheTrace is 1, single line trace messages are issued.
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
** is displayed for many operations, resulting in a lot of output.
*/
#if defined(SQLITE_DEBUG) && 0
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
void pcacheDump(PCache *pCache){
int N;
int i, j;
sqlite3_pcache_page *pLower;
PgHdr *pPg;
unsigned char *a;
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
N = sqlite3PcachePagecount(pCache);
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue;
pPg = (PgHdr*)pLower->pExtra;
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
a = (unsigned char *)pLower->pBuf;
for(j=0; j<12; j++) printf("%02x", a[j]);
printf("\n");
if( pPg->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
#else
# define pcacheTrace(X)
# define pcacheDump(X)
#endif
/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
** This routine is for use inside of assert() statements only. For
** example:
**
** assert( sqlite3PcachePageSanity(pPg) );
*/
#if SQLITE_DEBUG
int sqlite3PcachePageSanity(PgHdr *pPg){
PCache *pCache;
assert( pPg!=0 );
assert( pPg->pgno>0 ); /* Page number is 1 or more */
pCache = pPg->pCache;
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
assert( pCache->pDirtyTail!=pPg );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */
}
/* NEED_SYNC can be set independently of WRITEABLE. This can happen,
** for example, when using the sqlite3PagerDontWrite() optimization:
** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK.
** (2) Page X moved to freelist, WRITEABLE is cleared
** (3) Page X reused, WRITEABLE is set again
** If NEED_SYNC had been cleared in step 2, then it would not be reset
** in step 3, and page might be written into the database without first
** syncing the rollback journal, which might cause corruption on a power
** loss.
**
** Another example is when the database page size is smaller than the
** disk sector size. When any page of a sector is journalled, all pages
** in that sector are marked NEED_SYNC even if they are still CLEAN, just
** in case they are later modified, since all pages in the same sector
** must be journalled and synced before any of those pages can be safely
** written.
*/
return 1;
}
#endif /* SQLITE_DEBUG */
/********************************** Linked List Management ********************/
/* Allowed values for second argument to pcacheManageDirtyList() */
@@ -47,17 +158,16 @@ struct PCache {
static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
PCache *p = pPage->pCache;
pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
pPage->pgno));
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
PgHdr *pSynced = pPage->pDirtyPrev;
while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
pSynced = pSynced->pDirtyPrev;
}
p->pSynced = pSynced;
p->pSynced = pPage->pDirtyPrev;
}
if( pPage->pDirtyNext ){
@@ -69,10 +179,15 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
/* If there are now no dirty pages in the cache, set eCreate to 2.
** This is an optimization that allows sqlite3PcacheFetch() to skip
** searching for a dirty page to eject from the cache when it might
** otherwise have to. */
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
if( p->pDirty==0 && p->bPurgeable ){
assert( p->eCreate==1 );
assert( p->bPurgeable || p->eCreate==2 );
if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/
assert( p->bPurgeable==0 || p->eCreate==1 );
p->eCreate = 2;
}
}
@@ -94,10 +209,19 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
}
}
p->pDirty = pPage;
if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
** pSynced to point to it. Checking the NEED_SYNC flag is an
** optimization, as if pSynced points to a page with the NEED_SYNC
** flag set sqlite3PcacheFetchStress() searches through all newer
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
if( !p->pSynced
&& 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
){
p->pSynced = pPage;
}
}
pcacheDump(p);
}
/*
@@ -106,7 +230,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
*/
static void pcacheUnpin(PgHdr *p){
if( p->pCache->bPurgeable ){
pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
pcacheDump(p->pCache);
}
}
@@ -176,6 +302,7 @@ int sqlite3PcacheOpen(
p->pStress = pStress;
p->szCache = 100;
p->szSpill = 1;
pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
return sqlite3PcacheSetPageSize(p, szPage);
}
@@ -191,13 +318,14 @@ int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
pCache->bPurgeable
);
if( pNew==0 ) return SQLITE_NOMEM;
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
if( pCache->pCache ){
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
pCache->pCache = pNew;
pCache->szPage = szPage;
pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
}
return SQLITE_OK;
}
@@ -232,11 +360,13 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
int createFlag /* If true, create page if it does not exist already */
){
int eCreate;
sqlite3_pcache_page *pRes;
assert( pCache!=0 );
assert( pCache->pCache!=0 );
assert( createFlag==3 || createFlag==0 );
assert( pgno>0 );
assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
/* eCreate defines what to do if the page does not exist.
** 0 Do not allocate a new page. (createFlag==0)
@@ -249,12 +379,15 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
createFlag?" create":"",pRes));
return pRes;
}
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** page because new clean pages are available for reuse and the cache
** page because no clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
** try harder to allocate a page. This routine might invoke the stress
** callback to spill dirty pages to the journal. It will then try to
@@ -276,7 +409,11 @@ int sqlite3PcacheFetchStress(
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
** cleared), but if that is not possible settle for any other
** unreferenced dirty page.
*/
**
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
** flag is currently referenced, then the following may leave pSynced
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
** cleared). This is Ok, as pSynced is just an optimization. */
for(pPg=pCache->pSynced;
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pDirtyPrev
@@ -294,14 +431,16 @@ int sqlite3PcacheFetchStress(
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
numberOfCachePages(pCache));
#endif
pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
rc = pCache->xStress(pCache->pStress, pPg);
pcacheDump(pCache);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
return rc;
}
}
}
*ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
}
/*
@@ -322,7 +461,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
assert( pPage!=0 );
pPgHdr = (PgHdr*)pPage->pExtra;
assert( pPgHdr->pPage==0 );
memset(pPgHdr, 0, sizeof(PgHdr));
memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty));
pPgHdr->pPage = pPage;
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
@@ -354,6 +493,7 @@ PgHdr *sqlite3PcacheFetchFinish(
}
pCache->nRefSum++;
pPgHdr->nRef++;
assert( sqlite3PcachePageSanity(pPgHdr) );
return pPgHdr;
}
@@ -367,8 +507,11 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
}else if( p->pDirtyPrev!=0 ){
/* Move the page to the head of the dirty list. */
}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. */
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -379,6 +522,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
*/
void sqlite3PcacheRef(PgHdr *p){
assert(p->nRef>0);
assert( sqlite3PcachePageSanity(p) );
p->nRef++;
p->pCache->nRefSum++;
}
@@ -390,6 +534,7 @@ void sqlite3PcacheRef(PgHdr *p){
*/
void sqlite3PcacheDrop(PgHdr *p){
assert( p->nRef==1 );
assert( sqlite3PcachePageSanity(p) );
if( p->flags&PGHDR_DIRTY ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
}
@@ -403,13 +548,16 @@ void sqlite3PcacheDrop(PgHdr *p){
*/
void sqlite3PcacheMakeDirty(PgHdr *p){
assert( p->nRef>0 );
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){
assert( sqlite3PcachePageSanity(p) );
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_CLEAN ){
p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
assert( sqlite3PcachePageSanity(p) );
}
}
@@ -418,11 +566,14 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
** make it so.
*/
void sqlite3PcacheMakeClean(PgHdr *p){
if( (p->flags & PGHDR_DIRTY) ){
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);
}
@@ -434,11 +585,24 @@ void sqlite3PcacheMakeClean(PgHdr *p){
*/
void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p;
pcacheTrace(("%p.CLEAN-ALL\n",pCache));
while( (p = pCache->pDirty)!=0 ){
sqlite3PcacheMakeClean(p);
}
}
/*
** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
*/
void sqlite3PcacheClearWritable(PCache *pCache){
PgHdr *p;
pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
for(p=pCache->pDirty; p; p=p->pDirtyNext){
p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
}
pCache->pSynced = pCache->pDirtyTail;
}
/*
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
*/
@@ -457,6 +621,8 @@ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
@@ -477,6 +643,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
if( pCache->pCache ){
PgHdr *p;
PgHdr *pNext;
pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
/* This routine never gets call with a positive pgno except right
@@ -484,7 +651,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
** it must be that pgno==0.
*/
assert( p->pgno>0 );
if( ALWAYS(p->pgno>pgno) ){
if( p->pgno>pgno ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
@@ -507,6 +674,7 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
*/
void sqlite3PcacheClose(PCache *pCache){
assert( pCache->pCache!=0 );
pcacheTrace(("%p.CLOSE\n",pCache));
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
@@ -519,29 +687,31 @@ void sqlite3PcacheClear(PCache *pCache){
/*
** Merge two lists of pages connected by pDirty and in pgno order.
** Do not both fixing the pDirtyPrev pointers.
** Do not bother fixing the pDirtyPrev pointers.
*/
static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
PgHdr result, *pTail;
pTail = &result;
while( pA && pB ){
assert( pA!=0 && pB!=0 );
for(;;){
if( pA->pgno<pB->pgno ){
pTail->pDirty = pA;
pTail = pA;
pA = pA->pDirty;
if( pA==0 ){
pTail->pDirty = pB;
break;
}
}else{
pTail->pDirty = pB;
pTail = pB;
pB = pB->pDirty;
if( pB==0 ){
pTail->pDirty = pA;
break;
}
}
}
if( pA ){
pTail->pDirty = pA;
}else if( pB ){
pTail->pDirty = pB;
}else{
pTail->pDirty = 0;
}
return result.pDirty;
}
@@ -582,7 +752,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
}
p = a[0];
for(i=1; i<N_SORT_BUCKET; i++){
p = pcacheMergeDirtyList(p, a[i]);
if( a[i]==0 ) continue;
p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
}
return p;
}
@@ -675,6 +846,17 @@ void sqlite3PcacheShrink(PCache *pCache){
*/
int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
/*
** Return the number of dirty pages currently in the cache, as a percentage
** of the configured cache size.
*/
int sqlite3PCachePercentDirty(PCache *pCache){
PgHdr *pDirty;
int nDirty = 0;
int nCache = numberOfCachePages(pCache);
for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
}
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
+13 -5
View File
@@ -26,7 +26,7 @@ struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
PgHdr *pDirty; /* Transient list of dirty pages */
PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
@@ -51,11 +51,10 @@ struct PgHdr {
#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */
#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
** writing this page to the database */
#define PGHDR_NEED_READ 0x010 /* Content is unread */
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
#define PGHDR_MMAP 0x040 /* This is an mmap page object */
#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */
#define PGHDR_MMAP 0x020 /* This is an mmap page object */
#define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */
#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */
/* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void);
@@ -99,6 +98,7 @@ void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */
void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */
void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */
void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
void sqlite3PcacheClearWritable(PCache*);
/* Change a page number. Used by incr-vacuum. */
void sqlite3PcacheMove(PgHdr*, Pgno);
@@ -137,6 +137,11 @@ int sqlite3PcachePagecount(PCache*);
void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#endif
#if defined(SQLITE_DEBUG)
/* Check invariants on a PgHdr object */
int sqlite3PcachePageSanity(PgHdr*);
#endif
/* Set and get the suggested cache-size for the specified pager-cache.
**
** If no global maximum is configured, then the system attempts to limit
@@ -173,4 +178,7 @@ void sqlite3PCacheSetDefault(void);
int sqlite3HeaderSizePcache(void);
int sqlite3HeaderSizePcache1(void);
/* Number of dirty pages as a percentage of the configured cache size */
int sqlite3PCachePercentDirty(PCache*);
#endif /* _PCACHE_H_ */
+37 -15
View File
@@ -279,7 +279,7 @@ static int pcache1InitBulk(PCache1 *pCache){
szBulk = -1024 * (i64)pcache1.nInitPage;
}
if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
szBulk = pCache->szAlloc*pCache->nMax;
szBulk = pCache->szAlloc*(i64)pCache->nMax;
}
zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
sqlite3EndBenignMalloc();
@@ -348,7 +348,6 @@ static void *pcache1Alloc(int nByte){
** Free an allocated buffer obtained from pcache1Alloc().
*/
static void pcache1Free(void *p){
int nFreed = 0;
if( p==0 ) return;
if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
PgFreeslot *pSlot;
@@ -365,10 +364,13 @@ static void pcache1Free(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
nFreed = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
{
int nFreed = 0;
nFreed = sqlite3MallocSize(p);
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
sqlite3_mutex_leave(pcache1.mutex);
}
#endif
sqlite3_free(p);
}
@@ -630,12 +632,30 @@ static void pcache1TruncateUnsafe(
PCache1 *pCache, /* The cache to truncate */
unsigned int iLimit /* Drop pages with this pgno or larger */
){
TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
unsigned int h;
TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */
unsigned int h, iStop;
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
for(h=0; h<pCache->nHash; h++){
PgHdr1 **pp = &pCache->apHash[h];
assert( pCache->iMaxKey >= iLimit );
assert( pCache->nHash > 0 );
if( pCache->iMaxKey - iLimit < pCache->nHash ){
/* If we are just shaving the last few pages off the end of the
** cache, then there is no point in scanning the entire hash table.
** Only scan those hash slots that might contain pages that need to
** be removed. */
h = iLimit % pCache->nHash;
iStop = pCache->iMaxKey % pCache->nHash;
TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */
}else{
/* This is the general case where many pages are being removed.
** It is necessary to scan the entire hash table */
h = pCache->nHash/2;
iStop = h - 1;
}
for(;;){
PgHdr1 **pp;
PgHdr1 *pPage;
assert( h<pCache->nHash );
pp = &pCache->apHash[h];
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
pCache->nPage--;
@@ -644,11 +664,13 @@ static void pcache1TruncateUnsafe(
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
TESTONLY( nPage++; )
TESTONLY( if( nPage>=0 ) nPage++; )
}
}
if( h==iStop ) break;
h = (h+1) % pCache->nHash;
}
assert( pCache->nPage==nPage );
assert( nPage<0 || pCache->nPage==(unsigned)nPage );
}
/******************************************************************************/
@@ -688,8 +710,8 @@ static int pcache1Init(void *NotUsed){
#if SQLITE_THREADSAFE
if( sqlite3GlobalConfig.bCoreMutex ){
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU);
pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM);
}
#endif
if( pcache1.separateCache
@@ -1125,7 +1147,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
PGroup *pGroup = pCache->pGroup;
assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
pcache1EnterMutex(pGroup);
pcache1TruncateUnsafe(pCache, 0);
if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0);
assert( pGroup->nMaxPage >= pCache->nMax );
pGroup->nMaxPage -= pCache->nMax;
assert( pGroup->nMinPage >= pCache->nMin );
+44 -32
View File
@@ -343,7 +343,7 @@ void sqlite3Pragma(
}
assert( pId2 );
zDb = pId2->n>0 ? pDb->zName : 0;
zDb = pId2->n>0 ? pDb->zDbSName : 0;
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
@@ -1008,6 +1008,7 @@ void sqlite3Pragma(
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
pDb->bSyncSet = 1;
setAllPagerFlags(db);
}
}
@@ -1044,7 +1045,7 @@ void sqlite3Pragma(
** compiler (eg. count_changes). So add an opcode to expire all
** compiled SQL statements after modifying a pragma value.
*/
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
sqlite3VdbeAddOp0(v, OP_Expire);
setAllPagerFlags(db);
}
break;
@@ -1066,7 +1067,7 @@ void sqlite3Pragma(
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
pTab = sqlite3FindTable(db, zRight, zDb);
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
if( pTab ){
static const char *azCol[] = {
"cid", "name", "type", "notnull", "dflt_value", "pk"
@@ -1091,12 +1092,13 @@ void sqlite3Pragma(
}else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
sqlite3VdbeMultiLoad(v, 1, "issisi",
i-nHidden,
pCol->zName,
pCol->zType ? pCol->zType : "",
sqlite3ColumnType(pCol,""),
pCol->notNull ? 1 : 0,
pCol->zDflt,
pCol->pDflt ? pCol->pDflt->u.zToken : 0,
k);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
@@ -1117,14 +1119,14 @@ void sqlite3Pragma(
sqlite3VdbeMultiLoad(v, 1, "ssii",
pTab->zName,
0,
(int)sqlite3LogEstToInt(pTab->szTabRow),
(int)sqlite3LogEstToInt(pTab->nRowLogEst));
pTab->szTabRow,
pTab->nRowLogEst);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeMultiLoad(v, 2, "sii",
pIdx->zName,
(int)sqlite3LogEstToInt(pIdx->szIdxRow),
(int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
pIdx->szIdxRow,
pIdx->aiRowLogEst[0]);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
}
}
@@ -1204,10 +1206,10 @@ void sqlite3Pragma(
setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
assert( db->aDb[i].zDbSName!=0 );
sqlite3VdbeMultiLoad(v, 1, "iss",
i,
db->aDb[i].zName,
db->aDb[i].zDbSName,
sqlite3BtreeGetFilename(db->aDb[i].pBt));
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
@@ -1347,12 +1349,10 @@ void sqlite3Pragma(
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
sqlite3ColumnDefault(v, pTab, iKey, regRow);
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
}
sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
sqlite3VdbeGoto(v, addrOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
}else{
@@ -1450,7 +1450,10 @@ void sqlite3Pragma(
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
int *aRoot;
int cnt = 0;
int mxIdx = 0;
int nIdx;
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -1463,35 +1466,39 @@ void sqlite3Pragma(
/* Do an integrity check of the B-Tree
**
** Begin by filling registers 2, 3, ... with the root pages numbers
** Begin by finding the root pages numbers
** for all tables and indices in the database.
*/
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
VdbeComment((v, "%s", pTab->zName));
cnt++;
}
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
}
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
if( aRoot==0 ) break;
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
VdbeComment((v, "%s", pIdx->zName));
cnt++;
aRoot[cnt++] = pIdx->tnum;
}
}
aRoot[cnt] = 0;
/* Make sure sufficient number of registers have been allocated */
pParse->nMem = MAX( pParse->nMem, cnt+8 );
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
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);
@@ -1521,7 +1528,8 @@ void sqlite3Pragma(
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
pParse->nMem = MAX(pParse->nMem, 8+j);
assert( pParse->nMem>=8+j );
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
/* Verify that all NOT NULL columns really are NOT NULL */
@@ -1713,7 +1721,9 @@ void sqlite3Pragma(
** PRAGMA [schema.]user_version
** PRAGMA [schema.]user_version = <integer>
**
** PRAGMA [schema.]freelist_count = <integer>
** PRAGMA [schema.]freelist_count
**
** PRAGMA [schema.]data_version
**
** PRAGMA [schema.]application_id
** PRAGMA [schema.]application_id = <integer>
@@ -1769,6 +1779,7 @@ void sqlite3Pragma(
aOp[1].p3 = iCookie;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
sqlite3VdbeReusable(v);
}
}
break;
@@ -1790,6 +1801,7 @@ void sqlite3Pragma(
sqlite3VdbeLoadString(v, 1, zOpt);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
sqlite3VdbeReusable(v);
}
break;
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
@@ -1925,15 +1937,15 @@ void sqlite3Pragma(
Btree *pBt;
const char *zState = "unknown";
int j;
if( db->aDb[i].zName==0 ) continue;
if( db->aDb[i].zDbSName==0 ) continue;
pBt = db->aDb[i].pBt;
if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
}else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
}else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
zState = azLockName[j];
}
sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
break;
+38 -42
View File
@@ -33,7 +33,7 @@ static void corruptSchema(
sqlite3DbFree(db, *pData->pzErrMsg);
*pData->pzErrMsg = z;
}
pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
}
/*
@@ -73,6 +73,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
** structures that describe the table, index, or view.
*/
int rc;
u8 saved_iDb = db->init.iDb;
sqlite3_stmt *pStmt;
TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
@@ -83,7 +84,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = 0;
db->init.iDb = saved_iDb;
assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -107,7 +109,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
** to do here is record the root page number for that index.
*/
Index *pIndex;
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
if( pIndex==0 ){
/* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since
@@ -286,7 +288,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
db->aDb[iDb].zName, zMasterName);
db->aDb[iDb].zDbSName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
sqlite3_xauth xAuth;
@@ -307,7 +309,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
}
if( db->mallocFailed ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
sqlite3ResetAllSchemasOfConnection(db);
}
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
@@ -516,18 +518,14 @@ static int sqlite3Prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
Parse *pParse; /* Parsing context */
char *zErrMsg = 0; /* Error message */
int rc = SQLITE_OK; /* Result code */
int i; /* Loop counter */
Parse sParse; /* Parsing context */
/* Allocate the parsing context */
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
rc = SQLITE_NOMEM;
goto end_prepare;
}
pParse->pReprepare = pReprepare;
memset(&sParse, 0, PARSE_HDR_SZ);
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
assert( sqlite3_mutex_held(db->mutex) );
@@ -561,7 +559,7 @@ static int sqlite3Prepare(
assert( sqlite3BtreeHoldsMutex(pBt) );
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
const char *zDb = db->aDb[i].zName;
const char *zDb = db->aDb[i].zDbSName;
sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
testcase( db->flags & SQLITE_ReadUncommitted );
goto end_prepare;
@@ -571,8 +569,7 @@ static int sqlite3Prepare(
sqlite3VtabUnlockList(db);
pParse->db = db;
pParse->nQueryLoop = 0; /* Logarithmic, so 0 really means 1 */
sParse.db = db;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@@ -585,61 +582,61 @@ static int sqlite3Prepare(
}
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy);
}else{
pParse->zTail = &zSql[nBytes];
sParse.zTail = &zSql[nBytes];
}
}else{
sqlite3RunParser(pParse, zSql, &zErrMsg);
sqlite3RunParser(&sParse, zSql, &zErrMsg);
}
assert( 0==pParse->nQueryLoop );
assert( 0==sParse.nQueryLoop );
if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
if( pParse->checkSchema ){
schemaIsValid(pParse);
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
if( sParse.checkSchema ){
schemaIsValid(&sParse);
}
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
sParse.rc = SQLITE_NOMEM_BKPT;
}
if( pzTail ){
*pzTail = pParse->zTail;
*pzTail = sParse.zTail;
}
rc = pParse->rc;
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
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"
};
int iFirst, mx;
if( pParse->explain==2 ){
sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
iFirst = 8;
mx = 12;
}else{
sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
iFirst = 0;
mx = 8;
}
for(i=iFirst; i<mx; i++){
sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
}
#endif
if( db->init.busy==0 ){
Vdbe *pVdbe = pParse->pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
Vdbe *pVdbe = sParse.pVdbe;
sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
}
if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(pParse->pVdbe);
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)pParse->pVdbe;
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}
if( zErrMsg ){
@@ -650,16 +647,15 @@ static int sqlite3Prepare(
}
/* Delete any TriggerPrg structures allocated while parsing this statement. */
while( pParse->pTriggerPrg ){
TriggerPrg *pT = pParse->pTriggerPrg;
pParse->pTriggerPrg = pT->pNext;
while( sParse.pTriggerPrg ){
TriggerPrg *pT = sParse.pTriggerPrg;
sParse.pTriggerPrg = pT->pNext;
sqlite3DbFree(db, pT);
}
end_prepare:
sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
+18 -18
View File
@@ -15,26 +15,26 @@
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
#define etFLOAT 2 /* Floating point. %f */
#define etEXP 3 /* Exponentional notation. %e and %E */
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 5 /* Return number of characters processed so far. %n */
#define etSTRING 6 /* Strings. %s */
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
#define etPERCENT 8 /* Percent symbol. %% */
#define etCHARX 9 /* Characters. %c */
#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */
#define etFLOAT 1 /* Floating point. %f */
#define etEXP 2 /* Exponentional notation. %e and %E */
#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 4 /* Return number of characters processed so far. %n */
#define etSTRING 5 /* Strings. %s */
#define etDYNSTRING 6 /* Dynamically allocated strings. %z */
#define etPERCENT 7 /* Percent symbol. %% */
#define etCHARX 8 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */
#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 12 /* a pointer to a Token structure */
#define etSRCLIST 13 /* a pointer to a SrcList */
#define etPOINTER 14 /* The %p conversion */
#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
#define etTOKEN 11 /* a pointer to a Token structure */
#define etSRCLIST 12 /* a pointer to a SrcList */
#define etPOINTER 13 /* The %p conversion */
#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
#define etINVALID 0 /* Any unrecognized conversion type */
#define etINVALID 16 /* Any unrecognized conversion type */
/*
@@ -189,7 +189,7 @@ void sqlite3VXPrintf(
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
etByte xtype = 0; /* Conversion paradigm */
etByte xtype = etINVALID; /* Conversion paradigm */
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
u8 useIntern; /* Ok to use internal conversions (ex: %T) */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
+62 -17
View File
@@ -221,8 +221,8 @@ static int lookupName(
zDb = 0;
}else{
for(i=0; i<db->nDb; i++){
assert( db->aDb[i].zName );
if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
assert( db->aDb[i].zDbSName );
if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
pSchema = db->aDb[i].pSchema;
break;
}
@@ -400,6 +400,10 @@ static int lookupName(
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
return WRC_Abort;
}
if( sqlite3ExprVectorSize(pOrig)!=1 ){
sqlite3ErrorMsg(pParse, "row value misused");
return WRC_Abort;
}
resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
cnt = 1;
pMatch = 0;
@@ -623,7 +627,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* if( pSrcList==0 ) break; */
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
/*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
@@ -646,19 +649,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int auth; /* Authorization to use the function */
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
notValid(pParse, pNC, "functions", NC_PartIdx);
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{
@@ -690,15 +691,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
pDef->zName);
pNC->nErr++;
{
int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0);
if( auth!=SQLITE_OK ){
if( auth==SQLITE_DENY ){
sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
pDef->zName);
pNC->nErr++;
}
pExpr->op = TK_NULL;
return WRC_Prune;
}
pExpr->op = TK_NULL;
return WRC_Prune;
}
#endif
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
@@ -711,14 +714,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* Date/time functions that use 'now', and other functions like
** sqlite_version() that might change over time cannot be used
** in an index. */
notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
notValid(pParse, pNC, "non-deterministic functions",
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 ){
}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 ){
@@ -763,6 +771,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
pNC->ncFlags |= NC_VarSelect;
}
}
break;
@@ -771,6 +780,42 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
break;
}
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: {
int nLeft, nRight;
if( pParse->db->mallocFailed ) break;
assert( pExpr->pLeft!=0 );
nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
if( pExpr->op==TK_BETWEEN ){
nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
if( nRight==nLeft ){
nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
}
}else{
assert( pExpr->pRight!=0 );
nRight = sqlite3ExprVectorSize(pExpr->pRight);
}
if( nLeft!=nRight ){
testcase( pExpr->op==TK_EQ );
testcase( pExpr->op==TK_NE );
testcase( pExpr->op==TK_LT );
testcase( pExpr->op==TK_LE );
testcase( pExpr->op==TK_GT );
testcase( pExpr->op==TK_GE );
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_BETWEEN );
sqlite3ErrorMsg(pParse, "row value misused");
}
break;
}
}
return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
}
+65 -75
View File
@@ -57,8 +57,9 @@
** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
** primitives are constant time. The cost of DESTROY is O(N).
**
** There is an added cost of O(N) when switching between TEST and
** SMALLEST primitives.
** TEST and SMALLEST may not be used by the same RowSet. This used to
** be possible, but the feature was not used, so it was removed in order
** to simplify the code.
*/
#include "sqliteInt.h"
@@ -179,7 +180,9 @@ void sqlite3RowSetClear(RowSet *p){
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
assert( p!=0 );
if( p->nFresh==0 ){
if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/
/* We could allocate a fresh RowSetEntry each time one is needed, but it
** is more efficient to pull a preallocated entry from the pool */
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
if( pNew==0 ){
@@ -213,7 +216,9 @@ void sqlite3RowSetInsert(RowSet *p, i64 rowid){
pEntry->pRight = 0;
pLast = p->pLast;
if( pLast ){
if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/
/* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
** where possible */
p->rsFlags &= ~ROWSET_SORTED;
}
pLast->pRight = pEntry;
@@ -237,28 +242,26 @@ static struct RowSetEntry *rowSetEntryMerge(
struct RowSetEntry *pTail;
pTail = &head;
while( pA && pB ){
assert( pA!=0 && pB!=0 );
for(;;){
assert( pA->pRight==0 || pA->v<=pA->pRight->v );
assert( pB->pRight==0 || pB->v<=pB->pRight->v );
if( pA->v<pB->v ){
pTail->pRight = pA;
if( pA->v<=pB->v ){
if( pA->v<pB->v ) pTail = pTail->pRight = pA;
pA = pA->pRight;
pTail = pTail->pRight;
}else if( pB->v<pA->v ){
pTail->pRight = pB;
pB = pB->pRight;
pTail = pTail->pRight;
if( pA==0 ){
pTail->pRight = pB;
break;
}
}else{
pA = pA->pRight;
pTail = pTail->pRight = pB;
pB = pB->pRight;
if( pB==0 ){
pTail->pRight = pA;
break;
}
}
}
if( pA ){
assert( pA->pRight==0 || pA->v<=pA->pRight->v );
pTail->pRight = pA;
}else{
assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
pTail->pRight = pB;
}
return head.pRight;
}
@@ -281,9 +284,10 @@ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
aBucket[i] = pIn;
pIn = pNext;
}
pIn = 0;
for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
pIn = rowSetEntryMerge(pIn, aBucket[i]);
pIn = aBucket[0];
for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
if( aBucket[i]==0 ) continue;
pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i];
}
return pIn;
}
@@ -335,23 +339,29 @@ static struct RowSetEntry *rowSetNDeepTree(
){
struct RowSetEntry *p; /* Root of the new tree */
struct RowSetEntry *pLeft; /* Left subtree */
if( *ppList==0 ){
return 0;
if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
/* Prevent unnecessary deep recursion when we run out of entries */
return 0;
}
if( iDepth==1 ){
if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
/* This branch causes a *balanced* tree to be generated. A valid tree
** is still generated without this branch, but the tree is wildly
** unbalanced and inefficient. */
pLeft = rowSetNDeepTree(ppList, iDepth-1);
p = *ppList;
if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/
/* It is safe to always return here, but the resulting tree
** would be unbalanced */
return pLeft;
}
p->pLeft = pLeft;
*ppList = p->pRight;
p->pRight = rowSetNDeepTree(ppList, iDepth-1);
}else{
p = *ppList;
*ppList = p->pRight;
p->pLeft = p->pRight = 0;
return p;
}
pLeft = rowSetNDeepTree(ppList, iDepth-1);
p = *ppList;
if( p==0 ){
return pLeft;
}
p->pLeft = pLeft;
*ppList = p->pRight;
p->pRight = rowSetNDeepTree(ppList, iDepth-1);
return p;
}
@@ -378,59 +388,37 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
return p;
}
/*
** Take all the entries on p->pEntry and on the trees in p->pForest and
** sort them all together into one big ordered list on p->pEntry.
**
** This routine should only be called once in the life of a RowSet.
*/
static void rowSetToList(RowSet *p){
/* This routine is called only once */
assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
if( (p->rsFlags & ROWSET_SORTED)==0 ){
p->pEntry = rowSetEntrySort(p->pEntry);
}
/* While this module could theoretically support it, sqlite3RowSetNext()
** is never called after sqlite3RowSetText() for the same RowSet. So
** there is never a forest to deal with. Should this change, simply
** remove the assert() and the #if 0. */
assert( p->pForest==0 );
#if 0
while( p->pForest ){
struct RowSetEntry *pTree = p->pForest->pLeft;
if( pTree ){
struct RowSetEntry *pHead, *pTail;
rowSetTreeToList(pTree, &pHead, &pTail);
p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
}
p->pForest = p->pForest->pRight;
}
#endif
p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
}
/*
** Extract the smallest element from the RowSet.
** Write the element into *pRowid. Return 1 on success. Return
** 0 if the RowSet is already empty.
**
** After this routine has been called, the sqlite3RowSetInsert()
** routine may not be called again.
** routine may not be called again.
**
** This routine may not be called after sqlite3RowSetTest() has
** been used. Older versions of RowSet allowed that, but as the
** capability was not used by the code generator, it was removed
** for code economy.
*/
int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
assert( p!=0 );
assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */
/* Merge the forest into a single sorted list on first call */
if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/
if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
p->pEntry = rowSetEntrySort(p->pEntry);
}
p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
}
/* Return the next entry on the list */
if( p->pEntry ){
*pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pRight;
if( p->pEntry==0 ){
if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
/* Free memory immediately, rather than waiting on sqlite3_finalize() */
sqlite3RowSetClear(p);
}
return 1;
@@ -453,13 +441,15 @@ int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
/* This routine is never called after sqlite3RowSetNext() */
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
/* Sort entries into the forest on the first test of a new batch
/* Sort entries into the forest on the first test of a new batch.
** To save unnecessary work, only do this when the batch number changes.
*/
if( iBatch!=pRowSet->iBatch ){
if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/
p = pRowSet->pEntry;
if( p ){
struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
/* Only sort the current set of entiries if they need it */
p = rowSetEntrySort(p);
}
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
+149 -119
View File
@@ -56,6 +56,7 @@ struct SortCtx {
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
int labelDone; /* Jump here when done, ex: LIMIT reached */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
@@ -74,7 +75,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
sqlite3WithDelete(db, p->pWith);
if( p->pWith ) sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFree(db, p);
p = pPrior;
bFree = 1;
@@ -87,7 +88,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
pDest->eDest = (u8)eDest;
pDest->iSDParm = iParm;
pDest->affSdst = 0;
pDest->zAffSdst = 0;
pDest->iSdst = 0;
pDest->nSdst = 0;
}
@@ -105,7 +106,7 @@ Select *sqlite3SelectNew(
ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */
u16 selFlags, /* Flag parameters, such as SF_Distinct */
u32 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */
){
@@ -169,7 +170,7 @@ void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
void sqlite3SelectDelete(sqlite3 *db, Select *p){
clearSelect(db, p, 1);
if( p ) clearSelect(db, p, 1);
}
/*
@@ -589,9 +590,30 @@ static void pushOntoSorter(
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( iLimit ){
int addr;
int r1 = 0;
/* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit
** register is initialized with value of LIMIT+OFFSET.) After the sorter
** fills up, delete the least entry in the sorter after each insert.
** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
if( pSort->bOrderedInnerLoop ){
r1 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
VdbeComment((v, "seq"));
}
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
if( pSort->bOrderedInnerLoop ){
/* If the inner loop is driven by an index such that values from
** the same iteration of the inner loop are in sorted order, then
** immediately jump to the next iteration of an inner loop if the
** entry from the current iteration does not fit into the top
** LIMIT+OFFSET entries of the sorter. */
int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
VdbeCoverage(v);
}
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -637,30 +659,6 @@ static void codeDistinct(
sqlite3ReleaseTempReg(pParse, r1);
}
#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate an error message when a SELECT is used within a subexpression
** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
** column. We do this in a subroutine because the error used to occur
** in multiple places. (The error only occurs in one place now, but we
** retain the subroutine to minimize code disruption.)
*/
static int checkForMultiColumnSelectError(
Parse *pParse, /* Parse context. */
SelectDest *pDest, /* Destination of SELECT results */
int nExpr /* Number of result columns returned by SELECT */
){
int eDest = pDest->eDest;
if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
sqlite3ErrorMsg(pParse, "only a single result allowed for "
"a SELECT that is part of an expression");
return 1;
}else{
return 0;
}
}
#endif
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
@@ -870,19 +868,19 @@ static void selectInnerLoop(
** item into the set table with bogus data.
*/
case SRT_Set: {
assert( nResultCol==1 );
pDest->affSdst =
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pSort ){
/* At first glance you would think we could optimize out the
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
pushOntoSorter(
pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
r1, pDest->zAffSdst, nResultCol);
sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
}
@@ -898,13 +896,14 @@ static void selectInnerLoop(
}
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
** store the results in the appropriate memory cell or array of
** memory cells and break out of the scan loop.
*/
case SRT_Mem: {
assert( nResultCol==1 );
assert( nResultCol==pDest->nSdst );
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
pushOntoSorter(
pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
}else{
assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
@@ -1006,7 +1005,7 @@ static void selectInnerLoop(
*/
KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
int nExtra = (N+X)*(sizeof(CollSeq*)+1);
KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra);
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
p->nField = (u16)N;
@@ -1028,7 +1027,7 @@ void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->nRef>0 );
p->nRef--;
if( p->nRef==0 ) sqlite3DbFree(0, p);
if( p->nRef==0 ) sqlite3DbFree(p->db, p);
}
}
@@ -1219,21 +1218,21 @@ static void generateSortTail(
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
}
iTab = pSort->iECursor;
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
regRowid = 0;
regRow = pDest->iSdst;
nSortData = nColumn;
}else{
regRowid = sqlite3GetTempReg(pParse);
regRow = sqlite3GetTempReg(pParse);
nSortData = 1;
regRow = sqlite3GetTempRange(pParse, nColumn);
nSortData = nColumn;
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
iSortTab = pParse->nTab++;
if( pSort->labelBkOut ){
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
@@ -1261,16 +1260,14 @@ static void generateSortTail(
}
#ifndef SQLITE_OMIT_SUBQUERY
case SRT_Set: {
assert( nColumn==1 );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
&pDest->affSdst, 1);
sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
pDest->zAffSdst, nColumn);
sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
break;
}
case SRT_Mem: {
assert( nColumn==1 );
sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
/* The LIMIT clause will terminate the loop for us */
break;
}
@@ -1289,7 +1286,11 @@ static void generateSortTail(
}
}
if( regRowid ){
sqlite3ReleaseTempReg(pParse, regRow);
if( eDest==SRT_Set ){
sqlite3ReleaseTempRange(pParse, regRow, nColumn);
}else{
sqlite3ReleaseTempReg(pParse, regRow);
}
sqlite3ReleaseTempReg(pParse, regRowid);
}
/* The bottom of the loop
@@ -1429,20 +1430,20 @@ static const char *columnTypeImpl(
zType = "INTEGER";
zOrigCol = "rowid";
}else{
zType = pTab->aCol[iCol].zType;
zOrigCol = pTab->aCol[iCol].zName;
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
if( pNC->pParse ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
zOrigDb = pNC->pParse->db->aDb[iDb].zName;
zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
if( iCol<0 ){
zType = "INTEGER";
}else{
zType = pTab->aCol[iCol].zType;
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
estWidth = pTab->aCol[iCol].szEst;
}
#endif
@@ -1688,7 +1689,7 @@ int sqlite3ColumnsFromExprList(
sqlite3DbFree(db, aCol);
*paCol = 0;
*pnCol = 0;
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
return SQLITE_OK;
}
@@ -1704,7 +1705,7 @@ int sqlite3ColumnsFromExprList(
** This routine requires that all identifiers in the SELECT
** statement be resolved.
*/
static void selectAddColumnTypeAndCollation(
void sqlite3SelectAddColumnTypeAndCollation(
Parse *pParse, /* Parsing contexts */
Table *pTab, /* Add column type information to this table */
Select *pSelect /* SELECT used to determine types and collations */
@@ -1726,13 +1727,20 @@ static void selectAddColumnTypeAndCollation(
sNC.pSrcList = pSelect->pSrc;
a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const char *zType;
int n, m;
p = a[i].pExpr;
if( pCol->zType==0 ){
pCol->zType = sqlite3DbStrDup(db,
columnType(&sNC, p,0,0,0, &pCol->szEst));
}
zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p);
if( zType && (m = sqlite3Strlen30(zType))>0 ){
n = sqlite3Strlen30(pCol->zName);
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
if( pCol->zName ){
memcpy(&pCol->zName[n+1], zType, m+1);
pCol->colFlags |= COLFLAG_HASTYPE;
}
}
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl && pCol->zColl==0 ){
@@ -1769,7 +1777,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -1782,20 +1790,20 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
if( v==0 ){
v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
if( v ) sqlite3VdbeAddOp0(v, OP_Init);
if( pParse->pToplevel==0
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
){
pParse->okConstFactor = 1;
}
static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
if( pParse->pToplevel==0
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
){
pParse->okConstFactor = 1;
}
return v;
}
Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
return v ? v : allocVdbe(pParse);
}
/*
@@ -1845,8 +1853,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
sqlite3VdbeGoto(v, iBreak);
}else if( n>=0 && p->nSelectRow>(u64)n ){
p->nSelectRow = n;
}else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
p->nSelectRow = sqlite3LogEst((u64)n);
p->selFlags |= SF_FixedLimit;
}
}else{
sqlite3ExprCode(pParse, p->pLimit, iLimit);
@@ -2224,7 +2233,6 @@ static int multiSelect(
if( dest.eDest==SRT_EphemTab ){
assert( p->pEList );
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
dest.eDest = SRT_Table;
}
@@ -2287,12 +2295,12 @@ static int multiSelect(
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
p->nSelectRow += pPrior->nSelectRow;
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
if( pPrior->pLimit
&& sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
&& nLimit>0 && p->nSelectRow > (u64)nLimit
&& nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
){
p->nSelectRow = nLimit;
p->nSelectRow = sqlite3LogEst((u64)nLimit);
}
if( addr ){
sqlite3VdbeJumpHere(v, addr);
@@ -2364,7 +2372,9 @@ static int multiSelect(
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
if( p->op==TK_UNION ){
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
}
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -2499,7 +2509,7 @@ static int multiSelect(
nCol = p->pEList->nExpr;
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM_BKPT;
goto multi_select_end;
}
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
@@ -2621,18 +2631,15 @@ static int generateOutputSubroutine(
}
#ifndef SQLITE_OMIT_SUBQUERY
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack. Write this
** item into the set table with bogus data.
/* If we are creating a set for an "expr IN (SELECT ...)".
*/
case SRT_Set: {
int r1;
assert( pIn->nSdst==1 || pParse->nErr>0 );
pDest->affSdst =
sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
testcase( pIn->nSdst>1 );
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
r1, pDest->zAffSdst, pIn->nSdst);
sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
break;
@@ -2854,7 +2861,7 @@ static int multiSelectOrderBy(
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
if( pNew==0 ) return SQLITE_NOMEM;
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
@@ -3001,7 +3008,7 @@ static int multiSelectOrderBy(
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
VdbeCoverage(v);
sqlite3VdbeGoto(v, addrEofA);
p->nSelectRow += pPrior->nSelectRow;
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
}
/* Generate a subroutine to run when the results from select B
@@ -3688,12 +3695,13 @@ static int flattenSubquery(
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
sqlite3ExprDup(db, pSub->pHaving, 0));
pParent->pHaving = sqlite3ExprAnd(db,
sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
);
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
}
substSelect(db, pParent, iParent, pSub->pEList, 0);
@@ -3776,12 +3784,18 @@ static int pushDownWhereTerms(
){
Expr *pNew;
int nChng = 0;
Select *pX; /* For looping over compound SELECTs in pSubq */
if( pWhere==0 ) return 0;
if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
return 0; /* restrictions (1) and (2) */
for(pX=pSubq; pX; pX=pX->pPrior){
if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
testcase( pX->selFlags & SF_Aggregate );
testcase( pX->selFlags & SF_Recursive );
testcase( pX!=pSubq );
return 0; /* restrictions (1) and (2) */
}
}
if( pSubq->pLimit!=0 ){
return 0; /* restriction (3) */
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
@@ -4091,7 +4105,7 @@ static int withExpand(
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
if( db->mallocFailed ) return SQLITE_NOMEM;
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
assert( pFrom->pSelect );
/* Check if this is a recursive CTE. */
@@ -4377,7 +4391,7 @@ static int selectExpander(Walker *pWalker, Select *p){
continue;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
}
for(j=0; j<pTab->nCol; j++){
char *zName = pTab->aCol[j].zName;
@@ -4551,7 +4565,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Select *pSel = pFrom->pSelect;
if( pSel ){
while( pSel->pPrior ) pSel = pSel->pPrior;
selectAddColumnTypeAndCollation(pParse, pTab, pSel);
sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
}
}
}
@@ -4860,16 +4874,6 @@ int sqlite3Select(
}
#endif
/* If writing to memory or generating a set
** only a single column may be output.
*/
#ifndef SQLITE_OMIT_SUBQUERY
if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
goto select_end;
}
#endif
/* Try to flatten subqueries in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -4971,10 +4975,24 @@ int sqlite3Select(
}
/* Generate code to implement the subquery
**
** The subquery is implemented as a co-routine if all of these are true:
** (1) The subquery is guaranteed to be the outer loop (so that it
** does not need to be computed more than once)
** (2) The ALL keyword after SELECT is omitted. (Applications are
** allowed to say "SELECT ALL" instead of just "SELECT" to disable
** the use of co-routines.)
** (3) Co-routines are not disabled using sqlite3_test_control()
** with SQLITE_TESTCTRL_OPTIMIZATIONS.
**
** TODO: Are there other reasons beside (1) to use a co-routine
** implementation?
*/
if( pTabList->nSrc==1
&& (p->selFlags & SF_All)==0
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
if( i==0
&& (pTabList->nSrc==1
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
&& (p->selFlags & SF_All)==0 /* (2) */
&& OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
@@ -4987,7 +5005,7 @@ int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
pItem->regResult = dest.iSdst;
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
@@ -5010,7 +5028,7 @@ int sqlite3Select(
/* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
}else{
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
@@ -5018,7 +5036,7 @@ int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
@@ -5069,6 +5087,13 @@ int sqlite3Select(
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct );
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
}
/* If there is an ORDER BY clause, then create an ephemeral index to
@@ -5101,7 +5126,7 @@ int sqlite3Select(
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
p->nSelectRow = LARGEST_INT64;
p->nSelectRow = 320; /* 4 billion rows */
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
@@ -5125,10 +5150,12 @@ int sqlite3Select(
if( !isAgg && pGroupBy==0 ){
/* No aggregate functions and no GROUP BY clause */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
assert( WHERE_USE_LIMIT==SF_FixedLimit );
wctrlFlags |= p->selFlags & SF_FixedLimit;
/* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, wctrlFlags, 0);
p->pEList, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
@@ -5138,6 +5165,7 @@ int sqlite3Select(
}
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
@@ -5188,9 +5216,11 @@ int sqlite3Select(
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
pItem->u.x.iAlias = 0;
}
if( p->nSelectRow>100 ) p->nSelectRow = 100;
assert( 66==sqlite3LogEst(100) );
if( p->nSelectRow>66 ) p->nSelectRow = 66;
}else{
p->nSelectRow = 1;
assert( 0==sqlite3LogEst(1) );
p->nSelectRow = 0;
}
/* If there is both a GROUP BY and an ORDER BY clause and they are
+1065 -267
View File
File diff suppressed because it is too large Load Diff
+441 -46
View File
@@ -30,8 +30,8 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#ifndef SQLITE3_H
#define SQLITE3_H
#include <stdarg.h> /* Needed for the definition of va_list */
/*
@@ -54,8 +54,17 @@ extern "C" {
#ifndef SQLITE_CDECL
# define SQLITE_CDECL
#endif
#ifndef SQLITE_APICALL
# define SQLITE_APICALL
#endif
#ifndef SQLITE_STDCALL
# define SQLITE_STDCALL
# define SQLITE_STDCALL SQLITE_APICALL
#endif
#ifndef SQLITE_CALLBACK
# define SQLITE_CALLBACK
#endif
#ifndef SQLITE_SYSAPI
# define SQLITE_SYSAPI
#endif
/*
@@ -99,7 +108,8 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
** Since version 3.6.18, SQLite source code has been stored in the
** Since [version 3.6.18] ([dateof:3.6.18]),
** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
@@ -443,7 +453,8 @@ int sqlite3_exec(
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
** address this, newer versions of SQLite (version 3.3.8 and later) include
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
** and later) include
** support for additional result codes that provide more detailed information
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
@@ -506,6 +517,7 @@ int sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -966,6 +978,12 @@ struct sqlite3_io_methods {
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
** underlying native file handle associated with a file handle. This file
** control interprets its argument as a pointer to a native file handle and
** writes the resulting value there.
**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
** opcode causes the xFileControl method to swap the file handle with the one
@@ -1016,6 +1034,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_RBU 26
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1035,6 +1054,16 @@ struct sqlite3_io_methods {
*/
typedef struct sqlite3_mutex sqlite3_mutex;
/*
** CAPI3REF: Loadable Extension Thunk
**
** A pointer to the opaque sqlite3_api_routines structure is passed as
** the third parameter to entry points of [loadable extensions]. This
** structure must be typedefed in order to work around compiler warnings
** on some platforms.
*/
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** CAPI3REF: OS Interface Object
**
@@ -1228,7 +1257,7 @@ struct sqlite3_vfs {
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
** New fields may be appended in figure versions. The iVersion
** New fields may be appended in future versions. The iVersion
** value will increment whenever this happens.
*/
};
@@ -1820,6 +1849,20 @@ struct sqlite3_mem_methods {
** is enabled (using the [PRAGMA threads] command) and the amount of content
** to be sorted exceeds the page size times the minimum of the
** [PRAGMA cache_size] setting and this value.
**
** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
** becomes the [statement journal] spill-to-disk threshold.
** [Statement journals] are held in memory until their size (in bytes)
** exceeds this threshold, at which point they are written to disk.
** Or if the threshold is -1, statement journals are always held
** exclusively in memory.
** Since many statement journals never become large, setting the spill
** threshold to a value such as 64KiB can greatly reduce the amount of
** I/O required to support statement rollback.
** The default value for this setting is controlled by the
** [SQLITE_STMTJRNL_SPILL] compile-time option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1847,6 +1890,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1904,11 +1948,53 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
** <dd> ^This option is used to enable or disable the two-argument
** version of the [fts3_tokenizer()] function which is part of the
** [FTS3] full-text search engine extension.
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
** positive to enable fts3_tokenizer() or negative to leave the setting
** unchanged.
** The second parameter is a pointer to an integer into which
** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
** following this call. The second parameter may be a NULL pointer, in
** which case the new setting is not reported back. </dd>
**
** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
** interface independently of the [load_extension()] SQL function.
** The [sqlite3_enable_load_extension()] API enables or disables both the
** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
** There should be two additional arguments.
** When the first argument to this interface is 1, then only the C-API is
** enabled and the SQL function remains disabled. If the first argument to
** this interface is 0, then both the C-API and the SQL function are disabled.
** If the first argument is -1, then no changes are made to state of either the
** C-API or the SQL function.
** The second parameter is a pointer to an integer into which
** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
** is disabled or enabled following this call. The second parameter may
** be a NULL pointer, in which case the new setting is not reported back.
** </dd>
**
** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
** <dd> ^This option is used to change the name of the "main" database
** schema. ^The sole argument is a pointer to a constant UTF8 string
** which will become the new schema name in place of "main". ^SQLite
** does not make a copy of the new main schema name string, so the application
** must ensure that the argument passed into this DBCONFIG option is unchanged
** until after the database connection closes.
** </dd>
**
** </dl>
*/
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
/*
@@ -2185,7 +2271,7 @@ int sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
/*
** CAPI3REF: Set A Busy Timeout
@@ -2707,6 +2793,9 @@ int sqlite3_set_authorizer(
** CAPI3REF: Tracing And Profiling Functions
** METHOD: sqlite3
**
** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
** instead of the routines described here.
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
**
@@ -2732,10 +2821,104 @@ int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
void(*xTrace)(void*,const char*), void*);
SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
** CAPI3REF: SQL Trace Event Codes
** KEYWORDS: SQLITE_TRACE
**
** These constants identify classes of events that can be monitored
** using the [sqlite3_trace_v2()] tracing logic. The third argument
** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
** the following constants. ^The first argument to the trace callback
** is one of the following constants.
**
** New tracing constants may be added in future releases.
**
** ^A trace callback has four arguments: xCallback(T,C,P,X).
** ^The T argument is one of the integer type codes above.
** ^The C argument is a copy of the context pointer passed in as the
** fourth argument to [sqlite3_trace_v2()].
** The P and X arguments are pointers whose meanings depend on T.
**
** <dl>
** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
** first begins running and possibly at other times during the
** execution of the prepared statement, such as at the start of each
** trigger subprogram. ^The P argument is a pointer to the
** [prepared statement]. ^The X argument is a pointer to a string which
** is the unexpanded SQL text of the prepared statement or an SQL comment
** that indicates the invocation of a trigger. ^The callback can compute
** the same text that would have been returned by the legacy [sqlite3_trace()]
** interface by using the X argument when X begins with "--" and invoking
** [sqlite3_expanded_sql(P)] otherwise.
**
** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
** information as is provided by the [sqlite3_profile()] callback.
** ^The P argument is a pointer to the [prepared statement] and the
** X argument points to a 64-bit integer which is the estimated of
** the number of nanosecond that the prepared statement took to run.
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
** statement generates a single row of result.
** ^The P argument is a pointer to the [prepared statement] and the
** X argument is unused.
**
** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
** connection closes.
** ^The P argument is a pointer to the [database connection] object
** and the X argument is unused.
** </dl>
*/
#define SQLITE_TRACE_STMT 0x01
#define SQLITE_TRACE_PROFILE 0x02
#define SQLITE_TRACE_ROW 0x04
#define SQLITE_TRACE_CLOSE 0x08
/*
** CAPI3REF: SQL Trace Hook
** METHOD: sqlite3
**
** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
** function X against [database connection] D, using property mask M
** and context pointer P. ^If the X callback is
** NULL or if the M mask is zero, then tracing is disabled. The
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
** ignored, though this may change in future releases. Callback
** implementations should return zero to ensure future compatibility.
**
** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
** ^The T argument is one of the [SQLITE_TRACE]
** constants to indicate why the callback was invoked.
** ^The C argument is a copy of the context pointer.
** The P and X arguments are pointers whose meanings depend on T.
**
** The sqlite3_trace_v2() interface is intended to replace the legacy
** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
** are deprecated.
*/
int sqlite3_trace_v2(
sqlite3*,
unsigned uMask,
int(*xCallback)(unsigned,void*,void*,void*),
void *pCtx
);
/*
** CAPI3REF: Query Progress Callbacks
** METHOD: sqlite3
@@ -3354,11 +3537,35 @@ int sqlite3_prepare16_v2(
** CAPI3REF: Retrieving Statement SQL
** METHOD: sqlite3_stmt
**
** ^This interface can be used to retrieve a saved copy of the original
** SQL text used to create a [prepared statement] if that statement was
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
** SQL text used to create [prepared statement] P if P was
** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
** string containing the SQL text of prepared statement P with
** [bound parameters] expanded.
**
** ^(For example, if a prepared statement is created using the SQL
** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
** and parameter :xyz is unbound, then sqlite3_sql() will return
** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
** will return "SELECT 2345,NULL".)^
**
** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
** is available to hold the result, or if the result would exceed the
** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
**
** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
** option causes sqlite3_expanded_sql() to always return NULL.
**
** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
** automatically freed when the prepared statement is finalized.
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
** is obtained from [sqlite3_malloc()] and must be free by the application
** by passing it to [sqlite3_free()].
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt);
char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3853,7 +4060,8 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** other than [SQLITE_ROW] before any subsequent invocation of
** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
** break because any application that ever receives an SQLITE_MISUSE error
@@ -4516,12 +4724,13 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** SQLite will invoke the destructor function X with parameter P exactly
** once, when the metadata is discarded.
** SQLite is free to discard the metadata at any time, including: <ul>
** <li> when the corresponding function parameter changes, or
** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
** SQL statement, or
** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
** <li> during the original sqlite3_set_auxdata() call when a memory
** allocation error occurs. </ul>)^
** <li> ^(when the corresponding function parameter changes)^, or
** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
** SQL statement)^, or
** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
** <li> ^(during the original sqlite3_set_auxdata() call when a memory
** allocation error occurs.)^ </ul>
**
** Note the last bullet in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
@@ -5158,7 +5367,7 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted in
** a rowid table.
** a [rowid table].
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
@@ -5197,8 +5406,8 @@ void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** on the same [database connection] D, or NULL for
** the first call on D.
**
** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
** interfaces.
** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
** and [sqlite3_preupdate_hook()] interfaces.
*/
void *sqlite3_update_hook(
sqlite3*,
@@ -5215,7 +5424,8 @@ void *sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
@@ -5309,7 +5519,8 @@ int sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
** the soft heap limit is enforced
** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
** the soft heap limit is enforced on every memory allocation. Without
@@ -5348,7 +5559,7 @@ SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existance of the
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.
**
@@ -5445,9 +5656,18 @@ int sqlite3_table_column_metadata(
** should free this memory by calling [sqlite3_free()].
**
** ^Extension loading must be enabled using
** [sqlite3_enable_load_extension()] prior to calling this API,
** [sqlite3_enable_load_extension()] or
** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
** prior to calling this API,
** otherwise an error will be returned.
**
** <b>Security warning:</b> It is recommended that the
** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
** interface. The use of the [sqlite3_enable_load_extension()] interface
** should be avoided. This will keep the SQL function [load_extension()]
** disabled and prevent SQL injections from giving attackers
** access to extension loading capabilities.
**
** See also the [load_extension() SQL function].
*/
int sqlite3_load_extension(
@@ -5470,6 +5690,17 @@ int sqlite3_load_extension(
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
**
** ^This interface enables or disables both the C-API
** [sqlite3_load_extension()] and the SQL function [load_extension()].
** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
*/
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
@@ -5483,7 +5714,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
**
** ^(Even though the function prototype shows that xEntryPoint() takes
** no arguments and returns void, SQLite invokes xEntryPoint() with three
** arguments and expects and integer result as if the signature of the
** arguments and expects an integer result as if the signature of the
** entry point where as follows:
**
** <blockquote><pre>
@@ -5509,7 +5740,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
int sqlite3_auto_extension(void (*xEntryPoint)(void));
int sqlite3_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5521,7 +5752,7 @@ int sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5683,13 +5914,15 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
** was added for version 3.9.0. It may therefore only be used if
** was added for [version 3.9.0] ([dateof:3.9.0]).
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
@@ -6387,7 +6620,7 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
@@ -6491,6 +6724,7 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
@@ -6697,6 +6931,18 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
** pager cache is shared between two or more connections the bytes of heap
** memory used by that pager cache is divided evenly between the attached
** connections.)^ In other words, if none of the pager caches associated
** with the database connection are shared, this request returns the same
** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
** shared, the value returned by this call will be smaller than that returned
** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
@@ -6754,7 +7000,8 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
#define SQLITE_DBSTATUS_CACHE_MISS 8
#define SQLITE_DBSTATUS_CACHE_WRITE 9
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
/*
@@ -7108,7 +7355,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
** ^A call to sqlite3_backup_init() will fail, returning NULL, if
** there is already a read or read-write transaction open on the
** destination database.
**
@@ -7489,7 +7736,7 @@ void sqlite3_log(int iErrCode, const char *zFormat, ...);
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
** overwrite any prior [sqlite3_wal_hook()] settings.
*/
void *sqlite3_wal_hook(
sqlite3*,
@@ -7886,6 +8133,114 @@ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
*/
int sqlite3_db_cacheflush(sqlite3*);
/*
** CAPI3REF: The pre-update hook.
**
** ^These interfaces are only available if SQLite is compiled using the
** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
**
** ^The [sqlite3_preupdate_hook()] interface registers a callback function
** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
** on a [rowid table].
** ^At most one preupdate hook may be registered at a time on a single
** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
** the previous setting.
** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
** with a NULL pointer as the second parameter.
** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
** the first parameter to callbacks.
**
** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
** tables.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
** ^The third parameter to the preupdate callback is one of the constants
** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
** kind of update operation that is about to occur.
** ^(The fourth parameter to the preupdate callback is the name of the
** database within the database connection that is being modified. This
** will be "main" for the main database or "temp" for TEMP tables or
** the name given after the AS keyword in the [ATTACH] statement for attached
** databases.)^
** ^The fifth parameter to the preupdate callback is the name of the
** table that is being modified.
** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
** undefined for SQLITE_INSERT changes.
** ^The seventh parameter to the preupdate callback is the final [rowid] of
** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
** undefined for SQLITE_DELETE changes.
**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
** provide additional information about a preupdate event. These routines
** may only be called from within a preupdate callback. Invoking any of
** these routines from outside of a preupdate callback or with a
** [database connection] pointer that is different from the one supplied
** to the preupdate callback results in undefined and probably undesirable
** behavior.
**
** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
** in the row that is being inserted, updated, or deleted.
**
** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
** a [protected sqlite3_value] that contains the value of the Nth column of
** the table row before it is updated. The N parameter must be between 0
** and one less than the number of columns or the behavior will be
** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
** behavior is undefined. The [sqlite3_value] that P points to
** will be destroyed when the preupdate callback returns.
**
** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
** a [protected sqlite3_value] that contains the value of the Nth column of
** the table row after it is updated. The N parameter must be between 0
** and one less than the number of columns or the behavior will be
** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
** behavior is undefined. The [sqlite3_value] that P points to
** will be destroyed when the preupdate callback returns.
**
** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
** callback was invoked as a result of a direct insert, update, or delete
** operation; or 1 for inserts, updates, or deletes invoked by top-level
** triggers; or 2 for changes resulting from triggers called by top-level
** triggers; and so forth.
**
** See also: [sqlite3_update_hook()]
*/
SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
sqlite3 *db,
void(*xPreUpdate)(
void *pCtx, /* Copy of third arg to preupdate_hook() */
sqlite3 *db, /* Database handle */
int op, /* SQLITE_UPDATE, DELETE or INSERT */
char const *zDb, /* Database name */
char const *zName, /* Table name */
sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
),
void*
);
SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
/*
** CAPI3REF: Low-level system error code
**
** ^Attempt to return the underlying operating system error code or error
** number that caused the most recent I/O error or failure to open a file.
** The return value is OS-dependent. For example, on unix systems, after
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
** called to get back the underlying "errno" that caused the problem, such
** as ENOSPC, EAUTH, EISDIR, and so forth.
*/
int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
** KEYWORDS: {snapshot}
@@ -7944,17 +8299,30 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
** CAPI3REF: Start a read transaction on an historical snapshot
** EXPERIMENTAL
**
** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the
** read transaction that is currently open on schema S of
** [database connection] D so that it refers to historical [snapshot] P.
** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
** read transaction for schema S of
** [database connection] D such that the read transaction
** refers to historical [snapshot] P, rather than the most
** recent change to the database.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
** the first operation, apart from other sqlite3_snapshot_open() calls,
** following the [BEGIN] that starts a new read transaction.
** ^A [snapshot] will fail to open if it has been overwritten by a
** [checkpoint].
** the first operation following the [BEGIN] that takes the schema S
** out of [autocommit mode].
** ^In other words, schema S must not currently be in
** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
** database connection D must be out of [autocommit mode].
** ^A [snapshot] will fail to open if it has been overwritten by a
** [checkpoint].
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
** database connection D does not know that the database file for
** schema S is in [WAL mode]. A database connection might not know
** that the database file is in [WAL mode] if there has been no prior
** I/O on that database connection, or if the database entered [WAL mode]
** after the most recent I/O on the database connection.)^
** (Hint: Run "[PRAGMA application_id]" against a newly opened
** database connection in order to make it ready to use snapshots.)
**
** The [sqlite3_snapshot_open()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
@@ -7978,6 +8346,33 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
*/
SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
/*
** CAPI3REF: Compare the ages of two snapshot handles.
** EXPERIMENTAL
**
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
** of two valid snapshot handles.
**
** If the two snapshot handles are not associated with the same database
** file, the result of the comparison is undefined.
**
** Additionally, the result of the comparison is only valid if both of the
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
** last time the wal file was deleted. The wal file is deleted when the
** database is changed back to rollback mode or when the number of database
** clients drops to zero. If either snapshot handle was obtained before the
** wal file was last deleted, the value returned by this function
** is undefined.
**
** Otherwise, this API returns a negative value if P1 refers to an older
** snapshot than P2, zero if the two handles refer to the same database
** snapshot, and a positive value if P1 is a newer snapshot than P2.
*/
SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
sqlite3_snapshot *p1,
sqlite3_snapshot *p2
);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
@@ -7989,4 +8384,4 @@ SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
#endif /* _SQLITE3_H_ */
#endif /* SQLITE3_H */
+23 -5
View File
@@ -15,12 +15,10 @@
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure holds pointers to all of the SQLite API
** routines.
@@ -279,8 +277,23 @@ struct sqlite3_api_routines {
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
@@ -522,6 +535,11 @@ struct sqlite3_api_routines {
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -539,4 +557,4 @@ struct sqlite3_api_routines {
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* _SQLITE3EXT_H_ */
#endif /* SQLITE3EXT_H */
+446 -228
View File
File diff suppressed because it is too large Load Diff
+7 -6
View File
@@ -101,13 +101,13 @@
** The suggested maximum number of in-memory pages to use for
** the main database table and for temporary tables.
**
** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
** is 2000 pages.
** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
** which means the cache size is limited to 2048000 bytes of memory.
** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
# define SQLITE_DEFAULT_CACHE_SIZE 2000
# define SQLITE_DEFAULT_CACHE_SIZE -2000
#endif
/*
@@ -120,8 +120,9 @@
/*
** The maximum number of attached databases. This must be between 0
** and 62. The upper bound on 62 is because a 64-bit integer bitmap
** is used internally to track attached databases.
** and 125. The upper bound of 125 is because the attached databases are
** counted using a signed 8-bit integer which has a maximum value of 127
** and we have to allow 2 extra counts for the "main" and "temp" databases.
*/
#ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10
@@ -156,7 +157,7 @@
** The default size of a database page.
*/
#ifndef SQLITE_DEFAULT_PAGE_SIZE
# define SQLITE_DEFAULT_PAGE_SIZE 1024
# define SQLITE_DEFAULT_PAGE_SIZE 4096
#endif
#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
# undef SQLITE_DEFAULT_PAGE_SIZE
+7 -2
View File
@@ -158,7 +158,7 @@ int sqlite3_status64(
return SQLITE_OK;
}
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
sqlite3_int64 iCur, iHwtr;
sqlite3_int64 iCur = 0, iHwtr = 0;
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
@@ -219,6 +219,7 @@ int sqlite3_db_status(
** by all pagers associated with the given database connection. The
** highwater mark is meaningless and is returned as zero.
*/
case SQLITE_DBSTATUS_CACHE_USED_SHARED:
case SQLITE_DBSTATUS_CACHE_USED: {
int totalUsed = 0;
int i;
@@ -227,7 +228,11 @@ int sqlite3_db_status(
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
Pager *pPager = sqlite3BtreePager(pBt);
totalUsed += sqlite3PagerMemUsed(pPager);
int nByte = sqlite3PagerMemUsed(pPager);
if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
nByte = nByte / sqlite3BtreeConnectionCount(pBt);
}
totalUsed += nByte;
}
}
sqlite3BtreeLeaveAll(db);
+3 -3
View File
@@ -101,7 +101,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
return 0;
malloc_failed:
p->rc = SQLITE_NOMEM;
p->rc = SQLITE_NOMEM_BKPT;
return 1;
}
@@ -142,7 +142,7 @@ int sqlite3_get_table(
res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
@@ -171,7 +171,7 @@ int sqlite3_get_table(
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
return SQLITE_NOMEM;
return SQLITE_NOMEM_BKPT;
}
res.azResult = azNew;
}
+517 -152
View File
File diff suppressed because it is too large Load Diff
+551 -187
View File
File diff suppressed because it is too large Load Diff
+25 -21
View File
@@ -14,7 +14,11 @@
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
@@ -38,7 +42,7 @@ static void pager_test_reiniter(DbPage *pNotUsed){
**
** Open a new pager
*/
static int pager_open(
static int SQLITE_TCLAPI pager_open(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -75,7 +79,7 @@ static int pager_open(
**
** Close the given pager.
*/
static int pager_close(
static int SQLITE_TCLAPI pager_close(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -102,7 +106,7 @@ static int pager_close(
**
** Rollback changes
*/
static int pager_rollback(
static int SQLITE_TCLAPI pager_rollback(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -129,7 +133,7 @@ static int pager_rollback(
**
** Commit all changes
*/
static int pager_commit(
static int SQLITE_TCLAPI pager_commit(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -161,7 +165,7 @@ static int pager_commit(
**
** Start a new checkpoint.
*/
static int pager_stmt_begin(
static int SQLITE_TCLAPI pager_stmt_begin(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -188,7 +192,7 @@ static int pager_stmt_begin(
**
** Rollback changes to a checkpoint
*/
static int pager_stmt_rollback(
static int SQLITE_TCLAPI pager_stmt_rollback(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -216,7 +220,7 @@ static int pager_stmt_rollback(
**
** Commit changes to a checkpoint
*/
static int pager_stmt_commit(
static int SQLITE_TCLAPI pager_stmt_commit(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -243,7 +247,7 @@ static int pager_stmt_commit(
**
** Return pager statistics.
*/
static int pager_stats(
static int SQLITE_TCLAPI pager_stats(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -276,7 +280,7 @@ static int pager_stats(
**
** Return the size of the database file.
*/
static int pager_pagecount(
static int SQLITE_TCLAPI pager_pagecount(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -302,7 +306,7 @@ static int pager_pagecount(
**
** Return a pointer to a page from the database.
*/
static int page_get(
static int SQLITE_TCLAPI page_get(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -339,7 +343,7 @@ static int page_get(
** Return a pointer to a page if the page is already in cache.
** If not in cache, return an empty string.
*/
static int page_lookup(
static int SQLITE_TCLAPI page_lookup(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -367,7 +371,7 @@ static int page_lookup(
/*
** Usage: pager_truncate ID PGNO
*/
static int pager_truncate(
static int SQLITE_TCLAPI pager_truncate(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -392,7 +396,7 @@ static int pager_truncate(
**
** Drop a pointer to a page.
*/
static int page_unref(
static int SQLITE_TCLAPI page_unref(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -414,7 +418,7 @@ static int page_unref(
**
** Return the content of a page
*/
static int page_read(
static int SQLITE_TCLAPI page_read(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -438,7 +442,7 @@ static int page_read(
**
** Return the page number for a page.
*/
static int page_number(
static int SQLITE_TCLAPI page_number(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -462,7 +466,7 @@ static int page_number(
**
** Write something into a page.
*/
static int page_write(
static int SQLITE_TCLAPI page_write(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -498,7 +502,7 @@ static int page_write(
** new pages after N. If N is 2096 or bigger, this will test the
** ability of SQLite to write to large files.
*/
static int fake_big_file(
static int SQLITE_TCLAPI fake_big_file(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -551,7 +555,7 @@ static int fake_big_file(
**
** Set the PENDING_BYTE using the sqlite3_test_control() interface.
*/
static int testPendingByte(
static int SQLITE_TCLAPI testPendingByte(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -616,7 +620,7 @@ static int faultSimCallback(int x){
** appended, whenever sqlite3FaultSim() is called. Or, if SCRIPT is the
** empty string, cancel the sqlite3FaultSim() callback.
*/
static int faultInstallCmd(
static int SQLITE_TCLAPI faultInstallCmd(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -659,7 +663,7 @@ static int faultInstallCmd(
** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
** See comments on sqlite3BitvecBuiltinTest() for additional information.
*/
static int testBitvecBuiltinTest(
static int SQLITE_TCLAPI testBitvecBuiltinTest(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
+46 -44
View File
@@ -15,7 +15,11 @@
*/
#include "sqliteInt.h"
#include "btreeInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -33,7 +37,7 @@ static int nRefSqlite3 = 0;
**
** Open a new database
*/
static int btree_open(
static int SQLITE_TCLAPI btree_open(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -79,7 +83,7 @@ static int btree_open(
**
** Close the given database.
*/
static int btree_close(
static int SQLITE_TCLAPI btree_close(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -114,7 +118,7 @@ static int btree_close(
**
** Start a new transaction
*/
static int btree_begin_transaction(
static int SQLITE_TCLAPI btree_begin_transaction(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -143,7 +147,7 @@ static int btree_begin_transaction(
**
** Returns pager statistics
*/
static int btree_pager_stats(
static int SQLITE_TCLAPI btree_pager_stats(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -193,7 +197,7 @@ static int btree_pager_stats(
**
** Create a new cursor. Return the ID for the cursor.
*/
static int btree_cursor(
static int SQLITE_TCLAPI btree_cursor(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -242,14 +246,13 @@ static int btree_cursor(
**
** Close a cursor opened using btree_cursor.
*/
static int btree_close_cursor(
static int SQLITE_TCLAPI btree_close_cursor(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
BtCursor *pCur;
Btree *pBt;
int rc;
if( argc!=2 ){
@@ -258,12 +261,18 @@ static int btree_close_cursor(
return TCL_ERROR;
}
pCur = sqlite3TestTextToPtr(argv[1]);
pBt = pCur->pBtree;
sqlite3_mutex_enter(pBt->db->mutex);
sqlite3BtreeEnter(pBt);
#if SQLITE_THREADSAFE>0
{
Btree *pBt = pCur->pBtree;
sqlite3_mutex_enter(pBt->db->mutex);
sqlite3BtreeEnter(pBt);
rc = sqlite3BtreeCloseCursor(pCur);
sqlite3BtreeLeave(pBt);
sqlite3_mutex_leave(pBt->db->mutex);
}
#else
rc = sqlite3BtreeCloseCursor(pCur);
sqlite3BtreeLeave(pBt);
sqlite3_mutex_leave(pBt->db->mutex);
#endif
ckfree((char *)pCur);
if( rc ){
Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
@@ -279,7 +288,7 @@ static int btree_close_cursor(
** or 1 if the cursor was already on the last entry in the table or if
** the table is empty.
*/
static int btree_next(
static int SQLITE_TCLAPI btree_next(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -314,7 +323,7 @@ static int btree_next(
** Move the cursor to the first entry in the table. Return 0 if the
** cursor was left point to something and 1 if the table is empty.
*/
static int btree_first(
static int SQLITE_TCLAPI btree_first(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -349,7 +358,7 @@ static int btree_first(
** Return TRUE if the given cursor is not pointing at a valid entry.
** Return FALSE if the cursor does point to a valid entry.
*/
static int btree_eof(
static int SQLITE_TCLAPI btree_eof(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -378,15 +387,14 @@ static int btree_eof(
**
** Return the number of bytes of payload
*/
static int btree_payload_size(
static int SQLITE_TCLAPI btree_payload_size(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
BtCursor *pCur;
int n2;
u64 n1;
u32 n;
char zBuf[50];
if( argc!=2 ){
@@ -396,17 +404,9 @@ static int btree_payload_size(
}
pCur = sqlite3TestTextToPtr(argv[1]);
sqlite3BtreeEnter(pCur->pBtree);
/* The cursor may be in "require-seek" state. If this is the case, the
** call to BtreeDataSize() will fix it. */
sqlite3BtreeDataSize(pCur, (u32*)&n2);
if( pCur->apPage[pCur->iPage]->intKey ){
n1 = 0;
}else{
sqlite3BtreeKeySize(pCur, (i64*)&n1);
}
n = sqlite3BtreePayloadSize(pCur);
sqlite3BtreeLeave(pCur->pBtree);
sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);
Tcl_AppendResult(interp, zBuf, 0);
return SQLITE_OK;
}
@@ -425,7 +425,7 @@ static int btree_payload_size(
** This command returns nothing if it works. It returns an error message
** if something goes wrong.
*/
static int btree_varint_test(
static int SQLITE_TCLAPI btree_varint_test(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -509,7 +509,7 @@ static int btree_varint_test(
** sqlite3 db test.db
** set bt [btree_from_db db]
*/
static int btree_from_db(
static int SQLITE_TCLAPI btree_from_db(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -547,9 +547,9 @@ static int btree_from_db(
/*
** Usage: btree_ismemdb ID
**
** Return true if the B-Tree is in-memory.
** Return true if the B-Tree is currently stored entirely in memory.
*/
static int btree_ismemdb(
static int SQLITE_TCLAPI btree_ismemdb(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -557,6 +557,7 @@ static int btree_ismemdb(
){
Btree *pBt;
int res;
sqlite3_file *pFile;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -566,7 +567,8 @@ static int btree_ismemdb(
pBt = sqlite3TestTextToPtr(argv[1]);
sqlite3_mutex_enter(pBt->db->mutex);
sqlite3BtreeEnter(pBt);
res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
pFile = sqlite3PagerFile(sqlite3BtreePager(pBt));
res = (pFile->pMethods==0);
sqlite3BtreeLeave(pBt);
sqlite3_mutex_leave(pBt->db->mutex);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
@@ -578,7 +580,7 @@ static int btree_ismemdb(
**
** Set the size of the cache used by btree $ID.
*/
static int btree_set_cache_size(
static int SQLITE_TCLAPI btree_set_cache_size(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -608,7 +610,7 @@ static int btree_set_cache_size(
**
** Set the size of the cache used by btree $ID.
*/
static int btree_insert(
static int SQLITE_TCLAPI btree_insert(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -616,27 +618,27 @@ static int btree_insert(
){
BtCursor *pCur;
int rc;
void *pKey = 0;
int nKey = 0;
void *pData = 0;
int nData = 0;
BtreePayload x;
if( objc!=4 && objc!=3 ){
Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");
return TCL_ERROR;
}
memset(&x, 0, sizeof(x));
if( objc==4 ){
if( Tcl_GetIntFromObj(interp, objv[2], &nKey) ) return TCL_ERROR;
pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &nData);
if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;
x.nKey = rc;
x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData);
}else{
pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &nKey);
x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc);
x.nKey = rc;
}
pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
sqlite3_mutex_enter(pCur->pBtree->db->mutex);
sqlite3BtreeEnter(pCur->pBtree);
rc = sqlite3BtreeInsert(pCur, pKey, nKey, pData, nData, 0, 0, 0);
rc = sqlite3BtreeInsert(pCur, &x, 0, 0);
sqlite3BtreeLeave(pCur->pBtree);
sqlite3_mutex_leave(pCur->pBtree->db->mutex);
+20 -16
View File
@@ -12,7 +12,11 @@
** Code for testing the SQLite library in a multithreaded environment.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#if SQLITE_OS_UNIX && SQLITE_THREADSAFE
#include <stdlib.h>
#include <string.h>
@@ -121,7 +125,7 @@ static int parse_thread_id(Tcl_Interp *interp, const char *zArg){
** NAME should be an upper case letter. Start the thread running with
** an open connection to the given database.
*/
static int tcl_thread_create(
static int SQLITE_TCLAPI tcl_thread_create(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -170,7 +174,7 @@ static void thread_wait(Thread *p){
**
** Wait on thread ID to reach its idle state.
*/
static int tcl_thread_wait(
static int SQLITE_TCLAPI tcl_thread_wait(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -214,7 +218,7 @@ static void stop_thread(Thread *p){
** Cause a thread to shut itself down. Wait for the shutdown to be
** completed. If ID is "*" then stop all threads.
*/
static int tcl_thread_halt(
static int SQLITE_TCLAPI tcl_thread_halt(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -249,7 +253,7 @@ static int tcl_thread_halt(
** Wait on the most recent thread_step to complete, then return the
** number of columns in the result set.
*/
static int tcl_thread_argc(
static int SQLITE_TCLAPI tcl_thread_argc(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -281,7 +285,7 @@ static int tcl_thread_argc(
** Wait on the most recent thread_step to complete, then return the
** value of the N-th columns in the result set.
*/
static int tcl_thread_argv(
static int SQLITE_TCLAPI tcl_thread_argv(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -317,7 +321,7 @@ static int tcl_thread_argv(
** Wait on the most recent thread_step to complete, then return the
** name of the N-th columns in the result set.
*/
static int tcl_thread_colname(
static int SQLITE_TCLAPI tcl_thread_colname(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -353,7 +357,7 @@ static int tcl_thread_colname(
** Wait on the most recent operation to complete, then return the
** result code from that operation.
*/
static int tcl_thread_result(
static int SQLITE_TCLAPI tcl_thread_result(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -385,7 +389,7 @@ static int tcl_thread_result(
** Wait on the most recent operation to complete, then return the
** error string.
*/
static int tcl_thread_error(
static int SQLITE_TCLAPI tcl_thread_error(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -430,7 +434,7 @@ static void do_compile(Thread *p){
**
** Compile a new virtual machine.
*/
static int tcl_thread_compile(
static int SQLITE_TCLAPI tcl_thread_compile(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -483,7 +487,7 @@ static void do_step(Thread *p){
**
** Advance the virtual machine by one step
*/
static int tcl_thread_step(
static int SQLITE_TCLAPI tcl_thread_step(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -525,7 +529,7 @@ static void do_finalize(Thread *p){
**
** Finalize the virtual machine.
*/
static int tcl_thread_finalize(
static int SQLITE_TCLAPI tcl_thread_finalize(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -556,7 +560,7 @@ static int tcl_thread_finalize(
**
** Interchange the sqlite* pointer between two threads.
*/
static int tcl_thread_swap(
static int SQLITE_TCLAPI tcl_thread_swap(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -596,7 +600,7 @@ static int tcl_thread_swap(
** remove the pointer from the thread itself. Afterwards, the thread
** can be stopped and the connection can be used by the main thread.
*/
static int tcl_thread_db_get(
static int SQLITE_TCLAPI tcl_thread_db_get(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -627,7 +631,7 @@ static int tcl_thread_db_get(
** Usage: thread_db_put ID DB
**
*/
static int tcl_thread_db_put(
static int SQLITE_TCLAPI tcl_thread_db_put(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -659,7 +663,7 @@ static int tcl_thread_db_put(
** Return the database stmt pointer for the given thread. Then
** remove the pointer from the thread itself.
*/
static int tcl_thread_stmt_get(
static int SQLITE_TCLAPI tcl_thread_stmt_get(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
+9 -5
View File
@@ -17,7 +17,11 @@
*/
#include "sqliteInt.h"
#include "vdbeInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -26,7 +30,7 @@
** object with the encoded representation of the string, including
** the NULL terminator.
*/
static int binarize(
static int SQLITE_TCLAPI binarize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -54,7 +58,7 @@ static int binarize(
** If <do-calls> is 0, then the calls to sqlite3_value_text() are not
** actually made.
*/
static int test_value_overhead(
static int SQLITE_TCLAPI test_value_overhead(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -118,7 +122,7 @@ static u8 name_to_enc(Tcl_Interp *interp, Tcl_Obj *pObj){
** Usage: test_translate <string/blob> <from enc> <to enc> ?<transient>?
**
*/
static int test_translate(
static int SQLITE_TCLAPI test_translate(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -182,7 +186,7 @@ static int test_translate(
** translation. If there is a problem an assert() will fail.
**/
void sqlite3UtfSelfTest(void);
static int test_translate_selftest(
static int SQLITE_TCLAPI test_translate_selftest(
void * clientData,
Tcl_Interp *interp,
int objc,
+62 -8
View File
@@ -16,7 +16,11 @@
*/
#if SQLITE_TEST /* This file is used for testing only */
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */
@@ -215,7 +219,9 @@ static int writeListSync(CrashFile *pFile, int isCrash){
}
#ifdef TRACE_CRASHTEST
printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
if( pFile ){
printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
}
#endif
ppPtr = &g.pWriteList;
@@ -701,6 +707,10 @@ static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
return pVfs->xCurrentTime(pVfs, pTimeOut);
}
static int cfGetLastError(sqlite3_vfs *pCfVfs, int n, char *z){
sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
return pVfs->xGetLastError(pVfs, n, z);
}
static int processDevSymArgs(
Tcl_Interp *interp,
@@ -795,13 +805,34 @@ static int processDevSymArgs(
return TCL_OK;
}
/*
** tclcmd: sqlite3_crash_now
**
** Simulate a crash immediately. This function does not return
** (writeListSync() calls exit(-1)).
*/
static int SQLITE_TCLAPI crashNowCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
writeListSync(0, 1);
assert( 0 );
return TCL_OK;
}
/*
** tclcmd: sqlite_crash_enable ENABLE
**
** Parameter ENABLE must be a boolean value. If true, then the "crash"
** vfs is added to the system. If false, it is removed.
*/
static int crashEnableCmd(
static int SQLITE_TCLAPI crashEnableCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -827,7 +858,7 @@ static int crashEnableCmd(
cfRandomness, /* xRandomness */
cfSleep, /* xSleep */
cfCurrentTime, /* xCurrentTime */
0, /* xGetlastError */
cfGetLastError, /* xGetLastError */
0, /* xCurrentTimeInt64 */
};
@@ -876,7 +907,7 @@ static int crashEnableCmd(
** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
**
*/
static int crashParamsObjCmd(
static int SQLITE_TCLAPI crashParamsObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -923,7 +954,7 @@ error:
return TCL_ERROR;
}
static int devSymObjCmd(
static int SQLITE_TCLAPI devSymObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -940,12 +971,33 @@ static int devSymObjCmd(
devsym_register(iDc, iSectorSize);
return TCL_OK;
}
/*
** tclcmd: unregister_devsim
*/
static int SQLITE_TCLAPI dsUnregisterObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
void devsym_unregister(void);
if( objc!=1 ){
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
devsym_unregister();
return TCL_OK;
}
/*
** tclcmd: register_jt_vfs ?-default? PARENT-VFS
*/
static int jtObjCmd(
static int SQLITE_TCLAPI jtObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -983,7 +1035,7 @@ static int jtObjCmd(
/*
** tclcmd: unregister_jt_vfs
*/
static int jtUnregisterObjCmd(
static int SQLITE_TCLAPI jtUnregisterObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1009,7 +1061,9 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
#ifndef SQLITE_OMIT_DISKIO
Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
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, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
#endif
+18 -14
View File
@@ -13,7 +13,11 @@
** Derived from test4.c.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
/*
** This test only works on UNIX with a SQLITE_THREADSAFE build that includes
@@ -149,7 +153,7 @@ static int parse_client_id(Tcl_Interp *interp, const char *zArg){
** NAME should be an upper case letter. Start the thread running with
** an open connection to the given database.
*/
static int tcl_client_create(
static int SQLITE_TCLAPI tcl_client_create(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -202,7 +206,7 @@ static void client_wait(Thread *p){
**
** Wait on thread ID to reach its idle state.
*/
static int tcl_client_wait(
static int SQLITE_TCLAPI tcl_client_wait(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -246,7 +250,7 @@ static void stop_thread(Thread *p){
** Cause a client thread to shut itself down. Wait for the shutdown to be
** completed. If ID is "*" then stop all client threads.
*/
static int tcl_client_halt(
static int SQLITE_TCLAPI tcl_client_halt(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -294,7 +298,7 @@ static int tcl_client_halt(
** Wait on the most recent client_step to complete, then return the
** number of columns in the result set.
*/
static int tcl_client_argc(
static int SQLITE_TCLAPI tcl_client_argc(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -326,7 +330,7 @@ static int tcl_client_argc(
** Wait on the most recent client_step to complete, then return the
** value of the N-th columns in the result set.
*/
static int tcl_client_argv(
static int SQLITE_TCLAPI tcl_client_argv(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -362,7 +366,7 @@ static int tcl_client_argv(
** Wait on the most recent client_step to complete, then return the
** name of the N-th columns in the result set.
*/
static int tcl_client_colname(
static int SQLITE_TCLAPI tcl_client_colname(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -400,7 +404,7 @@ extern const char *sqlite3ErrName(int);
** Wait on the most recent operation to complete, then return the
** result code from that operation.
*/
static int tcl_client_result(
static int SQLITE_TCLAPI tcl_client_result(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -432,7 +436,7 @@ static int tcl_client_result(
** Wait on the most recent operation to complete, then return the
** error string.
*/
static int tcl_client_error(
static int SQLITE_TCLAPI tcl_client_error(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -477,7 +481,7 @@ static void do_compile(Thread *p){
**
** Compile a new virtual machine.
*/
static int tcl_client_compile(
static int SQLITE_TCLAPI tcl_client_compile(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -530,7 +534,7 @@ static void do_step(Thread *p){
**
** Advance the virtual machine by one step
*/
static int tcl_client_step(
static int SQLITE_TCLAPI tcl_client_step(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -572,7 +576,7 @@ static void do_finalize(Thread *p){
**
** Finalize the virtual machine.
*/
static int tcl_client_finalize(
static int SQLITE_TCLAPI tcl_client_finalize(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -616,7 +620,7 @@ static void do_reset(Thread *p){
**
** Finalize the virtual machine.
*/
static int tcl_client_reset(
static int SQLITE_TCLAPI tcl_client_reset(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
@@ -647,7 +651,7 @@ static int tcl_client_reset(
**
** Interchange the sqlite* pointer between two threads.
*/
static int tcl_client_swap(
static int SQLITE_TCLAPI tcl_client_swap(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
+7 -3
View File
@@ -14,7 +14,11 @@
** testing of the SQLite library.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -1353,7 +1357,7 @@ static void moduleDestroy(void *p){
/*
** Register the echo virtual table module.
*/
static int register_echo_module(
static int SQLITE_TCLAPI register_echo_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -1393,7 +1397,7 @@ static int register_echo_module(
**
** sqlite3_declare_vtab DB SQL
*/
static int declare_vtab(
static int SQLITE_TCLAPI declare_vtab(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+8 -4
View File
@@ -15,14 +15,18 @@
** as there is not much point in binding to Tcl.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
/*
** c_collation_test
*/
static int c_collation_test(
static int SQLITE_TCLAPI c_collation_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -63,7 +67,7 @@ error_out:
/*
** c_realloc_test
*/
static int c_realloc_test(
static int SQLITE_TCLAPI c_realloc_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -104,7 +108,7 @@ error_out:
/*
** c_misuse_test
*/
static int c_misuse_test(
static int SQLITE_TCLAPI c_misuse_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+13 -6
View File
@@ -15,7 +15,14 @@
*/
#define TCL_THREADS
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#ifdef SQLITE_ENABLE_ASYNCIO
@@ -36,7 +43,7 @@ TCL_DECLARE_MUTEX(testasync_g_writerMutex);
/*
** sqlite3async_initialize PARENT-VFS ISDEFAULT
*/
static int testAsyncInit(
static int SQLITE_TCLAPI testAsyncInit(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -69,7 +76,7 @@ static int testAsyncInit(
/*
** sqlite3async_shutdown
*/
static int testAsyncShutdown(
static int SQLITE_TCLAPI testAsyncShutdown(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -93,7 +100,7 @@ static Tcl_ThreadCreateType tclWriterThread(ClientData pIsStarted){
**
** Start a new writer thread.
*/
static int testAsyncStart(
static int SQLITE_TCLAPI testAsyncStart(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -125,7 +132,7 @@ static int testAsyncStart(
** If the current writer thread is set to run forever then this
** command would block forever. To prevent that, an error is returned.
*/
static int testAsyncWait(
static int SQLITE_TCLAPI testAsyncWait(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -151,7 +158,7 @@ static int testAsyncWait(
/*
** sqlite3async_control OPTION ?VALUE?
*/
static int testAsyncControl(
static int SQLITE_TCLAPI testAsyncControl(
void * clientData,
Tcl_Interp *interp,
int objc,
+21 -14
View File
@@ -11,7 +11,14 @@
*************************************************************************
** Test extension for testing the sqlite3_auto_extension() function.
*/
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "sqlite3ext.h"
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -87,13 +94,13 @@ static int broken_init(
**
** Register the "sqr" extension to be loaded automatically.
*/
static int autoExtSqrObjCmd(
static int SQLITE_TCLAPI autoExtSqrObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_auto_extension((void*)sqr_init);
int rc = sqlite3_auto_extension((void(*)(void))sqr_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -103,13 +110,13 @@ static int autoExtSqrObjCmd(
**
** Unregister the "sqr" extension.
*/
static int cancelAutoExtSqrObjCmd(
static int SQLITE_TCLAPI cancelAutoExtSqrObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_cancel_auto_extension((void*)sqr_init);
int rc = sqlite3_cancel_auto_extension((void(*)(void))sqr_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -119,13 +126,13 @@ static int cancelAutoExtSqrObjCmd(
**
** Register the "cube" extension to be loaded automatically.
*/
static int autoExtCubeObjCmd(
static int SQLITE_TCLAPI autoExtCubeObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_auto_extension((void*)cube_init);
int rc = sqlite3_auto_extension((void(*)(void))cube_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -135,13 +142,13 @@ static int autoExtCubeObjCmd(
**
** Unregister the "cube" extension.
*/
static int cancelAutoExtCubeObjCmd(
static int SQLITE_TCLAPI cancelAutoExtCubeObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_cancel_auto_extension((void*)cube_init);
int rc = sqlite3_cancel_auto_extension((void(*)(void))cube_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -151,13 +158,13 @@ static int cancelAutoExtCubeObjCmd(
**
** Register the broken extension to be loaded automatically.
*/
static int autoExtBrokenObjCmd(
static int SQLITE_TCLAPI autoExtBrokenObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_auto_extension((void*)broken_init);
int rc = sqlite3_auto_extension((void(*)(void))broken_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -167,13 +174,13 @@ static int autoExtBrokenObjCmd(
**
** Unregister the broken extension.
*/
static int cancelAutoExtBrokenObjCmd(
static int SQLITE_TCLAPI cancelAutoExtBrokenObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc = sqlite3_cancel_auto_extension((void*)broken_init);
int rc = sqlite3_cancel_auto_extension((void(*)(void))broken_init);
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return SQLITE_OK;
}
@@ -186,7 +193,7 @@ static int cancelAutoExtBrokenObjCmd(
**
** Reset all auto-extensions
*/
static int resetAutoExtObjCmd(
static int SQLITE_TCLAPI resetAutoExtObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
+11 -4
View File
@@ -13,7 +13,14 @@
**
*/
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include "sqlite3.h"
#include <assert.h>
@@ -23,7 +30,7 @@ extern const char *sqlite3ErrName(int);
/* These functions are implemented in test1.c. */
extern int getDbPointer(Tcl_Interp *, const char *, sqlite3 **);
static int backupTestCmd(
static int SQLITE_TCLAPI backupTestCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -98,7 +105,7 @@ static int backupTestCmd(
return TCL_OK;
}
static void backupTestFinish(ClientData clientData){
static void SQLITE_TCLAPI backupTestFinish(ClientData clientData){
sqlite3_backup *pBackup = (sqlite3_backup *)clientData;
sqlite3_backup_finish(pBackup);
}
@@ -107,7 +114,7 @@ static void backupTestFinish(ClientData clientData){
** sqlite3_backup CMDNAME DESTHANDLE DESTNAME SRCHANDLE SRCNAME
**
*/
static int backupTestInit(
static int SQLITE_TCLAPI backupTestInit(
ClientData clientData,
Tcl_Interp *interp,
int objc,
+610
View File
@@ -0,0 +1,610 @@
/*
** 2016-03-01
**
** 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.
**
*************************************************************************
** Code for testing the virtual table xBestIndex method and the query
** planner.
*/
/*
** INSTRUCTIONS
**
** This module exports a single tcl command - [register_tcl_module]. When
** invoked, it registers a special virtual table module with a database
** connection.
**
** The virtual table is currently read-only. And always returns zero rows.
** It is created with a single argument - the name of a Tcl command - as
** follows:
**
** CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
**
** The command [tcl_command] is invoked when the table is first created (or
** connected), when the xBestIndex() method is invoked and when the xFilter()
** method is called. When it is created (or connected), it is invoked as
** follows:
**
** tcl_command xConnect
**
** In this case the return value of the script is passed to the
** sqlite3_declare_vtab() function to create the virtual table schema.
**
** When the xBestIndex() method is called by SQLite, the Tcl command is
** invoked as:
**
** tcl_command xBestIndex CONSTRAINTS ORDERBY MASK
**
** where CONSTRAINTS is a tcl representation of the aConstraints[] array,
** ORDERBY is a representation of the contents of the aOrderBy[] array and
** MASK is a copy of sqlite3_index_info.colUsed. For example if the virtual
** table is declared as:
**
** CREATE TABLE x1(a, b, c)
**
** and the query is:
**
** SELECT * FROM x1 WHERE a=? AND c<? ORDER BY b, c;
**
** then the Tcl command is:
**
** tcl_command xBestIndex \
** {{op eq column 0 usable 1} {op lt column 2 usable 1}} \
** {{column 1 desc 0} {column 2 desc 0}} \
** 7
**
** The return value of the script is a list of key-value pairs used to
** populate the output fields of the sqlite3_index_info structure. Possible
** keys and the usage of the accompanying values are:
**
** "orderby" (value of orderByConsumed flag)
** "cost" (value of estimatedCost field)
** "rows" (value of estimatedRows field)
** "use" (index of used constraint in aConstraint[])
** "omit" (like "use", but also sets omit flag)
** "idxnum" (value of idxNum field)
** "idxstr" (value of idxStr field)
**
** Refer to code below for further details.
**
** When SQLite calls the xFilter() method, this module invokes the following
** Tcl script:
**
** tcl_command xFilter IDXNUM IDXSTR ARGLIST
**
** IDXNUM and IDXSTR are the values of the idxNum and idxStr parameters
** passed to xFilter. ARGLIST is a Tcl list containing each of the arguments
** passed to xFilter in text form.
**
** As with xBestIndex(), the return value of the script is interpreted as a
** list of key-value pairs. There is currently only one key defined - "sql".
** The value must be the full text of an SQL statement that returns the data
** for the current scan. The leftmost column returned by the SELECT is assumed
** to contain the rowid. Other columns must follow, in order from left to
** right.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef struct tcl_vtab tcl_vtab;
typedef struct tcl_cursor tcl_cursor;
/*
** A fs virtual-table object
*/
struct tcl_vtab {
sqlite3_vtab base;
Tcl_Interp *interp;
Tcl_Obj *pCmd;
sqlite3 *db;
};
/* A tcl cursor object */
struct tcl_cursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pStmt; /* Read data from here */
};
/*
** Dequote string z in place.
*/
static void tclDequote(char *z){
char q = z[0];
/* Set stack variable q to the close-quote character */
if( q=='[' || q=='\'' || q=='"' || q=='`' ){
int iIn = 1;
int iOut = 0;
if( q=='[' ) q = ']';
while( ALWAYS(z[iIn]) ){
if( z[iIn]==q ){
if( z[iIn+1]!=q ){
/* Character iIn was the close quote. */
iIn++;
break;
}else{
/* Character iIn and iIn+1 form an escaped quote character. Skip
** the input cursor past both and copy a single quote character
** to the output buffer. */
iIn += 2;
z[iOut++] = q;
}
}else{
z[iOut++] = z[iIn++];
}
}
z[iOut] = '\0';
}
}
/*
** This function is the implementation of both the xConnect and xCreate
** methods of the fs virtual table.
**
** The argv[] array contains the following:
**
** argv[0] -> module name ("fs")
** argv[1] -> database name
** argv[2] -> table name
** argv[...] -> other module argument fields.
*/
static int tclConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
Tcl_Interp *interp = (Tcl_Interp*)pAux;
tcl_vtab *pTab = 0;
char *zCmd = 0;
Tcl_Obj *pScript = 0;
int rc = SQLITE_OK;
if( argc!=4 ){
*pzErr = sqlite3_mprintf("wrong number of arguments");
return SQLITE_ERROR;
}
zCmd = sqlite3_malloc64(strlen(argv[3])+1);
pTab = (tcl_vtab*)sqlite3_malloc64(sizeof(tcl_vtab));
if( zCmd && pTab ){
memcpy(zCmd, argv[3], strlen(argv[3])+1);
tclDequote(zCmd);
memset(pTab, 0, sizeof(tcl_vtab));
pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
pTab->interp = interp;
pTab->db = db;
Tcl_IncrRefCount(pTab->pCmd);
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xConnect", -1));
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
*pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
rc = SQLITE_ERROR;
}else{
rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
}
if( rc!=SQLITE_OK ){
sqlite3_free(pTab);
pTab = 0;
}
}else{
rc = SQLITE_NOMEM;
}
sqlite3_free(zCmd);
*ppVtab = &pTab->base;
return rc;
}
/* The xDisconnect and xDestroy methods are also the same */
static int tclDisconnect(sqlite3_vtab *pVtab){
tcl_vtab *pTab = (tcl_vtab*)pVtab;
Tcl_DecrRefCount(pTab->pCmd);
sqlite3_free(pTab);
return SQLITE_OK;
}
/*
** Open a new tcl cursor.
*/
static int tclOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
tcl_cursor *pCur;
pCur = sqlite3_malloc(sizeof(tcl_cursor));
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(tcl_cursor));
*ppCursor = &pCur->base;
return SQLITE_OK;
}
/*
** Close a tcl cursor.
*/
static int tclClose(sqlite3_vtab_cursor *cur){
tcl_cursor *pCur = (tcl_cursor *)cur;
if( pCur ){
sqlite3_finalize(pCur->pStmt);
sqlite3_free(pCur);
}
return SQLITE_OK;
}
static int tclNext(sqlite3_vtab_cursor *pVtabCursor){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
if( pCsr->pStmt ){
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
int rc = sqlite3_step(pCsr->pStmt);
if( rc!=SQLITE_ROW ){
const char *zErr;
rc = sqlite3_finalize(pCsr->pStmt);
pCsr->pStmt = 0;
if( rc!=SQLITE_OK ){
zErr = sqlite3_errmsg(pTab->db);
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}
}
}
return SQLITE_OK;
}
static int tclFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
Tcl_Interp *interp = pTab->interp;
Tcl_Obj *pScript;
Tcl_Obj *pArg;
int ii;
int rc;
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xFilter", -1));
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(idxNum));
if( idxStr ){
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(idxStr, -1));
}else{
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("", -1));
}
pArg = Tcl_NewObj();
Tcl_IncrRefCount(pArg);
for(ii=0; ii<argc; ii++){
const char *zVal = (const char*)sqlite3_value_text(argv[ii]);
Tcl_Obj *pVal;
if( zVal==0 ){
pVal = Tcl_NewObj();
}else{
pVal = Tcl_NewStringObj(zVal, -1);
}
Tcl_ListObjAppendElement(interp, pArg, pVal);
}
Tcl_ListObjAppendElement(interp, pScript, pArg);
Tcl_DecrRefCount(pArg);
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
/* Analyze the scripts return value. The return value should be a tcl
** list object with an even number of elements. The first element of each
** pair must be one of:
**
** "sql" (SQL statement to return data)
*/
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
Tcl_Obj **apElem = 0;
int nElem;
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
const char *zCmd = Tcl_GetString(apElem[ii]);
Tcl_Obj *p = apElem[ii+1];
if( sqlite3_stricmp("sql", zCmd)==0 ){
const char *zSql = Tcl_GetString(p);
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
if( rc!=SQLITE_OK ){
const char *zErr = sqlite3_errmsg(pTab->db);
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zErr);
}
}else{
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
}
}
}
}
if( rc==SQLITE_OK ){
rc = tclNext(pVtabCursor);
}
return rc;
}
static int tclColumn(
sqlite3_vtab_cursor *pVtabCursor,
sqlite3_context *ctx,
int i
){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
return SQLITE_OK;
}
static int tclRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
*pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
return SQLITE_OK;
}
static int tclEof(sqlite3_vtab_cursor *pVtabCursor){
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
return (pCsr->pStmt==0);
}
static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
tcl_vtab *pTab = (tcl_vtab*)tab;
Tcl_Interp *interp = pTab->interp;
Tcl_Obj *pArg;
Tcl_Obj *pScript;
int ii;
int rc = SQLITE_OK;
pScript = Tcl_DuplicateObj(pTab->pCmd);
Tcl_IncrRefCount(pScript);
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xBestIndex", -1));
pArg = Tcl_NewObj();
Tcl_IncrRefCount(pArg);
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
Tcl_Obj *pElem = Tcl_NewObj();
const char *zOp = "?";
Tcl_IncrRefCount(pElem);
switch( pCons->op ){
case SQLITE_INDEX_CONSTRAINT_EQ:
zOp = "eq"; break;
case SQLITE_INDEX_CONSTRAINT_GT:
zOp = "gt"; break;
case SQLITE_INDEX_CONSTRAINT_LE:
zOp = "le"; break;
case SQLITE_INDEX_CONSTRAINT_LT:
zOp = "lt"; break;
case SQLITE_INDEX_CONSTRAINT_GE:
zOp = "ge"; break;
case SQLITE_INDEX_CONSTRAINT_MATCH:
zOp = "match"; break;
case SQLITE_INDEX_CONSTRAINT_LIKE:
zOp = "like"; break;
case SQLITE_INDEX_CONSTRAINT_GLOB:
zOp = "glob"; break;
case SQLITE_INDEX_CONSTRAINT_REGEXP:
zOp = "regexp"; break;
}
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->usable));
Tcl_ListObjAppendElement(0, pArg, pElem);
Tcl_DecrRefCount(pElem);
}
Tcl_ListObjAppendElement(0, pScript, pArg);
Tcl_DecrRefCount(pArg);
pArg = Tcl_NewObj();
Tcl_IncrRefCount(pArg);
for(ii=0; ii<pIdxInfo->nOrderBy; ii++){
struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[ii];
Tcl_Obj *pElem = Tcl_NewObj();
Tcl_IncrRefCount(pElem);
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->iColumn));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("desc", -1));
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->desc));
Tcl_ListObjAppendElement(0, pArg, pElem);
Tcl_DecrRefCount(pElem);
}
Tcl_ListObjAppendElement(0, pScript, pArg);
Tcl_DecrRefCount(pArg);
Tcl_ListObjAppendElement(0, pScript, Tcl_NewWideIntObj(pIdxInfo->colUsed));
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(pScript);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
/* Analyze the scripts return value. The return value should be a tcl
** list object with an even number of elements. The first element of each
** pair must be one of:
**
** "orderby" (value of orderByConsumed flag)
** "cost" (value of estimatedCost field)
** "rows" (value of estimatedRows field)
** "use" (index of used constraint in aConstraint[])
** "idxnum" (value of idxNum field)
** "idxstr" (value of idxStr field)
** "omit" (index of omitted constraint in aConstraint[])
*/
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
Tcl_Obj **apElem = 0;
int nElem;
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
if( rc!=TCL_OK ){
const char *zErr = Tcl_GetStringResult(interp);
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}else{
int iArgv = 1;
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
const char *zCmd = Tcl_GetString(apElem[ii]);
Tcl_Obj *p = apElem[ii+1];
if( sqlite3_stricmp("cost", zCmd)==0 ){
rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
}else
if( sqlite3_stricmp("orderby", zCmd)==0 ){
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);
}else
if( sqlite3_stricmp("idxnum", zCmd)==0 ){
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->idxNum);
}else
if( sqlite3_stricmp("idxstr", zCmd)==0 ){
sqlite3_free(pIdxInfo->idxStr);
pIdxInfo->idxStr = sqlite3_mprintf("%s", Tcl_GetString(p));
pIdxInfo->needToFreeIdxStr = 1;
}else
if( sqlite3_stricmp("rows", zCmd)==0 ){
Tcl_WideInt x = 0;
rc = Tcl_GetWideIntFromObj(interp, p, &x);
pIdxInfo->estimatedRows = (tRowcnt)x;
}else
if( sqlite3_stricmp("use", zCmd)==0
|| sqlite3_stricmp("omit", zCmd)==0
){
int iCons;
rc = Tcl_GetIntFromObj(interp, p, &iCons);
if( rc==SQLITE_OK ){
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %d", iCons);
}else{
int bOmit = (zCmd[0]=='o' || zCmd[0]=='O');
pIdxInfo->aConstraintUsage[iCons].argvIndex = iArgv++;
pIdxInfo->aConstraintUsage[iCons].omit = bOmit;
}
}
}else{
rc = SQLITE_ERROR;
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
}
if( rc!=SQLITE_OK && pTab->base.zErrMsg==0 ){
const char *zErr = Tcl_GetStringResult(interp);
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
}
}
}
}
return rc;
}
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
*/
static sqlite3_module tclModule = {
0, /* iVersion */
tclConnect,
tclConnect,
tclBestIndex,
tclDisconnect,
tclDisconnect,
tclOpen, /* xOpen - open a cursor */
tclClose, /* xClose - close a cursor */
tclFilter, /* xFilter - configure scan constraints */
tclNext, /* xNext - advance a cursor */
tclEof, /* xEof - check for end of scan */
tclColumn, /* xColumn - read data */
tclRowid, /* xRowid - read data */
0, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
};
/*
** Decode a pointer to an sqlite3 object.
*/
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/*
** Register the echo virtual table module.
*/
static int SQLITE_TCLAPI register_tcl_module(
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 */
){
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;
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_create_module(db, "tcl", &tclModule, (void *)interp);
#endif
return TCL_OK;
}
#endif
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetesttcl_Init(Tcl_Interp *interp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
static struct {
char *zName;
Tcl_ObjCmdProc *xProc;
void *clientData;
} aObjCmd[] = {
{ "register_tcl_module", register_tcl_module, 0 },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
}
#endif
return TCL_OK;
}
+11 -7
View File
@@ -12,7 +12,11 @@
**
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -95,7 +99,7 @@ static char *blobStringFromObj(Tcl_Obj *pObj){
**
** Tcl test harness for the sqlite3_blob_open() function.
*/
static int test_blob_open(
static int SQLITE_TCLAPI test_blob_open(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* Calling TCL interpreter */
int objc, /* Number of arguments */
@@ -105,7 +109,7 @@ static int test_blob_open(
const char *zDb;
const char *zTable;
const char *zColumn;
sqlite_int64 iRowid;
Tcl_WideInt iRowid;
int flags;
const char *zVarname;
int nVarname;
@@ -146,7 +150,7 @@ static int test_blob_open(
/*
** sqlite3_blob_close HANDLE
*/
static int test_blob_close(
static int SQLITE_TCLAPI test_blob_close(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -174,7 +178,7 @@ static int test_blob_close(
/*
** sqlite3_blob_bytes HANDLE
*/
static int test_blob_bytes(
static int SQLITE_TCLAPI test_blob_bytes(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -210,7 +214,7 @@ static int test_blob_bytes(
** text representation of the returned error code (i.e. "SQLITE_NOMEM")
** and a Tcl exception is thrown.
*/
static int test_blob_read(
static int SQLITE_TCLAPI test_blob_read(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -262,7 +266,7 @@ static int test_blob_read(
** result is set to the text representation of the returned error code
** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
*/
static int test_blob_write(
static int SQLITE_TCLAPI test_blob_write(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+6 -2
View File
@@ -14,7 +14,11 @@
** testing of the SQLite library.
*/
#include "btreeInt.h"
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
/*
** Usage: sqlite3_shared_cache_report
@@ -22,7 +26,7 @@
** Return a list of file that are shared and the number of
** references to each file.
*/
int sqlite3BtreeSharedCacheReport(
int SQLITE_TCLAPI sqlite3BtreeSharedCacheReport(
void * clientData,
Tcl_Interp *interp,
int objc,
+35 -8
View File
@@ -24,7 +24,11 @@
# include "os_win.h"
#endif
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -79,6 +83,13 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "debug", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC
Tcl_SetVar2(interp, "sqlite_options", "default_ckptfullfsync",
SQLITE_DEFAULT_CKPTFULLFSYNC ? "1" : "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "default_ckptfullfsync", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_DIRECT_OVERFLOW_READ
Tcl_SetVar2(interp, "sqlite_options", "direct_read", "1", TCL_GLOBAL_ONLY);
#else
@@ -97,6 +108,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
Tcl_SetVar2(interp, "sqlite_options", "pagecache_overflow_stats","0",TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "pagecache_overflow_stats","1",TCL_GLOBAL_ONLY);
#endif
#if SQLITE_MAX_MMAP_SIZE>0
Tcl_SetVar2(interp, "sqlite_options", "mmap", "1", TCL_GLOBAL_ONLY);
#else
@@ -143,6 +160,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mem5", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "preupdate", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
Tcl_SetVar2(interp, "sqlite_options", "snapshot", "1", TCL_GLOBAL_ONLY);
#else
@@ -370,12 +393,6 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "fts3", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
Tcl_SetVar2(interp, "sqlite_options", "fts3_tokenizer", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "fts3_tokenizer", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_FTS5
Tcl_SetVar2(interp, "sqlite_options", "fts5", "1", TCL_GLOBAL_ONLY);
#else
@@ -527,6 +544,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_SESSION
Tcl_SetVar2(interp, "sqlite_options", "session", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "session", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_STAT4
Tcl_SetVar2(interp, "sqlite_options", "stat4", "1", TCL_GLOBAL_ONLY);
#else
@@ -582,7 +605,11 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
#endif
Tcl_SetVar2(interp, "sqlite_options", "threadsafe",
STRINGVALUE(SQLITE_THREADSAFE), TCL_GLOBAL_ONLY);
SQLITE_THREADSAFE ? "1" : "0", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "threadsafe1",
SQLITE_THREADSAFE==1 ? "1" : "0", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "threadsafe2",
SQLITE_THREADSAFE==2 ? "1" : "0", TCL_GLOBAL_ONLY);
assert( sqlite3_threadsafe()==SQLITE_THREADSAFE );
#ifdef SQLITE_OMIT_TEMPDB
+138
View File
@@ -0,0 +1,138 @@
/*
** 2016 September 10
**
** 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 test code to delete an SQLite database and all
** of its associated files. Associated files include:
**
** * The journal file.
** * The wal file.
** * The SQLITE_ENABLE_8_3_NAMES version of the db, journal or wal files.
** * Files created by the test_multiplex.c module to extend any of the
** above.
*/
#if SQLITE_OS_WIN
# include <io.h>
# define F_OK 0
#else
# include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include "sqlite3.h"
/* The following #defines are copied from test_multiplex.c */
#ifndef MX_CHUNK_NUMBER
# define MX_CHUNK_NUMBER 299
#endif
#ifndef SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET
# define SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET 400
#endif
#ifndef SQLITE_MULTIPLEX_WAL_8_3_OFFSET
# define SQLITE_MULTIPLEX_WAL_8_3_OFFSET 700
#endif
/*
** This routine is a copy of (most of) the code from SQLite function
** sqlite3FileSuffix3(). It modifies the filename in buffer z in the
** same way as SQLite does when in 8.3 filenames mode.
*/
static void sqlite3Delete83Name(char *z){
int i, sz;
sz = strlen(z);
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
if( z[i]=='.' && (sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
}
/*
** zFile is a filename. Assuming no error occurs, if this file exists,
** set *pbExists to true and unlink it. Or, if the file does not exist,
** set *pbExists to false before returning.
**
** If an error occurs, the value of errno is returned. Or, if no error
** occurs, zero is returned.
*/
static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){
int rc;
rc = access(zFile, F_OK);
if( rc ){
if( errno==ENOENT ){
if( pbExists ) *pbExists = 0;
return 0;
}
return errno;
}
if( pbExists ) *pbExists = 1;
rc = unlink(zFile);
if( rc ) return errno;
return 0;
}
/*
** Delete the database file identified by the string argument passed to this
** function. The string must contain a filename, not an SQLite URI.
*/
int sqlite3_delete_database(
const char *zFile /* File to delete */
){
char *zBuf; /* Buffer to sprintf() filenames to */
int nBuf; /* Size of buffer in bytes */
int rc = 0; /* System error code */
int i; /* Iterate through azFmt[] and aMFile[] */
const char *azFmt[] = { "%s", "%s-journal", "%s-wal", "%s-shm" };
struct MFile {
const char *zFmt;
int iOffset;
int b83;
} aMFile[] = {
{ "%s%03d", 0, 0 },
{ "%s-journal%03d", 0, 0 },
{ "%s-wal%03d", 0, 0 },
{ "%s%03d", 0, 1 },
{ "%s-journal%03d", SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET, 1 },
{ "%s-wal%03d", SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 },
};
/* Allocate a buffer large enough for any of the files that need to be
** deleted. */
nBuf = strlen(zFile) + 100;
zBuf = (char*)sqlite3_malloc(nBuf);
if( zBuf==0 ) return SQLITE_NOMEM;
/* Delete both the regular and 8.3 filenames versions of the database,
** journal, wal and shm files. */
for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){
sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile);
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
if( rc==0 && i!=0 ){
sqlite3Delete83Name(zBuf);
rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
}
}
/* Delete any multiplexor files */
for(i=0; rc==0 && i<sizeof(aMFile)/sizeof(aMFile[0]); i++){
struct MFile *p = &aMFile[i];
int iChunk;
for(iChunk=1; iChunk<=MX_CHUNK_NUMBER; iChunk++){
int bExists;
sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset);
if( p->b83 ) sqlite3Delete83Name(zBuf);
rc = sqlite3DeleteUnlinkIfExists(zBuf, &bExists);
if( bExists==0 || rc!=0 ) break;
}
}
sqlite3_free(zBuf);
return (rc ? SQLITE_ERROR : SQLITE_OK);
}
+10 -3
View File
@@ -641,10 +641,17 @@ sqlite3_vfs *sqlite3_demovfs(void){
#ifdef SQLITE_TEST
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#if SQLITE_OS_UNIX
static int register_demovfs(
static int SQLITE_TCLAPI register_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -653,7 +660,7 @@ static int register_demovfs(
sqlite3_vfs_register(sqlite3_demovfs(), 1);
return TCL_OK;
}
static int unregister_demovfs(
static int SQLITE_TCLAPI unregister_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+9 -1
View File
@@ -133,7 +133,8 @@ struct DevsymGlobal g = {0, 0, 512};
*/
static int devsymClose(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsClose(p->pReal);
sqlite3OsClose(p->pReal);
return SQLITE_OK;
}
/*
@@ -395,4 +396,11 @@ void devsym_register(int iDeviceChar, int iSectorSize){
}
}
void devsym_unregister(){
sqlite3_vfs_unregister(&devsym_vfs);
g.pVfs = 0;
g.iDeviceChar = 0;
g.iSectorSize = 0;
}
#endif
+14 -6
View File
@@ -62,7 +62,11 @@
** SELECT * FROM fstree WHERE path LIKE '/home/dan/sqlite/%'
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -495,10 +499,14 @@ static int fstreeFilter(
char aWild[2] = { '\0', '\0' };
#if SQLITE_OS_WIN
zRoot = sqlite3_mprintf("%s%c", getenv("SystemDrive"), '/');
nRoot = strlen(zRoot);
zPrefix = sqlite3_mprintf("%s", getenv("SystemDrive"));
nPrefix = strlen(zPrefix);
const char *zDrive = windirent_getenv("fstreeDrive");
if( zDrive==0 ){
zDrive = windirent_getenv("SystemDrive");
}
zRoot = sqlite3_mprintf("%s%c", zDrive, '/');
nRoot = sqlite3Strlen30(zRoot);
zPrefix = sqlite3_mprintf("%s", zDrive);
nPrefix = sqlite3Strlen30(zPrefix);
#else
zRoot = "/";
nRoot = 1;
@@ -871,7 +879,7 @@ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/*
** Register the echo virtual table module.
*/
static int register_fs_module(
static int SQLITE_TCLAPI register_fs_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+19 -11
View File
@@ -13,7 +13,11 @@
** implements new SQL functions used by the test scripts.
*/
#include "sqlite3.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -21,7 +25,6 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** Allocate nByte bytes of space using sqlite3_malloc(). If the
** allocation fails, call sqlite3_result_error_nomem() to notify
@@ -640,7 +643,11 @@ static void test_setsubtype(
sqlite3_result_subtype(context, (unsigned int)sqlite3_value_int(argv[1]));
}
static int registerTestFunctions(sqlite3 *db){
static int registerTestFunctions(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pThunk
){
static const struct {
char *zName;
signed char nArg;
@@ -689,16 +696,16 @@ static int registerTestFunctions(sqlite3 *db){
** the standard set of test functions to be loaded into each new
** database connection.
*/
static int autoinstall_test_funcs(
static int SQLITE_TCLAPI autoinstall_test_funcs(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
extern int Md5_Register(sqlite3*);
int rc = sqlite3_auto_extension((void*)registerTestFunctions);
extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *);
int rc = sqlite3_auto_extension((void(*)(void))registerTestFunctions);
if( rc==SQLITE_OK ){
rc = sqlite3_auto_extension((void*)Md5_Register);
rc = sqlite3_auto_extension((void(*)(void))Md5_Register);
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_OK;
@@ -717,7 +724,7 @@ static void tFinal(sqlite3_context *a){}
** Make various calls to sqlite3_create_function that do not have valid
** parameters. Verify that the error condition is detected and reported.
*/
static int abuse_create_function(
static int SQLITE_TCLAPI abuse_create_function(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -783,6 +790,7 @@ abuse_err:
return TCL_ERROR;
}
/*
** Register commands with the TCL interpreter.
*/
@@ -795,13 +803,13 @@ int Sqlitetest_func_Init(Tcl_Interp *interp){
{ "abuse_create_function", abuse_create_function },
};
int i;
extern int Md5_Register(sqlite3*);
extern int Md5_Register(sqlite3 *, char **, const sqlite3_api_routines *);
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
}
sqlite3_initialize();
sqlite3_auto_extension((void*)registerTestFunctions);
sqlite3_auto_extension((void*)Md5_Register);
sqlite3_auto_extension((void(*)(void))registerTestFunctions);
sqlite3_auto_extension((void(*)(void))Md5_Register);
return TCL_OK;
}
+12 -8
View File
@@ -18,7 +18,11 @@
** easier and safer to build our own mechanism.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -94,7 +98,7 @@ int sqlite3TestHexToBin(const unsigned char *zIn, int N, unsigned char *aOut){
** beginning of the file. Convert that information to hexadecimal
** and return the resulting HEX string.
*/
static int hexio_read(
static int SQLITE_TCLAPI hexio_read(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -144,7 +148,7 @@ static int hexio_read(
** Write DATA into file FILENAME beginning at OFFSET from the
** beginning of the file. DATA is expressed in hexadecimal.
*/
static int hexio_write(
static int SQLITE_TCLAPI hexio_write(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -192,7 +196,7 @@ static int hexio_write(
** the value of that integer. HEXDATA can contain between 2 and 8
** hexadecimal digits.
*/
static int hexio_get_int(
static int SQLITE_TCLAPI hexio_get_int(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -232,7 +236,7 @@ static int hexio_get_int(
**
** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
*/
static int hexio_render_int16(
static int SQLITE_TCLAPI hexio_render_int16(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -259,7 +263,7 @@ static int hexio_render_int16(
**
** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
*/
static int hexio_render_int32(
static int SQLITE_TCLAPI hexio_render_int32(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -289,7 +293,7 @@ static int hexio_render_int32(
** The UTF8 might not be well-formed. Run this string through
** sqlite3Utf8to8() convert it back to hex and return the result.
*/
static int utf8_to_utf8(
static int SQLITE_TCLAPI utf8_to_utf8(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -340,7 +344,7 @@ static int getFts3Varint(const char *p, sqlite_int64 *v){
** Read a varint from the start of BLOB. Set variable VARNAME to contain
** the interpreted value. Return the number of bytes of BLOB consumed.
*/
static int read_fts3varint(
static int SQLITE_TCLAPI read_fts3varint(
void * clientData,
Tcl_Interp *interp,
int objc,
+9 -5
View File
@@ -27,7 +27,11 @@
#include "sqliteInt.h"
#include <string.h>
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
static struct Wrapped {
sqlite3_pcache_methods2 pcache;
@@ -184,7 +188,7 @@ static void installInitWrappers(void){
sqlite3_config(SQLITE_CONFIG_PCACHE2, &pcachemethods);
}
static int init_wrapper_install(
static int SQLITE_TCLAPI init_wrapper_install(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -208,7 +212,7 @@ static int init_wrapper_install(
return TCL_OK;
}
static int init_wrapper_uninstall(
static int SQLITE_TCLAPI init_wrapper_uninstall(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -226,7 +230,7 @@ static int init_wrapper_uninstall(
return TCL_OK;
}
static int init_wrapper_clear(
static int SQLITE_TCLAPI init_wrapper_clear(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -243,7 +247,7 @@ static int init_wrapper_clear(
return TCL_OK;
}
static int init_wrapper_query(
static int SQLITE_TCLAPI init_wrapper_query(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+10 -3
View File
@@ -270,7 +270,14 @@ SQLITE_API int sqlite3_intarray_bind(
** Everything below is interface for testing this module.
*/
#ifdef SQLITE_TEST
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
/*
** Routines to encode and decode pointers
@@ -286,7 +293,7 @@ extern const char *sqlite3ErrName(int);
** Invoke the sqlite3_intarray_create interface. A string that becomes
** the first parameter to sqlite3_intarray_bind.
*/
static int test_intarray_create(
static int SQLITE_TCLAPI test_intarray_create(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
@@ -322,7 +329,7 @@ static int test_intarray_create(
**
** Invoke the sqlite3_intarray_bind interface on the given array of integers.
*/
static int test_intarray_bind(
static int SQLITE_TCLAPI test_intarray_bind(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+3 -3
View File
@@ -75,8 +75,8 @@
** action to free the intarray objects.
*/
#include "sqlite3.h"
#ifndef _INTARRAY_H_
#define _INTARRAY_H_
#ifndef SQLITE_INTARRAY_H
#define SQLITE_INTARRAY_H
/*
** Make sure we can call this stuff from C++.
@@ -125,4 +125,4 @@ SQLITE_API int sqlite3_intarray_bind(
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
#endif /* _INTARRAY_H_ */
#endif /* SQLITE_INTARRAY_H */
+18 -12
View File
@@ -160,6 +160,7 @@ static int jtRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int jtSleep(sqlite3_vfs*, int microseconds);
static int jtCurrentTime(sqlite3_vfs*, double*);
static int jtCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static int jtGetLastError(sqlite3_vfs*, int, char*);
static sqlite3_vfs jt_vfs = {
2, /* iVersion */
@@ -179,7 +180,7 @@ static sqlite3_vfs jt_vfs = {
jtRandomness, /* xRandomness */
jtSleep, /* xSleep */
jtCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
jtGetLastError, /* xGetLastError */
jtCurrentTimeInt64 /* xCurrentTimeInt64 */
};
@@ -256,7 +257,8 @@ static int jtClose(sqlite3_file *pFile){
*pp = p->pNext;
}
leaveJtMutex();
return sqlite3OsClose(p->pReal);
sqlite3OsClose(p->pReal);
return SQLITE_OK;
}
/*
@@ -284,9 +286,10 @@ static int jtRead(
** b) The file-name specified when the file was opened matches
** all but the final 8 characters of the journal file name.
**
** c) There is currently a reserved lock on the file.
** c) There is currently a reserved lock on the file. This
** condition is waived if the noLock argument is non-zero.
**/
static jt_file *locateDatabaseHandle(const char *zJournal){
static jt_file *locateDatabaseHandle(const char *zJournal, int noLock){
jt_file *pMain = 0;
enterJtMutex();
for(pMain=g.pList; pMain; pMain=pMain->pNext){
@@ -294,7 +297,7 @@ static jt_file *locateDatabaseHandle(const char *zJournal){
if( (pMain->flags&SQLITE_OPEN_MAIN_DB)
&& ((int)strlen(pMain->zName)==nName)
&& 0==memcmp(pMain->zName, zJournal, nName)
&& (pMain->eLock>=SQLITE_LOCK_RESERVED)
&& ((pMain->eLock>=SQLITE_LOCK_RESERVED) || noLock)
){
break;
}
@@ -516,7 +519,7 @@ static int jtWrite(
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
if( iOfst==0 ){
jt_file *pMain = locateDatabaseHandle(p->zName);
jt_file *pMain = locateDatabaseHandle(p->zName, 0);
assert( pMain );
if( iAmt==28 ){
@@ -561,7 +564,7 @@ static int jtWrite(
rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){
jt_file *pMain = locateDatabaseHandle(p->zName);
jt_file *pMain = locateDatabaseHandle(p->zName, 0);
int rc2 = readJournalFile(p, pMain);
if( rc==SQLITE_OK ) rc = rc2;
}
@@ -575,7 +578,7 @@ static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
jt_file *p = (jt_file *)pFile;
if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
/* Truncating a journal file. This is the end of a transaction. */
jt_file *pMain = locateDatabaseHandle(p->zName);
jt_file *pMain = locateDatabaseHandle(p->zName, 0);
closeTransaction(pMain);
}
if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
@@ -603,11 +606,10 @@ static int jtSync(sqlite3_file *pFile, int flags){
** jt_file.pWritable bitvec of the main database file associated with
** this journal file.
*/
pMain = locateDatabaseHandle(p->zName);
assert(pMain);
pMain = locateDatabaseHandle(p->zName, 0);
/* Set the bitvec values */
if( pMain->pWritable ){
if( pMain && pMain->pWritable ){
pMain->nSync++;
rc = readJournalFile(p, pMain);
if( rc!=SQLITE_OK ){
@@ -729,7 +731,7 @@ static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
int nPath = (int)strlen(zPath);
if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){
/* Deleting a journal file. The end of a transaction. */
jt_file *pMain = locateDatabaseHandle(zPath);
jt_file *pMain = locateDatabaseHandle(zPath, 0);
if( pMain ){
closeTransaction(pMain);
}
@@ -824,6 +826,10 @@ static int jtCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
return g.pVfs->xCurrentTimeInt64(g.pVfs, pTimeOut);
}
static int jtGetLastError(sqlite3_vfs *pVfs, int n, char *z){
return g.pVfs->xGetLastError(g.pVfs, n, z);
}
/**************************************************************************
** Start of public API.
*/
+40 -35
View File
@@ -14,7 +14,11 @@
** memory allocation subsystem.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -306,7 +310,7 @@ static int textToPointer(const char *z, void **pp){
**
** Raw test interface for sqlite3_malloc().
*/
static int test_malloc(
static int SQLITE_TCLAPI test_malloc(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -331,7 +335,7 @@ static int test_malloc(
**
** Raw test interface for sqlite3_realloc().
*/
static int test_realloc(
static int SQLITE_TCLAPI test_realloc(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -360,7 +364,7 @@ static int test_realloc(
**
** Raw test interface for sqlite3_free().
*/
static int test_free(
static int SQLITE_TCLAPI test_free(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -391,7 +395,7 @@ int sqlite3TestBinToHex(char*,int);
** Set a chunk of memory (obtained from malloc, probably) to a
** specified hex pattern.
*/
static int test_memset(
static int SQLITE_TCLAPI test_memset(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -437,7 +441,7 @@ static int test_memset(
**
** Return memory as hexadecimal text.
*/
static int test_memget(
static int SQLITE_TCLAPI test_memget(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -484,7 +488,7 @@ static int test_memget(
**
** Raw test interface for sqlite3_memory_used().
*/
static int test_memory_used(
static int SQLITE_TCLAPI test_memory_used(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -499,7 +503,7 @@ static int test_memory_used(
**
** Raw test interface for sqlite3_memory_highwater().
*/
static int test_memory_highwater(
static int SQLITE_TCLAPI test_memory_highwater(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -524,7 +528,7 @@ static int test_memory_highwater(
** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
** then this routine is a no-op.
*/
static int test_memdebug_backtrace(
static int SQLITE_TCLAPI test_memdebug_backtrace(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -550,7 +554,7 @@ static int test_memdebug_backtrace(
**
** Write a summary of unfreed memory to FILENAME.
*/
static int test_memdebug_dump(
static int SQLITE_TCLAPI test_memdebug_dump(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -575,7 +579,7 @@ static int test_memdebug_dump(
**
** Return the total number of times malloc() has been called.
*/
static int test_memdebug_malloc_count(
static int SQLITE_TCLAPI test_memdebug_malloc_count(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -615,7 +619,7 @@ static int test_memdebug_malloc_count(
**
** To disable simulated failures, use a COUNTER of -1.
*/
static int test_memdebug_fail(
static int SQLITE_TCLAPI test_memdebug_fail(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -681,7 +685,7 @@ static int test_memdebug_fail(
** simulated failure occurs. A negative return value indicates that
** no malloc() failure is scheduled.
*/
static int test_memdebug_pending(
static int SQLITE_TCLAPI test_memdebug_pending(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -714,7 +718,7 @@ static int sqlite3_memdebug_title_count = 0;
**
** Each title overwrite the previous.
*/
static int test_memdebug_settitle(
static int SQLITE_TCLAPI test_memdebug_settitle(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -795,7 +799,7 @@ static void test_memdebug_log_clear(void){
Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
}
static int test_memdebug_log(
static int SQLITE_TCLAPI test_memdebug_log(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -893,7 +897,7 @@ static int test_memdebug_log(
**
** A negative SIZE causes the buffer pointer to be NULL.
*/
static int test_config_scratch(
static int SQLITE_TCLAPI test_config_scratch(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -933,7 +937,7 @@ static int test_config_scratch(
**
** A negative SIZE causes the buffer pointer to be NULL.
*/
static int test_config_pagecache(
static int SQLITE_TCLAPI test_config_pagecache(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -976,7 +980,7 @@ static int test_config_pagecache(
** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
** seed.
*/
static int test_alt_pcache(
static int SQLITE_TCLAPI test_alt_pcache(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1017,7 +1021,7 @@ static int test_alt_pcache(
**
** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
*/
static int test_config_memstatus(
static int SQLITE_TCLAPI test_config_memstatus(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1038,7 +1042,7 @@ static int test_config_memstatus(
** Usage: sqlite3_config_lookaside SIZE COUNT
**
*/
static int test_config_lookaside(
static int SQLITE_TCLAPI test_config_lookaside(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1072,7 +1076,7 @@ static int test_config_lookaside(
** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
** which will cause sqlite3_db_config() to allocate space on its own.
*/
static int test_db_config_lookaside(
static int SQLITE_TCLAPI test_db_config_lookaside(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1093,7 +1097,7 @@ static int test_db_config_lookaside(
if( Tcl_GetIntFromObj(interp, objv[3], &sz) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[4], &cnt) ) return TCL_ERROR;
if( bufid==0 ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, 0, sz, cnt);
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, (void*)0, sz, cnt);
}else if( bufid>=1 && bufid<=2 && sz*cnt<=sizeof(azBuf[0]) ){
rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz,cnt);
}else{
@@ -1107,7 +1111,7 @@ static int test_db_config_lookaside(
/*
** Usage: sqlite3_config_heap NBYTE NMINALLOC
*/
static int test_config_heap(
static int SQLITE_TCLAPI test_config_heap(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1144,7 +1148,7 @@ static int test_config_heap(
/*
** Usage: sqlite3_config_heap_size NBYTE
*/
static int test_config_heap_size(
static int SQLITE_TCLAPI test_config_heap_size(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1174,7 +1178,7 @@ static int test_config_heap_size(
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
*/
static int test_config_error(
static int SQLITE_TCLAPI test_config_error(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1212,7 +1216,7 @@ static int test_config_error(
** Enables or disables interpretation of URI parameters by default using
** SQLITE_CONFIG_URI.
*/
static int test_config_uri(
static int SQLITE_TCLAPI test_config_uri(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1241,7 +1245,7 @@ static int test_config_uri(
** Enables or disables the use of the covering-index scan optimization.
** SQLITE_CONFIG_COVERING_INDEX_SCAN.
*/
static int test_config_cis(
static int SQLITE_TCLAPI test_config_cis(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1269,7 +1273,7 @@ static int test_config_cis(
**
** Set the minimum PMA size.
*/
static int test_config_pmasz(
static int SQLITE_TCLAPI test_config_pmasz(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1299,7 +1303,7 @@ static int test_config_pmasz(
**
** Write a summary of unfreed memsys3 allocations to FILENAME.
*/
static int test_dump_memsys3(
static int SQLITE_TCLAPI test_dump_memsys3(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1335,7 +1339,7 @@ static int test_dump_memsys3(
** Return a list of three elements which are the sqlite3_status() return
** code, the current value, and the high-water mark value.
*/
static int test_status(
static int SQLITE_TCLAPI test_status(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1392,7 +1396,7 @@ static int test_status(
** Return a list of three elements which are the sqlite3_db_status() return
** code, the current value, and the high-water mark value.
*/
static int test_db_status(
static int SQLITE_TCLAPI test_db_status(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1417,7 +1421,8 @@ static int test_db_status(
{ "CACHE_HIT", SQLITE_DBSTATUS_CACHE_HIT },
{ "CACHE_MISS", SQLITE_DBSTATUS_CACHE_MISS },
{ "CACHE_WRITE", SQLITE_DBSTATUS_CACHE_WRITE },
{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS }
{ "DEFERRED_FKS", SQLITE_DBSTATUS_DEFERRED_FKS },
{ "CACHE_USED_SHARED", SQLITE_DBSTATUS_CACHE_USED_SHARED },
};
Tcl_Obj *pResult;
if( objc!=4 ){
@@ -1452,7 +1457,7 @@ static int test_db_status(
/*
** install_malloc_faultsim BOOLEAN
*/
static int test_install_malloc_faultsim(
static int SQLITE_TCLAPI test_install_malloc_faultsim(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1476,7 +1481,7 @@ static int test_install_malloc_faultsim(
/*
** sqlite3_install_memsys3
*/
static int test_install_memsys3(
static int SQLITE_TCLAPI test_install_memsys3(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1491,7 +1496,7 @@ static int test_install_memsys3(
return TCL_OK;
}
static int test_vfs_oom_test(
static int SQLITE_TCLAPI test_vfs_oom_test(
void * clientData,
Tcl_Interp *interp,
int objc,
+20 -9
View File
@@ -539,7 +539,7 @@ static int multiplexOpen(
memset(pGroup, 0, sz);
pMultiplexOpen->pGroup = pGroup;
pGroup->bEnabled = (unsigned char)-1;
pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate",
pGroup->bTruncate = (unsigned char)sqlite3_uri_boolean(zUri, "truncate",
(flags & SQLITE_OPEN_MAIN_DB)==0);
pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize",
SQLITE_MULTIPLEX_CHUNK_SIZE);
@@ -717,7 +717,11 @@ static int multiplexCurrentTime(sqlite3_vfs *a, double *b){
return gMultiplex.pOrigVfs->xCurrentTime(gMultiplex.pOrigVfs, b);
}
static int multiplexGetLastError(sqlite3_vfs *a, int b, char *c){
return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
if( gMultiplex.pOrigVfs->xGetLastError ){
return gMultiplex.pOrigVfs->xGetLastError(gMultiplex.pOrigVfs, b, c);
}else{
return 0;
}
}
static int multiplexCurrentTimeInt64(sqlite3_vfs *a, sqlite3_int64 *b){
return gMultiplex.pOrigVfs->xCurrentTimeInt64(gMultiplex.pOrigVfs, b);
@@ -974,7 +978,7 @@ static int multiplexFileControl(sqlite3_file *pConn, int op, void *pArg){
case MULTIPLEX_CTRL_ENABLE:
if( pArg ) {
int bEnabled = *(int *)pArg;
pGroup->bEnabled = bEnabled;
pGroup->bEnabled = (unsigned char)bEnabled;
rc = SQLITE_OK;
}
break;
@@ -1193,7 +1197,7 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
gMultiplex.sIoMethodsV2.xShmUnmap = multiplexShmUnmap;
sqlite3_vfs_register(&gMultiplex.sThisVfs, makeDefault);
sqlite3_auto_extension((void*)multiplexFuncInit);
sqlite3_auto_extension((void(*)(void))multiplexFuncInit);
return SQLITE_OK;
}
@@ -1225,14 +1229,21 @@ int sqlite3_multiplex_shutdown(int eForce){
/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
extern const char *sqlite3ErrName(int);
/*
** tclcmd: sqlite3_multiplex_initialize NAME MAKEDEFAULT
*/
static int test_multiplex_initialize(
static int SQLITE_TCLAPI test_multiplex_initialize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1263,7 +1274,7 @@ static int test_multiplex_initialize(
/*
** tclcmd: sqlite3_multiplex_shutdown
*/
static int test_multiplex_shutdown(
static int SQLITE_TCLAPI test_multiplex_shutdown(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1291,7 +1302,7 @@ static int test_multiplex_shutdown(
/*
** tclcmd: sqlite3_multiplex_dump
*/
static int test_multiplex_dump(
static int SQLITE_TCLAPI test_multiplex_dump(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1346,7 +1357,7 @@ static int test_multiplex_dump(
/*
** Tclcmd: test_multiplex_control HANDLE DBNAME SUB-COMMAND ?INT-VALUE?
*/
static int test_multiplex_control(
static int SQLITE_TCLAPI test_multiplex_control(
ClientData cd,
Tcl_Interp *interp,
int objc,
+3 -3
View File
@@ -20,8 +20,8 @@
**
*/
#ifndef _TEST_MULTIPLEX_H
#define _TEST_MULTIPLEX_H
#ifndef SQLITE_TEST_MULTIPLEX_H
#define SQLITE_TEST_MULTIPLEX_H
/*
** CAPI: File-control Operations Supported by Multiplex VFS
@@ -96,4 +96,4 @@ extern int sqlite3_multiplex_shutdown(int eForce);
} /* End of the 'extern "C"' block */
#endif
#endif /* _TEST_MULTIPLEX_H */
#endif /* SQLITE_TEST_MULTIPLEX_H */
+16 -12
View File
@@ -12,7 +12,11 @@
** This file contains test logic for the sqlite3_mutex interfaces.
*/
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
@@ -152,7 +156,7 @@ static void counterMutexLeave(sqlite3_mutex *p){
/*
** sqlite3_shutdown
*/
static int test_shutdown(
static int SQLITE_TCLAPI test_shutdown(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -173,7 +177,7 @@ static int test_shutdown(
/*
** sqlite3_initialize
*/
static int test_initialize(
static int SQLITE_TCLAPI test_initialize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -194,7 +198,7 @@ static int test_initialize(
/*
** install_mutex_counters BOOLEAN
*/
static int test_install_mutex_counters(
static int SQLITE_TCLAPI test_install_mutex_counters(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -255,7 +259,7 @@ static int test_install_mutex_counters(
/*
** read_mutex_counters
*/
static int test_read_mutex_counters(
static int SQLITE_TCLAPI test_read_mutex_counters(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -284,7 +288,7 @@ static int test_read_mutex_counters(
/*
** clear_mutex_counters
*/
static int test_clear_mutex_counters(
static int SQLITE_TCLAPI test_clear_mutex_counters(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -308,7 +312,7 @@ static int test_clear_mutex_counters(
** will be invalid since the mutex has already been freed. The
** return pointer just checks to see if the mutex really was allocated.
*/
static int test_alloc_mutex(
static int SQLITE_TCLAPI test_alloc_mutex(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -335,7 +339,7 @@ static int test_alloc_mutex(
**
** Or OPTION can be an raw integer.
*/
static int test_config(
static int SQLITE_TCLAPI test_config(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -397,7 +401,7 @@ static sqlite3_mutex *getStaticMutexPointer(
return counterMutexAlloc(iMutex);
}
static int test_enter_static_mutex(
static int SQLITE_TCLAPI test_enter_static_mutex(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -416,7 +420,7 @@ static int test_enter_static_mutex(
return TCL_OK;
}
static int test_leave_static_mutex(
static int SQLITE_TCLAPI test_leave_static_mutex(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -435,7 +439,7 @@ static int test_leave_static_mutex(
return TCL_OK;
}
static int test_enter_db_mutex(
static int SQLITE_TCLAPI test_enter_db_mutex(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -454,7 +458,7 @@ static int test_enter_db_mutex(
return TCL_OK;
}
static int test_leave_db_mutex(
static int SQLITE_TCLAPI test_leave_db_mutex(
void * clientData,
Tcl_Interp *interp,
int objc,
+1 -1
View File
@@ -508,7 +508,7 @@ static int fsSync(sqlite3_file *pFile, int flags){
if( p->eType==DATABASE_FILE ){
unsigned char zSize[4];
zSize[0] = (pReal->nDatabase&0xFF000000)>>24;
zSize[1] = (pReal->nDatabase&0x00FF0000)>>16;
zSize[1] = (unsigned char)((pReal->nDatabase&0x00FF0000)>>16);
zSize[2] = (pReal->nDatabase&0x0000FF00)>>8;
zSize[3] = (pReal->nDatabase&0x000000FF);
rc = pRealFile->pMethods->xWrite(pRealFile, zSize, 4, 0);
+12 -5
View File
@@ -644,9 +644,9 @@ static void vfslog_flush(VfslogVfs *p){
static void put32bits(unsigned char *p, unsigned int v){
p[0] = v>>24;
p[1] = v>>16;
p[2] = v>>8;
p[3] = v;
p[1] = (unsigned char)(v>>16);
p[2] = (unsigned char)(v>>8);
p[3] = (unsigned char)v;
}
static void vfslog_call(
@@ -1104,9 +1104,16 @@ int sqlite3_vfslog_register(sqlite3 *db){
#if defined(SQLITE_TEST) || defined(TCLSH)
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
static int test_vfslog(
static int SQLITE_TCLAPI test_vfslog(
void *clientData,
Tcl_Interp *interp,
int objc,
+43 -36
View File
@@ -111,7 +111,7 @@ struct quotaFile {
/*
** An instance of the following object represents each open connection
** to a file that participates in quota tracking. This object is a
** to a file that participates in quota tracking. This object is a
** subclass of sqlite3_file. The sqlite3_file object for the underlying
** VFS is appended to this structure.
*/
@@ -154,11 +154,11 @@ static struct {
*/
sqlite3_vfs sThisVfs;
/* The sIoMethods defines the methods used by sqlite3_file objects
/* The sIoMethods defines the methods used by sqlite3_file objects
** associated with this shim. It is initialized at start-time and does
** not require a mutex.
**
** When the underlying VFS is called to open a file, it might return
** When the underlying VFS is called to open a file, it might return
** either a version 1 or a version 2 sqlite3_file object. This shim
** has to create a wrapper sqlite3_file of the same version. Hence
** there are two I/O method structures, one for version 1 and the other
@@ -190,7 +190,7 @@ static struct {
static void quotaEnter(void){ sqlite3_mutex_enter(gQuota.pMutex); }
static void quotaLeave(void){ sqlite3_mutex_leave(gQuota.pMutex); }
/* Count the number of open files in a quotaGroup
/* Count the number of open files in a quotaGroup
*/
static int quotaGroupOpenFileCount(quotaGroup *pGroup){
int N = 0;
@@ -399,7 +399,7 @@ static char *quota_utf8_to_mbcs(const char *zUtf8){
return zMbcs;
#else
return (char*)zUtf8; /* No-op on unix */
#endif
#endif
}
/*
@@ -410,7 +410,7 @@ static void quota_mbcs_free(char *zOld){
sqlite3_free(zOld);
#else
/* No-op on unix */
#endif
#endif
}
/************************* VFS Method Wrappers *****************************/
@@ -428,7 +428,7 @@ static int quotaOpen(
int flags, /* Flags to control the opening */
int *pOutFlags /* Flags showing results of opening */
){
int rc; /* Result code */
int rc; /* Result code */
quotaConn *pQuotaOpen; /* The new quota file descriptor */
quotaFile *pFile; /* Corresponding quotaFile obj */
quotaGroup *pGroup; /* The group file belongs to */
@@ -488,7 +488,7 @@ static int quotaDelete(
const char *zName, /* Name of file to be deleted */
int syncDir /* Do a directory sync after deleting */
){
int rc; /* Result code */
int rc; /* Result code */
quotaFile *pFile; /* Files in the quota */
quotaGroup *pGroup; /* The group file belongs to */
sqlite3_vfs *pOrigVfs = gQuota.pOrigVfs; /* Real VFS */
@@ -581,7 +581,7 @@ static int quotaWrite(
szNew = pGroup->iSize - pFile->iSize + iEnd;
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
if( pGroup->xCallback ){
pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew,
pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew,
pGroup->pArg);
}
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
@@ -738,7 +738,7 @@ static int quotaShmUnmap(sqlite3_file *pConn, int deleteFlag){
/*
** Initialize the quota VFS shim. Use the VFS named zOrigVfsName
** as the VFS that does the actual work. Use the default if
** zOrigVfsName==NULL.
** zOrigVfsName==NULL.
**
** The quota VFS shim is named "quota". It will become the default
** VFS if makeDefault is non-zero.
@@ -908,7 +908,7 @@ int sqlite3_quota_file(const char *zFilename){
if( rc==SQLITE_OK ){
zFull[strlen(zFull)+1] = '\0';
rc = quotaOpen(&gQuota.sThisVfs, zFull, fd,
rc = quotaOpen(&gQuota.sThisVfs, zFull, fd,
SQLITE_OPEN_READONLY | SQLITE_OPEN_MAIN_DB, &outFlags);
if( rc==SQLITE_OK ){
fd->pMethods->xFileSize(fd, &iSize);
@@ -1016,7 +1016,7 @@ size_t sqlite3_quota_fwrite(
szNew = pGroup->iSize - pFile->iSize + iEnd;
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
if( pGroup->xCallback ){
pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew,
pGroup->xCallback(pFile->zFilename, &pGroup->iLimit, szNew,
pGroup->pArg);
}
if( szNew>pGroup->iLimit && pGroup->iLimit>0 ){
@@ -1203,7 +1203,7 @@ sqlite3_int64 sqlite3_quota_file_truesize(quota_FILE *p){
sqlite3_int64 sqlite3_quota_file_size(quota_FILE *p){
return p->pFile ? p->pFile->iSize : -1;
}
/*
** Determine the amount of data in bytes available for reading
** in the given file.
@@ -1275,10 +1275,17 @@ int sqlite3_quota_remove(const char *zFilename){
sqlite3_free(zFull);
return rc;
}
/***************************** Test Code ***********************************/
#ifdef SQLITE_TEST
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
/*
** Argument passed to a TCL quota-over-limit callback.
@@ -1350,7 +1357,7 @@ static void tclCallbackDestructor(void *pObj){
/*
** tclcmd: sqlite3_quota_initialize NAME MAKEDEFAULT
*/
static int test_quota_initialize(
static int SQLITE_TCLAPI test_quota_initialize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1379,7 +1386,7 @@ static int test_quota_initialize(
/*
** tclcmd: sqlite3_quota_shutdown
*/
static int test_quota_shutdown(
static int SQLITE_TCLAPI test_quota_shutdown(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1402,7 +1409,7 @@ static int test_quota_shutdown(
/*
** tclcmd: sqlite3_quota_set PATTERN LIMIT SCRIPT
*/
static int test_quota_set(
static int SQLITE_TCLAPI test_quota_set(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1456,7 +1463,7 @@ static int test_quota_set(
/*
** tclcmd: sqlite3_quota_file FILENAME
*/
static int test_quota_file(
static int SQLITE_TCLAPI test_quota_file(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1482,7 +1489,7 @@ static int test_quota_file(
/*
** tclcmd: sqlite3_quota_dump
*/
static int test_quota_dump(
static int SQLITE_TCLAPI test_quota_dump(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1530,7 +1537,7 @@ static int test_quota_dump(
/*
** tclcmd: sqlite3_quota_fopen FILENAME MODE
*/
static int test_quota_fopen(
static int SQLITE_TCLAPI test_quota_fopen(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1560,7 +1567,7 @@ extern void *sqlite3TestTextToPtr(const char*);
/*
** tclcmd: sqlite3_quota_fread HANDLE SIZE NELEM
*/
static int test_quota_fread(
static int SQLITE_TCLAPI test_quota_fread(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1594,7 +1601,7 @@ static int test_quota_fread(
/*
** tclcmd: sqlite3_quota_fwrite HANDLE SIZE NELEM CONTENT
*/
static int test_quota_fwrite(
static int SQLITE_TCLAPI test_quota_fwrite(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1622,7 +1629,7 @@ static int test_quota_fwrite(
/*
** tclcmd: sqlite3_quota_fclose HANDLE
*/
static int test_quota_fclose(
static int SQLITE_TCLAPI test_quota_fclose(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1644,7 +1651,7 @@ static int test_quota_fclose(
/*
** tclcmd: sqlite3_quota_fflush HANDLE ?HARDSYNC?
*/
static int test_quota_fflush(
static int SQLITE_TCLAPI test_quota_fflush(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1670,7 +1677,7 @@ static int test_quota_fflush(
/*
** tclcmd: sqlite3_quota_fseek HANDLE OFFSET WHENCE
*/
static int test_quota_fseek(
static int SQLITE_TCLAPI test_quota_fseek(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1708,7 +1715,7 @@ static int test_quota_fseek(
/*
** tclcmd: sqlite3_quota_rewind HANDLE
*/
static int test_quota_rewind(
static int SQLITE_TCLAPI test_quota_rewind(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1727,7 +1734,7 @@ static int test_quota_rewind(
/*
** tclcmd: sqlite3_quota_ftell HANDLE
*/
static int test_quota_ftell(
static int SQLITE_TCLAPI test_quota_ftell(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1748,7 +1755,7 @@ static int test_quota_ftell(
/*
** tclcmd: sqlite3_quota_ftruncate HANDLE SIZE
*/
static int test_quota_ftruncate(
static int SQLITE_TCLAPI test_quota_ftruncate(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1773,7 +1780,7 @@ static int test_quota_ftruncate(
/*
** tclcmd: sqlite3_quota_file_size HANDLE
*/
static int test_quota_file_size(
static int SQLITE_TCLAPI test_quota_file_size(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1794,7 +1801,7 @@ static int test_quota_file_size(
/*
** tclcmd: sqlite3_quota_file_truesize HANDLE
*/
static int test_quota_file_truesize(
static int SQLITE_TCLAPI test_quota_file_truesize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1815,7 +1822,7 @@ static int test_quota_file_truesize(
/*
** tclcmd: sqlite3_quota_file_mtime HANDLE
*/
static int test_quota_file_mtime(
static int SQLITE_TCLAPI test_quota_file_mtime(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1838,7 +1845,7 @@ static int test_quota_file_mtime(
/*
** tclcmd: sqlite3_quota_remove FILENAME
*/
static int test_quota_remove(
static int SQLITE_TCLAPI test_quota_remove(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1862,7 +1869,7 @@ static int test_quota_remove(
** Test the glob pattern matching. Return 1 if TEXT matches PATTERN
** and return 0 if it does not.
*/
static int test_quota_glob(
static int SQLITE_TCLAPI test_quota_glob(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1888,7 +1895,7 @@ static int test_quota_glob(
** Return the number of bytes from the current file point to the end of
** the file.
*/
static int test_quota_file_available(
static int SQLITE_TCLAPI test_quota_file_available(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -1911,7 +1918,7 @@ static int test_quota_file_available(
**
** Return true if the file handle is in the error state.
*/
static int test_quota_ferror(
static int SQLITE_TCLAPI test_quota_ferror(
void * clientData,
Tcl_Interp *interp,
int objc,
+12 -4
View File
@@ -14,7 +14,11 @@
*/
#include "sqlite3.h"
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"
@@ -353,7 +357,11 @@ static int bfs_query_func(sqlite3_rtree_query_info *p){
*************************************************************************/
#include <assert.h>
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
typedef struct Cube Cube;
struct Cube {
@@ -432,7 +440,7 @@ static int cube_geom(
}
#endif /* SQLITE_ENABLE_RTREE */
static int register_cube_geom(
static int SQLITE_TCLAPI register_cube_geom(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -460,7 +468,7 @@ static int register_cube_geom(
return TCL_OK;
}
static int register_circle_geom(
static int SQLITE_TCLAPI register_circle_geom(
void * clientData,
Tcl_Interp *interp,
int objc,
+8 -4
View File
@@ -35,10 +35,14 @@
** to be compiled into an sqlite dynamic extension.
*/
#ifdef SQLITE_TEST
#include "sqliteInt.h"
#include "tcl.h"
# include "sqliteInt.h"
# if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
# else
# include "tcl.h"
# endif
#else
#include "sqlite3ext.h"
# include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#endif
@@ -302,7 +306,7 @@ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/*
** Register the schema virtual table module.
*/
static int register_schema_module(
static int SQLITE_TCLAPI register_schema_module(
ClientData clientData, /* Not used */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+11 -4
View File
@@ -256,7 +256,14 @@ int sqlite3demo_superlock(
#ifdef SQLITE_TEST
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
struct InterpAndScript {
Tcl_Interp *interp;
@@ -264,11 +271,11 @@ struct InterpAndScript {
};
typedef struct InterpAndScript InterpAndScript;
static void superunlock_del(ClientData cd){
static void SQLITE_TCLAPI superunlock_del(ClientData cd){
sqlite3demo_superunlock((void *)cd);
}
static int superunlock_cmd(
static int SQLITE_TCLAPI superunlock_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
@@ -300,7 +307,7 @@ static int superlock_busy(void *pCtx, int nBusy){
/*
** Tclcmd: sqlite3demo_superlock CMDNAME PATH VFS BUSY-HANDLER-SCRIPT
*/
static int superlock_cmd(
static int SQLITE_TCLAPI superlock_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
+33 -20
View File
@@ -76,7 +76,11 @@
#include "sqliteInt.h"
#include "sqlite3.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -108,10 +112,13 @@ static int ts_ftruncate(int fd, off_t n);
static int ts_fcntl(int fd, int cmd, ... );
static int ts_read(int fd, void *aBuf, size_t nBuf);
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off);
/* Note: pread64() and pwrite64() actually use off64_t as the type on their
** last parameter. But that datatype is not defined on many systems
** (ex: Mac, OpenBSD). So substitute a likely equivalent: sqlite3_uint64 */
static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off);
static int ts_write(int fd, const void *aBuf, size_t nBuf);
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off);
static int ts_fchmod(int fd, mode_t mode);
static int ts_fallocate(int fd, off_t off, off_t len);
static void *ts_mmap(void *, size_t, int, int, int, off_t);
@@ -155,11 +162,11 @@ struct TestSyscallArray {
#define orig_fcntl ((int(*)(int,int,...))aSyscall[7].xOrig)
#define orig_read ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig)
#define orig_pread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig)
#define orig_pread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig)
#define orig_pread64 ((ssize_t(*)(int,void*,size_t,sqlite3_uint64))aSyscall[10].xOrig)
#define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig)
#define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
aSyscall[12].xOrig)
#define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
#define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,sqlite3_uint64))\
aSyscall[13].xOrig)
#define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
@@ -326,7 +333,7 @@ static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
/*
** A wrapper around pread64().
*/
static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
static int ts_pread64(int fd, void *aBuf, size_t nBuf, sqlite3_uint64 off){
if( tsIsFailErrno("pread64") ){
return -1;
}
@@ -357,7 +364,7 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
/*
** A wrapper around pwrite64().
*/
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, sqlite3_uint64 off){
if( tsIsFailErrno("pwrite64") ){
return -1;
}
@@ -415,7 +422,7 @@ static void *ts_mremap(void *a, size_t b, size_t c, int d, ...){
return orig_mremap(a, b, c, d, pArg);
}
static int test_syscall_install(
static int SQLITE_TCLAPI test_syscall_install(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -451,7 +458,7 @@ static int test_syscall_install(
return TCL_OK;
}
static int test_syscall_uninstall(
static int SQLITE_TCLAPI test_syscall_uninstall(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -475,7 +482,7 @@ static int test_syscall_uninstall(
return TCL_OK;
}
static int test_syscall_reset(
static int SQLITE_TCLAPI test_syscall_reset(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -513,7 +520,7 @@ static int test_syscall_reset(
return TCL_OK;
}
static int test_syscall_exists(
static int SQLITE_TCLAPI test_syscall_exists(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -534,7 +541,7 @@ static int test_syscall_exists(
return TCL_OK;
}
static int test_syscall_fault(
static int SQLITE_TCLAPI test_syscall_fault(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -563,7 +570,7 @@ static int test_syscall_fault(
return TCL_OK;
}
static int test_syscall_errno(
static int SQLITE_TCLAPI test_syscall_errno(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -609,7 +616,7 @@ static int test_syscall_errno(
return TCL_OK;
}
static int test_syscall_list(
static int SQLITE_TCLAPI test_syscall_list(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -639,7 +646,7 @@ static int test_syscall_list(
return TCL_OK;
}
static int test_syscall_defaultvfs(
static int SQLITE_TCLAPI test_syscall_defaultvfs(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -661,7 +668,7 @@ static int ts_getpagesize(void){
return gSyscall.pgsz;
}
static int test_syscall_pagesize(
static int SQLITE_TCLAPI test_syscall_pagesize(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -696,7 +703,7 @@ static int test_syscall_pagesize(
return TCL_OK;
}
static int test_syscall(
static int SQLITE_TCLAPI test_syscall(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -719,14 +726,20 @@ static int test_syscall(
};
int iCmd;
int rc;
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
return TCL_ERROR;
}
rc = Tcl_GetIndexFromObjStruct(interp,
objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
);
if( pVfs->iVersion<3 || pVfs->xSetSystemCall==0 ){
Tcl_AppendResult(interp, "VFS does not support xSetSystemCall", 0);
rc = TCL_ERROR;
}else{
rc = Tcl_GetIndexFromObjStruct(interp,
objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
);
}
if( rc!=TCL_OK ) return rc;
return aCmd[iCmd].xCmd(clientData, interp, objc, objv);
}
+6 -2
View File
@@ -17,7 +17,11 @@
** access to TCL variables.
*/
#include "sqliteInt.h"
#include "tcl.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -407,7 +411,7 @@ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
/*
** Register the echo virtual table module.
*/
static int register_tclvar_module(
static int SQLITE_TCLAPI register_tclvar_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
+16 -12
View File
@@ -16,7 +16,11 @@
*/
#include "sqliteInt.h"
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#if SQLITE_THREADSAFE
@@ -72,7 +76,7 @@ extern int sqlite3TestErrCode(Tcl_Interp *, sqlite3 *, int);
/*
** Handler for events of type EvalEvent.
*/
static int tclScriptEvent(Tcl_Event *evPtr, int flags){
static int SQLITE_TCLAPI tclScriptEvent(Tcl_Event *evPtr, int flags){
int rc;
EvalEvent *p = (EvalEvent *)evPtr;
rc = Tcl_Eval(p->interp, p->zScript);
@@ -167,7 +171,7 @@ static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
**
** The caller can wait for the script to terminate using [vwait VARNAME].
*/
static int sqlthread_spawn(
static int SQLITE_TCLAPI sqlthread_spawn(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -220,7 +224,7 @@ static int sqlthread_spawn(
**
** NOTE: At the moment, this doesn't work. FIXME.
*/
static int sqlthread_parent(
static int SQLITE_TCLAPI sqlthread_parent(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -265,7 +269,7 @@ static int xBusy(void *pArg, int nBusy){
** Open a database handle and return the string representation of
** the pointer value.
*/
static int sqlthread_open(
static int SQLITE_TCLAPI sqlthread_open(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -276,7 +280,7 @@ static int sqlthread_open(
const char *zFilename;
sqlite3 *db;
char zBuf[100];
extern void Md5_Register(sqlite3*);
extern int Md5_Register(sqlite3*,char**,const sqlite3_api_routines*);
UNUSED_PARAMETER(clientData);
UNUSED_PARAMETER(objc);
@@ -299,7 +303,7 @@ static int sqlthread_open(
}
}
#endif
Md5_Register(db);
Md5_Register(db, 0, 0);
sqlite3_busy_handler(db, xBusy, 0);
if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
@@ -315,7 +319,7 @@ static int sqlthread_open(
** Return the current thread-id (Tcl_GetCurrentThread()) cast to
** an integer.
*/
static int sqlthread_id(
static int SQLITE_TCLAPI sqlthread_id(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -333,7 +337,7 @@ static int sqlthread_id(
/*
** Dispatch routine for the sub-commands of [sqlthread].
*/
static int sqlthread_proc(
static int SQLITE_TCLAPI sqlthread_proc(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -381,7 +385,7 @@ static int sqlthread_proc(
** implemented as a script in Tcl 8.5, it is not usually available to
** testfixture.
*/
static int clock_seconds_proc(
static int SQLITE_TCLAPI clock_seconds_proc(
ClientData clientData,
Tcl_Interp *interp,
int objc,
@@ -543,7 +547,7 @@ int sqlite3_blocking_prepare_v2(
**
** Advance the statement to the next row.
*/
static int blocking_step_proc(
static int SQLITE_TCLAPI blocking_step_proc(
void * clientData,
Tcl_Interp *interp,
int objc,
@@ -569,7 +573,7 @@ static int blocking_step_proc(
** Usage: sqlite3_blocking_prepare_v2 DB sql bytes ?tailvar?
** Usage: sqlite3_nonblocking_prepare_v2 DB sql bytes ?tailvar?
*/
static int blocking_prepare_v2_proc(
static int SQLITE_TCLAPI blocking_prepare_v2_proc(
void * clientData,
Tcl_Interp *interp,
int objc,
+10 -7
View File
@@ -28,7 +28,11 @@
#include "sqlite3.h"
#include "sqliteInt.h"
#include <tcl.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;
@@ -306,7 +310,6 @@ static void tvfsExecTcl(
** Close an tvfs-file.
*/
static int tvfsClose(sqlite3_file *pFile){
int rc;
TestvfsFile *pTestfile = (TestvfsFile *)pFile;
TestvfsFd *pFd = pTestfile->pFd;
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
@@ -324,10 +327,10 @@ static int tvfsClose(sqlite3_file *pFile){
if( pFile->pMethods ){
ckfree((char *)pFile->pMethods);
}
rc = sqlite3OsClose(pFd->pReal);
sqlite3OsClose(pFd->pReal);
ckfree((char *)pFd);
pTestfile->pFd = 0;
return rc;
return SQLITE_OK;
}
/*
@@ -1037,7 +1040,7 @@ static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){
return sqlite3OsUnfetch(pFd->pReal, iOfst, p);
}
static int testvfs_obj_cmd(
static int SQLITE_TCLAPI testvfs_obj_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
@@ -1349,7 +1352,7 @@ static int testvfs_obj_cmd(
return TCL_OK;
}
static void testvfs_obj_del(ClientData cd){
static void SQLITE_TCLAPI testvfs_obj_del(ClientData cd){
Testvfs *p = (Testvfs *)cd;
if( p->pScript ) Tcl_DecrRefCount(p->pScript);
sqlite3_vfs_unregister(p->pVfs);
@@ -1392,7 +1395,7 @@ static void testvfs_obj_del(ClientData cd){
**
** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive"
*/
static int testvfs_cmd(
static int SQLITE_TCLAPI testvfs_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
+29 -1
View File
@@ -17,6 +17,34 @@
#include "test_windirent.h"
/*
** Implementation of the POSIX getenv() function using the Win32 API.
** This function is not thread-safe.
*/
const char *windirent_getenv(
const char *name
){
static char value[32768]; /* Maximum length, per MSDN */
DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */
memset(value, 0, sizeof(value));
dwRet = GetEnvironmentVariableA(name, value, dwSize);
if( dwRet==0 || dwRet>dwSize ){
/*
** The function call to GetEnvironmentVariableA() failed -OR-
** the buffer is not large enough. Either way, return NULL.
*/
return 0;
}else{
/*
** The function call to GetEnvironmentVariableA() succeeded
** -AND- the buffer contains the entire value.
*/
return value;
}
}
/*
** Implementation of the POSIX opendir() function using the MSVCRT.
*/
@@ -32,7 +60,7 @@ LPDIR opendir(
/* TODO: Remove this if Unix-style root paths are not used. */
if( sqlite3_stricmp(dirname, "/")==0 ){
dirname = getenv("SystemDrive");
dirname = windirent_getenv("SystemDrive");
}
_snprintf(data.name, namesize, "%s\\*", dirname);

Some files were not shown because too many files have changed in this diff Show More