Upgrade SQLite to 3.40 (#699)

This commit is contained in:
Paul Kulchenko 2022-11-28 12:54:48 -08:00 committed by GitHub
parent bcae817215
commit 0dc0758574
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 27917 additions and 22169 deletions

View file

@ -5,7 +5,7 @@ DESCRIPTION
ORIGIN ORIGIN
https://www.sqlite.org/2021/sqlite-preprocessed-3350500.zip https://www.sqlite.org/2022/sqlite-preprocessed-3400000.zip
LICENSE LICENSE

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@
** created and used by SQLite versions 3.7.9 through 3.29.0 when ** created and used by SQLite versions 3.7.9 through 3.29.0 when
** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
** is a superset of sqlite_stat2 and is also now deprecated. The ** is a superset of sqlite_stat2 and is also now deprecated. The
** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only ** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only
** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite ** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite
** versions 3.8.1 and later. STAT4 is the only variant that is still ** versions 3.8.1 and later. STAT4 is the only variant that is still
** supported. ** supported.
@ -49,7 +49,7 @@
** integer is the average number of rows in the index that have the same ** integer is the average number of rows in the index that have the same
** value in the first column of the index. The third integer is the average ** value in the first column of the index. The third integer is the average
** number of rows in the index that have the same value for the first two ** number of rows in the index that have the same value for the first two
** columns. The N-th integer (for N>1) is the average number of rows in ** columns. The N-th integer (for N>1) is the average number of rows in
** the index which have the same value for the first N-1 columns. For ** the index which have the same value for the first N-1 columns. For
** a K-column index, there will be K+1 integers in the stat column. If ** a K-column index, there will be K+1 integers in the stat column. If
** the index is unique, then the last integer will be 1. ** the index is unique, then the last integer will be 1.
@ -59,7 +59,7 @@
** must be separated from the last integer by a single space. If the ** must be separated from the last integer by a single space. If the
** "unordered" keyword is present, then the query planner assumes that ** "unordered" keyword is present, then the query planner assumes that
** the index is unordered and will not use the index for a range query. ** the index is unordered and will not use the index for a range query.
** **
** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat ** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat
** column contains a single integer which is the (estimated) number of ** column contains a single integer which is the (estimated) number of
** rows in the table identified by sqlite_stat1.tbl. ** rows in the table identified by sqlite_stat1.tbl.
@ -117,9 +117,9 @@
** number of entries that are strictly less than the sample. The first ** number of entries that are strictly less than the sample. The first
** integer in nLt contains the number of entries in the index where the ** integer in nLt contains the number of entries in the index where the
** left-most column is less than the left-most column of the sample. ** left-most column is less than the left-most column of the sample.
** The K-th integer in the nLt entry is the number of index entries ** The K-th integer in the nLt entry is the number of index entries
** where the first K columns are less than the first K columns of the ** where the first K columns are less than the first K columns of the
** sample. The nDLt column is like nLt except that it contains the ** sample. The nDLt column is like nLt except that it contains the
** number of distinct entries in the index that are less than the ** number of distinct entries in the index that are less than the
** sample. ** sample.
** **
@ -140,8 +140,7 @@
** integer in the equivalent columns in sqlite_stat4. ** integer in the equivalent columns in sqlite_stat4.
*/ */
#ifndef SQLITE_OMIT_ANALYZE #ifndef SQLITE_OMIT_ANALYZE
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#if defined(SQLITE_ENABLE_STAT4) #if defined(SQLITE_ENABLE_STAT4)
# define IsStat4 1 # define IsStat4 1
@ -434,7 +433,6 @@ static void statInit(
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample); + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
} }
#endif #endif
db = sqlite3_context_db_handle(context);
p = sqlite3DbMallocZero(db, n); p = sqlite3DbMallocZero(db, n);
if( p==0 ){ if( p==0 ){
sqlite3_result_error_nomem(context); sqlite3_result_error_nomem(context);
@ -849,32 +847,29 @@ static void statGet(
** * "WHERE a=? AND b=?" matches 2 rows. ** * "WHERE a=? AND b=?" matches 2 rows.
** **
** If D is the count of distinct values and K is the total number of ** If D is the count of distinct values and K is the total number of
** rows, then each estimate is computed as: ** rows, then each estimate is usually computed as:
** **
** I = (K+D-1)/D ** I = (K+D-1)/D
**
** In other words, I is K/D rounded up to the next whole integer.
** However, if I is between 1.0 and 1.1 (in other words if I is
** close to 1.0 but just a little larger) then do not round up but
** instead keep the I value at 1.0.
*/ */
char *z; sqlite3_str sStat; /* Text of the constructed "stat" line */
int i; int i; /* Loop counter */
char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100);
if( zRet==0 ){ sqlite3_str_appendf(&sStat, "%llu",
sqlite3_result_error_nomem(context);
return;
}
sqlite3_snprintf(24, zRet, "%llu",
p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow); p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<p->nKeyCol; i++){ for(i=0; i<p->nKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1; u64 nDistinct = p->current.anDLt[i] + 1;
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
sqlite3_snprintf(24, z, " %llu", iVal); if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
z += sqlite3Strlen30(z); sqlite3_str_appendf(&sStat, " %llu", iVal);
assert( p->current.anEq[i] ); assert( p->current.anEq[i] );
} }
assert( z[0]=='\0' && z>zRet ); sqlite3ResultStrAccum(context, &sStat);
sqlite3_result_text(context, zRet, -1, sqlite3_free);
} }
#ifdef SQLITE_ENABLE_STAT4 #ifdef SQLITE_ENABLE_STAT4
else if( eCall==STAT_GET_ROWID ){ else if( eCall==STAT_GET_ROWID ){
@ -893,6 +888,8 @@ static void statGet(
} }
}else{ }else{
tRowcnt *aCnt = 0; tRowcnt *aCnt = 0;
sqlite3_str sStat;
int i;
assert( p->iGet<p->nSample ); assert( p->iGet<p->nSample );
switch( eCall ){ switch( eCall ){
@ -904,23 +901,12 @@ static void statGet(
break; break;
} }
} }
sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100);
{ for(i=0; i<p->nCol; i++){
char *zRet = sqlite3MallocZero(p->nCol * 25); sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]);
if( zRet==0 ){
sqlite3_result_error_nomem(context);
}else{
int i;
char *z = zRet;
for(i=0; i<p->nCol; i++){
sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
z += sqlite3Strlen30(z);
}
assert( z[0]=='\0' && z>zRet );
z[-1] = '\0';
sqlite3_result_text(context, zRet, -1, sqlite3_free);
}
} }
if( sStat.nChar ) sStat.nChar--;
sqlite3ResultStrAccum(context, &sStat);
} }
#endif /* SQLITE_ENABLE_STAT4 */ #endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG #ifndef SQLITE_DEBUG
@ -967,9 +953,10 @@ static void analyzeVdbeCommentIndexWithColumnName(
if( NEVER(i==XN_ROWID) ){ if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName)); VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){ }else if( i==XN_EXPR ){
assert( pIdx->bHasExpr );
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k)); VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{ }else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zName)); VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
} }
} }
#else #else
@ -1016,7 +1003,7 @@ static void analyzeOneTable(
if( v==0 || NEVER(pTab==0) ){ if( v==0 || NEVER(pTab==0) ){
return; return;
} }
if( pTab->tnum==0 ){ if( !IsOrdinaryTable(pTab) ){
/* Do not gather statistics on views or virtual tables */ /* Do not gather statistics on views or virtual tables */
return; return;
} }
@ -1043,7 +1030,7 @@ static void analyzeOneTable(
memcpy(pStat1->zName, "sqlite_stat1", 13); memcpy(pStat1->zName, "sqlite_stat1", 13);
pStat1->nCol = 3; pStat1->nCol = 3;
pStat1->iPKey = -1; pStat1->iPKey = -1;
sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB); sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNAMIC);
} }
#endif #endif
@ -1841,9 +1828,12 @@ static int loadStatTbl(
*/ */
static int loadStat4(sqlite3 *db, const char *zDb){ static int loadStat4(sqlite3 *db, const char *zDb){
int rc = SQLITE_OK; /* Result codes from subroutines */ int rc = SQLITE_OK; /* Result codes from subroutines */
const Table *pStat4;
assert( db->lookaside.bDisable ); assert( db->lookaside.bDisable );
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db, rc = loadStatTbl(db,
"SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
@ -1880,6 +1870,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
char *zSql; char *zSql;
int rc = SQLITE_OK; int rc = SQLITE_OK;
Schema *pSchema = db->aDb[iDb].pSchema; Schema *pSchema = db->aDb[iDb].pSchema;
const Table *pStat1;
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 ); assert( db->aDb[iDb].pBt!=0 );
@ -1902,7 +1893,9 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Load new statistics out of the sqlite_stat1 table */ /* Load new statistics out of the sqlite_stat1 table */
sInfo.db = db; sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zDbSName; sInfo.zDatabase = db->aDb[iDb].zDbSName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase))
&& IsOrdinaryTable(pStat1)
){
zSql = sqlite3MPrintf(db, zSql = sqlite3MPrintf(db,
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase); "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){ if( zSql==0 ){

View file

@ -11,8 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the ATTACH and DETACH commands. ** This file contains code used to implement the ATTACH and DETACH commands.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifndef SQLITE_OMIT_ATTACH #ifndef SQLITE_OMIT_ATTACH
/* /*
@ -96,7 +95,7 @@ static void attachFunc(
if( zFile==0 ) zFile = ""; if( zFile==0 ) zFile = "";
if( zName==0 ) zName = ""; if( zName==0 ) zName = "";
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
# define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) # define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb)
#else #else
# define REOPEN_AS_MEMDB(db) (0) # define REOPEN_AS_MEMDB(db) (0)
@ -347,17 +346,18 @@ static void codeAttach(
sName.pParse = pParse; sName.pParse = pParse;
if( if(
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || SQLITE_OK!=resolveAttachExpr(&sName, pFilename) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || SQLITE_OK!=resolveAttachExpr(&sName, pDbname) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) SQLITE_OK!=resolveAttachExpr(&sName, pKey)
){ ){
goto attach_end; goto attach_end;
} }
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
if( pAuthArg ){ if( ALWAYS(pAuthArg) ){
char *zAuthArg; char *zAuthArg;
if( pAuthArg->op==TK_STRING ){ if( pAuthArg->op==TK_STRING ){
assert( !ExprHasProperty(pAuthArg, EP_IntValue) );
zAuthArg = pAuthArg->u.zToken; zAuthArg = pAuthArg->u.zToken;
}else{ }else{
zAuthArg = 0; zAuthArg = 0;
@ -465,19 +465,26 @@ static int fixSelectCb(Walker *p, Select *pSelect){
if( NEVER(pList==0) ) return WRC_Continue; if( NEVER(pList==0) ) return WRC_Continue;
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
if( pFix->bTemp==0 ){ if( pFix->bTemp==0 ){
if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ if( pItem->zDatabase ){
sqlite3ErrorMsg(pFix->pParse, if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
"%s %T cannot reference objects in database %s", sqlite3ErrorMsg(pFix->pParse,
pFix->zType, pFix->pName, pItem->zDatabase); "%s %T cannot reference objects in database %s",
return WRC_Abort; pFix->zType, pFix->pName, pItem->zDatabase);
return WRC_Abort;
}
sqlite3DbFree(db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->fg.notCte = 1;
} }
sqlite3DbFree(db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema; pItem->pSchema = pFix->pSchema;
pItem->fg.fromDDL = 1; pItem->fg.fromDDL = 1;
} }
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3WalkExpr(&pFix->w, pList->a[i].pOn) ) return WRC_Abort; if( pList->a[i].fg.isUsing==0
&& sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
){
return WRC_Abort;
}
#endif #endif
} }
if( pSelect->pWith ){ if( pSelect->pWith ){
@ -512,7 +519,7 @@ void sqlite3FixInit(
pFix->w.pParse = pParse; pFix->w.pParse = pParse;
pFix->w.xExprCallback = fixExprCb; pFix->w.xExprCallback = fixExprCb;
pFix->w.xSelectCallback = fixSelectCb; pFix->w.xSelectCallback = fixSelectCb;
pFix->w.xSelectCallback2 = 0; pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback;
pFix->w.walkerDepth = 0; pFix->w.walkerDepth = 0;
pFix->w.eCode = 0; pFix->w.eCode = 0;
pFix->w.u.pFix = pFix; pFix->w.u.pFix = pFix;
@ -574,14 +581,16 @@ int sqlite3FixTriggerStep(
return 1; return 1;
} }
#ifndef SQLITE_OMIT_UPSERT #ifndef SQLITE_OMIT_UPSERT
if( pStep->pUpsert ){ {
Upsert *pUp = pStep->pUpsert; Upsert *pUp;
if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget)
|| sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere)
|| sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet)
){ || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere)
return 1; ){
return 1;
}
} }
} }
#endif #endif

View file

@ -14,8 +14,7 @@
** systems that do not need this facility may omit it by recompiling ** systems that do not need this facility may omit it by recompiling
** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** the library with -DSQLITE_OMIT_AUTHORIZATION=1
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** All of the code in this file may be omitted by defining a single ** All of the code in this file may be omitted by defining a single
@ -176,10 +175,10 @@ void sqlite3AuthRead(
if( iCol>=0 ){ if( iCol>=0 ){
assert( iCol<pTab->nCol ); assert( iCol<pTab->nCol );
zCol = pTab->aCol[iCol].zName; zCol = pTab->aCol[iCol].zCnName;
}else if( pTab->iPKey>=0 ){ }else if( pTab->iPKey>=0 ){
assert( pTab->iPKey<pTab->nCol ); assert( pTab->iPKey<pTab->nCol );
zCol = pTab->aCol[pTab->iPKey].zName; zCol = pTab->aCol[pTab->iPKey].zCnName;
}else{ }else{
zCol = "ROWID"; zCol = "ROWID";
} }

View file

@ -9,12 +9,11 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** This file contains the implementation of the sqlite3_backup_XXX() ** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features. ** API functions and the related features.
*/ */
#include "third_party/sqlite3/btreeInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/btreeInt.h"
/* clang-format off */
/* /*
** Structure allocated for each backup operation. ** Structure allocated for each backup operation.
@ -86,14 +85,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
if( i==1 ){ if( i==1 ){
Parse sParse; Parse sParse;
int rc = 0; int rc = 0;
memset(&sParse, 0, sizeof(sParse)); sqlite3ParseObjectInit(&sParse,pDb);
sParse.db = pDb;
if( sqlite3OpenTempDatabase(&sParse) ){ if( sqlite3OpenTempDatabase(&sParse) ){
sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
sqlite3DbFree(pErrorDb, sParse.zErrMsg); sqlite3DbFree(pErrorDb, sParse.zErrMsg);
sqlite3ParserReset(&sParse); sqlite3ParseObjectReset(&sParse);
if( rc ){ if( rc ){
return 0; return 0;
} }

View file

@ -17,8 +17,8 @@
** property. Usually only a few pages are meet either condition. ** property. Usually only a few pages are meet either condition.
** So the bitmap is usually sparse and has low cardinality. ** So the bitmap is usually sparse and has low cardinality.
** But sometimes (for example when during a DROP of a large table) most ** But sometimes (for example when during a DROP of a large table) most
** or all of the pages in a database can get journalled. In those cases, ** or all of the pages in a database can get journalled. In those cases,
** the bitmap becomes dense with high cardinality. The algorithm needs ** the bitmap becomes dense with high cardinality. The algorithm needs
** to handle both cases well. ** to handle both cases well.
** **
** The size of the bitmap is fixed when the object is created. ** The size of the bitmap is fixed when the object is created.
@ -34,8 +34,7 @@
** start of a transaction, and is thus usually less than a few thousand, ** start of a transaction, and is thus usually less than a few thousand,
** but can be as large as 2 billion for a really big database. ** but can be as large as 2 billion for a really big database.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* Size of the Bitvec structure in bytes. */ /* Size of the Bitvec structure in bytes. */
#define BITVEC_SZ 512 #define BITVEC_SZ 512
@ -354,7 +353,7 @@ int sqlite3BitvecBuiltinTest(int sz, int *aOp){
sqlite3BitvecClear(0, 1, pTmpSpace); sqlite3BitvecClear(0, 1, pTmpSpace);
/* Run the program */ /* Run the program */
pc = 0; pc = i = 0;
while( (op = aOp[pc])!=0 ){ while( (op = aOp[pc])!=0 ){
switch( op ){ switch( op ){
case 1: case 1:

View file

@ -15,9 +15,7 @@
** big and we want to break it down some. This packaged seemed like ** big and we want to break it down some. This packaged seemed like
** a good breakout. ** a good breakout.
*/ */
#include "third_party/sqlite3/btreeInt.inc" #include "third_party/sqlite3/btreeInt.h"
/* clang-format off */
#ifndef SQLITE_OMIT_SHARED_CACHE #ifndef SQLITE_OMIT_SHARED_CACHE
#if SQLITE_THREADSAFE #if SQLITE_THREADSAFE
@ -254,6 +252,7 @@ int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){ int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p; Btree *p;
assert( db!=0 ); assert( db!=0 );
if( db->pVfs==0 && db->nDb==0 ) return 1;
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema); if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0; if( !sqlite3_mutex_held(db->mutex) ) return 0;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,20 @@
/*
** 2001 September 15
**
** 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 header file defines the interface that the sqlite B-Tree file
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
*/
#ifndef SQLITE_BTREE_H #ifndef SQLITE_BTREE_H
#define SQLITE_BTREE_H #define SQLITE_BTREE_H
/* clang-format off */
/* TODO: This definition is just included so other modules compile. It /* TODO: This definition is just included so other modules compile. It
** needs to be revisited. ** needs to be revisited.
@ -109,7 +123,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */
int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, i64*);
int sqlite3BtreeClearTableOfCursor(BtCursor*); int sqlite3BtreeClearTableOfCursor(BtCursor*);
int sqlite3BtreeTripAllCursors(Btree*, int, int); int sqlite3BtreeTripAllCursors(Btree*, int, int);
@ -233,13 +247,17 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...);
#endif #endif
int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMovetoUnpacked( int sqlite3BtreeTableMoveto(
BtCursor*, BtCursor*,
UnpackedRecord *pUnKey,
i64 intKey, i64 intKey,
int bias, int bias,
int *pRes int *pRes
); );
int sqlite3BtreeIndexMoveto(
BtCursor*,
UnpackedRecord *pUnKey,
int *pRes
);
int sqlite3BtreeCursorHasMoved(BtCursor*); int sqlite3BtreeCursorHasMoved(BtCursor*);
int sqlite3BtreeCursorRestore(BtCursor*, int*); int sqlite3BtreeCursorRestore(BtCursor*, int*);
int sqlite3BtreeDelete(BtCursor*, u8 flags); int sqlite3BtreeDelete(BtCursor*, u8 flags);
@ -345,7 +363,7 @@ void sqlite3BtreeCursorList(Btree*);
#endif #endif
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
/* int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); */ int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
#endif #endif
int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64); int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);

View file

@ -29,16 +29,16 @@
** on Ptr(N) and its subpages have values greater than Key(N-1). And ** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth. ** so forth.
** **
** Finding a particular key requires reading O(log(M)) pages from the ** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree. ** disk where M is the number of entries in the tree.
** **
** In this implementation, a single file can hold one or more separate ** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The ** BTrees. Each BTree is identified by the index of its root page. The
** key and data for any entry are combined to form the "payload". A ** key and data for any entry are combined to form the "payload". A
** fixed amount of payload can be carried directly on the database ** fixed amount of payload can be carried directly on the database
** page. If the payload is larger than the preset amount then surplus ** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry ** bytes are stored on overflow pages. The payload for an entry
** and the preceding pointer are combined to form a "Cell". Each ** and the preceding pointer are combined to form a "Cell". Each
** page has a small header which contains the Ptr(N) pointer and other ** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data. ** information such as the size of key and data.
** **
@ -168,7 +168,7 @@
** contiguous or in order, but cell pointers are contiguous and in order. ** contiguous or in order, but cell pointers are contiguous and in order.
** **
** Cell content makes use of variable length integers. A variable ** Cell content makes use of variable length integers. A variable
** length integer is 1 to 9 bytes where the lower 7 bits of each ** length integer is 1 to 9 bytes where the lower 7 bits of each
** byte are used. The integer consists of all bytes that have bit 8 set and ** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer ** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long. ** appears first. A variable-length integer may not be more than 9 bytes long.
@ -213,9 +213,8 @@
** 4 Number of leaf pointers on this page ** 4 Number of leaf pointers on this page
** * zero or more pages numbers of leaves ** * zero or more pages numbers of leaves
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* The following value is the maximum cell size assuming a maximum page /* The following value is the maximum cell size assuming a maximum page
** size give above. ** size give above.
@ -273,7 +272,6 @@ typedef struct CellInfo CellInfo;
*/ */
struct MemPage { struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */ u8 isInit; /* True if previously initialized. MUST BE FIRST! */
u8 bBusy; /* Prevent endless loops on corrupt database files */
u8 intKey; /* True if table b-trees. False for index b-trees */ u8 intKey; /* True if table b-trees. False for index b-trees */
u8 intKeyLeaf; /* True if the leaf of an intKey table */ u8 intKeyLeaf; /* True if the leaf of an intKey table */
Pgno pgno; /* Page number for this page */ Pgno pgno; /* Page number for this page */
@ -295,7 +293,9 @@ struct MemPage {
u8 *apOvfl[4]; /* Pointers to the body of overflow cells */ u8 *apOvfl[4]; /* Pointers to the body of overflow cells */
BtShared *pBt; /* Pointer to BtShared that this page is part of */ BtShared *pBt; /* Pointer to BtShared that this page is part of */
u8 *aData; /* Pointer to disk image of the page data */ u8 *aData; /* Pointer to disk image of the page data */
u8 *aDataEnd; /* One byte past the end of usable data */ u8 *aDataEnd; /* One byte past the end of the entire page - not just
** the usable space, the entire page. Used to prevent
** corruption-induced buffer overflow. */
u8 *aCellIdx; /* The cell index area */ u8 *aCellIdx; /* The cell index area */
u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */
DbPage *pDbPage; /* Pager page handle */ DbPage *pDbPage; /* Pager page handle */
@ -600,7 +600,7 @@ struct BtCursor {
/* /*
** The database page the PENDING_BYTE occupies. This page is never used. ** The database page the PENDING_BYTE occupies. This page is never used.
*/ */
# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) #define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/((pBt)->pageSize))+1))
/* /*
** These macros define the location of the pointer-map entry for a ** These macros define the location of the pointer-map entry for a

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
** 2005 May 23 ** 2005 May 23
** **
** The author disclaims copyright to this source code. In place of ** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing: ** a legal notice, here is a blessing:
@ -13,9 +13,8 @@
** This file contains functions used to access the internal hash tables ** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences. ** of user defined functions and collation sequences.
*/ */
#include "third_party/sqlite3/sqliteInt.inc"
/* clang-format off */ #include "third_party/sqlite3/sqliteInt.h"
/* /*
** Invoke the 'collation needed' callback to request a collation sequence ** Invoke the 'collation needed' callback to request a collation sequence
@ -338,6 +337,7 @@ FuncDef *sqlite3FunctionSearch(
){ ){
FuncDef *p; FuncDef *p;
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
if( sqlite3StrICmp(p->zName, zFunc)==0 ){ if( sqlite3StrICmp(p->zName, zFunc)==0 ){
return p; return p;
} }
@ -358,7 +358,7 @@ void sqlite3InsertBuiltinFuncs(
const char *zName = aDef[i].zName; const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName); int nName = sqlite3Strlen30(zName);
int h = SQLITE_FUNC_HASH(zName[0], nName); int h = SQLITE_FUNC_HASH(zName[0], nName);
assert( zName[0]>='a' && zName[0]<='z' ); assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN );
pOther = sqlite3FunctionSearch(h, zName); pOther = sqlite3FunctionSearch(h, zName);
if( pOther ){ if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] ); assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
@ -490,19 +490,21 @@ void sqlite3SchemaClear(void *p){
Hash temp2; Hash temp2;
HashElem *pElem; HashElem *pElem;
Schema *pSchema = (Schema *)p; Schema *pSchema = (Schema *)p;
sqlite3 xdb;
memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash; temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash; temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash); sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash); sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem)); sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
} }
sqlite3HashClear(&temp2); sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash); sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem); Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(0, pTab); sqlite3DeleteTable(&xdb, pTab);
} }
sqlite3HashClear(&temp1); sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash); sqlite3HashClear(&pSchema->fkeyHash);

View file

@ -16,10 +16,7 @@
** separating it out, the code will be automatically omitted from ** separating it out, the code will be automatically omitted from
** static links that do not use it. ** static links that do not use it.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifndef SQLITE_OMIT_COMPLETE #ifndef SQLITE_OMIT_COMPLETE
/* /*

View file

@ -1,3 +1,11 @@
/* DO NOT EDIT!
** This file is automatically generated by the script in the canonical
** SQLite source tree at tool/mkctimec.tcl.
**
** To modify this header, edit any of the various lists in that script
** which specify categories of generated conditionals in this file.
*/
/* /*
** 2010 February 23 ** 2010 February 23
** **
@ -13,10 +21,17 @@
** This file implements routines used to report what compile-time options ** This file implements routines used to report what compile-time options
** SQLite was built with. ** SQLite was built with.
*/ */
/* clang-format off */
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */
/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
#include "sqlite_cfg.h"
#define SQLITECONFIG_H 1
#endif
/* These macros are provided to "stringify" the value of the define /* These macros are provided to "stringify" the value of the define
** for those options in which the value is meaningful. */ ** for those options in which the value is meaningful. */
#define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL_(opt) #opt
@ -27,6 +42,7 @@
** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */ ** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2 #define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt) #define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
#include "third_party/sqlite3/sqliteInt.h"
/* /*
** An array of names of all compile-time options. This array should ** An array of names of all compile-time options. This array should
@ -38,34 +54,36 @@
*/ */
static const char * const sqlite3azCompileOpt[] = { static const char * const sqlite3azCompileOpt[] = {
/* #ifdef SQLITE_32BIT_ROWID
** BEGIN CODE GENERATED BY tool/mkctime.tcl
*/
#if SQLITE_32BIT_ROWID
"32BIT_ROWID", "32BIT_ROWID",
#endif #endif
#if SQLITE_4_BYTE_ALIGNED_MALLOC #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC", "4_BYTE_ALIGNED_MALLOC",
#endif #endif
#if SQLITE_64BIT_STATS #ifdef SQLITE_64BIT_STATS
"64BIT_STATS", "64BIT_STATS",
#endif #endif
#if SQLITE_ALLOW_COVERING_INDEX_SCAN #ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
"ALLOW_COVERING_INDEX_SCAN", # if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
# endif
#endif #endif
#if SQLITE_ALLOW_URI_AUTHORITY #ifdef SQLITE_ALLOW_URI_AUTHORITY
"ALLOW_URI_AUTHORITY", "ALLOW_URI_AUTHORITY",
#endif #endif
#ifdef SQLITE_ATOMIC_INTRINSICS
"ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS),
#endif
#ifdef SQLITE_BITMASK_TYPE #ifdef SQLITE_BITMASK_TYPE
"BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
#endif #endif
#if SQLITE_BUG_COMPATIBLE_20160819 #ifdef SQLITE_BUG_COMPATIBLE_20160819
"BUG_COMPATIBLE_20160819", "BUG_COMPATIBLE_20160819",
#endif #endif
#if SQLITE_CASE_SENSITIVE_LIKE #ifdef SQLITE_CASE_SENSITIVE_LIKE
"CASE_SENSITIVE_LIKE", "CASE_SENSITIVE_LIKE",
#endif #endif
#if SQLITE_CHECK_PAGES #ifdef SQLITE_CHECK_PAGES
"CHECK_PAGES", "CHECK_PAGES",
#endif #endif
#if defined(__clang__) && defined(__clang_major__) #if defined(__clang__) && defined(__clang_major__)
@ -77,22 +95,22 @@ static const char * const sqlite3azCompileOpt[] = {
#elif defined(__GNUC__) && defined(__VERSION__) #elif defined(__GNUC__) && defined(__VERSION__)
"COMPILER=gcc-" __VERSION__, "COMPILER=gcc-" __VERSION__,
#endif #endif
#if SQLITE_COVERAGE_TEST #ifdef SQLITE_COVERAGE_TEST
"COVERAGE_TEST", "COVERAGE_TEST",
#endif #endif
#if SQLITE_DEBUG #ifdef SQLITE_DEBUG
"DEBUG", "DEBUG",
#endif #endif
#if SQLITE_DEFAULT_AUTOMATIC_INDEX #ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX
"DEFAULT_AUTOMATIC_INDEX", "DEFAULT_AUTOMATIC_INDEX",
#endif #endif
#if SQLITE_DEFAULT_AUTOVACUUM #ifdef SQLITE_DEFAULT_AUTOVACUUM
"DEFAULT_AUTOVACUUM", "DEFAULT_AUTOVACUUM",
#endif #endif
#ifdef SQLITE_DEFAULT_CACHE_SIZE #ifdef SQLITE_DEFAULT_CACHE_SIZE
"DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
#endif #endif
#if SQLITE_DEFAULT_CKPTFULLFSYNC #ifdef SQLITE_DEFAULT_CKPTFULLFSYNC
"DEFAULT_CKPTFULLFSYNC", "DEFAULT_CKPTFULLFSYNC",
#endif #endif
#ifdef SQLITE_DEFAULT_FILE_FORMAT #ifdef SQLITE_DEFAULT_FILE_FORMAT
@ -101,7 +119,7 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS #ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
"DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS), "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
#endif #endif
#if SQLITE_DEFAULT_FOREIGN_KEYS #ifdef SQLITE_DEFAULT_FOREIGN_KEYS
"DEFAULT_FOREIGN_KEYS", "DEFAULT_FOREIGN_KEYS",
#endif #endif
#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT #ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
@ -113,8 +131,10 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DEFAULT_LOOKASIDE #ifdef SQLITE_DEFAULT_LOOKASIDE
"DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE), "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
#endif #endif
#if SQLITE_DEFAULT_MEMSTATUS #ifdef SQLITE_DEFAULT_MEMSTATUS
"DEFAULT_MEMSTATUS", # if SQLITE_DEFAULT_MEMSTATUS != 1
"DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS),
# endif
#endif #endif
#ifdef SQLITE_DEFAULT_MMAP_SIZE #ifdef SQLITE_DEFAULT_MMAP_SIZE
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE), "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
@ -128,7 +148,7 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS #ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
"DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS), "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
#endif #endif
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS #ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS
"DEFAULT_RECURSIVE_TRIGGERS", "DEFAULT_RECURSIVE_TRIGGERS",
#endif #endif
#ifdef SQLITE_DEFAULT_ROWEST #ifdef SQLITE_DEFAULT_ROWEST
@ -149,193 +169,196 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DEFAULT_WORKER_THREADS #ifdef SQLITE_DEFAULT_WORKER_THREADS
"DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS), "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
#endif #endif
#if SQLITE_DIRECT_OVERFLOW_READ #ifdef SQLITE_DIRECT_OVERFLOW_READ
"DIRECT_OVERFLOW_READ", "DIRECT_OVERFLOW_READ",
#endif #endif
#if SQLITE_DISABLE_DIRSYNC #ifdef SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC", "DISABLE_DIRSYNC",
#endif #endif
#if SQLITE_DISABLE_FTS3_UNICODE #ifdef SQLITE_DISABLE_FTS3_UNICODE
"DISABLE_FTS3_UNICODE", "DISABLE_FTS3_UNICODE",
#endif #endif
#if SQLITE_DISABLE_FTS4_DEFERRED #ifdef SQLITE_DISABLE_FTS4_DEFERRED
"DISABLE_FTS4_DEFERRED", "DISABLE_FTS4_DEFERRED",
#endif #endif
#if SQLITE_DISABLE_INTRINSIC #ifdef SQLITE_DISABLE_INTRINSIC
"DISABLE_INTRINSIC", "DISABLE_INTRINSIC",
#endif #endif
#if SQLITE_DISABLE_LFS #ifdef SQLITE_DISABLE_LFS
"DISABLE_LFS", "DISABLE_LFS",
#endif #endif
#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS #ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
"DISABLE_PAGECACHE_OVERFLOW_STATS", "DISABLE_PAGECACHE_OVERFLOW_STATS",
#endif #endif
#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT #ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
"DISABLE_SKIPAHEAD_DISTINCT", "DISABLE_SKIPAHEAD_DISTINCT",
#endif #endif
#ifdef SQLITE_DQS
"DQS=" CTIMEOPT_VAL(SQLITE_DQS),
#endif
#ifdef SQLITE_ENABLE_8_3_NAMES #ifdef SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES), "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif #endif
#if SQLITE_ENABLE_API_ARMOR #ifdef SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR", "ENABLE_API_ARMOR",
#endif #endif
#if SQLITE_ENABLE_ATOMIC_WRITE #ifdef SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE", "ENABLE_ATOMIC_WRITE",
#endif #endif
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
"ENABLE_BATCH_ATOMIC_WRITE", "ENABLE_BATCH_ATOMIC_WRITE",
#endif #endif
#if SQLITE_ENABLE_BYTECODE_VTAB #ifdef SQLITE_ENABLE_BYTECODE_VTAB
"ENABLE_BYTECODE_VTAB", "ENABLE_BYTECODE_VTAB",
#endif #endif
#if SQLITE_ENABLE_CEROD #ifdef SQLITE_ENABLE_CEROD
"ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
#endif #endif
#if SQLITE_ENABLE_COLUMN_METADATA #ifdef SQLITE_ENABLE_COLUMN_METADATA
"ENABLE_COLUMN_METADATA", "ENABLE_COLUMN_METADATA",
#endif #endif
#if SQLITE_ENABLE_COLUMN_USED_MASK #ifdef SQLITE_ENABLE_COLUMN_USED_MASK
"ENABLE_COLUMN_USED_MASK", "ENABLE_COLUMN_USED_MASK",
#endif #endif
#if SQLITE_ENABLE_COSTMULT #ifdef SQLITE_ENABLE_COSTMULT
"ENABLE_COSTMULT", "ENABLE_COSTMULT",
#endif #endif
#if SQLITE_ENABLE_CURSOR_HINTS #ifdef SQLITE_ENABLE_CURSOR_HINTS
"ENABLE_CURSOR_HINTS", "ENABLE_CURSOR_HINTS",
#endif #endif
#if SQLITE_ENABLE_DBSTAT_VTAB #ifdef SQLITE_ENABLE_DBPAGE_VTAB
"ENABLE_DBPAGE_VTAB",
#endif
#ifdef SQLITE_ENABLE_DBSTAT_VTAB
"ENABLE_DBSTAT_VTAB", "ENABLE_DBSTAT_VTAB",
#endif #endif
#if SQLITE_ENABLE_EXPENSIVE_ASSERT #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
"ENABLE_EXPENSIVE_ASSERT", "ENABLE_EXPENSIVE_ASSERT",
#endif #endif
#if SQLITE_ENABLE_FTS1 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
"ENABLE_FTS1", "ENABLE_EXPLAIN_COMMENTS",
#endif #endif
#if SQLITE_ENABLE_FTS2 #ifdef SQLITE_ENABLE_FTS3
"ENABLE_FTS2",
#endif
#if SQLITE_ENABLE_FTS3
"ENABLE_FTS3", "ENABLE_FTS3",
#endif #endif
#if SQLITE_ENABLE_FTS3_PARENTHESIS #ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
"ENABLE_FTS3_PARENTHESIS", "ENABLE_FTS3_PARENTHESIS",
#endif #endif
#if SQLITE_ENABLE_FTS3_TOKENIZER #ifdef SQLITE_ENABLE_FTS3_TOKENIZER
"ENABLE_FTS3_TOKENIZER", "ENABLE_FTS3_TOKENIZER",
#endif #endif
#if SQLITE_ENABLE_FTS4 #ifdef SQLITE_ENABLE_FTS4
"ENABLE_FTS4", "ENABLE_FTS4",
#endif #endif
#if SQLITE_ENABLE_FTS5 #ifdef SQLITE_ENABLE_FTS5
"ENABLE_FTS5", "ENABLE_FTS5",
#endif #endif
#if SQLITE_ENABLE_GEOPOLY #ifdef SQLITE_ENABLE_GEOPOLY
"ENABLE_GEOPOLY", "ENABLE_GEOPOLY",
#endif #endif
#if SQLITE_ENABLE_HIDDEN_COLUMNS #ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
"ENABLE_HIDDEN_COLUMNS", "ENABLE_HIDDEN_COLUMNS",
#endif #endif
#if SQLITE_ENABLE_ICU #ifdef SQLITE_ENABLE_ICU
"ENABLE_ICU", "ENABLE_ICU",
#endif #endif
#if SQLITE_ENABLE_IOTRACE #ifdef SQLITE_ENABLE_IOTRACE
"ENABLE_IOTRACE", "ENABLE_IOTRACE",
#endif #endif
#if SQLITE_ENABLE_JSON1 #ifdef SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_JSON1",
#endif
#if SQLITE_ENABLE_LOAD_EXTENSION
"ENABLE_LOAD_EXTENSION", "ENABLE_LOAD_EXTENSION",
#endif #endif
#ifdef SQLITE_ENABLE_LOCKING_STYLE #ifdef SQLITE_ENABLE_LOCKING_STYLE
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif #endif
#if SQLITE_ENABLE_MATH_FUNCTIONS #ifdef SQLITE_ENABLE_MATH_FUNCTIONS
"ENABLE_MATH_FUNCTIONS", "ENABLE_MATH_FUNCTIONS",
#endif #endif
#if SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
"ENABLE_MEMORY_MANAGEMENT", "ENABLE_MEMORY_MANAGEMENT",
#endif #endif
#if SQLITE_ENABLE_MEMSYS3 #ifdef SQLITE_ENABLE_MEMSYS3
"ENABLE_MEMSYS3", "ENABLE_MEMSYS3",
#endif #endif
#if SQLITE_ENABLE_MEMSYS5 #ifdef SQLITE_ENABLE_MEMSYS5
"ENABLE_MEMSYS5", "ENABLE_MEMSYS5",
#endif #endif
#if SQLITE_ENABLE_MULTIPLEX #ifdef SQLITE_ENABLE_MULTIPLEX
"ENABLE_MULTIPLEX", "ENABLE_MULTIPLEX",
#endif #endif
#if SQLITE_ENABLE_NORMALIZE #ifdef SQLITE_ENABLE_NORMALIZE
"ENABLE_NORMALIZE", "ENABLE_NORMALIZE",
#endif #endif
#if SQLITE_ENABLE_NULL_TRIM #ifdef SQLITE_ENABLE_NULL_TRIM
"ENABLE_NULL_TRIM", "ENABLE_NULL_TRIM",
#endif #endif
#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
"ENABLE_OFFSET_SQL_FUNC",
#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
"ENABLE_OVERSIZE_CELL_CHECK", "ENABLE_OVERSIZE_CELL_CHECK",
#endif #endif
#if SQLITE_ENABLE_PREUPDATE_HOOK #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
"ENABLE_PREUPDATE_HOOK", "ENABLE_PREUPDATE_HOOK",
#endif #endif
#if SQLITE_ENABLE_QPSG #ifdef SQLITE_ENABLE_QPSG
"ENABLE_QPSG", "ENABLE_QPSG",
#endif #endif
#if SQLITE_ENABLE_RBU #ifdef SQLITE_ENABLE_RBU
"ENABLE_RBU", "ENABLE_RBU",
#endif #endif
#if SQLITE_ENABLE_RTREE #ifdef SQLITE_ENABLE_RTREE
"ENABLE_RTREE", "ENABLE_RTREE",
#endif #endif
#if SQLITE_ENABLE_SELECTTRACE #ifdef SQLITE_ENABLE_SESSION
"ENABLE_SELECTTRACE",
#endif
#if SQLITE_ENABLE_SESSION
"ENABLE_SESSION", "ENABLE_SESSION",
#endif #endif
#if SQLITE_ENABLE_SNAPSHOT #ifdef SQLITE_ENABLE_SNAPSHOT
"ENABLE_SNAPSHOT", "ENABLE_SNAPSHOT",
#endif #endif
#if SQLITE_ENABLE_SORTER_REFERENCES #ifdef SQLITE_ENABLE_SORTER_REFERENCES
"ENABLE_SORTER_REFERENCES", "ENABLE_SORTER_REFERENCES",
#endif #endif
#if SQLITE_ENABLE_SQLLOG #ifdef SQLITE_ENABLE_SQLLOG
"ENABLE_SQLLOG", "ENABLE_SQLLOG",
#endif #endif
#if defined(SQLITE_ENABLE_STAT4) #ifdef SQLITE_ENABLE_STAT4
"ENABLE_STAT4", "ENABLE_STAT4",
#endif #endif
#if SQLITE_ENABLE_STMTVTAB #ifdef SQLITE_ENABLE_STMTVTAB
"ENABLE_STMTVTAB", "ENABLE_STMTVTAB",
#endif #endif
#if SQLITE_ENABLE_STMT_SCANSTATUS #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
"ENABLE_STMT_SCANSTATUS", "ENABLE_STMT_SCANSTATUS",
#endif #endif
#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION #ifdef SQLITE_ENABLE_TREETRACE
"ENABLE_TREETRACE",
#endif
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
"ENABLE_UNKNOWN_SQL_FUNCTION", "ENABLE_UNKNOWN_SQL_FUNCTION",
#endif #endif
#if SQLITE_ENABLE_UNLOCK_NOTIFY #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
"ENABLE_UNLOCK_NOTIFY", "ENABLE_UNLOCK_NOTIFY",
#endif #endif
#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
"ENABLE_UPDATE_DELETE_LIMIT", "ENABLE_UPDATE_DELETE_LIMIT",
#endif #endif
#if SQLITE_ENABLE_URI_00_ERROR #ifdef SQLITE_ENABLE_URI_00_ERROR
"ENABLE_URI_00_ERROR", "ENABLE_URI_00_ERROR",
#endif #endif
#if SQLITE_ENABLE_VFSTRACE #ifdef SQLITE_ENABLE_VFSTRACE
"ENABLE_VFSTRACE", "ENABLE_VFSTRACE",
#endif #endif
#if SQLITE_ENABLE_WHERETRACE #ifdef SQLITE_ENABLE_WHERETRACE
"ENABLE_WHERETRACE", "ENABLE_WHERETRACE",
#endif #endif
#if SQLITE_ENABLE_ZIPVFS #ifdef SQLITE_ENABLE_ZIPVFS
"ENABLE_ZIPVFS", "ENABLE_ZIPVFS",
#endif #endif
#if SQLITE_EXPLAIN_ESTIMATED_ROWS #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
"EXPLAIN_ESTIMATED_ROWS", "EXPLAIN_ESTIMATED_ROWS",
#endif #endif
#if SQLITE_EXTRA_IFNULLROW #ifdef SQLITE_EXTRA_IFNULLROW
"EXTRA_IFNULLROW", "EXTRA_IFNULLROW",
#endif #endif
#ifdef SQLITE_EXTRA_INIT #ifdef SQLITE_EXTRA_INIT
@ -347,40 +370,42 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
"FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
#endif #endif
#if SQLITE_FTS5_ENABLE_TEST_MI #ifdef SQLITE_FTS5_ENABLE_TEST_MI
"FTS5_ENABLE_TEST_MI", "FTS5_ENABLE_TEST_MI",
#endif #endif
#if SQLITE_FTS5_NO_WITHOUT_ROWID #ifdef SQLITE_FTS5_NO_WITHOUT_ROWID
"FTS5_NO_WITHOUT_ROWID", "FTS5_NO_WITHOUT_ROWID",
#endif #endif
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN #if HAVE_ISNAN || SQLITE_HAVE_ISNAN
"HAVE_ISNAN", "HAVE_ISNAN",
#endif #endif
#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX #ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
"HOMEGROWN_RECURSIVE_MUTEX", # if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1
"HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX),
# endif
#endif #endif
#if SQLITE_IGNORE_AFP_LOCK_ERRORS #ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
"IGNORE_AFP_LOCK_ERRORS", "IGNORE_AFP_LOCK_ERRORS",
#endif #endif
#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
"IGNORE_FLOCK_LOCK_ERRORS", "IGNORE_FLOCK_LOCK_ERRORS",
#endif #endif
#if SQLITE_INLINE_MEMCPY #ifdef SQLITE_INLINE_MEMCPY
"INLINE_MEMCPY", "INLINE_MEMCPY",
#endif #endif
#if SQLITE_INT64_TYPE #ifdef SQLITE_INT64_TYPE
"INT64_TYPE", "INT64_TYPE",
#endif #endif
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX #ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
#endif #endif
#if SQLITE_LIKE_DOESNT_MATCH_BLOBS #ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS", "LIKE_DOESNT_MATCH_BLOBS",
#endif #endif
#if SQLITE_LOCK_TRACE #ifdef SQLITE_LOCK_TRACE
"LOCK_TRACE", "LOCK_TRACE",
#endif #endif
#if SQLITE_LOG_CACHE_SPILL #ifdef SQLITE_LOG_CACHE_SPILL
"LOG_CACHE_SPILL", "LOG_CACHE_SPILL",
#endif #endif
#ifdef SQLITE_MALLOC_SOFT_LIMIT #ifdef SQLITE_MALLOC_SOFT_LIMIT
@ -443,250 +468,254 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_MAX_WORKER_THREADS #ifdef SQLITE_MAX_WORKER_THREADS
"MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS), "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
#endif #endif
#if SQLITE_MEMDEBUG #ifdef SQLITE_MEMDEBUG
"MEMDEBUG", "MEMDEBUG",
#endif #endif
#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
"MIXED_ENDIAN_64BIT_FLOAT", "MIXED_ENDIAN_64BIT_FLOAT",
#endif #endif
#if SQLITE_MMAP_READWRITE #ifdef SQLITE_MMAP_READWRITE
"MMAP_READWRITE", "MMAP_READWRITE",
#endif #endif
#if SQLITE_MUTEX_NOOP #ifdef SQLITE_MUTEX_NOOP
"MUTEX_NOOP", "MUTEX_NOOP",
#endif #endif
#if SQLITE_MUTEX_NREF #ifdef SQLITE_MUTEX_OMIT
"MUTEX_NREF",
#endif
#if SQLITE_MUTEX_OMIT
"MUTEX_OMIT", "MUTEX_OMIT",
#endif #endif
#if SQLITE_MUTEX_PTHREADS #ifdef SQLITE_MUTEX_PTHREADS
"MUTEX_PTHREADS", "MUTEX_PTHREADS",
#endif #endif
#if SQLITE_MUTEX_W32 #ifdef SQLITE_MUTEX_W32
"MUTEX_W32", "MUTEX_W32",
#endif #endif
#if SQLITE_NEED_ERR_NAME #ifdef SQLITE_NEED_ERR_NAME
"NEED_ERR_NAME", "NEED_ERR_NAME",
#endif #endif
#if SQLITE_NOINLINE #ifdef SQLITE_NO_SYNC
"NOINLINE",
#endif
#if SQLITE_NO_SYNC
"NO_SYNC", "NO_SYNC",
#endif #endif
#if SQLITE_OMIT_ALTERTABLE #ifdef SQLITE_OMIT_ALTERTABLE
"OMIT_ALTERTABLE", "OMIT_ALTERTABLE",
#endif #endif
#if SQLITE_OMIT_ANALYZE #ifdef SQLITE_OMIT_ANALYZE
"OMIT_ANALYZE", "OMIT_ANALYZE",
#endif #endif
#if SQLITE_OMIT_ATTACH #ifdef SQLITE_OMIT_ATTACH
"OMIT_ATTACH", "OMIT_ATTACH",
#endif #endif
#if SQLITE_OMIT_AUTHORIZATION #ifdef SQLITE_OMIT_AUTHORIZATION
"OMIT_AUTHORIZATION", "OMIT_AUTHORIZATION",
#endif #endif
#if SQLITE_OMIT_AUTOINCREMENT #ifdef SQLITE_OMIT_AUTOINCREMENT
"OMIT_AUTOINCREMENT", "OMIT_AUTOINCREMENT",
#endif #endif
#if SQLITE_OMIT_AUTOINIT #ifdef SQLITE_OMIT_AUTOINIT
"OMIT_AUTOINIT", "OMIT_AUTOINIT",
#endif #endif
#if SQLITE_OMIT_AUTOMATIC_INDEX #ifdef SQLITE_OMIT_AUTOMATIC_INDEX
"OMIT_AUTOMATIC_INDEX", "OMIT_AUTOMATIC_INDEX",
#endif #endif
#if SQLITE_OMIT_AUTORESET #ifdef SQLITE_OMIT_AUTORESET
"OMIT_AUTORESET", "OMIT_AUTORESET",
#endif #endif
#if SQLITE_OMIT_AUTOVACUUM #ifdef SQLITE_OMIT_AUTOVACUUM
"OMIT_AUTOVACUUM", "OMIT_AUTOVACUUM",
#endif #endif
#if SQLITE_OMIT_BETWEEN_OPTIMIZATION #ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
"OMIT_BETWEEN_OPTIMIZATION", "OMIT_BETWEEN_OPTIMIZATION",
#endif #endif
#if SQLITE_OMIT_BLOB_LITERAL #ifdef SQLITE_OMIT_BLOB_LITERAL
"OMIT_BLOB_LITERAL", "OMIT_BLOB_LITERAL",
#endif #endif
#if SQLITE_OMIT_CAST #ifdef SQLITE_OMIT_CAST
"OMIT_CAST", "OMIT_CAST",
#endif #endif
#if SQLITE_OMIT_CHECK #ifdef SQLITE_OMIT_CHECK
"OMIT_CHECK", "OMIT_CHECK",
#endif #endif
#if SQLITE_OMIT_COMPLETE #ifdef SQLITE_OMIT_COMPLETE
"OMIT_COMPLETE", "OMIT_COMPLETE",
#endif #endif
#if SQLITE_OMIT_COMPOUND_SELECT #ifdef SQLITE_OMIT_COMPOUND_SELECT
"OMIT_COMPOUND_SELECT", "OMIT_COMPOUND_SELECT",
#endif #endif
#if SQLITE_OMIT_CONFLICT_CLAUSE #ifdef SQLITE_OMIT_CONFLICT_CLAUSE
"OMIT_CONFLICT_CLAUSE", "OMIT_CONFLICT_CLAUSE",
#endif #endif
#if SQLITE_OMIT_CTE #ifdef SQLITE_OMIT_CTE
"OMIT_CTE", "OMIT_CTE",
#endif #endif
#if SQLITE_OMIT_DATETIME_FUNCS #if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT)
"OMIT_DATETIME_FUNCS", "OMIT_DATETIME_FUNCS",
#endif #endif
#if SQLITE_OMIT_DECLTYPE #ifdef SQLITE_OMIT_DECLTYPE
"OMIT_DECLTYPE", "OMIT_DECLTYPE",
#endif #endif
#if SQLITE_OMIT_DEPRECATED #ifdef SQLITE_OMIT_DEPRECATED
"OMIT_DEPRECATED", "OMIT_DEPRECATED",
#endif #endif
#if SQLITE_OMIT_DISKIO #ifdef SQLITE_OMIT_DESERIALIZE
"OMIT_DESERIALIZE",
#endif
#ifdef SQLITE_OMIT_DISKIO
"OMIT_DISKIO", "OMIT_DISKIO",
#endif #endif
#if SQLITE_OMIT_EXPLAIN #ifdef SQLITE_OMIT_EXPLAIN
"OMIT_EXPLAIN", "OMIT_EXPLAIN",
#endif #endif
#if SQLITE_OMIT_FLAG_PRAGMAS #ifdef SQLITE_OMIT_FLAG_PRAGMAS
"OMIT_FLAG_PRAGMAS", "OMIT_FLAG_PRAGMAS",
#endif #endif
#if SQLITE_OMIT_FLOATING_POINT #ifdef SQLITE_OMIT_FLOATING_POINT
"OMIT_FLOATING_POINT", "OMIT_FLOATING_POINT",
#endif #endif
#if SQLITE_OMIT_FOREIGN_KEY #ifdef SQLITE_OMIT_FOREIGN_KEY
"OMIT_FOREIGN_KEY", "OMIT_FOREIGN_KEY",
#endif #endif
#if SQLITE_OMIT_GET_TABLE #ifdef SQLITE_OMIT_GET_TABLE
"OMIT_GET_TABLE", "OMIT_GET_TABLE",
#endif #endif
#if SQLITE_OMIT_HEX_INTEGER #ifdef SQLITE_OMIT_HEX_INTEGER
"OMIT_HEX_INTEGER", "OMIT_HEX_INTEGER",
#endif #endif
#if SQLITE_OMIT_INCRBLOB #ifdef SQLITE_OMIT_INCRBLOB
"OMIT_INCRBLOB", "OMIT_INCRBLOB",
#endif #endif
#if SQLITE_OMIT_INTEGRITY_CHECK #ifdef SQLITE_OMIT_INTEGRITY_CHECK
"OMIT_INTEGRITY_CHECK", "OMIT_INTEGRITY_CHECK",
#endif #endif
#if SQLITE_OMIT_LIKE_OPTIMIZATION #ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS
"OMIT_INTROSPECTION_PRAGMAS",
#endif
#ifdef SQLITE_OMIT_JSON
"OMIT_JSON",
#endif
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
"OMIT_LIKE_OPTIMIZATION", "OMIT_LIKE_OPTIMIZATION",
#endif #endif
#if SQLITE_OMIT_LOAD_EXTENSION #ifdef SQLITE_OMIT_LOAD_EXTENSION
"OMIT_LOAD_EXTENSION", "OMIT_LOAD_EXTENSION",
#endif #endif
#if SQLITE_OMIT_LOCALTIME #ifdef SQLITE_OMIT_LOCALTIME
"OMIT_LOCALTIME", "OMIT_LOCALTIME",
#endif #endif
#if SQLITE_OMIT_LOOKASIDE #ifdef SQLITE_OMIT_LOOKASIDE
"OMIT_LOOKASIDE", "OMIT_LOOKASIDE",
#endif #endif
#if SQLITE_OMIT_MEMORYDB #ifdef SQLITE_OMIT_MEMORYDB
"OMIT_MEMORYDB", "OMIT_MEMORYDB",
#endif #endif
#if SQLITE_OMIT_OR_OPTIMIZATION #ifdef SQLITE_OMIT_OR_OPTIMIZATION
"OMIT_OR_OPTIMIZATION", "OMIT_OR_OPTIMIZATION",
#endif #endif
#if SQLITE_OMIT_PAGER_PRAGMAS #ifdef SQLITE_OMIT_PAGER_PRAGMAS
"OMIT_PAGER_PRAGMAS", "OMIT_PAGER_PRAGMAS",
#endif #endif
#if SQLITE_OMIT_PARSER_TRACE #ifdef SQLITE_OMIT_PARSER_TRACE
"OMIT_PARSER_TRACE", "OMIT_PARSER_TRACE",
#endif #endif
#if SQLITE_OMIT_POPEN #ifdef SQLITE_OMIT_POPEN
"OMIT_POPEN", "OMIT_POPEN",
#endif #endif
#if SQLITE_OMIT_PRAGMA #ifdef SQLITE_OMIT_PRAGMA
"OMIT_PRAGMA", "OMIT_PRAGMA",
#endif #endif
#if SQLITE_OMIT_PROGRESS_CALLBACK #ifdef SQLITE_OMIT_PROGRESS_CALLBACK
"OMIT_PROGRESS_CALLBACK", "OMIT_PROGRESS_CALLBACK",
#endif #endif
#if SQLITE_OMIT_QUICKBALANCE #ifdef SQLITE_OMIT_QUICKBALANCE
"OMIT_QUICKBALANCE", "OMIT_QUICKBALANCE",
#endif #endif
#if SQLITE_OMIT_REINDEX #ifdef SQLITE_OMIT_REINDEX
"OMIT_REINDEX", "OMIT_REINDEX",
#endif #endif
#if SQLITE_OMIT_SCHEMA_PRAGMAS #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
"OMIT_SCHEMA_PRAGMAS", "OMIT_SCHEMA_PRAGMAS",
#endif #endif
#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS", "OMIT_SCHEMA_VERSION_PRAGMAS",
#endif #endif
#if SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE", "OMIT_SHARED_CACHE",
#endif #endif
#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES #ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES
"OMIT_SHUTDOWN_DIRECTORIES", "OMIT_SHUTDOWN_DIRECTORIES",
#endif #endif
#if SQLITE_OMIT_SUBQUERY #ifdef SQLITE_OMIT_SUBQUERY
"OMIT_SUBQUERY", "OMIT_SUBQUERY",
#endif #endif
#if SQLITE_OMIT_TCL_VARIABLE #ifdef SQLITE_OMIT_TCL_VARIABLE
"OMIT_TCL_VARIABLE", "OMIT_TCL_VARIABLE",
#endif #endif
#if SQLITE_OMIT_TEMPDB #ifdef SQLITE_OMIT_TEMPDB
"OMIT_TEMPDB", "OMIT_TEMPDB",
#endif #endif
#if SQLITE_OMIT_TEST_CONTROL #ifdef SQLITE_OMIT_TEST_CONTROL
"OMIT_TEST_CONTROL", "OMIT_TEST_CONTROL",
#endif #endif
#if SQLITE_OMIT_TRACE #ifdef SQLITE_OMIT_TRACE
"OMIT_TRACE", # if SQLITE_OMIT_TRACE != 1
"OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE),
# endif
#endif #endif
#if SQLITE_OMIT_TRIGGER #ifdef SQLITE_OMIT_TRIGGER
"OMIT_TRIGGER", "OMIT_TRIGGER",
#endif #endif
#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
"OMIT_TRUNCATE_OPTIMIZATION", "OMIT_TRUNCATE_OPTIMIZATION",
#endif #endif
#if SQLITE_OMIT_UTF16 #ifdef SQLITE_OMIT_UTF16
"OMIT_UTF16", "OMIT_UTF16",
#endif #endif
#if SQLITE_OMIT_VACUUM #ifdef SQLITE_OMIT_VACUUM
"OMIT_VACUUM", "OMIT_VACUUM",
#endif #endif
#if SQLITE_OMIT_VIEW #ifdef SQLITE_OMIT_VIEW
"OMIT_VIEW", "OMIT_VIEW",
#endif #endif
#if SQLITE_OMIT_VIRTUALTABLE #ifdef SQLITE_OMIT_VIRTUALTABLE
"OMIT_VIRTUALTABLE", "OMIT_VIRTUALTABLE",
#endif #endif
#if SQLITE_OMIT_WAL #ifdef SQLITE_OMIT_WAL
"OMIT_WAL", "OMIT_WAL",
#endif #endif
#if SQLITE_OMIT_WSD #ifdef SQLITE_OMIT_WSD
"OMIT_WSD", "OMIT_WSD",
#endif #endif
#if SQLITE_OMIT_XFER_OPT #ifdef SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT", "OMIT_XFER_OPT",
#endif #endif
#if SQLITE_PCACHE_SEPARATE_HEADER #ifdef SQLITE_PERFORMANCE_TRACE
"PCACHE_SEPARATE_HEADER",
#endif
#if SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE", "PERFORMANCE_TRACE",
#endif #endif
#if SQLITE_POWERSAFE_OVERWRITE #ifdef SQLITE_POWERSAFE_OVERWRITE
"POWERSAFE_OVERWRITE", # if SQLITE_POWERSAFE_OVERWRITE != 1
"POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE),
# endif
#endif #endif
#if SQLITE_PREFER_PROXY_LOCKING #ifdef SQLITE_PREFER_PROXY_LOCKING
"PREFER_PROXY_LOCKING", "PREFER_PROXY_LOCKING",
#endif #endif
#if SQLITE_PROXY_DEBUG #ifdef SQLITE_PROXY_DEBUG
"PROXY_DEBUG", "PROXY_DEBUG",
#endif #endif
#if SQLITE_REVERSE_UNORDERED_SELECTS #ifdef SQLITE_REVERSE_UNORDERED_SELECTS
"REVERSE_UNORDERED_SELECTS", "REVERSE_UNORDERED_SELECTS",
#endif #endif
#if SQLITE_RTREE_INT_ONLY #ifdef SQLITE_RTREE_INT_ONLY
"RTREE_INT_ONLY", "RTREE_INT_ONLY",
#endif #endif
#if SQLITE_SECURE_DELETE #ifdef SQLITE_SECURE_DELETE
"SECURE_DELETE", "SECURE_DELETE",
#endif #endif
#if SQLITE_SMALL_STACK #ifdef SQLITE_SMALL_STACK
"SMALL_STACK", "SMALL_STACK",
#endif #endif
#ifdef SQLITE_SORTER_PMASZ #ifdef SQLITE_SORTER_PMASZ
"SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
#endif #endif
#if SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
"SOUNDEX", "SOUNDEX",
#endif #endif
#ifdef SQLITE_STAT4_SAMPLES #ifdef SQLITE_STAT4_SAMPLES
@ -695,19 +724,22 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_STMTJRNL_SPILL #ifdef SQLITE_STMTJRNL_SPILL
"STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
#endif #endif
#if SQLITE_SUBSTR_COMPATIBILITY #ifdef SQLITE_SUBSTR_COMPATIBILITY
"SUBSTR_COMPATIBILITY", "SUBSTR_COMPATIBILITY",
#endif #endif
#if SQLITE_SYSTEM_MALLOC #if (!defined(SQLITE_WIN32_MALLOC) \
&& !defined(SQLITE_ZERO_MALLOC) \
&& !defined(SQLITE_MEMDEBUG) \
) || defined(SQLITE_SYSTEM_MALLOC)
"SYSTEM_MALLOC", "SYSTEM_MALLOC",
#endif #endif
#if SQLITE_TCL #ifdef SQLITE_TCL
"TCL", "TCL",
#endif #endif
#ifdef SQLITE_TEMP_STORE #ifdef SQLITE_TEMP_STORE
"TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif #endif
#if SQLITE_TEST #ifdef SQLITE_TEST
"TEST", "TEST",
#endif #endif
#if defined(SQLITE_THREADSAFE) #if defined(SQLITE_THREADSAFE)
@ -717,37 +749,35 @@ static const char * const sqlite3azCompileOpt[] = {
#else #else
"THREADSAFE=1", "THREADSAFE=1",
#endif #endif
#if SQLITE_UNLINK_AFTER_CLOSE #ifdef SQLITE_UNLINK_AFTER_CLOSE
"UNLINK_AFTER_CLOSE", "UNLINK_AFTER_CLOSE",
#endif #endif
#if SQLITE_UNTESTABLE #ifdef SQLITE_UNTESTABLE
"UNTESTABLE", "UNTESTABLE",
#endif #endif
#if SQLITE_USER_AUTHENTICATION #ifdef SQLITE_USER_AUTHENTICATION
"USER_AUTHENTICATION", "USER_AUTHENTICATION",
#endif #endif
#if SQLITE_USE_ALLOCA #ifdef SQLITE_USE_ALLOCA
"USE_ALLOCA", "USE_ALLOCA",
#endif #endif
#if SQLITE_USE_FCNTL_TRACE #ifdef SQLITE_USE_FCNTL_TRACE
"USE_FCNTL_TRACE", "USE_FCNTL_TRACE",
#endif #endif
#if SQLITE_USE_URI #ifdef SQLITE_USE_URI
"USE_URI", "USE_URI",
#endif #endif
#if SQLITE_VDBE_COVERAGE #ifdef SQLITE_VDBE_COVERAGE
"VDBE_COVERAGE", "VDBE_COVERAGE",
#endif #endif
#if SQLITE_WIN32_MALLOC #ifdef SQLITE_WIN32_MALLOC
"WIN32_MALLOC", "WIN32_MALLOC",
#endif #endif
#if SQLITE_ZERO_MALLOC #ifdef SQLITE_ZERO_MALLOC
"ZERO_MALLOC", "ZERO_MALLOC",
#endif #endif
/*
** END CODE GENERATED BY tool/mkctime.tcl } ;
*/
};
const char **sqlite3CompileOptions(int *pnOpt){ const char **sqlite3CompileOptions(int *pnOpt){
*pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]); *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);

View file

@ -10,7 +10,7 @@
** **
************************************************************************* *************************************************************************
** This file contains the C functions that implement date and time ** This file contains the C functions that implement date and time
** functions for SQLite. ** functions for SQLite.
** **
** There is only one exported symbol in this file - the function ** There is only one exported symbol in this file - the function
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
@ -19,7 +19,7 @@
** SQLite processes all times and dates as julian day numbers. The ** SQLite processes all times and dates as julian day numbers. The
** dates and times are stored as the number of days since noon ** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian ** in Greenwich on November 24, 4714 B.C. according to the Gregorian
** calendar system. ** calendar system.
** **
** 1970-01-01 00:00:00 is JD 2440587.5 ** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5 ** 2000-01-01 00:00:00 is JD 2451544.5
@ -48,9 +48,7 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/time/struct/tm.h" #include "libc/time/struct/tm.h"
#include "libc/time/time.h" #include "libc/time/time.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifndef SQLITE_OMIT_DATETIME_FUNCS #ifndef SQLITE_OMIT_DATETIME_FUNCS
@ -280,7 +278,7 @@ static void computeJD(DateTime *p){
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1; p->validJD = 1;
if( p->validHMS ){ if( p->validHMS ){
p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000); p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
if( p->validTZ ){ if( p->validTZ ){
p->iJD -= p->tz*60000; p->iJD -= p->tz*60000;
p->validYMD = 0; p->validYMD = 0;
@ -507,8 +505,10 @@ static void clearYMD_HMS_TZ(DateTime *p){
** is available. This routine returns 0 on success and ** is available. This routine returns 0 on success and
** non-zero on any kind of error. ** non-zero on any kind of error.
** **
** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this ** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this
** routine will always fail. ** routine will always fail. If bLocaltimeFault is nonzero and
** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is
** invoked in place of the OS-defined localtime() function.
** **
** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
** library function localtime_r() is used to assist in the calculation of ** library function localtime_r() is used to assist in the calculation of
@ -524,14 +524,30 @@ static int osLocaltime(time_t *t, struct tm *pTm){
sqlite3_mutex_enter(mutex); sqlite3_mutex_enter(mutex);
pX = localtime(t); pX = localtime(t);
#ifndef SQLITE_UNTESTABLE #ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; if( sqlite3GlobalConfig.bLocaltimeFault ){
if( sqlite3GlobalConfig.xAltLocaltime!=0
&& 0==sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm)
){
pX = pTm;
}else{
pX = 0;
}
}
#endif #endif
if( pX ) *pTm = *pX; if( pX ) *pTm = *pX;
#if SQLITE_THREADSAFE>0
sqlite3_mutex_leave(mutex); sqlite3_mutex_leave(mutex);
#endif
rc = pX==0; rc = pX==0;
#else #else
#ifndef SQLITE_UNTESTABLE #ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; if( sqlite3GlobalConfig.bLocaltimeFault ){
if( sqlite3GlobalConfig.xAltLocaltime!=0 ){
return sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm);
}else{
return 1;
}
}
#endif #endif
#if HAVE_LOCALTIME_R #if HAVE_LOCALTIME_R
rc = localtime_r(t, pTm)==0; rc = localtime_r(t, pTm)==0;
@ -546,67 +562,56 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#ifndef SQLITE_OMIT_LOCALTIME #ifndef SQLITE_OMIT_LOCALTIME
/* /*
** Compute the difference (in milliseconds) between localtime and UTC ** Assuming the input DateTime is UTC, move it to its localtime equivalent.
** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
** return this value and set *pRc to SQLITE_OK.
**
** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
** is undefined in this case.
*/ */
static sqlite3_int64 localtimeOffset( static int toLocaltime(
DateTime *p, /* Date at which to calculate offset */ DateTime *p, /* Date at which to calculate offset */
sqlite3_context *pCtx, /* Write error here if one occurs */ sqlite3_context *pCtx /* Write error here if one occurs */
int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
){ ){
DateTime x, y;
time_t t; time_t t;
struct tm sLocal; struct tm sLocal;
int iYearDiff;
/* Initialize the contents of sLocal to avoid a compiler warning. */ /* Initialize the contents of sLocal to avoid a compiler warning. */
memset(&sLocal, 0, sizeof(sLocal)); memset(&sLocal, 0, sizeof(sLocal));
x = *p; computeJD(p);
computeYMD_HMS(&x); if( p->iJD<2108667600*(i64)100000 /* 1970-01-01 */
if( x.Y<1971 || x.Y>=2038 ){ || p->iJD>2130141456*(i64)100000 /* 2038-01-18 */
){
/* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only
** works for years between 1970 and 2037. For dates outside this range, ** works for years between 1970 and 2037. For dates outside this range,
** SQLite attempts to map the year into an equivalent year within this ** SQLite attempts to map the year into an equivalent year within this
** range, do the calculation, then map the year back. ** range, do the calculation, then map the year back.
*/ */
x.Y = 2000; DateTime x = *p;
x.M = 1; computeYMD_HMS(&x);
x.D = 1; iYearDiff = (2000 + x.Y%4) - x.Y;
x.h = 0; x.Y += iYearDiff;
x.m = 0; x.validJD = 0;
x.s = 0.0; computeJD(&x);
} else { t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
int s = (int)(x.s + 0.5); }else{
x.s = s; iYearDiff = 0;
t = (time_t)(p->iJD/1000 - 21086676*(i64)10000);
} }
x.tz = 0;
x.validJD = 0;
computeJD(&x);
t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
if( osLocaltime(&t, &sLocal) ){ if( osLocaltime(&t, &sLocal) ){
sqlite3_result_error(pCtx, "local time unavailable", -1); sqlite3_result_error(pCtx, "local time unavailable", -1);
*pRc = SQLITE_ERROR; return SQLITE_ERROR;
return 0;
} }
y.Y = sLocal.tm_year + 1900; p->Y = sLocal.tm_year + 1900 - iYearDiff;
y.M = sLocal.tm_mon + 1; p->M = sLocal.tm_mon + 1;
y.D = sLocal.tm_mday; p->D = sLocal.tm_mday;
y.h = sLocal.tm_hour; p->h = sLocal.tm_hour;
y.m = sLocal.tm_min; p->m = sLocal.tm_min;
y.s = sLocal.tm_sec; p->s = sLocal.tm_sec + (p->iJD%1000)*0.001;
y.validYMD = 1; p->validYMD = 1;
y.validHMS = 1; p->validHMS = 1;
y.validJD = 0; p->validJD = 0;
y.rawS = 0; p->rawS = 0;
y.validTZ = 0; p->validTZ = 0;
y.isError = 0; p->isError = 0;
computeJD(&y); return SQLITE_OK;
*pRc = SQLITE_OK;
return y.iJD - x.iJD;
} }
#endif /* SQLITE_OMIT_LOCALTIME */ #endif /* SQLITE_OMIT_LOCALTIME */
@ -619,18 +624,17 @@ static sqlite3_int64 localtimeOffset(
** of several units of time. ** of several units of time.
*/ */
static const struct { static const struct {
u8 eType; /* Transformation type code */ u8 nName; /* Length of the name */
u8 nName; /* Length of th name */ char zName[7]; /* Name of the transformation */
char *zName; /* Name of the transformation */ float rLimit; /* Maximum NNN value for this transform */
double rLimit; /* Maximum NNN value for this transform */ float rXform; /* Constant used for this transform */
double rXform; /* Constant used for this transform */
} aXformType[] = { } aXformType[] = {
{ 0, 6, "second", 464269060800.0, 1000.0 }, { 6, "second", 4.6427e+14, 1.0 },
{ 0, 6, "minute", 7737817680.0, 60000.0 }, { 6, "minute", 7.7379e+12, 60.0 },
{ 0, 4, "hour", 128963628.0, 3600000.0 }, { 4, "hour", 1.2897e+11, 3600.0 },
{ 0, 3, "day", 5373485.0, 86400000.0 }, { 3, "day", 5373485.0, 86400.0 },
{ 1, 5, "month", 176546.0, 2592000000.0 }, { 5, "month", 176546.0, 2592000.0 },
{ 2, 4, "year", 14713.0, 31536000000.0 }, { 4, "year", 14713.0, 31536000.0 },
}; };
/* /*
@ -661,11 +665,55 @@ static int parseModifier(
sqlite3_context *pCtx, /* Function context */ sqlite3_context *pCtx, /* Function context */
const char *z, /* The text of the modifier */ const char *z, /* The text of the modifier */
int n, /* Length of zMod in bytes */ int n, /* Length of zMod in bytes */
DateTime *p /* The date/time value to be modified */ DateTime *p, /* The date/time value to be modified */
int idx /* Parameter index of the modifier */
){ ){
int rc = 1; int rc = 1;
double r; double r;
switch(sqlite3UpperToLower[(u8)z[0]] ){ switch(sqlite3UpperToLower[(u8)z[0]] ){
case 'a': {
/*
** auto
**
** If rawS is available, then interpret as a julian day number, or
** a unix timestamp, depending on its magnitude.
*/
if( sqlite3_stricmp(z, "auto")==0 ){
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
if( !p->rawS || p->validJD ){
rc = 0;
p->rawS = 0;
}else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
&& p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
){
r = p->s*1000.0 + 210866760000000.0;
clearYMD_HMS_TZ(p);
p->iJD = (sqlite3_int64)(r + 0.5);
p->validJD = 1;
p->rawS = 0;
rc = 0;
}
}
break;
}
case 'j': {
/*
** julianday
**
** Always interpret the prior number as a julian-day value. If this
** is not the first modifier, or if the prior argument is not a numeric
** value in the allowed range of julian day numbers understood by
** SQLite (0..5373484.5) then the result will be NULL.
*/
if( sqlite3_stricmp(z, "julianday")==0 ){
if( idx>1 ) return 1; /* IMP: R-31176-64601 */
if( p->validJD && p->rawS ){
rc = 0;
p->rawS = 0;
}
}
break;
}
#ifndef SQLITE_OMIT_LOCALTIME #ifndef SQLITE_OMIT_LOCALTIME
case 'l': { case 'l': {
/* localtime /* localtime
@ -674,9 +722,7 @@ static int parseModifier(
** show local time. ** show local time.
*/ */
if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
computeJD(p); rc = toLocaltime(p, pCtx);
p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p);
} }
break; break;
} }
@ -689,6 +735,7 @@ static int parseModifier(
** seconds since 1970. Convert to a real julian day number. ** seconds since 1970. Convert to a real julian day number.
*/ */
if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
if( idx>1 ) return 1; /* IMP: R-49255-55373 */
r = p->s*1000.0 + 210866760000000.0; r = p->s*1000.0 + 210866760000000.0;
if( r>=0.0 && r<464269060800000.0 ){ if( r>=0.0 && r<464269060800000.0 ){
clearYMD_HMS_TZ(p); clearYMD_HMS_TZ(p);
@ -701,18 +748,31 @@ static int parseModifier(
#ifndef SQLITE_OMIT_LOCALTIME #ifndef SQLITE_OMIT_LOCALTIME
else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
if( p->tzSet==0 ){ if( p->tzSet==0 ){
sqlite3_int64 c1; i64 iOrigJD; /* Original localtime */
i64 iGuess; /* Guess at the corresponding utc time */
int cnt = 0; /* Safety to prevent infinite loop */
int iErr; /* Guess is off by this much */
computeJD(p); computeJD(p);
c1 = localtimeOffset(p, pCtx, &rc); iGuess = iOrigJD = p->iJD;
if( rc==SQLITE_OK ){ iErr = 0;
p->iJD -= c1; do{
clearYMD_HMS_TZ(p); DateTime new;
p->iJD += c1 - localtimeOffset(p, pCtx, &rc); memset(&new, 0, sizeof(new));
} iGuess -= iErr;
new.iJD = iGuess;
new.validJD = 1;
rc = toLocaltime(&new, pCtx);
if( rc ) return rc;
computeJD(&new);
iErr = new.iJD - iOrigJD;
}while( iErr && cnt++<3 );
memset(p, 0, sizeof(*p));
p->iJD = iGuess;
p->validJD = 1;
p->tzSet = 1; p->tzSet = 1;
}else{
rc = SQLITE_OK;
} }
rc = SQLITE_OK;
} }
#endif #endif
break; break;
@ -727,7 +787,7 @@ static int parseModifier(
*/ */
if( sqlite3_strnicmp(z, "weekday ", 8)==0 if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
&& (n=(int)r)==r && n>=0 && r<7 ){ && r>=0.0 && r<7.0 && (n=(int)r)==r ){
sqlite3_int64 Z; sqlite3_int64 Z;
computeYMD_HMS(p); computeYMD_HMS(p);
p->validTZ = 0; p->validTZ = 0;
@ -828,9 +888,10 @@ static int parseModifier(
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0 && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
&& r>-aXformType[i].rLimit && r<aXformType[i].rLimit && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
){ ){
switch( aXformType[i].eType ){ switch( i ){
case 1: { /* Special processing to add months */ case 4: { /* Special processing to add months */
int x; int x;
assert( strcmp(aXformType[i].zName,"month")==0 );
computeYMD_HMS(p); computeYMD_HMS(p);
p->M += (int)r; p->M += (int)r;
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
@ -840,8 +901,9 @@ static int parseModifier(
r -= (int)r; r -= (int)r;
break; break;
} }
case 2: { /* Special processing to add years */ case 5: { /* Special processing to add years */
int y = (int)r; int y = (int)r;
assert( strcmp(aXformType[i].zName,"year")==0 );
computeYMD_HMS(p); computeYMD_HMS(p);
p->Y += y; p->Y += y;
p->validJD = 0; p->validJD = 0;
@ -850,7 +912,7 @@ static int parseModifier(
} }
} }
computeJD(p); computeJD(p);
p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder);
rc = 0; rc = 0;
break; break;
} }
@ -900,7 +962,7 @@ static int isDate(
for(i=1; i<argc; i++){ for(i=1; i<argc; i++){
z = sqlite3_value_text(argv[i]); z = sqlite3_value_text(argv[i]);
n = sqlite3_value_bytes(argv[i]); n = sqlite3_value_bytes(argv[i]);
if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1; if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1;
} }
computeJD(p); computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1; if( p->isError || !validJulianDay(p->iJD) ) return 1;
@ -930,6 +992,24 @@ static void juliandayFunc(
} }
} }
/*
** unixepoch( TIMESTRING, MOD, MOD, ...)
**
** Return the number of seconds (including fractional seconds) since
** the unix epoch of 1970-01-01 00:00:00 GMT.
*/
static void unixepochFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
}
}
/* /*
** datetime( TIMESTRING, MOD, MOD, ...) ** datetime( TIMESTRING, MOD, MOD, ...)
** **
@ -942,11 +1022,38 @@ static void datetimeFunc(
){ ){
DateTime x; DateTime x;
if( isDate(context, argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; int Y, s;
char zBuf[24];
computeYMD_HMS(&x); computeYMD_HMS(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", Y = x.Y;
x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); if( Y<0 ) Y = -Y;
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); zBuf[1] = '0' + (Y/1000)%10;
zBuf[2] = '0' + (Y/100)%10;
zBuf[3] = '0' + (Y/10)%10;
zBuf[4] = '0' + (Y)%10;
zBuf[5] = '-';
zBuf[6] = '0' + (x.M/10)%10;
zBuf[7] = '0' + (x.M)%10;
zBuf[8] = '-';
zBuf[9] = '0' + (x.D/10)%10;
zBuf[10] = '0' + (x.D)%10;
zBuf[11] = ' ';
zBuf[12] = '0' + (x.h/10)%10;
zBuf[13] = '0' + (x.h)%10;
zBuf[14] = ':';
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
s = (int)x.s;
zBuf[18] = '0' + (s/10)%10;
zBuf[19] = '0' + (s)%10;
zBuf[20] = 0;
if( x.Y<0 ){
zBuf[0] = '-';
sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
}else{
sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
}
} }
} }
@ -962,10 +1069,20 @@ static void timeFunc(
){ ){
DateTime x; DateTime x;
if( isDate(context, argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; int s;
char zBuf[16];
computeHMS(&x); computeHMS(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); zBuf[0] = '0' + (x.h/10)%10;
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); zBuf[1] = '0' + (x.h)%10;
zBuf[2] = ':';
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
s = (int)x.s;
zBuf[6] = '0' + (s/10)%10;
zBuf[7] = '0' + (s)%10;
zBuf[8] = 0;
sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
} }
} }
@ -981,10 +1098,28 @@ static void dateFunc(
){ ){
DateTime x; DateTime x;
if( isDate(context, argc, argv, &x)==0 ){ if( isDate(context, argc, argv, &x)==0 ){
char zBuf[100]; int Y;
char zBuf[16];
computeYMD(&x); computeYMD(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); Y = x.Y;
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); if( Y<0 ) Y = -Y;
zBuf[1] = '0' + (Y/1000)%10;
zBuf[2] = '0' + (Y/100)%10;
zBuf[3] = '0' + (Y/10)%10;
zBuf[4] = '0' + (Y)%10;
zBuf[5] = '-';
zBuf[6] = '0' + (x.M/10)%10;
zBuf[7] = '0' + (x.M)%10;
zBuf[8] = '-';
zBuf[9] = '0' + (x.D/10)%10;
zBuf[10] = '0' + (x.D)%10;
zBuf[11] = 0;
if( x.Y<0 ){
zBuf[0] = '-';
sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT);
}else{
sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT);
}
} }
} }
@ -1013,131 +1148,100 @@ static void strftimeFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
DateTime x; DateTime x;
u64 n;
size_t i,j; size_t i,j;
char *z;
sqlite3 *db; sqlite3 *db;
const char *zFmt; const char *zFmt;
char zBuf[100]; sqlite3_str sRes;
if( argc==0 ) return; if( argc==0 ) return;
zFmt = (const char*)sqlite3_value_text(argv[0]); zFmt = (const char*)sqlite3_value_text(argv[0]);
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return; if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
db = sqlite3_context_db_handle(context); db = sqlite3_context_db_handle(context);
for(i=0, n=1; zFmt[i]; i++, n++){ sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
if( zFmt[i]=='%' ){
switch( zFmt[i+1] ){
case 'd':
case 'H':
case 'm':
case 'M':
case 'S':
case 'W':
n++;
/* fall thru */
case 'w':
case '%':
break;
case 'f':
n += 8;
break;
case 'j':
n += 3;
break;
case 'Y':
n += 8;
break;
case 's':
case 'J':
n += 50;
break;
default:
return; /* ERROR. return a NULL */
}
i++;
}
}
testcase( n==sizeof(zBuf)-1 );
testcase( n==sizeof(zBuf) );
testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
if( n<sizeof(zBuf) ){
z = zBuf;
}else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(context);
return;
}else{
z = sqlite3DbMallocRawNN(db, (int)n);
if( z==0 ){
sqlite3_result_error_nomem(context);
return;
}
}
computeJD(&x); computeJD(&x);
computeYMD_HMS(&x); computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){ for(i=j=0; zFmt[i]; i++){
if( zFmt[i]!='%' ){ if( zFmt[i]!='%' ) continue;
z[j++] = zFmt[i]; if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
}else{ i++;
i++; j = i + 1;
switch( zFmt[i] ){ switch( zFmt[i] ){
case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; case 'd': {
case 'f': { sqlite3_str_appendf(&sRes, "%02d", x.D);
double s = x.s; break;
if( s>59.999 ) s = 59.999; }
sqlite3_snprintf(7, &z[j],"%06.3f", s); case 'f': {
j += sqlite3Strlen30(&z[j]); double s = x.s;
break; if( s>59.999 ) s = 59.999;
sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
case 'H': {
sqlite3_str_appendf(&sRes, "%02d", x.h);
break;
}
case 'W': /* Fall thru */
case 'j': {
int nDay; /* Number of days since 1st day of year */
DateTime y = x;
y.validJD = 0;
y.M = 1;
y.D = 1;
computeJD(&y);
nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = (int)(((x.iJD+43200000)/86400000)%7);
sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
}else{
sqlite3_str_appendf(&sRes,"%03d",nDay+1);
} }
case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break; break;
case 'W': /* Fall thru */ }
case 'j': { case 'J': {
int nDay; /* Number of days since 1st day of year */ sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
DateTime y = x; break;
y.validJD = 0; }
y.M = 1; case 'm': {
y.D = 1; sqlite3_str_appendf(&sRes,"%02d",x.M);
computeJD(&y); break;
nDay = (int)((x.iJD-y.iJD+43200000)/86400000); }
if( zFmt[i]=='W' ){ case 'M': {
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */ sqlite3_str_appendf(&sRes,"%02d",x.m);
wd = (int)(((x.iJD+43200000)/86400000)%7); break;
sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); }
j += 2; case 's': {
}else{ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
sqlite3_snprintf(4, &z[j],"%03d",nDay+1); sqlite3_str_appendf(&sRes,"%lld",iS);
j += 3; break;
} }
break; case 'S': {
} sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
case 'J': { break;
sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); }
j+=sqlite3Strlen30(&z[j]); case 'w': {
break; sqlite3_str_appendchar(&sRes, 1,
} (char)(((x.iJD+129600000)/86400000) % 7) + '0');
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; break;
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; }
case 's': { case 'Y': {
i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000); sqlite3_str_appendf(&sRes,"%04d",x.Y);
sqlite3Int64ToText(iS, &z[j]); break;
j += sqlite3Strlen30(&z[j]); }
break; case '%': {
} sqlite3_str_appendchar(&sRes, 1, '%');
case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; break;
case 'w': { }
z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; default: {
break; sqlite3_str_reset(&sRes);
} return;
case 'Y': {
sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
break;
}
default: z[j++] = '%'; break;
} }
} }
} }
z[j] = 0; if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
sqlite3_result_text(context, z, -1, sqlite3ResultStrAccum(context, &sRes);
z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
} }
/* /*
@ -1237,6 +1341,7 @@ void sqlite3RegisterDateTimeFunctions(void){
static FuncDef aDateTimeFuncs[] = { static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS #ifndef SQLITE_OMIT_DATETIME_FUNCS
PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), PURE_DATE(julianday, -1, 0, 0, juliandayFunc ),
PURE_DATE(unixepoch, -1, 0, 0, unixepochFunc ),
PURE_DATE(date, -1, 0, 0, dateFunc ), PURE_DATE(date, -1, 0, 0, dateFunc ),
PURE_DATE(time, -1, 0, 0, timeFunc ), PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),

View file

@ -13,7 +13,7 @@
** This file contains an implementation of the "sqlite_dbpage" virtual table. ** This file contains an implementation of the "sqlite_dbpage" virtual table.
** **
** The sqlite_dbpage virtual table is used to read or write whole raw ** The sqlite_dbpage virtual table is used to read or write whole raw
** pages of the database file. The pager interface is used so that ** pages of the database file. The pager interface is used so that
** uncommitted changes and changes recorded in the WAL file are correctly ** uncommitted changes and changes recorded in the WAL file are correctly
** retrieved. ** retrieved.
** **
@ -30,12 +30,10 @@
** value must be a BLOB which is the correct page size, otherwise the ** value must be a BLOB which is the correct page size, otherwise the
** update fails. Rows may not be deleted or inserted. ** update fails. Rows may not be deleted or inserted.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" /* Requires access to internal data inc */
/* clang-format off */ #include "third_party/sqlite3/sqliteInt.h" /* Requires access to internal data structures */
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) && \ && !defined(SQLITE_OMIT_VIRTUALTABLE)
!defined(SQLITE_OMIT_VIRTUALTABLE)
typedef struct DbpageTable DbpageTable; typedef struct DbpageTable DbpageTable;
typedef struct DbpageCursor DbpageCursor; typedef struct DbpageCursor DbpageCursor;
@ -158,6 +156,7 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){ ){
pIdxInfo->orderByConsumed = 1; pIdxInfo->orderByConsumed = 1;
} }
sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK; return SQLITE_OK;
} }
@ -275,12 +274,18 @@ static int dbpageColumn(
} }
case 1: { /* data */ case 1: { /* data */
DbPage *pDbPage = 0; DbPage *pDbPage = 0;
rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
if( rc==SQLITE_OK ){ /* The pending byte page. Assume it is zeroed out. Attempting to
sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, ** request this page from the page is an SQLITE_CORRUPT error. */
SQLITE_TRANSIENT); sqlite3_result_zeroblob(ctx, pCsr->szPage);
}else{
rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
SQLITE_TRANSIENT);
}
sqlite3PagerUnref(pDbPage);
} }
sqlite3PagerUnref(pDbPage);
break; break;
} }
default: { /* schema */ default: { /* schema */
@ -289,7 +294,7 @@ static int dbpageColumn(
break; break;
} }
} }
return SQLITE_OK; return rc;
} }
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
@ -335,7 +340,7 @@ static int dbpageUpdate(
goto update_fail; goto update_fail;
} }
pBt = pTab->db->aDb[iDb].pBt; pBt = pTab->db->aDb[iDb].pBt;
if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){ if( pgno<1 || pBt==0 || pgno>sqlite3BtreeLastPage(pBt) ){
zErr = "bad page number"; zErr = "bad page number";
goto update_fail; goto update_fail;
} }
@ -349,11 +354,12 @@ static int dbpageUpdate(
pPager = sqlite3BtreePager(pBt); pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pDbPage); const void *pData = sqlite3_value_blob(argv[3]);
if( rc==SQLITE_OK ){ assert( pData!=0 || pTab->db->mallocFailed );
memcpy(sqlite3PagerGetData(pDbPage), if( pData
sqlite3_value_blob(argv[3]), && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
szPage); ){
memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
} }
} }
sqlite3PagerUnref(pDbPage); sqlite3PagerUnref(pDbPage);
@ -373,11 +379,12 @@ static int dbpageBegin(sqlite3_vtab *pVtab){
DbpageTable *pTab = (DbpageTable *)pVtab; DbpageTable *pTab = (DbpageTable *)pVtab;
sqlite3 *db = pTab->db; sqlite3 *db = pTab->db;
int i; int i;
for(i=0; i<db->nDb; i++){ int rc = SQLITE_OK;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); if( pBt ) rc = sqlite3BtreeBeginTrans(pBt, 1, 0);
} }
return SQLITE_OK; return rc;
} }

View file

@ -20,12 +20,19 @@
** Additional information is available on the "dbstat.html" page of the ** Additional information is available on the "dbstat.html" page of the
** official SQLite documentation. ** official SQLite documentation.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" /* Requires access to internal data inc */
/* clang-format off */ #include "third_party/sqlite3/sqliteInt.h" /* Requires access to internal data structures */
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) && \ /*
!defined(SQLITE_OMIT_VIRTUALTABLE) ** The pager and btree modules arrange objects in memory so that there are
** always approximately 200 bytes of addressable memory following each page
** buffer. This way small buffer overreads caused by corrupt database pages
** do not cause undefined behaviour. This module pads each page buffer
** by the following number of bytes for the same purpose.
*/
#define DBSTAT_PAGE_PADDING_BYTES 256
/* /*
** Page paths: ** Page paths:
@ -94,9 +101,8 @@ struct StatCell {
/* Size information for a single btree page */ /* Size information for a single btree page */
struct StatPage { struct StatPage {
u32 iPgno; /* Page number */ u32 iPgno; /* Page number */
DbPage *pPg; /* Page content */ u8 *aPg; /* Page buffer from sqlite3_malloc() */
int iCell; /* Current cell */ int iCell; /* Current cell */
char *zPath; /* Path to this page */ char *zPath; /* Path to this page */
/* Variables populated by statDecodePage(): */ /* Variables populated by statDecodePage(): */
@ -308,18 +314,25 @@ static void statClearCells(StatPage *p){
} }
static void statClearPage(StatPage *p){ static void statClearPage(StatPage *p){
u8 *aPg = p->aPg;
statClearCells(p); statClearCells(p);
sqlite3PagerUnref(p->pPg);
sqlite3_free(p->zPath); sqlite3_free(p->zPath);
memset(p, 0, sizeof(StatPage)); memset(p, 0, sizeof(StatPage));
p->aPg = aPg;
} }
static void statResetCsr(StatCursor *pCsr){ static void statResetCsr(StatCursor *pCsr){
int i; int i;
sqlite3_reset(pCsr->pStmt); /* In some circumstances, specifically if an OOM has occurred, the call
** to sqlite3_reset() may cause the pager to be reset (emptied). It is
** important that statClearPage() is called to free any page refs before
** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */
for(i=0; i<ArraySize(pCsr->aPage); i++){ for(i=0; i<ArraySize(pCsr->aPage); i++){
statClearPage(&pCsr->aPage[i]); statClearPage(&pCsr->aPage[i]);
sqlite3_free(pCsr->aPage[i].aPg);
pCsr->aPage[i].aPg = 0;
} }
sqlite3_reset(pCsr->pStmt);
pCsr->iPage = 0; pCsr->iPage = 0;
sqlite3_free(pCsr->zPath); sqlite3_free(pCsr->zPath);
pCsr->zPath = 0; pCsr->zPath = 0;
@ -384,7 +397,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
int isLeaf; int isLeaf;
int szPage; int szPage;
u8 *aData = sqlite3PagerGetData(p->pPg); u8 *aData = p->aPg;
u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
p->flags = aHdr[0]; p->flags = aHdr[0];
@ -455,7 +468,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
if( nPayload>(u32)nLocal ){ if( nPayload>(u32)nLocal ){
int j; int j;
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){ if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){
goto statPageIsCorrupt; goto statPageIsCorrupt;
} }
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
@ -514,6 +527,38 @@ static void statSizeAndOffset(StatCursor *pCsr){
} }
} }
/*
** Load a copy of the page data for page iPg into the buffer belonging
** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK
** if successful, or an SQLite error code otherwise.
*/
static int statGetPage(
Btree *pBt, /* Load page from this b-tree */
u32 iPg, /* Page number to load */
StatPage *pPg /* Load page into this object */
){
int pgsz = sqlite3BtreeGetPageSize(pBt);
DbPage *pDbPage = 0;
int rc;
if( pPg->aPg==0 ){
pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES);
if( pPg->aPg==0 ){
return SQLITE_NOMEM_BKPT;
}
memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES);
}
rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0);
if( rc==SQLITE_OK ){
const u8 *a = sqlite3PagerGetData(pDbPage);
memcpy(pPg->aPg, a, pgsz);
sqlite3PagerUnref(pDbPage);
}
return rc;
}
/* /*
** Move a DBSTAT cursor to the next entry. Normally, the next ** Move a DBSTAT cursor to the next entry. Normally, the next
** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0), ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
@ -532,7 +577,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
pCsr->zPath = 0; pCsr->zPath = 0;
statNextRestart: statNextRestart:
if( pCsr->aPage[0].pPg==0 ){ if( pCsr->iPage<0 ){
/* Start measuring space on the next btree */ /* Start measuring space on the next btree */
statResetCounts(pCsr); statResetCounts(pCsr);
rc = sqlite3_step(pCsr->pStmt); rc = sqlite3_step(pCsr->pStmt);
@ -544,7 +589,7 @@ statNextRestart:
pCsr->isEof = 1; pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt); return sqlite3_reset(pCsr->pStmt);
} }
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0); rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]);
pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iPgno = iRoot;
pCsr->aPage[0].iCell = 0; pCsr->aPage[0].iCell = 0;
if( !pCsr->isAgg ){ if( !pCsr->isAgg ){
@ -595,9 +640,8 @@ statNextRestart:
if( !p->iRightChildPg || p->iCell>p->nCell ){ if( !p->iRightChildPg || p->iCell>p->nCell ){
statClearPage(p); statClearPage(p);
if( pCsr->iPage>0 ){ pCsr->iPage--;
pCsr->iPage--; if( pCsr->isAgg && pCsr->iPage<0 ){
}else if( pCsr->isAgg ){
/* label-statNext-done: When computing aggregate space usage over /* label-statNext-done: When computing aggregate space usage over
** an entire btree, this is the exit point from this function */ ** an entire btree, this is the exit point from this function */
return SQLITE_OK; return SQLITE_OK;
@ -616,7 +660,7 @@ statNextRestart:
}else{ }else{
p[1].iPgno = p->aCell[p->iCell].iChildPg; p[1].iPgno = p->aCell[p->iCell].iChildPg;
} }
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0); rc = statGetPage(pBt, p[1].iPgno, &p[1]);
pCsr->nPage++; pCsr->nPage++;
p[1].iCell = 0; p[1].iCell = 0;
if( !pCsr->isAgg ){ if( !pCsr->isAgg ){
@ -746,6 +790,7 @@ static int statFilter(
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pCsr->iPage = -1;
rc = statNext(pCursor); rc = statNext(pCursor);
} }
return rc; return rc;

View file

@ -12,9 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** in order to generate code for DELETE FROM statements. ** in order to generate code for DELETE FROM statements.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** While a SrcList can in general represent multiple tables and subqueries ** While a SrcList can in general represent multiple tables and subqueries
@ -46,6 +44,16 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
return pTab; return pTab;
} }
/* Generate byte-code that will report the number of rows modified
** by a DELETE, INSERT, or UPDATE statement.
*/
void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){
sqlite3VdbeAddOp0(v, OP_FkCheck);
sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC);
}
/* Return true if table pTab is read-only. /* Return true if table pTab is read-only.
** **
** A table is read-only if any of the following are true: ** A table is read-only if any of the following are true:
@ -53,18 +61,42 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
** 1) It is a virtual table and no implementation of the xUpdate method ** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided ** has been provided
** **
** 2) It is a system table (i.e. sqlite_schema), this call is not ** 2) A trigger is currently being coded and the table is a virtual table
** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
** the table is not SQLITE_VTAB_INNOCUOUS.
**
** 3) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not ** part of a nested parse and writable_schema pragma has not
** been specified ** been specified
** **
** 3) The table is a shadow table, the database connection is in ** 4) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlite3_prepare() ** defensive mode, and the current sqlite3_prepare()
** is for a top-level SQL statement. ** is for a top-level SQL statement.
*/ */
static int vtabIsReadOnly(Parse *pParse, Table *pTab){
if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
return 1;
}
/* Within triggers:
** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
** virtual tables
** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
** virtual tables if PRAGMA trusted_schema=ON.
*/
if( pParse->pToplevel!=0
&& pTab->u.vtab.p->eVtabRisk >
((pParse->db->flags & SQLITE_TrustedSchema)!=0)
){
sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
pTab->zName);
}
return 0;
}
static int tabIsReadOnly(Parse *pParse, Table *pTab){ static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlite3 *db; sqlite3 *db;
if( IsVirtual(pTab) ){ if( IsVirtual(pTab) ){
return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0; return vtabIsReadOnly(pParse, pTab);
} }
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0; if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db; db = pParse->db;
@ -76,9 +108,11 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
} }
/* /*
** Check to make sure the given table is writable. If it is not ** Check to make sure the given table is writable.
** writable, generate an error message and return 1. If it is **
** writable return 0; ** If pTab is not writable -> generate an error message and return 1.
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/ */
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( tabIsReadOnly(pParse, pTab) ){ if( tabIsReadOnly(pParse, pTab) ){
@ -86,7 +120,7 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
return 1; return 1;
} }
#ifndef SQLITE_OMIT_VIEW #ifndef SQLITE_OMIT_VIEW
if( !viewOk && pTab->pSelect ){ if( !viewOk && IsView(pTab) ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1; return 1;
} }
@ -120,8 +154,8 @@ void sqlite3MaterializeView(
assert( pFrom->nSrc==1 ); assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].fg.isUsing==0 );
assert( pFrom->a[0].pUsing==0 ); assert( pFrom->a[0].u3.pOn==0 );
} }
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
SF_IncludeHidden, pLimit); SF_IncludeHidden, pLimit);
@ -190,13 +224,13 @@ Expr *sqlite3LimitWhere(
}else{ }else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab); Index *pPk = sqlite3PrimaryKeyIndex(pTab);
if( pPk->nKeyCol==1 ){ if( pPk->nKeyCol==1 ){
const char *zName = pTab->aCol[pPk->aiColumn[0]].zName; const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
pLhs = sqlite3Expr(db, TK_ID, zName); pLhs = sqlite3Expr(db, TK_ID, zName);
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName)); pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
}else{ }else{
int i; int i;
for(i=0; i<pPk->nKeyCol; i++){ for(i=0; i<pPk->nKeyCol; i++){
Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName); Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
pEList = sqlite3ExprListAppend(pParse, pEList, p); pEList = sqlite3ExprListAppend(pParse, pEList, p);
} }
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@ -212,6 +246,7 @@ Expr *sqlite3LimitWhere(
pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
pSrc->a[0].pTab = pTab; pSrc->a[0].pTab = pTab;
if( pSrc->a[0].fg.isIndexedBy ){ if( pSrc->a[0].fg.isIndexedBy ){
assert( pSrc->a[0].fg.isCte==0 );
pSrc->a[0].u2.pIBIndex = 0; pSrc->a[0].u2.pIBIndex = 0;
pSrc->a[0].fg.isIndexedBy = 0; pSrc->a[0].fg.isIndexedBy = 0;
sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
@ -284,12 +319,13 @@ void sqlite3DeleteFrom(
memset(&sContext, 0, sizeof(sContext)); memset(&sContext, 0, sizeof(sContext));
db = pParse->db; db = pParse->db;
if( pParse->nErr || db->mallocFailed ){ assert( db->pParse==pParse );
if( pParse->nErr ){
goto delete_from_cleanup; goto delete_from_cleanup;
} }
assert( db->mallocFailed==0 );
assert( pTabList->nSrc==1 ); assert( pTabList->nSrc==1 );
/* Locate the table which we want to delete. This table has to be /* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we ** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect ** will be calling are designed to work with multiple tables and expect
@ -303,7 +339,7 @@ void sqlite3DeleteFrom(
*/ */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0; isView = IsView(pTab);
#else #else
# define pTrigger 0 # define pTrigger 0
# define isView 0 # define isView 0
@ -314,6 +350,14 @@ void sqlite3DeleteFrom(
# define isView 0 # define isView 0
#endif #endif
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere,
pOrderBy, pLimit, pTrigger);
}
#endif
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
if( !isView ){ if( !isView ){
pWhere = sqlite3LimitWhere( pWhere = sqlite3LimitWhere(
@ -429,7 +473,11 @@ void sqlite3DeleteFrom(
} }
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema ); assert( pIdx->pSchema==pTab->pSchema );
sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
}else{
sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
} }
}else }else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
@ -464,7 +512,7 @@ void sqlite3DeleteFrom(
** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
*/ */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1);
if( pWInfo==0 ) goto delete_from_cleanup; if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
@ -550,7 +598,7 @@ void sqlite3DeleteFrom(
if( eOnePass!=ONEPASS_OFF ){ if( eOnePass!=ONEPASS_OFF ){
assert( nKey==nPk ); /* OP_Found will use an unpacked key */ assert( nKey==nPk ); /* OP_Found will use an unpacked key */
if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){ if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
assert( pPk!=0 || pTab->pSelect!=0 ); assert( pPk!=0 || IsView(pTab) );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
VdbeCoverage(v); VdbeCoverage(v);
} }
@ -617,9 +665,7 @@ void sqlite3DeleteFrom(
** invoke the callback function. ** invoke the callback function.
*/ */
if( memCnt ){ if( memCnt ){
sqlite3VdbeAddOp2(v, OP_ChngCntRow, memCnt, 1); sqlite3CodeChangeCount(v, memCnt, "rows deleted");
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
} }
delete_from_cleanup: delete_from_cleanup:
@ -630,7 +676,7 @@ delete_from_cleanup:
sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit); sqlite3ExprDelete(db, pLimit);
#endif #endif
sqlite3DbFree(db, aToOpen); if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen);
return; return;
} }
/* Make sure "isView" and other macros defined above are undefined. Otherwise /* Make sure "isView" and other macros defined above are undefined. Otherwise
@ -784,7 +830,7 @@ void sqlite3GenerateRowDelete(
** the update-hook is not invoked for rows removed by REPLACE, but the ** the update-hook is not invoked for rows removed by REPLACE, but the
** pre-update-hook is. ** pre-update-hook is.
*/ */
if( pTab->pSelect==0 ){ if( !IsView(pTab) ){
u8 p5 = 0; u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
@ -941,13 +987,15 @@ int sqlite3GenerateIndexKey(
continue; continue;
} }
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
/* If the column affinity is REAL but the number is an integer, then it if( pIdx->aiColumn[j]>=0 ){
** might be stored in the table as an integer (using a compact /* If the column affinity is REAL but the number is an integer, then it
** representation) then converted to REAL by an OP_RealAffinity opcode. ** might be stored in the table as an integer (using a compact
** But we are getting ready to store this value back into an index, where ** representation) then converted to REAL by an OP_RealAffinity opcode.
** it should be converted by to INTEGER again. So omit the OP_RealAffinity ** But we are getting ready to store this value back into an index, where
** opcode if it is present */ ** it should be converted by to INTEGER again. So omit the
sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity); ** OP_RealAffinity opcode if it is present */
sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
}
} }
if( regOut ){ if( regOut ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);

View file

@ -43,7 +43,7 @@ hash
icu icu
ieee754 ieee754
insert insert
json1 json
legacy legacy
loadext loadext
main main

File diff suppressed because it is too large Load diff

View file

@ -10,22 +10,21 @@
** **
************************************************************************* *************************************************************************
** **
** This file contains code to support the concept of "benign" ** This file contains code to support the concept of "benign"
** malloc failures (when the xMalloc() or xRealloc() method of the ** malloc failures (when the xMalloc() or xRealloc() method of the
** sqlite3_mem_methods structure fails to allocate a block of memory ** sqlite3_mem_methods structure fails to allocate a block of memory
** and returns 0). ** and returns 0).
** **
** Most malloc failures are non-benign. After they occur, SQLite ** Most malloc failures are non-benign. After they occur, SQLite
** abandons the current operation and returns an error code (usually ** abandons the current operation and returns an error code (usually
** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily ** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
** fatal. For example, if a malloc fails while resizing a hash table, this ** fatal. For example, if a malloc fails while resizing a hash table, this
** is completely recoverable simply by not carrying out the resize. The ** is completely recoverable simply by not carrying out the resize. The
** hash table will continue to function normally. So a malloc failure ** hash table will continue to function normally. So a malloc failure
** during a hash table resize is a benign fault. ** during a hash table resize is a benign fault.
*/ */
#include "third_party/sqlite3/sqliteInt.inc"
/* clang-format off */ #include "third_party/sqlite3/sqliteInt.h"
#ifndef SQLITE_UNTESTABLE #ifndef SQLITE_UNTESTABLE

View file

@ -1,18 +1,3 @@
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.macros.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/s.h"
#include "libc/time/time.h"
#include "third_party/sqlite3/sqlite3ext.h"
// clang-format off
/* /*
** 2014-06-13 ** 2014-06-13
** **
@ -88,6 +73,21 @@
** And the paths returned in the "name" column of the table are also ** And the paths returned in the "name" column of the table are also
** relative to directory $dir. ** relative to directory $dir.
*/ */
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.macros.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/isystem/unistd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/s.h"
#include "libc/time/time.h"
#include "third_party/sqlite3/sqlite3ext.h"
// clang-format off
SQLITE_EXTENSION_INIT1 SQLITE_EXTENSION_INIT1

View file

@ -11,9 +11,7 @@
** This file contains code used by the compiler to add foreign key ** This file contains code used by the compiler to add foreign key
** support to compiled SQL statements. ** support to compiled SQL statements.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_FOREIGN_KEY
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
@ -217,7 +215,9 @@ int sqlite3FkLocateIndex(
*/ */
if( pParent->iPKey>=0 ){ if( pParent->iPKey>=0 ){
if( !zKey ) return 0; if( !zKey ) return 0;
if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0; if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){
return 0;
}
} }
}else if( paiCol ){ }else if( paiCol ){
assert( nCol>1 ); assert( nCol>1 );
@ -259,11 +259,11 @@ int sqlite3FkLocateIndex(
/* If the index uses a collation sequence that is different from /* If the index uses a collation sequence that is different from
** the default collation sequence for the column, this index is ** the default collation sequence for the column, this index is
** unusable. Bail out early in this case. */ ** unusable. Bail out early in this case. */
zDfltColl = pParent->aCol[iCol].zColl; zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]);
if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
zIdxCol = pParent->aCol[iCol].zName; zIdxCol = pParent->aCol[iCol].zCnName;
for(j=0; j<nCol; j++){ for(j=0; j<nCol; j++){
if( sqlite3StrICmp(pFKey->aCol[j].zCol, zIdxCol)==0 ){ if( sqlite3StrICmp(pFKey->aCol[j].zCol, zIdxCol)==0 ){
if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom; if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom;
@ -390,7 +390,6 @@ static void fkLookupParent(
}else{ }else{
int nCol = pFKey->nCol; int nCol = pFKey->nCol;
int regTemp = sqlite3GetTempRange(pParse, nCol); int regTemp = sqlite3GetTempRange(pParse, nCol);
int regRec = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx); sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
@ -429,12 +428,11 @@ static void fkLookupParent(
} }
sqlite3VdbeGoto(v, iOk); sqlite3VdbeGoto(v, iOk);
} }
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, sqlite3VdbeAddOp4(v, OP_Affinity, regTemp, nCol, 0,
sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regTemp, nCol);
VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempRange(pParse, regTemp, nCol); sqlite3ReleaseTempRange(pParse, regTemp, nCol);
} }
} }
@ -487,7 +485,7 @@ static Expr *exprTableRegister(
pCol = &pTab->aCol[iCol]; pCol = &pTab->aCol[iCol];
pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1; pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
pExpr->affExpr = pCol->affinity; pExpr->affExpr = pCol->affinity;
zColl = pCol->zColl; zColl = sqlite3ColumnColl(pCol);
if( zColl==0 ) zColl = db->pDfltColl->zName; if( zColl==0 ) zColl = db->pDfltColl->zName;
pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
}else{ }else{
@ -510,6 +508,7 @@ static Expr *exprTableColumn(
){ ){
Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0); Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
if( pExpr ){ if( pExpr ){
assert( ExprUseYTab(pExpr) );
pExpr->y.pTab = pTab; pExpr->y.pTab = pTab;
pExpr->iTable = iCursor; pExpr->iTable = iCursor;
pExpr->iColumn = iCol; pExpr->iColumn = iCol;
@ -535,14 +534,10 @@ static Expr *exprTableColumn(
** Operation | FK type | Action taken ** Operation | FK type | Action taken
** -------------------------------------------------------------------------- ** --------------------------------------------------------------------------
** DELETE immediate Increment the "immediate constraint counter". ** DELETE immediate Increment the "immediate constraint counter".
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
** throw a "FOREIGN KEY constraint failed" exception.
** **
** INSERT immediate Decrement the "immediate constraint counter". ** INSERT immediate Decrement the "immediate constraint counter".
** **
** DELETE deferred Increment the "deferred constraint counter". ** DELETE deferred Increment the "deferred constraint counter".
** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
** throw a "FOREIGN KEY constraint failed" exception.
** **
** INSERT deferred Decrement the "deferred constraint counter". ** INSERT deferred Decrement the "deferred constraint counter".
** **
@ -596,7 +591,7 @@ static void fkScanChildren(
pLeft = exprTableRegister(pParse, pTab, regData, iCol); pLeft = exprTableRegister(pParse, pTab, regData, iCol);
iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
assert( iCol>=0 ); assert( iCol>=0 );
zCol = pFKey->pFrom->aCol[iCol].zName; zCol = pFKey->pFrom->aCol[iCol].zCnName;
pRight = sqlite3Expr(db, TK_ID, zCol); pRight = sqlite3Expr(db, TK_ID, zCol);
pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); pWhere = sqlite3ExprAnd(pParse, pWhere, pEq);
@ -631,7 +626,7 @@ static void fkScanChildren(
i16 iCol = pIdx->aiColumn[i]; i16 iCol = pIdx->aiColumn[i];
assert( iCol>=0 ); assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol); pLeft = exprTableRegister(pParse, pTab, regData, iCol);
pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName); pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName);
pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight);
pAll = sqlite3ExprAnd(pParse, pAll, pEq); pAll = sqlite3ExprAnd(pParse, pAll, pEq);
} }
@ -650,7 +645,7 @@ static void fkScanChildren(
** clause. For each row found, increment either the deferred or immediate ** clause. For each row found, increment either the deferred or immediate
** foreign key constraint counter. */ ** foreign key constraint counter. */
if( pParse->nErr==0 ){ if( pParse->nErr==0 ){
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
if( pWInfo ){ if( pWInfo ){
sqlite3WhereEnd(pWInfo); sqlite3WhereEnd(pWInfo);
@ -701,6 +696,25 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
} }
} }
/*
** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys
** in a particular database. This needs to happen when the schema
** changes.
*/
void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
HashElem *k;
Hash *pHash = &db->aDb[iDb].pSchema->tblHash;
for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){
Table *pTab = sqliteHashData(k);
FKey *pFKey;
if( !IsOrdinaryTable(pTab) ) continue;
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0;
fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0;
}
}
}
/* /*
** This function is called to generate code that runs when table pTab is ** This function is called to generate code that runs when table pTab is
** being dropped from the database. The SrcList passed as the second argument ** being dropped from the database. The SrcList passed as the second argument
@ -720,12 +734,12 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
*/ */
void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){ if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){
int iSkip = 0; int iSkip = 0;
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
assert( v ); /* VDBE has already been allocated */ assert( v ); /* VDBE has already been allocated */
assert( pTab->pSelect==0 ); /* Not a view */ assert( IsOrdinaryTable(pTab) );
if( sqlite3FkReferences(pTab)==0 ){ if( sqlite3FkReferences(pTab)==0 ){
/* Search for a deferred foreign key constraint for which this table /* Search for a deferred foreign key constraint for which this table
** is the child table. If one cannot be found, return without ** is the child table. If one cannot be found, return without
@ -733,7 +747,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** the entire DELETE if there are no outstanding deferred constraints ** the entire DELETE if there are no outstanding deferred constraints
** when this statement is run. */ ** when this statement is run. */
FKey *p; FKey *p;
for(p=pTab->pFKey; p; p=p->pNextFrom){ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break; if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
} }
if( !p ) return; if( !p ) return;
@ -822,7 +836,7 @@ static int fkParentIsModified(
if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){ if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){
Column *pCol = &pTab->aCol[iKey]; Column *pCol = &pTab->aCol[iKey];
if( zKey ){ if( zKey ){
if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1; if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1;
}else if( pCol->colFlags & COLFLAG_PRIMKEY ){ }else if( pCol->colFlags & COLFLAG_PRIMKEY ){
return 1; return 1;
} }
@ -889,13 +903,14 @@ void sqlite3FkCheck(
/* If foreign-keys are disabled, this function is a no-op. */ /* If foreign-keys are disabled, this function is a no-op. */
if( (db->flags&SQLITE_ForeignKeys)==0 ) return; if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
if( !IsOrdinaryTable(pTab) ) return;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName; zDb = db->aDb[iDb].zDbSName;
/* Loop through all the foreign key constraints for which pTab is the /* Loop through all the foreign key constraints for which pTab is the
** child table (the table that the foreign key definition is part of). */ ** child table (the table that the foreign key definition is part of). */
for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
Table *pTo; /* Parent table of foreign key pFKey */ Table *pTo; /* Parent table of foreign key pFKey */
Index *pIdx = 0; /* Index on key columns in pTo */ Index *pIdx = 0; /* Index on key columns in pTo */
int *aiFree = 0; int *aiFree = 0;
@ -962,7 +977,7 @@ void sqlite3FkCheck(
** values read from the parent table are NULL. */ ** values read from the parent table are NULL. */
if( db->xAuth ){ if( db->xAuth ){
int rcauth; int rcauth;
char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName;
rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
bIgnore = (rcauth==SQLITE_IGNORE); bIgnore = (rcauth==SQLITE_IGNORE);
} }
@ -1077,10 +1092,10 @@ u32 sqlite3FkOldmask(
Table *pTab /* Table being modified */ Table *pTab /* Table being modified */
){ ){
u32 mask = 0; u32 mask = 0;
if( pParse->db->flags&SQLITE_ForeignKeys ){ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){
FKey *p; FKey *p;
int i; int i;
for(p=pTab->pFKey; p; p=p->pNextFrom){ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom);
} }
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
@ -1130,19 +1145,19 @@ int sqlite3FkRequired(
){ ){
int eRet = 1; /* Value to return if bHaveFK is true */ int eRet = 1; /* Value to return if bHaveFK is true */
int bHaveFK = 0; /* If FK processing is required */ int bHaveFK = 0; /* If FK processing is required */
if( pParse->db->flags&SQLITE_ForeignKeys ){ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){
if( !aChange ){ if( !aChange ){
/* A DELETE operation. Foreign key processing is required if the /* A DELETE operation. Foreign key processing is required if the
** table in question is either the child or parent table for any ** table in question is either the child or parent table for any
** foreign key constraint. */ ** foreign key constraint. */
bHaveFK = (sqlite3FkReferences(pTab) || pTab->pFKey); bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey);
}else{ }else{
/* This is an UPDATE. Foreign key processing is only required if the /* This is an UPDATE. Foreign key processing is only required if the
** operation modifies one or more child or parent key columns. */ ** operation modifies one or more child or parent key columns. */
FKey *p; FKey *p;
/* Check if any child key columns are being modified. */ /* Check if any child key columns are being modified. */
for(p=pTab->pFKey; p; p=p->pNextFrom){ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2; if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2;
bHaveFK = 1; bHaveFK = 1;
@ -1170,9 +1185,9 @@ int sqlite3FkRequired(
** **
** It returns a pointer to a Trigger structure containing a trigger ** It returns a pointer to a Trigger structure containing a trigger
** equivalent to the ON UPDATE or ON DELETE action specified by pFKey. ** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is ** If the action is "NO ACTION" then a NULL pointer is returned (these actions
** returned (these actions require no special handling by the triggers ** require no special handling by the triggers sub-system, code for them is
** sub-system, code for them is created by fkScanChildren()). ** created by fkScanChildren()).
** **
** For example, if pFKey is the foreign key and pTab is table "p" in ** For example, if pFKey is the foreign key and pTab is table "p" in
** the following schema: ** the following schema:
@ -1235,8 +1250,8 @@ static Trigger *fkActionTrigger(
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) ); assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
sqlite3TokenInit(&tToCol, sqlite3TokenInit(&tToCol,
pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName); pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName);
sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName);
/* Create the expression "OLD.zToCol = zFromCol". It is important /* Create the expression "OLD.zToCol = zFromCol". It is important
** that the "OLD.zToCol" term is on the LHS of the = operator, so ** that the "OLD.zToCol" term is on the LHS of the = operator, so
@ -1281,7 +1296,7 @@ static Trigger *fkActionTrigger(
testcase( pCol->colFlags & COLFLAG_STORED ); testcase( pCol->colFlags & COLFLAG_STORED );
pDflt = 0; pDflt = 0;
}else{ }else{
pDflt = pCol->pDflt; pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol);
} }
if( pDflt ){ if( pDflt ){
pNew = sqlite3ExprDup(db, pDflt, 0); pNew = sqlite3ExprDup(db, pDflt, 0);
@ -1301,18 +1316,23 @@ static Trigger *fkActionTrigger(
nFrom = sqlite3Strlen30(zFrom); nFrom = sqlite3Strlen30(zFrom);
if( action==OE_Restrict ){ if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
Token tFrom; Token tFrom;
Token tDb;
Expr *pRaise; Expr *pRaise;
tFrom.z = zFrom; tFrom.z = zFrom;
tFrom.n = nFrom; tFrom.n = nFrom;
tDb.z = db->aDb[iDb].zDbSName;
tDb.n = sqlite3Strlen30(tDb.z);
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){ if( pRaise ){
pRaise->affExpr = OE_Abort; pRaise->affExpr = OE_Abort;
} }
pSelect = sqlite3SelectNew(pParse, pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise), sqlite3ExprListAppend(pParse, 0, pRaise),
sqlite3SrcListAppend(pParse, 0, &tFrom, 0), sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
pWhere, pWhere,
0, 0, 0, 0, 0 0, 0, 0, 0, 0
); );
@ -1418,12 +1438,13 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */ FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */ FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( db==0 || IsVirtual(pTab) assert( IsOrdinaryTable(pTab) );
|| sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); assert( db!=0 );
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */ /* Remove the FK from the fkeyHash hash table. */
if( !db || db->pnBytesFreed==0 ){ if( db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){ if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo; pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{ }else{

View file

@ -61,7 +61,7 @@
** A doclist (document list) holds a docid-sorted list of hits for a ** A doclist (document list) holds a docid-sorted list of hits for a
** given term. Doclists hold docids and associated token positions. ** given term. Doclists hold docids and associated token positions.
** A docid is the unique integer identifier for a single document. ** A docid is the unique integer identifier for a single document.
** A position is the index of a word within the document. The first ** A position is the index of a word within the document. The first
** word of the document has a position of 0. ** word of the document has a position of 0.
** **
** FTS3 used to optionally store character offsets using a compile-time ** FTS3 used to optionally store character offsets using a compile-time
@ -86,7 +86,7 @@
** **
** Here, array { X } means zero or more occurrences of X, adjacent in ** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream ** memory. A "position" is an index of a token in the token stream
** generated by the tokenizer. Note that POS_END and POS_COLUMN occur ** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
** in the same logical place as the position element, and act as sentinals ** in the same logical place as the position element, and act as sentinals
** ending a position list array. POS_END is 0. POS_COLUMN is 1. ** ending a position list array. POS_END is 0. POS_COLUMN is 1.
** The positions numbers are not stored literally but rather as two more ** The positions numbers are not stored literally but rather as two more
@ -110,7 +110,7 @@
** a document record consists of a docid followed by a position-list and ** a document record consists of a docid followed by a position-list and
** a doclist consists of one or more document records. ** a doclist consists of one or more document records.
** **
** A bare doclist omits the position information, becoming an ** A bare doclist omits the position information, becoming an
** array of varint-encoded docids. ** array of varint-encoded docids.
** **
**** Segment leaf nodes **** **** Segment leaf nodes ****
@ -287,9 +287,8 @@
** query logic likewise merges doclists so that newer data knocks out ** query logic likewise merges doclists so that newer data knocks out
** older data. ** older data.
*/ */
/* clang-format off */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE) #if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE)
@ -300,31 +299,33 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/sqlite3/fts3.inc"
#ifndef SQLITE_CORE #include "third_party/sqlite3/fts3.h"
#include "third_party/sqlite3/sqlite3ext.h" #ifndef SQLITE_CORE
SQLITE_EXTENSION_INIT1 # include "third_party/sqlite3/sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#endif #endif
typedef struct Fts3HashWrapper Fts3HashWrapper;
struct Fts3HashWrapper {
Fts3Hash hash; /* Hash table */
int nRef; /* Number of pointers to this object */
};
static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor( static int fts3TermSegReaderCursor(
Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);
#ifndef SQLITE_AMALGAMATION
# if defined(SQLITE_DEBUG)
int sqlite3Fts3Always(int b) { assert( b ); return b; }
int sqlite3Fts3Never(int b) { assert( !b ); return b; }
# endif
#endif
/* /*
** This variable is set to false when running tests for which the on disk ** This variable is set to false when running tests for which the on disk
** structures should not be corrupt. Otherwise, true. If it is false, extra ** structures should not be corrupt. Otherwise, true. If it is false, extra
** assert() conditions in the fts3 code are activated - conditions that are ** assert() conditions in the fts3 code are activated - conditions that are
** only true if it is guaranteed that the fts3 database is not corrupt. ** only true if it is guaranteed that the fts3 database is not corrupt.
*/ */
#ifdef SQLITE_DEBUG
int sqlite3_fts3_may_be_corrupt = 1; int sqlite3_fts3_may_be_corrupt = 1;
#endif
/* /*
** Write a 64-bit variable-length integer to memory starting at p[0]. ** Write a 64-bit variable-length integer to memory starting at p[0].
@ -1175,7 +1176,7 @@ static int fts3InitVtab(
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
char **pzErr /* Write any error message here */ char **pzErr /* Write any error message here */
){ ){
Fts3Hash *pHash = (Fts3Hash *)pAux; Fts3Hash *pHash = &((Fts3HashWrapper*)pAux)->hash;
Fts3Table *p = 0; /* Pointer to allocated vtab */ Fts3Table *p = 0; /* Pointer to allocated vtab */
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */ int i; /* Iterator variable */
@ -1895,7 +1896,7 @@ static int fts3ScanInteriorNode(
char *zBuffer = 0; /* Buffer to load terms into */ char *zBuffer = 0; /* Buffer to load terms into */
i64 nAlloc = 0; /* Size of allocated buffer */ i64 nAlloc = 0; /* Size of allocated buffer */
int isFirstTerm = 1; /* True when processing first term on page */ int isFirstTerm = 1; /* True when processing first term on page */
sqlite3_int64 iChild; /* Block id of child node to descend to */ u64 iChild; /* Block id of child node to descend to */
int nBuffer = 0; /* Total term size */ int nBuffer = 0; /* Total term size */
/* Skip over the 'height' varint that occurs at the start of every /* Skip over the 'height' varint that occurs at the start of every
@ -1911,8 +1912,8 @@ static int fts3ScanInteriorNode(
** table, then there are always 20 bytes of zeroed padding following the ** table, then there are always 20 bytes of zeroed padding following the
** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
*/ */
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild);
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild);
if( zCsr>zEnd ){ if( zCsr>zEnd ){
return FTS_CORRUPT_VTAB; return FTS_CORRUPT_VTAB;
} }
@ -1965,20 +1966,20 @@ static int fts3ScanInteriorNode(
*/ */
cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){
*piFirst = iChild; *piFirst = (i64)iChild;
piFirst = 0; piFirst = 0;
} }
if( piLast && cmp<0 ){ if( piLast && cmp<0 ){
*piLast = iChild; *piLast = (i64)iChild;
piLast = 0; piLast = 0;
} }
iChild++; iChild++;
}; };
if( piFirst ) *piFirst = iChild; if( piFirst ) *piFirst = (i64)iChild;
if( piLast ) *piLast = iChild; if( piLast ) *piLast = (i64)iChild;
finish_scan: finish_scan:
sqlite3_free(zBuffer); sqlite3_free(zBuffer);
@ -2885,7 +2886,7 @@ static int fts3TermSelectMerge(
** **
** Similar padding is added in the fts3DoclistOrMerge() function. ** Similar padding is added in the fts3DoclistOrMerge() function.
*/ */
pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist; pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){ if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist); memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@ -3584,14 +3585,20 @@ static int fts3SetHasStat(Fts3Table *p){
*/ */
static int fts3BeginMethod(sqlite3_vtab *pVtab){ static int fts3BeginMethod(sqlite3_vtab *pVtab){
Fts3Table *p = (Fts3Table*)pVtab; Fts3Table *p = (Fts3Table*)pVtab;
int rc;
UNUSED_PARAMETER(pVtab); UNUSED_PARAMETER(pVtab);
assert( p->pSegments==0 ); assert( p->pSegments==0 );
assert( p->nPendingData==0 ); assert( p->nPendingData==0 );
assert( p->inTransaction!=1 ); assert( p->inTransaction!=1 );
TESTONLY( p->inTransaction = 1 );
TESTONLY( p->mxSavepoint = -1; );
p->nLeafAdd = 0; p->nLeafAdd = 0;
return fts3SetHasStat(p); rc = fts3SetHasStat(p);
#ifdef SQLITE_DEBUG
if( rc==SQLITE_OK ){
p->inTransaction = 1;
p->mxSavepoint = -1;
}
#endif
return rc;
} }
/* /*
@ -4004,9 +4011,12 @@ static const sqlite3_module fts3Module = {
** allocated for the tokenizer hash table. ** allocated for the tokenizer hash table.
*/ */
static void hashDestroy(void *p){ static void hashDestroy(void *p){
Fts3Hash *pHash = (Fts3Hash *)p; Fts3HashWrapper *pHash = (Fts3HashWrapper *)p;
sqlite3Fts3HashClear(pHash); pHash->nRef--;
sqlite3_free(pHash); if( pHash->nRef<=0 ){
sqlite3Fts3HashClear(&pHash->hash);
sqlite3_free(pHash);
}
} }
/* /*
@ -4036,7 +4046,7 @@ void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule);
*/ */
int sqlite3Fts3Init(sqlite3 *db){ int sqlite3Fts3Init(sqlite3 *db){
int rc = SQLITE_OK; int rc = SQLITE_OK;
Fts3Hash *pHash = 0; Fts3HashWrapper *pHash = 0;
const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pSimple = 0;
const sqlite3_tokenizer_module *pPorter = 0; const sqlite3_tokenizer_module *pPorter = 0;
#ifndef SQLITE_DISABLE_FTS3_UNICODE #ifndef SQLITE_DISABLE_FTS3_UNICODE
@ -4064,23 +4074,24 @@ int sqlite3Fts3Init(sqlite3 *db){
sqlite3Fts3PorterTokenizerModule(&pPorter); sqlite3Fts3PorterTokenizerModule(&pPorter);
/* Allocate and initialize the hash-table used to store tokenizers. */ /* Allocate and initialize the hash-table used to store tokenizers. */
pHash = sqlite3_malloc(sizeof(Fts3Hash)); pHash = sqlite3_malloc(sizeof(Fts3HashWrapper));
if( !pHash ){ if( !pHash ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); sqlite3Fts3HashInit(&pHash->hash, FTS3_HASH_STRING, 1);
pHash->nRef = 0;
} }
/* Load the built-in tokenizers into the hash table */ /* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) if( sqlite3Fts3HashInsert(&pHash->hash, "simple", 7, (void *)pSimple)
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) || sqlite3Fts3HashInsert(&pHash->hash, "porter", 7, (void *)pPorter)
#ifndef SQLITE_DISABLE_FTS3_UNICODE #ifndef SQLITE_DISABLE_FTS3_UNICODE
|| sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode)
#endif #endif
#ifdef SQLITE_ENABLE_ICU #ifdef SQLITE_ENABLE_ICU
|| (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu)) || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu))
#endif #endif
){ ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
@ -4089,7 +4100,7 @@ int sqlite3Fts3Init(sqlite3 *db){
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3Fts3ExprInitTestInterface(db, pHash); rc = sqlite3Fts3ExprInitTestInterface(db, &pHash->hash);
} }
#endif #endif
@ -4098,23 +4109,26 @@ int sqlite3Fts3Init(sqlite3 *db){
** module with sqlite. ** module with sqlite.
*/ */
if( SQLITE_OK==rc if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) && SQLITE_OK==(rc=sqlite3Fts3InitHashTable(db,&pHash->hash,"fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
){ ){
pHash->nRef++;
rc = sqlite3_create_module_v2( rc = sqlite3_create_module_v2(
db, "fts3", &fts3Module, (void *)pHash, hashDestroy db, "fts3", &fts3Module, (void *)pHash, hashDestroy
); );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pHash->nRef++;
rc = sqlite3_create_module_v2( rc = sqlite3_create_module_v2(
db, "fts4", &fts3Module, (void *)pHash, 0 db, "fts4", &fts3Module, (void *)pHash, hashDestroy
); );
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3Fts3InitTok(db, (void *)pHash); pHash->nRef++;
rc = sqlite3Fts3InitTok(db, (void *)pHash, hashDestroy);
} }
return rc; return rc;
} }
@ -4123,7 +4137,7 @@ int sqlite3Fts3Init(sqlite3 *db){
/* An error has occurred. Delete the hash table and return the error code. */ /* An error has occurred. Delete the hash table and return the error code. */
assert( rc!=SQLITE_OK ); assert( rc!=SQLITE_OK );
if( pHash ){ if( pHash ){
sqlite3Fts3HashClear(pHash); sqlite3Fts3HashClear(&pHash->hash);
sqlite3_free(pHash); sqlite3_free(pHash);
} }
return rc; return rc;
@ -4292,8 +4306,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
char *aPoslist = 0; /* Position list for deferred tokens */ char *aPoslist = 0; /* Position list for deferred tokens */
int nPoslist = 0; /* Number of bytes in aPoslist */ int nPoslist = 0; /* Number of bytes in aPoslist */
int iPrev = -1; /* Token number of previous deferred token */ int iPrev = -1; /* Token number of previous deferred token */
char *aFree = (pPhrase->doclist.bFreeList ? pPhrase->doclist.pList : 0);
assert( pPhrase->doclist.bFreeList==0 );
for(iToken=0; iToken<pPhrase->nToken; iToken++){ for(iToken=0; iToken<pPhrase->nToken; iToken++){
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
@ -4307,6 +4320,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
if( pList==0 ){ if( pList==0 ){
sqlite3_free(aPoslist); sqlite3_free(aPoslist);
sqlite3_free(aFree);
pPhrase->doclist.pList = 0; pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0; pPhrase->doclist.nList = 0;
return SQLITE_OK; return SQLITE_OK;
@ -4327,6 +4341,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nPoslist = (int)(aOut - aPoslist); nPoslist = (int)(aOut - aPoslist);
if( nPoslist==0 ){ if( nPoslist==0 ){
sqlite3_free(aPoslist); sqlite3_free(aPoslist);
sqlite3_free(aFree);
pPhrase->doclist.pList = 0; pPhrase->doclist.pList = 0;
pPhrase->doclist.nList = 0; pPhrase->doclist.nList = 0;
return SQLITE_OK; return SQLITE_OK;
@ -4359,13 +4374,14 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nDistance = iPrev - nMaxUndeferred; nDistance = iPrev - nMaxUndeferred;
} }
aOut = (char *)sqlite3_malloc(nPoslist+8); aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
if( !aOut ){ if( !aOut ){
sqlite3_free(aPoslist); sqlite3_free(aPoslist);
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
pPhrase->doclist.pList = aOut; pPhrase->doclist.pList = aOut;
assert( p1 && p2 );
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1; pPhrase->doclist.bFreeList = 1;
pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList);
@ -4378,6 +4394,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
} }
} }
if( pPhrase->doclist.pList!=aFree ) sqlite3_free(aFree);
return SQLITE_OK; return SQLITE_OK;
} }
#endif /* SQLITE_DISABLE_FTS4_DEFERRED */ #endif /* SQLITE_DISABLE_FTS4_DEFERRED */
@ -4470,7 +4487,7 @@ void sqlite3Fts3DoclistPrev(
assert( nDoclist>0 ); assert( nDoclist>0 );
assert( *pbEof==0 ); assert( *pbEof==0 );
assert( p || *piDocid==0 ); assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) );
if( p==0 ){ if( p==0 ){
@ -4726,7 +4743,7 @@ static int fts3EvalIncrPhraseNext(
if( bEof==0 ){ if( bEof==0 ){
int nList = 0; int nList = 0;
int nByte = a[p->nToken-1].nList; int nByte = a[p->nToken-1].nList;
char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM; if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
@ -5120,16 +5137,15 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
#ifndef SQLITE_DISABLE_FTS4_DEFERRED #ifndef SQLITE_DISABLE_FTS4_DEFERRED
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){ if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
Fts3TokenAndCost *aTC; Fts3TokenAndCost *aTC;
Fts3Expr **apOr;
aTC = (Fts3TokenAndCost *)sqlite3_malloc64( aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
sizeof(Fts3TokenAndCost) * nToken sizeof(Fts3TokenAndCost) * nToken
+ sizeof(Fts3Expr *) * nOr * 2 + sizeof(Fts3Expr *) * nOr * 2
); );
apOr = (Fts3Expr **)&aTC[nToken];
if( !aTC ){ if( !aTC ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken];
int ii; int ii;
Fts3TokenAndCost *pTC = aTC; Fts3TokenAndCost *pTC = aTC;
Fts3Expr **ppOr = apOr; Fts3Expr **ppOr = apOr;
@ -5335,8 +5351,8 @@ static void fts3EvalNextRow(
Fts3Expr *pRight = pExpr->pRight; Fts3Expr *pRight = pExpr->pRight;
sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid); sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid);
assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid );
assert( pRight->bStart || pLeft->iDocid==pRight->iDocid ); assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid );
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){ if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
fts3EvalNextRow(pCsr, pLeft, pRc); fts3EvalNextRow(pCsr, pLeft, pRc);
@ -5553,11 +5569,10 @@ static int fts3EvalTestExpr(
default: { default: {
#ifndef SQLITE_DISABLE_FTS4_DEFERRED #ifndef SQLITE_DISABLE_FTS4_DEFERRED
if( pCsr->pDeferred if( pCsr->pDeferred && (pExpr->bDeferred || (
&& (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred) pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.pList
){ ))){
Fts3Phrase *pPhrase = pExpr->pPhrase; Fts3Phrase *pPhrase = pExpr->pPhrase;
assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 );
if( pExpr->bDeferred ){ if( pExpr->bDeferred ){
fts3EvalInvalidatePoslist(pPhrase); fts3EvalInvalidatePoslist(pPhrase);
} }
@ -5974,6 +5989,9 @@ int sqlite3Fts3EvalPhrasePoslist(
if( bEofSave==0 && pNear->iDocid==iDocid ) break; if( bEofSave==0 && pNear->iDocid==iDocid ) break;
} }
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 ); assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){
rc = FTS_CORRUPT_VTAB;
}
} }
if( bTreeEof ){ if( bTreeEof ){
while( rc==SQLITE_OK && !pNear->bEof ){ while( rc==SQLITE_OK && !pNear->bEof ){

View file

@ -13,7 +13,6 @@
*/ */
#ifndef _FTSINT_H #ifndef _FTSINT_H
#define _FTSINT_H #define _FTSINT_H
/* clang-format off */
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) #if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1 # define NDEBUG 1
@ -38,13 +37,13 @@
/* If not building as part of the core, include sqlite3ext.h. */ /* If not building as part of the core, include sqlite3ext.h. */
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
#include "third_party/sqlite3/sqlite3ext.h" # include "third_party/sqlite3/sqlite3ext.h"
SQLITE_EXTENSION_INIT3 SQLITE_EXTENSION_INIT3
#endif #endif
#include "third_party/sqlite3/fts3_hash.inc"
#include "third_party/sqlite3/fts3_tokenizer.inc"
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
#include "third_party/sqlite3/fts3_tokenizer.h"
#include "third_party/sqlite3/fts3_hash.h"
/* /*
** This constant determines the maximum depth of an FTS expression tree ** This constant determines the maximum depth of an FTS expression tree
@ -135,7 +134,7 @@ SQLITE_EXTENSION_INIT3
** is used for assert() conditions that are true only if it can be ** is used for assert() conditions that are true only if it can be
** guranteed that the database is not corrupt. ** guranteed that the database is not corrupt.
*/ */
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) #ifdef SQLITE_DEBUG
extern int sqlite3_fts3_may_be_corrupt; extern int sqlite3_fts3_may_be_corrupt;
# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x)) # define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x))
#else #else
@ -152,17 +151,18 @@ extern int sqlite3_fts3_may_be_corrupt;
** Macros indicating that conditional expressions are always true or ** Macros indicating that conditional expressions are always true or
** false. ** false.
*/ */
#ifdef SQLITE_COVERAGE_TEST #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(x) (1) # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
# define NEVER(X) (0) #endif
#elif defined(SQLITE_DEBUG) #if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(x) sqlite3Fts3Always((x)!=0) # define ALWAYS(X) (1)
# define NEVER(x) sqlite3Fts3Never((x)!=0) # define NEVER(X) (0)
int sqlite3Fts3Always(int b); #elif !defined(NDEBUG)
int sqlite3Fts3Never(int b); # define ALWAYS(X) ((X)?1:(assert(0),0))
# define NEVER(X) ((X)?(assert(0),1):0)
#else #else
# define ALWAYS(x) (x) # define ALWAYS(X) (X)
# define NEVER(x) (x) # define NEVER(X) (X)
#endif #endif
/* /*
@ -558,7 +558,7 @@ struct Fts3MultiSegReader {
int nAdvance; /* How many seg-readers to advance */ int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */ Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */ char *aBuffer; /* Buffer to merge doclists in */
int nBuffer; /* Allocated size of aBuffer[] in bytes */ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
int iColFilter; /* If >=0, filter for this column */ int iColFilter; /* If >=0, filter for this column */
int bRestart; int bRestart;
@ -621,6 +621,7 @@ void sqlite3Fts3ExprFree(Fts3Expr *);
int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*); int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*);
int sqlite3Fts3InitTerm(sqlite3 *db); int sqlite3Fts3InitTerm(sqlite3 *db);
#endif #endif
void *sqlite3Fts3MallocZero(i64 nByte);
int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int, int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int,
sqlite3_tokenizer_cursor ** sqlite3_tokenizer_cursor **
@ -640,7 +641,7 @@ int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
/* fts3_tokenize_vtab.c */ /* fts3_tokenize_vtab.c */
int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
/* fts3_unicode2.c (functions generated by parsing unicode text files) */ /* fts3_unicode2.c (functions generated by parsing unicode text files) */
#ifndef SQLITE_DISABLE_FTS3_UNICODE #ifndef SQLITE_DISABLE_FTS3_UNICODE

View file

@ -11,8 +11,7 @@
****************************************************************************** ******************************************************************************
** **
*/ */
/* clang-format off */ #include "third_party/sqlite3/fts3Int.h"
#include "third_party/sqlite3/fts3Int.inc"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h" #include "libc/assert.h"
@ -298,6 +297,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM;
memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat);
iCol = 0; iCol = 0;
rc = SQLITE_OK;
while( i<nDoclist ){ while( i<nDoclist ){
sqlite3_int64 v = 0; sqlite3_int64 v = 0;
@ -341,6 +341,10 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
/* State 3. The integer just read is a column number. */ /* State 3. The integer just read is a column number. */
default: assert( eState==3 ); default: assert( eState==3 );
iCol = (int)v; iCol = (int)v;
if( iCol<1 ){
rc = SQLITE_CORRUPT_VTAB;
break;
}
if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM; if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM;
pCsr->aStat[iCol+1].nDoc++; pCsr->aStat[iCol+1].nDoc++;
eState = 2; eState = 2;
@ -349,7 +353,6 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
} }
pCsr->iCol = 0; pCsr->iCol = 0;
rc = SQLITE_OK;
}else{ }else{
pCsr->isEof = 1; pCsr->isEof = 1;
} }
@ -407,6 +410,7 @@ static int fts3auxFilterMethod(
sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3Fts3SegReaderFinish(&pCsr->csr);
sqlite3_free((void *)pCsr->filter.zTerm); sqlite3_free((void *)pCsr->filter.zTerm);
sqlite3_free(pCsr->aStat); sqlite3_free(pCsr->aStat);
sqlite3_free(pCsr->zStop);
memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr);
pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;

View file

@ -11,13 +11,12 @@
****************************************************************************** ******************************************************************************
** **
** This module contains code that implements a parser for fts3 query strings ** This module contains code that implements a parser for fts3 query strings
** (the right-hand argument to the MATCH operator). Because the supported ** (the right-hand argument to the MATCH operator). Because the supported
** syntax is relatively simple, the whole tokenizer/parser system is ** syntax is relatively simple, the whole tokenizer/parser system is
** hand-coded. ** hand-coded.
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* clang-format off */
/* /*
** By default, this module parses the legacy syntax that has been ** By default, this module parses the legacy syntax that has been
@ -123,7 +122,7 @@ static int fts3isspace(char c){
** zero the memory before returning a pointer to it. If unsuccessful, ** zero the memory before returning a pointer to it. If unsuccessful,
** return NULL. ** return NULL.
*/ */
static void *fts3MallocZero(sqlite3_int64 nByte){ void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){
void *pRet = sqlite3_malloc64(nByte); void *pRet = sqlite3_malloc64(nByte);
if( pRet ) memset(pRet, 0, nByte); if( pRet ) memset(pRet, 0, nByte);
return pRet; return pRet;
@ -204,7 +203,7 @@ static int getNextToken(
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition); rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken; nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
pRet = (Fts3Expr *)fts3MallocZero(nByte); pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
if( !pRet ){ if( !pRet ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
@ -459,7 +458,7 @@ static int getNextNode(
if( fts3isspace(cNext) if( fts3isspace(cNext)
|| cNext=='"' || cNext=='(' || cNext==')' || cNext==0 || cNext=='"' || cNext=='(' || cNext==')' || cNext==0
){ ){
pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr)); pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr));
if( !pRet ){ if( !pRet ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -638,7 +637,7 @@ static int fts3ExprParse(
&& p->eType==FTSQUERY_PHRASE && pParse->isNot && p->eType==FTSQUERY_PHRASE && pParse->isNot
){ ){
/* Create an implicit NOT operator. */ /* Create an implicit NOT operator. */
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr));
if( !pNot ){ if( !pNot ){
sqlite3Fts3ExprFree(p); sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
@ -672,7 +671,7 @@ static int fts3ExprParse(
/* Insert an implicit AND operator. */ /* Insert an implicit AND operator. */
Fts3Expr *pAnd; Fts3Expr *pAnd;
assert( pRet && pPrev ); assert( pRet && pPrev );
pAnd = fts3MallocZero(sizeof(Fts3Expr)); pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr));
if( !pAnd ){ if( !pAnd ){
sqlite3Fts3ExprFree(p); sqlite3Fts3ExprFree(p);
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
@ -1108,7 +1107,7 @@ void sqlite3Fts3ExprFree(Fts3Expr *pDel){
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
#include "libc/stdio/stdio.h" #include <stdio.h>
/* /*
** Return a pointer to a buffer containing a text representation of the ** Return a pointer to a buffer containing a text representation of the

View file

@ -13,7 +13,6 @@
** We've modified it slightly to serve as a standalone hash table ** We've modified it slightly to serve as a standalone hash table
** implementation for the full-text indexing module. ** implementation for the full-text indexing module.
*/ */
/* clang-format off */
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
@ -24,13 +23,14 @@
** * The FTS3 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/sqlite3/fts3_hash.inc"
#include "third_party/sqlite3/fts3_hash.h"
/* /*
** Malloc and Free functions ** Malloc and Free functions

View file

@ -16,7 +16,6 @@
*/ */
#ifndef _FTS3_HASH_H_ #ifndef _FTS3_HASH_H_
#define _FTS3_HASH_H_ #define _FTS3_HASH_H_
/* clang-format off */
/* Forward declarations of structures. */ /* Forward declarations of structures. */
typedef struct Fts3Hash Fts3Hash; typedef struct Fts3Hash Fts3Hash;

View file

@ -11,15 +11,14 @@
************************************************************************* *************************************************************************
** This file implements a tokenizer for fts3 based on the ICU library. ** This file implements a tokenizer for fts3 based on the ICU library.
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#ifdef SQLITE_ENABLE_ICU #ifdef SQLITE_ENABLE_ICU
/* clang-format off */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/unicode.h" #include "libc/str/unicode.h"
#include "third_party/sqlite3/fts3_tokenizer.inc" #include "third_party/sqlite3/fts3_tokenizer.h"
typedef struct IcuTokenizer IcuTokenizer; typedef struct IcuTokenizer IcuTokenizer;
typedef struct IcuCursor IcuCursor; typedef struct IcuCursor IcuCursor;

View file

@ -12,7 +12,6 @@
** Implementation of the full-text-search tokenizer that implements ** Implementation of the full-text-search tokenizer that implements
** a Porter stemmer. ** a Porter stemmer.
*/ */
/* clang-format off */
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
@ -23,14 +22,15 @@
** * The FTS3 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/sqlite3/fts3_tokenizer.inc"
#include "third_party/sqlite3/fts3_tokenizer.h"
/* /*
** Class derived from sqlite3_tokenizer ** Class derived from sqlite3_tokenizer
@ -621,7 +621,7 @@ static int porterNext(
if( n>c->nAllocated ){ if( n>c->nAllocated ){
char *pNew; char *pNew;
c->nAllocated = n+20; c->nAllocated = n+20;
pNew = sqlite3_realloc(c->zToken, c->nAllocated); pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
if( !pNew ) return SQLITE_NOMEM; if( !pNew ) return SQLITE_NOMEM;
c->zToken = pNew; c->zToken = pNew;
} }

View file

@ -10,13 +10,16 @@
** **
****************************************************************************** ******************************************************************************
*/ */
/* clang-format off */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/assert.h"
#ifndef SQLITE_AMALGAMATION
typedef sqlite3_int64 i64;
#endif
/* /*
** Characters that may appear in the second argument to matchinfo(). ** Characters that may appear in the second argument to matchinfo().
@ -68,9 +71,9 @@ struct SnippetIter {
struct SnippetPhrase { struct SnippetPhrase {
int nToken; /* Number of tokens in phrase */ int nToken; /* Number of tokens in phrase */
char *pList; /* Pointer to start of phrase position list */ char *pList; /* Pointer to start of phrase position list */
int iHead; /* Next value in position list */ i64 iHead; /* Next value in position list */
char *pHead; /* Position list data following iHead */ char *pHead; /* Position list data following iHead */
int iTail; /* Next value in trailing position list */ i64 iTail; /* Next value in trailing position list */
char *pTail; /* Position list data following iTail */ char *pTail; /* Position list data following iTail */
}; };
@ -135,9 +138,8 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
+ sizeof(MatchinfoBuffer); + sizeof(MatchinfoBuffer);
sqlite3_int64 nStr = strlen(zMatchinfo); sqlite3_int64 nStr = strlen(zMatchinfo);
pRet = sqlite3_malloc64(nByte + nStr+1); pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
if( pRet ){ if( pRet ){
memset(pRet, 0, nByte);
pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
+ sizeof(u32)*((int)nElem+1); + sizeof(u32)*((int)nElem+1);
@ -235,7 +237,7 @@ void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
** After it returns, *piPos contains the value of the next element of the ** After it returns, *piPos contains the value of the next element of the
** list and *pp is advanced to the following varint. ** list and *pp is advanced to the following varint.
*/ */
static void fts3GetDeltaPosition(char **pp, int *piPos){ static void fts3GetDeltaPosition(char **pp, i64 *piPos){
int iVal; int iVal;
*pp += fts3GetVarint32(*pp, &iVal); *pp += fts3GetVarint32(*pp, &iVal);
*piPos += (iVal-2); *piPos += (iVal-2);
@ -344,10 +346,10 @@ static int fts3ExprPhraseCount(Fts3Expr *pExpr){
** arguments so that it points to the first element with a value greater ** arguments so that it points to the first element with a value greater
** than or equal to parameter iNext. ** than or equal to parameter iNext.
*/ */
static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){ static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){
char *pIter = *ppIter; char *pIter = *ppIter;
if( pIter ){ if( pIter ){
int iIter = *piIter; i64 iIter = *piIter;
while( iIter<iNext ){ while( iIter<iNext ){
if( 0==(*pIter & 0xFE) ){ if( 0==(*pIter & 0xFE) ){
@ -430,7 +432,7 @@ static void fts3SnippetDetails(
SnippetPhrase *pPhrase = &pIter->aPhrase[i]; SnippetPhrase *pPhrase = &pIter->aPhrase[i];
if( pPhrase->pTail ){ if( pPhrase->pTail ){
char *pCsr = pPhrase->pTail; char *pCsr = pPhrase->pTail;
int iCsr = pPhrase->iTail; i64 iCsr = pPhrase->iTail;
while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){
int j; int j;
@ -476,7 +478,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr); rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr);
assert( rc==SQLITE_OK || pCsr==0 ); assert( rc==SQLITE_OK || pCsr==0 );
if( pCsr ){ if( pCsr ){
int iFirst = 0; i64 iFirst = 0;
pPhrase->pList = pCsr; pPhrase->pList = pCsr;
fts3GetDeltaPosition(&pCsr, &iFirst); fts3GetDeltaPosition(&pCsr, &iFirst);
if( iFirst<0 ){ if( iFirst<0 ){
@ -541,11 +543,10 @@ static int fts3BestSnippet(
** the required space using malloc(). ** the required space using malloc().
*/ */
nByte = sizeof(SnippetPhrase) * nList; nByte = sizeof(SnippetPhrase) * nList;
sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte); sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte);
if( !sIter.aPhrase ){ if( !sIter.aPhrase ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
memset(sIter.aPhrase, 0, nByte);
/* Initialize the contents of the SnippetIter object. Then iterate through /* Initialize the contents of the SnippetIter object. Then iterate through
** the set of phrases in the expression to populate the aPhrase[] array. ** the set of phrases in the expression to populate the aPhrase[] array.
@ -1109,10 +1110,12 @@ static int fts3MatchinfoLcsCb(
** position list for the next column. ** position list for the next column.
*/ */
static int fts3LcsIteratorAdvance(LcsIterator *pIter){ static int fts3LcsIteratorAdvance(LcsIterator *pIter){
char *pRead = pIter->pRead; char *pRead;
sqlite3_int64 iRead; sqlite3_int64 iRead;
int rc = 0; int rc = 0;
if( NEVER(pIter==0) ) return 1;
pRead = pIter->pRead;
pRead += sqlite3Fts3GetVarint(pRead, &iRead); pRead += sqlite3Fts3GetVarint(pRead, &iRead);
if( iRead==0 || iRead==1 ){ if( iRead==0 || iRead==1 ){
pRead = 0; pRead = 0;
@ -1146,9 +1149,8 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
/* Allocate and populate the array of LcsIterator objects. The array /* Allocate and populate the array of LcsIterator objects. The array
** contains one element for each matchable phrase in the query. ** contains one element for each matchable phrase in the query.
**/ **/
aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase); aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase);
if( !aIter ) return SQLITE_NOMEM; if( !aIter ) return SQLITE_NOMEM;
memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
for(i=0; i<pInfo->nPhrase; i++){ for(i=0; i<pInfo->nPhrase; i++){
@ -1540,8 +1542,8 @@ typedef struct TermOffsetCtx TermOffsetCtx;
struct TermOffset { struct TermOffset {
char *pList; /* Position-list */ char *pList; /* Position-list */
int iPos; /* Position just read from pList */ i64 iPos; /* Position just read from pList */
int iOff; /* Offset of this term from read positions */ i64 iOff; /* Offset of this term from read positions */
}; };
struct TermOffsetCtx { struct TermOffsetCtx {
@ -1560,7 +1562,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
int nTerm; /* Number of tokens in phrase */ int nTerm; /* Number of tokens in phrase */
int iTerm; /* For looping through nTerm phrase terms */ int iTerm; /* For looping through nTerm phrase terms */
char *pList; /* Pointer to position list for phrase */ char *pList; /* Pointer to position list for phrase */
int iPos = 0; /* First position in position-list */ i64 iPos = 0; /* First position in position-list */
int rc; int rc;
UNUSED_PARAMETER(iPhrase); UNUSED_PARAMETER(iPhrase);
@ -1609,7 +1611,7 @@ void sqlite3Fts3Offsets(
if( rc!=SQLITE_OK ) goto offsets_out; if( rc!=SQLITE_OK ) goto offsets_out;
/* Allocate the array of TermOffset iterators. */ /* Allocate the array of TermOffset iterators. */
sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken); sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken);
if( 0==sCtx.aTerm ){ if( 0==sCtx.aTerm ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
goto offsets_out; goto offsets_out;
@ -1630,13 +1632,13 @@ void sqlite3Fts3Offsets(
const char *zDoc; const char *zDoc;
int nDoc; int nDoc;
/* Initialize the contents of sCtx.aTerm[] for column iCol. There is /* Initialize the contents of sCtx.aTerm[] for column iCol. This
** no way that this operation can fail, so the return code from ** operation may fail if the database contains corrupt records.
** fts3ExprIterate() can be discarded.
*/ */
sCtx.iCol = iCol; sCtx.iCol = iCol;
sCtx.iTerm = 0; sCtx.iTerm = 0;
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
if( rc!=SQLITE_OK ) goto offsets_out;
/* Retreive the text stored in column iCol. If an SQL NULL is stored /* Retreive the text stored in column iCol. If an SQL NULL is stored
** in column iCol, jump immediately to the next iteration of the loop. ** in column iCol, jump immediately to the next iteration of the loop.

View file

@ -25,8 +25,8 @@
** **
** input = <string> ** input = <string>
** **
** The virtual table module tokenizes this <string>, using the FTS3 ** The virtual table module tokenizes this <string>, using the FTS3
** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE ** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
** statement and returns one row for each token in the result. With ** statement and returns one row for each token in the result. With
** fields set as follows: ** fields set as follows:
** **
@ -38,12 +38,11 @@
** pos: Token offset of token within input. ** pos: Token offset of token within input.
** **
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/* clang-format off */
#include "libc/assert.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/assert.h"
typedef struct Fts3tokTable Fts3tokTable; typedef struct Fts3tokTable Fts3tokTable;
typedef struct Fts3tokCursor Fts3tokCursor; typedef struct Fts3tokCursor Fts3tokCursor;
@ -421,7 +420,7 @@ static int fts3tokRowidMethod(
** Register the fts3tok module with database connection db. Return SQLITE_OK ** Register the fts3tok module with database connection db. Return SQLITE_OK
** if successful or an error code if sqlite3_create_module() fails. ** if successful or an error code if sqlite3_create_module() fails.
*/ */
int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){
static const sqlite3_module fts3tok_module = { static const sqlite3_module fts3tok_module = {
0, /* iVersion */ 0, /* iVersion */
fts3tokConnectMethod, /* xCreate */ fts3tokConnectMethod, /* xCreate */
@ -450,7 +449,9 @@ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
}; };
int rc; /* Return code */ int rc; /* Return code */
rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); rc = sqlite3_create_module_v2(
db, "fts3tokenize", &fts3tok_module, (void*)pHash, xDestroy
);
return rc; return rc;
} }

View file

@ -13,7 +13,6 @@
** This is part of an SQLite module implementing full-text search. ** This is part of an SQLite module implementing full-text search.
** This particular file implements the generic tokenizer interface. ** This particular file implements the generic tokenizer interface.
*/ */
/* clang-format off */
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
@ -24,11 +23,11 @@
** * The FTS3 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/assert.h"
/* /*
** Return true if the two-argument version of fts3_tokenizer() ** Return true if the two-argument version of fts3_tokenizer()
@ -226,7 +225,13 @@ int sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
#include "libc/str/str.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <string.h>
/* /*
** Implementation of a special SQL scalar function for testing tokenizers ** Implementation of a special SQL scalar function for testing tokenizers

View file

@ -19,7 +19,6 @@
*/ */
#ifndef _FTS3_TOKENIZER_H_ #ifndef _FTS3_TOKENIZER_H_
#define _FTS3_TOKENIZER_H_ #define _FTS3_TOKENIZER_H_
/* clang-format off */
/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time.
** If tokenizers are to be allowed to call sqlite3_*() functions, then ** If tokenizers are to be allowed to call sqlite3_*() functions, then

View file

@ -12,7 +12,6 @@
** **
** Implementation of the "simple" full-text-search tokenizer. ** Implementation of the "simple" full-text-search tokenizer.
*/ */
/* clang-format off */
/* /*
** The code in this file is only compiled if: ** The code in this file is only compiled if:
@ -23,14 +22,15 @@
** * The FTS3 module is being built into the core of ** * The FTS3 module is being built into the core of
** SQLite (in which case SQLITE_ENABLE_FTS3 is defined). ** SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
*/ */
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/sqlite3/fts3_tokenizer.inc"
#include "third_party/sqlite3/fts3_tokenizer.h"
typedef struct simple_tokenizer { typedef struct simple_tokenizer {
sqlite3_tokenizer base; sqlite3_tokenizer base;
@ -185,7 +185,7 @@ static int simpleNext(
if( n>c->nTokenAllocated ){ if( n>c->nTokenAllocated ){
char *pNew; char *pNew;
c->nTokenAllocated = n+20; c->nTokenAllocated = n+20;
pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM; if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew; c->pToken = pNew;
} }

View file

@ -12,18 +12,18 @@
** **
** Implementation of the "unicode" full-text-search tokenizer. ** Implementation of the "unicode" full-text-search tokenizer.
*/ */
/* clang-format off */
#ifndef SQLITE_DISABLE_FTS3_UNICODE #ifndef SQLITE_DISABLE_FTS3_UNICODE
#include "third_party/sqlite3/fts3Int.inc" #include "third_party/sqlite3/fts3Int.h"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/sqlite3/fts3_tokenizer.inc"
#include "third_party/sqlite3/fts3_tokenizer.h"
/* /*
** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied ** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied

View file

@ -10,7 +10,6 @@
** **
****************************************************************************** ******************************************************************************
*/ */
/* clang-format off */
/* /*
** DO NOT EDIT THIS MACHINE GENERATED FILE. ** DO NOT EDIT THIS MACHINE GENERATED FILE.

View file

@ -13,17 +13,16 @@
** This file is part of the SQLite FTS3 extension module. Specifically, ** This file is part of the SQLite FTS3 extension module. Specifically,
** this file contains code to insert, update and delete rows from FTS3 ** this file contains code to insert, update and delete rows from FTS3
** tables. It also contains code to merge FTS3 b-tree segments. Some ** tables. It also contains code to merge FTS3 b-tree segments. Some
** of the sub-routines used to merge segments are also used by the query ** of the sub-routines used to merge segments are also used by the query
** code in fts3.c. ** code in fts3.c.
*/ */
/* clang-format off */
#include "libc/fmt/conv.h" #include "third_party/sqlite3/fts3Int.h"
#include "third_party/sqlite3/fts3Int.inc"
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
#include "libc/mem/alg.h"
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/fmt/conv.h"
#include "libc/mem/alg.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -652,7 +651,7 @@ static int fts3PendingListAppendVarint(
/* Allocate or grow the PendingList as required. */ /* Allocate or grow the PendingList as required. */
if( !p ){ if( !p ){
p = sqlite3_malloc(sizeof(*p) + 100); p = sqlite3_malloc64(sizeof(*p) + 100);
if( !p ){ if( !p ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -661,14 +660,14 @@ static int fts3PendingListAppendVarint(
p->nData = 0; p->nData = 0;
} }
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
int nNew = p->nSpace * 2; i64 nNew = p->nSpace * 2;
p = sqlite3_realloc(p, sizeof(*p) + nNew); p = sqlite3_realloc64(p, sizeof(*p) + nNew);
if( !p ){ if( !p ){
sqlite3_free(*pp); sqlite3_free(*pp);
*pp = 0; *pp = 0;
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
p->nSpace = nNew; p->nSpace = (int)nNew;
p->aData = (char *)&p[1]; p->aData = (char *)&p[1];
} }
@ -1225,7 +1224,7 @@ int sqlite3Fts3ReadBlock(
int nByte = sqlite3_blob_bytes(p->pSegments); int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte; *pnBlob = nByte;
if( paBlob ){ if( paBlob ){
char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
if( !aByte ){ if( !aByte ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
}else{ }else{
@ -1338,9 +1337,19 @@ static int fts3SegReaderNext(
char *aCopy; char *aCopy;
PendingList *pList = (PendingList *)fts3HashData(pElem); PendingList *pList = (PendingList *)fts3HashData(pElem);
int nCopy = pList->nData+1; int nCopy = pList->nData+1;
pReader->zTerm = (char *)fts3HashKey(pElem);
pReader->nTerm = fts3HashKeysize(pElem); int nTerm = fts3HashKeysize(pElem);
aCopy = (char*)sqlite3_malloc(nCopy); if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
if( !pReader->zTerm ) return SQLITE_NOMEM;
pReader->nTermAlloc = (nTerm+1)*2;
}
memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm);
pReader->zTerm[nTerm] = '\0';
pReader->nTerm = nTerm;
aCopy = (char*)sqlite3_malloc64(nCopy);
if( !aCopy ) return SQLITE_NOMEM; if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy); memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy; pReader->nNode = pReader->nDoclist = nCopy;
@ -1592,9 +1601,7 @@ int sqlite3Fts3MsrOvfl(
*/ */
void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
if( pReader ){ if( pReader ){
if( !fts3SegReaderIsPending(pReader) ){ sqlite3_free(pReader->zTerm);
sqlite3_free(pReader->zTerm);
}
if( !fts3SegReaderIsRootOnly(pReader) ){ if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode); sqlite3_free(pReader->aNode);
} }
@ -1629,7 +1636,7 @@ int sqlite3Fts3SegReaderNew(
nExtra = nRoot + FTS3_NODE_PADDING; nExtra = nRoot + FTS3_NODE_PADDING;
} }
pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){ if( !pReader ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -1721,7 +1728,7 @@ int sqlite3Fts3SegReaderPending(
if( nElem==nAlloc ){ if( nElem==nAlloc ){
Fts3HashElem **aElem2; Fts3HashElem **aElem2;
nAlloc += 16; nAlloc += 16;
aElem2 = (Fts3HashElem **)sqlite3_realloc( aElem2 = (Fts3HashElem **)sqlite3_realloc64(
aElem, nAlloc*sizeof(Fts3HashElem *) aElem, nAlloc*sizeof(Fts3HashElem *)
); );
if( !aElem2 ){ if( !aElem2 ){
@ -1810,7 +1817,7 @@ static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
if( rc==0 ){ if( rc==0 ){
rc = pRhs->iIdx - pLhs->iIdx; rc = pRhs->iIdx - pLhs->iIdx;
} }
assert( rc!=0 ); assert_fts3_nc( rc!=0 );
return rc; return rc;
} }
@ -2006,8 +2013,8 @@ static int fts3PrefixCompress(
int nNext /* Size of buffer zNext in bytes */ int nNext /* Size of buffer zNext in bytes */
){ ){
int n; int n;
UNUSED_PARAMETER(nNext); for(n=0; n<nPrev && n<nNext && zPrev[n]==zNext[n]; n++);
for(n=0; n<nPrev && zPrev[n]==zNext[n]; n++); assert_fts3_nc( n<nNext );
return n; return n;
} }
@ -2055,7 +2062,7 @@ static int fts3NodeAddTerm(
** this is not expected to be a serious problem. ** this is not expected to be a serious problem.
*/ */
assert( pTree->aData==(char *)&pTree[1] ); assert( pTree->aData==(char *)&pTree[1] );
pTree->aData = (char *)sqlite3_malloc(nReq); pTree->aData = (char *)sqlite3_malloc64(nReq);
if( !pTree->aData ){ if( !pTree->aData ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -2073,7 +2080,7 @@ static int fts3NodeAddTerm(
if( isCopyTerm ){ if( isCopyTerm ){
if( pTree->nMalloc<nTerm ){ if( pTree->nMalloc<nTerm ){
char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2); char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
if( !zNew ){ if( !zNew ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -2099,7 +2106,7 @@ static int fts3NodeAddTerm(
** now. Instead, the term is inserted into the parent of pTree. If pTree ** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here. ** has no parent, one is created here.
*/ */
pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
if( !pNew ){ if( !pNew ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -2237,7 +2244,7 @@ static int fts3SegWriterAdd(
){ ){
int nPrefix; /* Size of term prefix in bytes */ int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */ int nSuffix; /* Size of term suffix in bytes */
int nReq; /* Number of bytes required on leaf page */ i64 nReq; /* Number of bytes required on leaf page */
int nData; int nData;
SegmentWriter *pWriter = *ppWriter; SegmentWriter *pWriter = *ppWriter;
@ -2246,13 +2253,13 @@ static int fts3SegWriterAdd(
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
/* Allocate the SegmentWriter structure */ /* Allocate the SegmentWriter structure */
pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
if( !pWriter ) return SQLITE_NOMEM; if( !pWriter ) return SQLITE_NOMEM;
memset(pWriter, 0, sizeof(SegmentWriter)); memset(pWriter, 0, sizeof(SegmentWriter));
*ppWriter = pWriter; *ppWriter = pWriter;
/* Allocate a buffer in which to accumulate data */ /* Allocate a buffer in which to accumulate data */
pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
if( !pWriter->aData ) return SQLITE_NOMEM; if( !pWriter->aData ) return SQLITE_NOMEM;
pWriter->nSize = p->nNodeSize; pWriter->nSize = p->nNodeSize;
@ -2327,7 +2334,7 @@ static int fts3SegWriterAdd(
** the buffer to make it large enough. ** the buffer to make it large enough.
*/ */
if( nReq>pWriter->nSize ){ if( nReq>pWriter->nSize ){
char *aNew = sqlite3_realloc(pWriter->aData, nReq); char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
if( !aNew ) return SQLITE_NOMEM; if( !aNew ) return SQLITE_NOMEM;
pWriter->aData = aNew; pWriter->aData = aNew;
pWriter->nSize = nReq; pWriter->nSize = nReq;
@ -2352,7 +2359,7 @@ static int fts3SegWriterAdd(
*/ */
if( isCopyTerm ){ if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){ if( nTerm>pWriter->nMalloc ){
char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
if( !zNew ){ if( !zNew ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -2660,12 +2667,12 @@ static void fts3ColumnFilter(
static int fts3MsrBufferData( static int fts3MsrBufferData(
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
char *pList, char *pList,
int nList i64 nList
){ ){
if( nList>pMsr->nBuffer ){ if( nList>pMsr->nBuffer ){
char *pNew; char *pNew;
pMsr->nBuffer = nList*2; pMsr->nBuffer = nList*2;
pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
if( !pNew ) return SQLITE_NOMEM; if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew; pMsr->aBuffer = pNew;
} }
@ -2721,7 +2728,7 @@ int sqlite3Fts3MsrIncrNext(
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pMsr, pList, nList+1); rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
pList = pMsr->aBuffer; pList = pMsr->aBuffer;
@ -2858,11 +2865,11 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK; return SQLITE_OK;
} }
static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
if( nReq>pCsr->nBuffer ){ if( nReq>pCsr->nBuffer ){
char *aNew; char *aNew;
pCsr->nBuffer = nReq*2; pCsr->nBuffer = nReq*2;
aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){ if( !aNew ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
@ -2953,7 +2960,8 @@ int sqlite3Fts3SegReaderStep(
){ ){
pCsr->nDoclist = apSegment[0]->nDoclist; pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){ if( fts3SegReaderIsPending(apSegment[0]) ){
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
(i64)pCsr->nDoclist);
pCsr->aDoclist = pCsr->aBuffer; pCsr->aDoclist = pCsr->aBuffer;
}else{ }else{
pCsr->aDoclist = apSegment[0]->aDoclist; pCsr->aDoclist = apSegment[0]->aDoclist;
@ -3006,7 +3014,8 @@ int sqlite3Fts3SegReaderStep(
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist); rc = fts3GrowSegReaderBuffer(pCsr,
(i64)nByte+nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc; if( rc ) return rc;
if( isFirst ){ if( isFirst ){
@ -3032,7 +3041,7 @@ int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp); fts3SegReaderSort(apSegment, nMerge, j, xCmp);
} }
if( nDoclist>0 ){ if( nDoclist>0 ){
rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc; if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer; pCsr->aDoclist = pCsr->aBuffer;
@ -3745,7 +3754,7 @@ struct NodeReader {
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin; int nAlloc = nMin;
char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
if( a ){ if( a ){
pBlob->nAlloc = nAlloc; pBlob->nAlloc = nAlloc;
pBlob->a = a; pBlob->a = a;
@ -3786,7 +3795,7 @@ static int nodeReaderNext(NodeReader *p){
return FTS_CORRUPT_VTAB; return FTS_CORRUPT_VTAB;
} }
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix); memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
p->term.n = nPrefix+nSuffix; p->term.n = nPrefix+nSuffix;
p->iOff += nSuffix; p->iOff += nSuffix;
@ -3894,6 +3903,8 @@ static int fts3IncrmergePush(
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix);
} }
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix);
assert( nPrefix+nSuffix<=nTerm );
assert( nPrefix>=0 );
memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix);
pBlk->n += nSuffix; pBlk->n += nSuffix;
@ -4016,6 +4027,7 @@ static int fts3IncrmergeAppend(
pLeaf = &pWriter->aNodeWriter[0]; pLeaf = &pWriter->aNodeWriter[0];
nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm);
nSuffix = nTerm - nPrefix; nSuffix = nTerm - nPrefix;
if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace = sqlite3Fts3VarintLen(nPrefix);
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
@ -4180,7 +4192,11 @@ static int fts3TermCmp(
int nCmp = MIN(nLhs, nRhs); int nCmp = MIN(nLhs, nRhs);
int res; int res;
res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0); if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){
res = memcmp(zLhs, zRhs, nCmp);
}else{
res = 0;
}
if( res==0 ) res = nLhs - nRhs; if( res==0 ) res = nLhs - nRhs;
return res; return res;
@ -4535,7 +4551,7 @@ static int fts3RepackSegdirLevel(
if( nIdx>=nAlloc ){ if( nIdx>=nAlloc ){
int *aNew; int *aNew;
nAlloc += 16; nAlloc += 16;
aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
if( !aNew ){ if( !aNew ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
break; break;
@ -4824,7 +4840,7 @@ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
if( aHint ){ if( aHint ){
blobGrowBuffer(pHint, nHint, &rc); blobGrowBuffer(pHint, nHint, &rc);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
memcpy(pHint->a, aHint, nHint); if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint);
pHint->n = nHint; pHint->n = nHint;
} }
} }
@ -4909,7 +4925,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* Allocate space for the cursor, filter and writer objects */ /* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
if( !pWriter ) return SQLITE_NOMEM; if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1]; pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1]; pCsr = (Fts3MultiSegReader *)&pFilter[1];
@ -5545,7 +5561,7 @@ int sqlite3Fts3DeferredTokenList(
return SQLITE_OK; return SQLITE_OK;
} }
pRet = (char *)sqlite3_malloc(p->pList->nData); pRet = (char *)sqlite3_malloc64(p->pList->nData);
if( !pRet ) return SQLITE_NOMEM; if( !pRet ) return SQLITE_NOMEM;
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
@ -5565,7 +5581,7 @@ int sqlite3Fts3DeferToken(
int iCol /* Column that token must appear in (or -1) */ int iCol /* Column that token must appear in (or -1) */
){ ){
Fts3DeferredToken *pDeferred; Fts3DeferredToken *pDeferred;
pDeferred = sqlite3_malloc(sizeof(*pDeferred)); pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
if( !pDeferred ){ if( !pDeferred ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }

File diff suppressed because it is too large Load diff

View file

@ -10,13 +10,12 @@
** **
****************************************************************************** ******************************************************************************
** **
** Interfaces to extend FTS5. Using the interfaces defined in this file, ** Interfaces to extend FTS5. Using the interfaces defined in this file,
** FTS5 may be extended with: ** FTS5 may be extended with:
** **
** * custom tokenizers, and ** * custom tokenizers, and
** * custom auxiliary functions. ** * custom auxiliary functions.
*/ */
/* clang-format off */
#ifndef _FTS5_H #ifndef _FTS5_H

View file

@ -15,7 +15,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#ifndef SQLITE_OMIT_FLOATING_POINT #ifndef SQLITE_OMIT_FLOATING_POINT
#include "libc/math.h" #include "libc/math.h"
#endif #endif
@ -98,6 +98,18 @@ static void typeofFunc(
sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC); sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
} }
/* subtype(X)
**
** Return the subtype of X
*/
static void subtypeFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
UNUSED_PARAMETER(argc);
sqlite3_result_int(context, sqlite3_value_subtype(argv[0]));
}
/* /*
** Implementation of the length() function ** Implementation of the length() function
@ -259,7 +271,7 @@ endInstrOOM:
} }
/* /*
** Implementation of the printf() function. ** Implementation of the printf() (a.k.a. format()) SQL function.
*/ */
static void printfFunc( static void printfFunc(
sqlite3_context *context, sqlite3_context *context,
@ -572,9 +584,9 @@ static void last_insert_rowid(
/* /*
** Implementation of the changes() SQL function. ** Implementation of the changes() SQL function.
** **
** IMP: R-62073-11209 The changes() SQL function is a wrapper ** IMP: R-32760-32347 The changes() SQL function is a wrapper
** around the sqlite3_changes() C/C++ function and hence follows the same ** around the sqlite3_changes64() C/C++ function and hence follows the
** rules for counting changes. ** same rules for counting changes.
*/ */
static void changes( static void changes(
sqlite3_context *context, sqlite3_context *context,
@ -583,12 +595,12 @@ static void changes(
){ ){
sqlite3 *db = sqlite3_context_db_handle(context); sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2); UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_result_int(context, sqlite3_changes(db)); sqlite3_result_int64(context, sqlite3_changes64(db));
} }
/* /*
** Implementation of the total_changes() SQL function. The return value is ** Implementation of the total_changes() SQL function. The return value is
** the same as the sqlite3_total_changes() API function. ** the same as the sqlite3_total_changes64() API function.
*/ */
static void total_changes( static void total_changes(
sqlite3_context *context, sqlite3_context *context,
@ -597,9 +609,9 @@ static void total_changes(
){ ){
sqlite3 *db = sqlite3_context_db_handle(context); sqlite3 *db = sqlite3_context_db_handle(context);
UNUSED_PARAMETER2(NotUsed, NotUsed2); UNUSED_PARAMETER2(NotUsed, NotUsed2);
/* IMP: R-52756-41993 This function is a wrapper around the /* IMP: R-11217-42568 This function is a wrapper around the
** sqlite3_total_changes() C/C++ interface. */ ** sqlite3_total_changes64() C/C++ interface. */
sqlite3_result_int(context, sqlite3_total_changes(db)); sqlite3_result_int64(context, sqlite3_total_changes64(db));
} }
/* /*
@ -729,7 +741,7 @@ static int patternCompare(
** c but in the other case and search the input string for either ** c but in the other case and search the input string for either
** c or cx. ** c or cx.
*/ */
if( c<=0x80 ){ if( c<0x80 ){
char zStop[3]; char zStop[3];
int bMatch; int bMatch;
if( noCase ){ if( noCase ){
@ -812,7 +824,13 @@ static int patternCompare(
** non-zero if there is no match. ** non-zero if there is no match.
*/ */
int sqlite3_strglob(const char *zGlobPattern, const char *zString){ int sqlite3_strglob(const char *zGlobPattern, const char *zString){
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); if( zString==0 ){
return zGlobPattern!=0;
}else if( zGlobPattern==0 ){
return 1;
}else {
return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
}
} }
/* /*
@ -820,7 +838,13 @@ int sqlite3_strglob(const char *zGlobPattern, const char *zString){
** a miss - like strcmp(). ** a miss - like strcmp().
*/ */
int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); if( zStr==0 ){
return zPattern!=0;
}else if( zPattern==0 ){
return 1;
}else{
return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
}
} }
/* /*
@ -1028,39 +1052,42 @@ static const char hexdigits[] = {
}; };
/* /*
** Implementation of the QUOTE() function. This function takes a single ** Append to pStr text that is the SQL literal representation of the
** argument. If the argument is numeric, the return value is the same as ** value contained in pValue.
** the argument. If the argument is NULL, the return value is the string
** "NULL". Otherwise, the argument is enclosed in single quotes with
** single-quote escapes.
*/ */
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
assert( argc==1 ); /* As currently implemented, the string must be initially empty.
UNUSED_PARAMETER(argc); ** we might relax this requirement in the future, but that will
switch( sqlite3_value_type(argv[0]) ){ ** require enhancements to the implementation. */
assert( pStr!=0 && pStr->nChar==0 );
switch( sqlite3_value_type(pValue) ){
case SQLITE_FLOAT: { case SQLITE_FLOAT: {
double r1, r2; double r1, r2;
char zBuf[50]; const char *zVal;
r1 = sqlite3_value_double(argv[0]); r1 = sqlite3_value_double(pValue);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1); sqlite3_str_appendf(pStr, "%!.15g", r1);
sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8); zVal = sqlite3_str_value(pStr);
if( r1!=r2 ){ if( zVal ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1); sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
if( r1!=r2 ){
sqlite3_str_reset(pStr);
sqlite3_str_appendf(pStr, "%!.20e", r1);
}
} }
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
break; break;
} }
case SQLITE_INTEGER: { case SQLITE_INTEGER: {
sqlite3_result_value(context, argv[0]); sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue));
break; break;
} }
case SQLITE_BLOB: { case SQLITE_BLOB: {
char *zText = 0; char const *zBlob = sqlite3_value_blob(pValue);
char const *zBlob = sqlite3_value_blob(argv[0]); int nBlob = sqlite3_value_bytes(pValue);
int nBlob = sqlite3_value_bytes(argv[0]); assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */
assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4);
zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4); if( pStr->accError==0 ){
if( zText ){ char *zText = pStr->zText;
int i; int i;
for(i=0; i<nBlob; i++){ for(i=0; i<nBlob; i++){
zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
@ -1070,42 +1097,48 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
zText[(nBlob*2)+3] = '\0'; zText[(nBlob*2)+3] = '\0';
zText[0] = 'X'; zText[0] = 'X';
zText[1] = '\''; zText[1] = '\'';
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); pStr->nChar = nBlob*2 + 3;
sqlite3_free(zText);
} }
break; break;
} }
case SQLITE_TEXT: { case SQLITE_TEXT: {
int i,j; const unsigned char *zArg = sqlite3_value_text(pValue);
u64 n; sqlite3_str_appendf(pStr, "%Q", zArg);
const unsigned char *zArg = sqlite3_value_text(argv[0]);
char *z;
if( zArg==0 ) return;
for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
z = contextMalloc(context, ((i64)i)+((i64)n)+3);
if( z ){
z[0] = '\'';
for(i=0, j=1; zArg[i]; i++){
z[j++] = zArg[i];
if( zArg[i]=='\'' ){
z[j++] = '\'';
}
}
z[j++] = '\'';
z[j] = 0;
sqlite3_result_text(context, z, j, sqlite3_free);
}
break; break;
} }
default: { default: {
assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); assert( sqlite3_value_type(pValue)==SQLITE_NULL );
sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); sqlite3_str_append(pStr, "NULL", 4);
break; break;
} }
} }
} }
/*
** Implementation of the QUOTE() function.
**
** The quote(X) function returns the text of an SQL literal which is the
** value of its argument suitable for inclusion into an SQL statement.
** Strings are surrounded by single-quotes with escapes on interior quotes
** as needed. BLOBs are encoded as hexadecimal literals. Strings with
** embedded NUL characters cannot be represented as string literals in SQL
** and hence the returned string literal is truncated prior to the first NUL.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_str str;
sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==1 );
UNUSED_PARAMETER(argc);
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
sqlite3QuoteValue(&str,argv[0]);
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
SQLITE_DYNAMIC);
if( str.accError!=SQLITE_OK ){
sqlite3_result_null(context);
sqlite3_result_error_code(context, str.accError);
}
}
/* /*
** The unicode() function. Return the integer unicode code-point value ** The unicode() function. Return the integer unicode code-point value
** for the first character of the input string. ** for the first character of the input string.
@ -1317,10 +1350,10 @@ static void trimFunc(
){ ){
const unsigned char *zIn; /* Input string */ const unsigned char *zIn; /* Input string */
const unsigned char *zCharSet; /* Set of characters to trim */ const unsigned char *zCharSet; /* Set of characters to trim */
int nIn; /* Number of bytes in input */ unsigned int nIn; /* Number of bytes in input */
int flags; /* 1: trimleft 2: trimright 3: trim */ int flags; /* 1: trimleft 2: trimright 3: trim */
int i; /* Loop counter */ int i; /* Loop counter */
unsigned char *aLen = 0; /* Length of each character in zCharSet */ unsigned int *aLen = 0; /* Length of each character in zCharSet */
unsigned char **azChar = 0; /* Individual characters in zCharSet */ unsigned char **azChar = 0; /* Individual characters in zCharSet */
int nChar; /* Number of characters in zCharSet */ int nChar; /* Number of characters in zCharSet */
@ -1329,13 +1362,13 @@ static void trimFunc(
} }
zIn = sqlite3_value_text(argv[0]); zIn = sqlite3_value_text(argv[0]);
if( zIn==0 ) return; if( zIn==0 ) return;
nIn = sqlite3_value_bytes(argv[0]); nIn = (unsigned)sqlite3_value_bytes(argv[0]);
assert( zIn==sqlite3_value_text(argv[0]) ); assert( zIn==sqlite3_value_text(argv[0]) );
if( argc==1 ){ if( argc==1 ){
static const unsigned char lenOne[] = { 1 }; static const unsigned lenOne[] = { 1 };
static unsigned char * const azOne[] = { (u8*)" " }; static unsigned char * const azOne[] = { (u8*)" " };
nChar = 1; nChar = 1;
aLen = (u8*)lenOne; aLen = (unsigned*)lenOne;
azChar = (unsigned char **)azOne; azChar = (unsigned char **)azOne;
zCharSet = 0; zCharSet = 0;
}else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){ }else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
@ -1346,15 +1379,16 @@ static void trimFunc(
SQLITE_SKIP_UTF8(z); SQLITE_SKIP_UTF8(z);
} }
if( nChar>0 ){ if( nChar>0 ){
azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1)); azChar = contextMalloc(context,
((i64)nChar)*(sizeof(char*)+sizeof(unsigned)));
if( azChar==0 ){ if( azChar==0 ){
return; return;
} }
aLen = (unsigned char*)&azChar[nChar]; aLen = (unsigned*)&azChar[nChar];
for(z=zCharSet, nChar=0; *z; nChar++){ for(z=zCharSet, nChar=0; *z; nChar++){
azChar[nChar] = (unsigned char *)z; azChar[nChar] = (unsigned char *)z;
SQLITE_SKIP_UTF8(z); SQLITE_SKIP_UTF8(z);
aLen[nChar] = (u8)(z - azChar[nChar]); aLen[nChar] = (unsigned)(z - azChar[nChar]);
} }
} }
} }
@ -1362,7 +1396,7 @@ static void trimFunc(
flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context));
if( flags & 1 ){ if( flags & 1 ){
while( nIn>0 ){ while( nIn>0 ){
int len = 0; unsigned int len = 0;
for(i=0; i<nChar; i++){ for(i=0; i<nChar; i++){
len = aLen[i]; len = aLen[i];
if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break; if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break;
@ -1374,7 +1408,7 @@ static void trimFunc(
} }
if( flags & 2 ){ if( flags & 2 ){
while( nIn>0 ){ while( nIn>0 ){
int len = 0; unsigned int len = 0;
for(i=0; i<nChar; i++){ for(i=0; i<nChar; i++){
len = aLen[i]; len = aLen[i];
if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break; if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break;
@ -1715,97 +1749,167 @@ static void minMaxFinalize(sqlite3_context *context){
/* /*
** group_concat(EXPR, ?SEPARATOR?) ** group_concat(EXPR, ?SEPARATOR?)
**
** The SEPARATOR goes before the EXPR string. This is tragic. The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR. And the order is undocumented,
** so we could change it, in theory. But the old behavior has been
** around for so long that we dare not, for fear of breaking something.
*/ */
typedef struct {
StrAccum str; /* The accumulated concatenation */
#ifndef SQLITE_OMIT_WINDOWFUNC
int nAccum; /* Number of strings presently concatenated */
int nFirstSepLength; /* Used to detect separator length change */
/* If pnSepLengths!=0, refs an array of inter-string separator lengths,
** stored as actually incorporated into presently accumulated result.
** (Hence, its slots in use number nAccum-1 between method calls.)
** If pnSepLengths==0, nFirstSepLength is the length used throughout.
*/
int *pnSepLengths;
#endif
} GroupConcatCtx;
static void groupConcatStep( static void groupConcatStep(
sqlite3_context *context, sqlite3_context *context,
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
const char *zVal; const char *zVal;
StrAccum *pAccum; GroupConcatCtx *pGCC;
const char *zSep; const char *zSep;
int nVal, nSep; int nVal, nSep;
assert( argc==1 || argc==2 ); assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
if( pGCC ){
if( pAccum ){
sqlite3 *db = sqlite3_context_db_handle(context); sqlite3 *db = sqlite3_context_db_handle(context);
int firstTerm = pAccum->mxAlloc==0; int firstTerm = pGCC->str.mxAlloc==0;
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
if( !firstTerm ){ if( argc==1 ){
if( argc==2 ){ if( !firstTerm ){
zSep = (char*)sqlite3_value_text(argv[1]); sqlite3_str_appendchar(&pGCC->str, 1, ',');
nSep = sqlite3_value_bytes(argv[1]);
}else{
zSep = ",";
nSep = 1;
} }
if( zSep ) sqlite3_str_append(pAccum, zSep, nSep); #ifndef SQLITE_OMIT_WINDOWFUNC
else{
pGCC->nFirstSepLength = 1;
}
#endif
}else if( !firstTerm ){
zSep = (char*)sqlite3_value_text(argv[1]);
nSep = sqlite3_value_bytes(argv[1]);
if( zSep ){
sqlite3_str_append(&pGCC->str, zSep, nSep);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
else{
nSep = 0;
}
if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){
int *pnsl = pGCC->pnSepLengths;
if( pnsl == 0 ){
/* First separator length variation seen, start tracking them. */
pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int));
if( pnsl!=0 ){
int i = 0, nA = pGCC->nAccum-1;
while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength;
}
}else{
pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int));
}
if( pnsl!=0 ){
if( ALWAYS(pGCC->nAccum>0) ){
pnsl[pGCC->nAccum-1] = nSep;
}
pGCC->pnSepLengths = pnsl;
}else{
sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM);
}
}
#endif
} }
#ifndef SQLITE_OMIT_WINDOWFUNC
else{
pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]);
}
pGCC->nAccum += 1;
#endif
zVal = (char*)sqlite3_value_text(argv[0]); zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]); nVal = sqlite3_value_bytes(argv[0]);
if( zVal ) sqlite3_str_append(pAccum, zVal, nVal); if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal);
} }
} }
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatInverse( static void groupConcatInverse(
sqlite3_context *context, sqlite3_context *context,
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
int n; GroupConcatCtx *pGCC;
StrAccum *pAccum;
assert( argc==1 || argc==2 ); assert( argc==1 || argc==2 );
(void)argc; /* Suppress unused parameter warning */
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pAccum is always non-NULL since groupConcatStep() will have always /* pGCC is always non-NULL since groupConcatStep() will have always
** run frist to initialize it */ ** run frist to initialize it */
if( ALWAYS(pAccum) ){ if( ALWAYS(pGCC) ){
n = sqlite3_value_bytes(argv[0]); int nVS;
if( argc==2 ){ /* Must call sqlite3_value_text() to convert the argument into text prior
n += sqlite3_value_bytes(argv[1]); ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
(void)sqlite3_value_text(argv[0]);
nVS = sqlite3_value_bytes(argv[0]);
pGCC->nAccum -= 1;
if( pGCC->pnSepLengths!=0 ){
assert(pGCC->nAccum >= 0);
if( pGCC->nAccum>0 ){
nVS += *pGCC->pnSepLengths;
memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1,
(pGCC->nAccum-1)*sizeof(int));
}
}else{ }else{
n++; /* If removing single accumulated string, harmlessly over-do. */
nVS += pGCC->nFirstSepLength;
} }
if( n>=(int)pAccum->nChar ){ if( nVS>=(int)pGCC->str.nChar ){
pAccum->nChar = 0; pGCC->str.nChar = 0;
}else{ }else{
pAccum->nChar -= n; pGCC->str.nChar -= nVS;
memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar); memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar);
}
if( pGCC->str.nChar==0 ){
pGCC->str.mxAlloc = 0;
sqlite3_free(pGCC->pnSepLengths);
pGCC->pnSepLengths = 0;
} }
if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
} }
} }
#else #else
# define groupConcatInverse 0 # define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */ #endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){ static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum; GroupConcatCtx *pGCC
pAccum = sqlite3_aggregate_context(context, 0); = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
if( pAccum ){ if( pGCC ){
if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3ResultStrAccum(context, &pGCC->str);
sqlite3_result_error_toobig(context); #ifndef SQLITE_OMIT_WINDOWFUNC
}else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_free(pGCC->pnSepLengths);
sqlite3_result_error_nomem(context); #endif
}else{
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
sqlite3_free);
}
} }
} }
#ifndef SQLITE_OMIT_WINDOWFUNC #ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){ static void groupConcatValue(sqlite3_context *context){
sqlite3_str *pAccum; GroupConcatCtx *pGCC
pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0); = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
if( pAccum ){ if( pGCC ){
StrAccum *pAccum = &pGCC->str;
if( pAccum->accError==SQLITE_TOOBIG ){ if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context); sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){ }else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context); sqlite3_result_error_nomem(context);
}else{ }else{
const char *zText = sqlite3_str_value(pAccum); const char *zText = sqlite3_str_value(pAccum);
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
} }
} }
} }
@ -1869,11 +1973,12 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
int nExpr; int nExpr;
assert( pExpr!=0 ); assert( pExpr!=0 );
assert( pExpr->op==TK_FUNCTION ); assert( pExpr->op==TK_FUNCTION );
assert( ExprUseXList(pExpr) );
if( !pExpr->x.pList ){ if( !pExpr->x.pList ){
return 0; return 0;
} }
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
nExpr = pExpr->x.pList->nExpr; nExpr = pExpr->x.pList->nExpr;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
if( pDef==0 ) return 0; if( pDef==0 ) return 0;
@ -1897,6 +2002,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
Expr *pEscape = pExpr->x.pList->a[2].pExpr; Expr *pEscape = pExpr->x.pList->a[2].pExpr;
char *zEscape; char *zEscape;
if( pEscape->op!=TK_STRING ) return 0; if( pEscape->op!=TK_STRING ) return 0;
assert( !ExprHasProperty(pEscape, EP_IntValue) );
zEscape = pEscape->u.zToken; zEscape = pEscape->u.zToken;
if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
if( zEscape[0]==aWc[0] ) return 0; if( zEscape[0]==aWc[0] ) return 0;
@ -2005,11 +2111,11 @@ static void logFunc(
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
case 1: case 1:
/* Convert from natural logarithm to log base 10 */ /* Convert from natural logarithm to log base 10 */
ans *= 1.0/M_LN10; ans /= M_LN10;
break; break;
case 2: case 2:
/* Convert from natural logarithm to log base 2 */ /* Convert from natural logarithm to log base 2 */
ans *= 1.0/M_LN2; ans /= M_LN2;
break; break;
default: default:
break; break;
@ -2072,9 +2178,7 @@ static void math2Func(
} }
/* /*
** Implementation of 2-argument SQL math functions: ** Implementation of 0-argument pi() function.
**
** power(X,Y) - Compute X to the Y-th power
*/ */
static void piFunc( static void piFunc(
sqlite3_context *context, sqlite3_context *context,
@ -2125,12 +2229,12 @@ void sqlite3RegisterBuiltinFunctions(void){
*/ */
static FuncDef aBuiltinFunc[] = { static FuncDef aBuiltinFunc[] = {
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/ /***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
#if !defined(SQLITE_UNTESTABLE)
TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0), TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0), TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0), TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
#ifdef SQLITE_DEBUG TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0), #endif /* !defined(SQLITE_UNTESTABLE) */
#endif
/***** Regular functions *****/ /***** Regular functions *****/
#ifdef SQLITE_SOUNDEX #ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ), FUNCTION(soundex, 1, 0, 0, soundexFunc ),
@ -2150,8 +2254,7 @@ void sqlite3RegisterBuiltinFunctions(void){
INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY), INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET| INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ),
SQLITE_FUNC_TYPEOF),
#endif #endif
FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ),
@ -2162,15 +2265,17 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(min, -1, 0, 1, minmaxFunc ), FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ), FUNCTION(min, 0, 0, 1, 0 ),
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ), SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ), FUNCTION(max, 0, 1, 1, 0 ),
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ), SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ), FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ), FUNCTION(abs, 1, 0, 0, absFunc ),
@ -2202,9 +2307,10 @@ void sqlite3RegisterBuiltinFunctions(void){
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
WAGGREGATE(count, 0,0,0, countStep, WAGGREGATE(count, 0,0,0, countStep,
countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ), countFinalize, countFinalize, countInverse,
SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ),
WAGGREGATE(count, 1,0,0, countStep, WAGGREGATE(count, 1,0,0, countStep,
countFinalize, countFinalize, countInverse, 0 ), countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ),
WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0), groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
@ -2268,6 +2374,7 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif #endif
sqlite3WindowFunctions(); sqlite3WindowFunctions();
sqlite3RegisterDateTimeFunctions(); sqlite3RegisterDateTimeFunctions();
sqlite3RegisterJsonFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc)); sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
#if 0 /* Enable to print out how the built-in functions are hashed */ #if 0 /* Enable to print out how the built-in functions are hashed */
@ -2279,6 +2386,7 @@ void sqlite3RegisterBuiltinFunctions(void){
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
int n = sqlite3Strlen30(p->zName); int n = sqlite3Strlen30(p->zName);
int h = p->zName[0] + n; int h = p->zName[0] + n;
assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
printf(" %s(%d)", p->zName, h); printf(" %s(%d)", p->zName, h);
} }
printf("\n"); printf("\n");

View file

@ -27,11 +27,11 @@
# define GEODEBUG(X) # define GEODEBUG(X)
#endif #endif
#ifndef JSON_NULL /* The following stuff repeats things found in json1 */ #if defined(__GNUC__) && !defined(__llvm__)
/* #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
** Versions of isspace(), isalnum() and isdigit() to which it is safe #endif
** to pass signed char values.
*/ /* Character class routines */
#ifdef sqlite3Isdigit #ifdef sqlite3Isdigit
/* Use the SQLite core versions if this routine is part of the /* Use the SQLite core versions if this routine is part of the
** SQLite amalgamation */ ** SQLite amalgamation */
@ -39,13 +39,14 @@
# define safe_isalnum(x) sqlite3Isalnum(x) # define safe_isalnum(x) sqlite3Isalnum(x)
# define safe_isxdigit(x) sqlite3Isxdigit(x) # define safe_isxdigit(x) sqlite3Isxdigit(x)
#else #else
/* Use the standard library for separate compilation */ /* Use the standard library for separate compilation */
#include "libc/str/str.h" /* amalgamator: keep */ #include "libc/str/str.h" /* amalgamator: keep */
#define safe_isdigit(x) isdigit((unsigned char)(x)) # define safe_isdigit(x) isdigit((unsigned char)(x))
#define safe_isalnum(x) isalnum((unsigned char)(x)) # define safe_isalnum(x) isalnum((unsigned char)(x))
#define safe_isxdigit(x) isxdigit((unsigned char)(x)) # define safe_isxdigit(x) isxdigit((unsigned char)(x))
#endif #endif
#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
/* /*
** Growing our own isspace() routine this way is twice as fast as ** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function. ** the library isspace() function.
@ -68,7 +69,7 @@ static const char geopolyIsSpace[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}; };
#define safe_isspace(x) (geopolyIsSpace[(unsigned char)x]) #define fast_isspace(x) (geopolyIsSpace[(unsigned char)x])
#endif /* JSON NULL - back to original code */ #endif /* JSON NULL - back to original code */
/* Compiler and version */ /* Compiler and version */
@ -157,7 +158,7 @@ static void geopolySwab32(unsigned char *a){
/* Skip whitespace. Return the next non-whitespace character. */ /* Skip whitespace. Return the next non-whitespace character. */
static char geopolySkipSpace(GeoParse *p){ static char geopolySkipSpace(GeoParse *p){
while( safe_isspace(p->z[0]) ) p->z++; while( fast_isspace(p->z[0]) ) p->z++;
return p->z[0]; return p->z[0];
} }
@ -306,11 +307,16 @@ static GeoPoly *geopolyFuncParam(
){ ){
GeoPoly *p = 0; GeoPoly *p = 0;
int nByte; int nByte;
testcase( pCtx==0 );
if( sqlite3_value_type(pVal)==SQLITE_BLOB if( sqlite3_value_type(pVal)==SQLITE_BLOB
&& (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
){ ){
const unsigned char *a = sqlite3_value_blob(pVal); const unsigned char *a = sqlite3_value_blob(pVal);
int nVertex; int nVertex;
if( a==0 ){
if( pCtx ) sqlite3_result_error_nomem(pCtx);
return 0;
}
nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
if( (a[0]==0 || a[0]==1) if( (a[0]==0 || a[0]==1)
&& (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
@ -684,7 +690,7 @@ static GeoPoly *geopolyBBox(
aCoord[2].f = mnY; aCoord[2].f = mnY;
aCoord[3].f = mxY; aCoord[3].f = mxY;
} }
}else{ }else if( aCoord ){
memset(aCoord, 0, sizeof(RtreeCoord)*4); memset(aCoord, 0, sizeof(RtreeCoord)*4);
} }
return pOut; return pOut;
@ -1135,11 +1141,11 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
}else{ }else{
/* Remove a segment */ /* Remove a segment */
if( pActive==pThisEvent->pSeg ){ if( pActive==pThisEvent->pSeg ){
pActive = pActive->pNext; pActive = ALWAYS(pActive) ? pActive->pNext : 0;
}else{ }else{
for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
if( pSeg->pNext==pThisEvent->pSeg ){ if( pSeg->pNext==pThisEvent->pSeg ){
pSeg->pNext = pSeg->pNext->pNext; pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0;
break; break;
} }
} }
@ -1383,6 +1389,7 @@ static int geopolyFilter(
RtreeCoord bbox[4]; RtreeCoord bbox[4];
RtreeConstraint *p; RtreeConstraint *p;
assert( argc==1 ); assert( argc==1 );
assert( argv[0]!=0 );
geopolyBBox(0, argv[0], bbox, &rc); geopolyBBox(0, argv[0], bbox, &rc);
if( rc ){ if( rc ){
goto geopoly_filter_end; goto geopoly_filter_end;
@ -1610,6 +1617,7 @@ static int geopolyUpdate(
|| !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */
|| oldRowid!=newRowid) /* Rowid change */ || oldRowid!=newRowid) /* Rowid change */
){ ){
assert( aData[2]!=0 );
geopolyBBox(0, aData[2], cell.aCoord, &rc); geopolyBBox(0, aData[2], cell.aCoord, &rc);
if( rc ){ if( rc ){
if( rc==SQLITE_ERROR ){ if( rc==SQLITE_ERROR ){
@ -1692,7 +1700,7 @@ static int geopolyUpdate(
sqlite3_free(p); sqlite3_free(p);
nChange = 1; nChange = 1;
} }
for(jj=1; jj<pRtree->nAux; jj++){ for(jj=1; jj<nData-2; jj++){
nChange++; nChange++;
sqlite3_bind_value(pUp, jj+2, aData[jj+2]); sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
} }

View file

@ -12,8 +12,7 @@
** **
** This file contains definitions of global variables and constants. ** This file contains definitions of global variables and constants.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* An array to map all upper-case characters into their corresponding /* An array to map all upper-case characters into their corresponding
** lower-case character. ** lower-case character.
@ -38,7 +37,7 @@ const unsigned char sqlite3UpperToLower[] = {
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
252,253,254,255 252,253,254,255,
#endif #endif
#ifdef SQLITE_EBCDIC #ifdef SQLITE_EBCDIC
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
@ -58,7 +57,35 @@ const unsigned char sqlite3UpperToLower[] = {
224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */ 224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
#endif #endif
/* All of the upper-to-lower conversion data is above. The following
** 18 integers are completely unrelated. They are appended to the
** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is
** going on:
**
** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented
** by invoking sqlite3MemCompare(A,B) which compares values A and B and
** returns negative, zero, or positive if A is less then, equal to, or
** greater than B, respectively. Then the true false results is found by
** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or
** sqlite3aGTb[opcode] depending on whether the result of compare(A,B)
** is negative, zero, or positive, where opcode is the specific opcode.
** The only works because the comparison opcodes are consecutive and in
** this order: NE EQ GT LE LT GE. Various assert()s throughout the code
** ensure that is the case.
**
** These elements must be appended to another array. Otherwise the
** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus
** be undefined behavior. That's goofy, but the C-standards people thought
** it was a good idea, so here we are.
*/
/* NE EQ GT LE LT GE */
1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */
0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */
1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/
}; };
const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne];
const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne];
const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne];
/* /*
** The following 256 byte lookup table is used to support SQLites built-in ** The following 256 byte lookup table is used to support SQLites built-in
@ -252,16 +279,20 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xVdbeBranch */ 0, /* xVdbeBranch */
0, /* pVbeBranchArg */ 0, /* pVbeBranchArg */
#endif #endif
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */
#endif #endif
#ifndef SQLITE_UNTESTABLE #ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */ 0, /* xTestCallback */
#endif #endif
0, /* bLocaltimeFault */ 0, /* bLocaltimeFault */
0, /* xAltLocaltime */
0x7ffffffe, /* iOnceResetThreshold */ 0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */ 0, /* iPrngSeed */
#ifdef SQLITE_DEBUG
{0,0,0,0,0,0} /* aTune */
#endif
}; };
/* /*
@ -271,6 +302,18 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
*/ */
FuncDefHash sqlite3BuiltinFunctions; FuncDefHash sqlite3BuiltinFunctions;
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
/*
** Counter used for coverage testing. Does not come into play for
** release builds.
**
** Access to this global variable is not mutex protected. This might
** result in TSAN warnings. But as the variable does not exist in
** release builds, that should not be a concern.
*/
unsigned int sqlite3CoverageCounter;
#endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */
#ifdef VDBE_PROFILE #ifdef VDBE_PROFILE
/* /*
** The following performance counter can be used in place of ** The following performance counter can be used in place of
@ -304,10 +347,10 @@ int sqlite3PendingByte = 0x40000000;
/* /*
** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS. ** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS.
*/ */
u32 sqlite3SelectTrace = 0; u32 sqlite3TreeTrace = 0;
u32 sqlite3WhereTrace = 0; u32 sqlite3WhereTrace = 0;
#include "third_party/sqlite3/opcodes.inc" #include "third_party/sqlite3/opcodes.h"
/* /*
** Properties of opcodes. The OPFLG_INITIALIZER macro is ** Properties of opcodes. The OPFLG_INITIALIZER macro is
** created by mkopcodeh.awk during compilation. Data is obtained ** created by mkopcodeh.awk during compilation. Data is obtained
@ -320,3 +363,33 @@ const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
** Name of the default collating sequence ** Name of the default collating sequence
*/ */
const char sqlite3StrBINARY[] = "BINARY"; const char sqlite3StrBINARY[] = "BINARY";
/*
** Standard typenames. These names must match the COLTYPE_* definitions.
** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
**
** sqlite3StdType[] The actual names of the datatypes.
**
** sqlite3StdTypeLen[] The length (in bytes) of each entry
** in sqlite3StdType[].
**
** sqlite3StdTypeAffinity[] The affinity associated with each entry
** in sqlite3StdType[].
*/
const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
const char sqlite3StdTypeAffinity[] = {
SQLITE_AFF_NUMERIC,
SQLITE_AFF_BLOB,
SQLITE_AFF_INTEGER,
SQLITE_AFF_INTEGER,
SQLITE_AFF_REAL,
SQLITE_AFF_TEXT
};
const char *sqlite3StdType[] = {
"ANY",
"BLOB",
"INT",
"INTEGER",
"REAL",
"TEXT"
};

View file

@ -12,9 +12,8 @@
** This is the implementation of generic hash-tables ** This is the implementation of generic hash-tables
** used in SQLite. ** used in SQLite.
*/ */
#include "third_party/sqlite3/sqliteInt.h"
#include "libc/assert.h" #include "libc/assert.h"
#include "third_party/sqlite3/sqliteInt.inc"
/* clang-format off */
/* Turn bulk memory into a hash table object by initializing the /* Turn bulk memory into a hash table object by initializing the
** fields of the Hash structure. ** fields of the Hash structure.

View file

@ -14,7 +14,6 @@
*/ */
#ifndef SQLITE_HASH_H #ifndef SQLITE_HASH_H
#define SQLITE_HASH_H #define SQLITE_HASH_H
/* clang-format off */
/* Forward declarations of structures. */ /* Forward declarations of structures. */
typedef struct Hash Hash; typedef struct Hash Hash;
@ -92,6 +91,6 @@ void sqlite3HashClear(Hash*);
/* /*
** Number of entries in a hash table ** Number of entries in a hash table
*/ */
/* #define sqliteHashCount(H) ((H)->count) // NOT USED */ #define sqliteHashCount(H) ((H)->count)
#endif /* SQLITE_HASH_H */ #endif /* SQLITE_HASH_H */

View file

@ -15,7 +15,6 @@
*/ */
#ifndef SQLITE_HWTIME_H #ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H #define SQLITE_HWTIME_H
/* clang-format off */
/* /*
** The following routine only works on pentium-class (or newer) processors. ** The following routine only works on pentium-class (or newer) processors.

View file

@ -11,9 +11,9 @@
************************************************************************* *************************************************************************
** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $ ** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
** **
** This file implements an integration between the ICU library ** This file implements an integration between the ICU library
** ("International Components for Unicode", an open-source library ** ("International Components for Unicode", an open-source library
** for handling unicode data) and SQLite. The integration uses ** for handling unicode data) and SQLite. The integration uses
** ICU to provide the following to SQLite: ** ICU to provide the following to SQLite:
** **
** * An implementation of the SQL regexp() function (and hence REGEXP ** * An implementation of the SQL regexp() function (and hence REGEXP
@ -24,23 +24,23 @@
** **
** * Integration of ICU and SQLite collation sequences. ** * Integration of ICU and SQLite collation sequences.
** **
** * An implementation of the LIKE operator that uses ICU to ** * An implementation of the LIKE operator that uses ICU to
** provide case-independent matching. ** provide case-independent matching.
*/ */
/* clang-format off */
#if 0 && !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) || \ #if !defined(SQLITE_CORE) \
defined(SQLITE_ENABLE_ICU_COLLATIONS) || defined(SQLITE_ENABLE_ICU) \
|| defined(SQLITE_ENABLE_ICU_COLLATIONS)
/* Include ICU headers */ /* Include ICU headers */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/str/unicode.h" #include "libc/str/unicode.h"
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
#include "third_party/sqlite3/sqlite3ext.h" #include "third_party/sqlite3/sqlite3ext.h"
SQLITE_EXTENSION_INIT1 SQLITE_EXTENSION_INIT1
#else #else
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
#endif #endif
/* /*
@ -295,8 +295,9 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( U_SUCCESS(status) ){ if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
}else{ pExpr = sqlite3_get_auxdata(p, 0);
assert(!pExpr); }
if( !pExpr ){
icuFunctionError(p, "uregex_open", status); icuFunctionError(p, "uregex_open", status);
return; return;
} }

View file

@ -12,8 +12,7 @@
** This file contains C code routines that are called by the parser ** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite. ** to handle INSERT statements in SQLite.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** Generate code that will ** Generate code that will
@ -44,7 +43,7 @@ void sqlite3OpenTable(
}else{ }else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab); Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 ); assert( pPk!=0 );
assert( pPk->tnum==pTab->tnum ); assert( pPk->tnum==pTab->tnum || CORRUPT_DB );
sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb); sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk);
VdbeComment((v, "%s", pTab->zName)); VdbeComment((v, "%s", pTab->zName));
@ -97,6 +96,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
aff = SQLITE_AFF_INTEGER; aff = SQLITE_AFF_INTEGER;
}else{ }else{
assert( x==XN_EXPR ); assert( x==XN_EXPR );
assert( pIdx->bHasExpr );
assert( pIdx->aColExpr!=0 ); assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
} }
@ -111,38 +111,16 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
} }
/* /*
** Compute the affinity string for table pTab, if it has not already been ** Compute an affinity string for a table. Space is obtained
** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** from sqlite3DbMalloc(). The caller is responsible for freeing
** ** the space when done.
** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and
** if iReg>0 then code an OP_Affinity opcode that will set the affinities
** for register iReg and following. Or if affinities exists and iReg==0,
** then just set the P4 operand of the previous opcode (which should be
** an OP_MakeRecord) to the affinity string.
**
** A column affinity string has one character per column:
**
** Character Column affinity
** ------------------------------
** 'A' BLOB
** 'B' TEXT
** 'C' NUMERIC
** 'D' INTEGER
** 'E' REAL
*/ */
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
int i, j; char *zColAff;
char *zColAff = pTab->zColAff; zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
if( zColAff==0 ){ if( zColAff ){
sqlite3 *db = sqlite3VdbeDb(v); int i, j;
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
if( !zColAff ){
sqlite3OomFault(db);
return;
}
for(i=j=0; i<pTab->nCol; i++){ for(i=j=0; i<pTab->nCol; i++){
assert( pTab->aCol[i].affinity!=0 );
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
zColAff[j++] = pTab->aCol[i].affinity; zColAff[j++] = pTab->aCol[i].affinity;
} }
@ -150,6 +128,79 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
do{ do{
zColAff[j--] = 0; zColAff[j--] = 0;
}while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB ); }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
}
return zColAff;
}
/*
** Make changes to the evolving bytecode to do affinity transformations
** of values that are about to be gathered into a row for table pTab.
**
** For ordinary (legacy, non-strict) tables:
** -----------------------------------------
**
** Compute the affinity string for table pTab, if it has not already been
** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
**
** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries
** which were then optimized out) then this routine becomes a no-op.
**
** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the
** affinities for register iReg and following. Or if iReg==0,
** then just set the P4 operand of the previous opcode (which should be
** an OP_MakeRecord) to the affinity string.
**
** A column affinity string has one character per column:
**
** Character Column affinity
** --------- ---------------
** 'A' BLOB
** 'B' TEXT
** 'C' NUMERIC
** 'D' INTEGER
** 'E' REAL
**
** For STRICT tables:
** ------------------
**
** Generate an appropropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab. If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated. The new OP_TypeCheck needs to be inserted
** before the OP_MakeRecord. The new OP_TypeCheck should use the same
** register set as the OP_MakeRecord. If iReg>0 then register iReg is
** the first of a series of registers that will form the new record.
** Apply the type checking to that array of registers.
*/
void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
int i;
char *zColAff;
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
/* Move the previous opcode (which should be OP_MakeRecord) forward
** by one slot and insert a new OP_TypeCheck where the current
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
pPrev = sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3);
}else{
/* Insert an isolated OP_Typecheck */
sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
return;
}
zColAff = pTab->zColAff;
if( zColAff==0 ){
zColAff = sqlite3TableAffinityStr(0, pTab);
if( !zColAff ){
sqlite3OomFault(sqlite3VdbeDb(v));
return;
}
pTab->zColAff = zColAff; pTab->zColAff = zColAff;
} }
assert( zColAff!=0 ); assert( zColAff!=0 );
@ -158,6 +209,8 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
if( iReg ){ if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i); sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{ }else{
assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlite3VdbeDb(v)->mallocFailed );
sqlite3VdbeChangeP4(v, -1, zColAff, i); sqlite3VdbeChangeP4(v, -1, zColAff, i);
} }
} }
@ -241,24 +294,30 @@ void sqlite3ComputeGeneratedColumns(
** that appropriate affinity has been applied to the regular columns ** that appropriate affinity has been applied to the regular columns
*/ */
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore); sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 if( (pTab->tabFlags & TF_HasStored)!=0 ){
&& (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
){ if( pOp->opcode==OP_Affinity ){
/* Change the OP_Affinity argument to '@' (NONE) for all stored /* Change the OP_Affinity argument to '@' (NONE) for all stored
** columns. '@' is the no-op affinity and those columns have not ** columns. '@' is the no-op affinity and those columns have not
** yet been computed. */ ** yet been computed. */
int ii, jj; int ii, jj;
char *zP4 = pOp->p4.z; char *zP4 = pOp->p4.z;
assert( zP4!=0 ); assert( zP4!=0 );
assert( pOp->p4type==P4_DYNAMIC ); assert( pOp->p4type==P4_DYNAMIC );
for(ii=jj=0; zP4[jj]; ii++){ for(ii=jj=0; zP4[jj]; ii++){
if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
continue; continue;
}
if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
zP4[jj] = SQLITE_AFF_NONE;
}
jj++;
} }
if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){ }else if( pOp->opcode==OP_TypeCheck ){
zP4[jj] = SQLITE_AFF_NONE; /* If an OP_TypeCheck was generated because the table is STRICT,
} ** then set the P3 operand to indicate that generated columns should
jj++; ** not be checked */
pOp->p3 = 1;
} }
} }
@ -294,7 +353,7 @@ void sqlite3ComputeGeneratedColumns(
int x; int x;
pCol->colFlags |= COLFLAG_BUSY; pCol->colFlags |= COLFLAG_BUSY;
w.eCode = 0; w.eCode = 0;
sqlite3WalkExpr(&w, pCol->pDflt); sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol));
pCol->colFlags &= ~COLFLAG_BUSY; pCol->colFlags &= ~COLFLAG_BUSY;
if( w.eCode & COLFLAG_NOTAVAIL ){ if( w.eCode & COLFLAG_NOTAVAIL ){
pRedo = pCol; pRedo = pCol;
@ -303,13 +362,13 @@ void sqlite3ComputeGeneratedColumns(
eProgress = 1; eProgress = 1;
assert( pCol->colFlags & COLFLAG_GENERATED ); assert( pCol->colFlags & COLFLAG_GENERATED );
x = sqlite3TableColumnToStorage(pTab, i) + iRegStore; x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
sqlite3ExprCodeGeneratedColumn(pParse, pCol, x); sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x);
pCol->colFlags &= ~COLFLAG_NOTAVAIL; pCol->colFlags &= ~COLFLAG_NOTAVAIL;
} }
} }
}while( pRedo && eProgress ); }while( pRedo && eProgress );
if( pRedo ){ if( pRedo ){
sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName); sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName);
} }
pParse->iSelfTab = 0; pParse->iSelfTab = 0;
} }
@ -359,7 +418,7 @@ static int autoIncBegin(
** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */ ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
if( pSeqTab==0 if( pSeqTab==0
|| !HasRowid(pSeqTab) || !HasRowid(pSeqTab)
|| IsVirtual(pSeqTab) || NEVER(IsVirtual(pSeqTab))
|| pSeqTab->nCol!=2 || pSeqTab->nCol!=2
){ ){
pParse->nErr++; pParse->nErr++;
@ -668,9 +727,11 @@ void sqlite3Insert(
#endif #endif
db = pParse->db; db = pParse->db;
if( pParse->nErr || db->mallocFailed ){ assert( db->pParse==pParse );
if( pParse->nErr ){
goto insert_cleanup; goto insert_cleanup;
} }
assert( db->mallocFailed==0 );
dest.iSDParm = 0; /* Suppress a harmless compiler warning */ dest.iSDParm = 0; /* Suppress a harmless compiler warning */
/* If the Select object is really just a simple VALUES() list with a /* If the Select object is really just a simple VALUES() list with a
@ -704,7 +765,7 @@ void sqlite3Insert(
*/ */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask); pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
isView = pTab->pSelect!=0; isView = IsView(pTab);
#else #else
# define pTrigger 0 # define pTrigger 0
# define tmask 0 # define tmask 0
@ -716,6 +777,14 @@ void sqlite3Insert(
#endif #endif
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) ); assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__);
sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList,
onError, pUpsert, pTrigger);
}
#endif
/* If pTab is really a view, make sure it has been initialized. /* If pTab is really a view, make sure it has been initialized.
** ViewGetColumnNames() is a no-op if pTab is not a view. ** ViewGetColumnNames() is a no-op if pTab is not a view.
*/ */
@ -746,7 +815,11 @@ void sqlite3Insert(
** **
** This is the 2nd template. ** This is the 2nd template.
*/ */
if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ if( pColumn==0
&& pSelect!=0
&& pTrigger==0
&& xferOptimization(pParse, pTab, pSelect, onError, iDb)
){
assert( !pTrigger ); assert( !pTrigger );
assert( pList==0 ); assert( pList==0 );
goto insert_end; goto insert_end;
@ -790,13 +863,15 @@ void sqlite3Insert(
*/ */
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){ if( pColumn ){
assert( pColumn->eU4!=EU4_EXPR );
pColumn->eU4 = EU4_IDX;
for(i=0; i<pColumn->nId; i++){ for(i=0; i<pColumn->nId; i++){
pColumn->a[i].idx = -1; pColumn->a[i].u4.idx = -1;
} }
for(i=0; i<pColumn->nId; i++){ for(i=0; i<pColumn->nId; i++){
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){ if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
pColumn->a[i].idx = j; pColumn->a[i].u4.idx = j;
if( i!=j ) bIdListInOrder = 0; if( i!=j ) bIdListInOrder = 0;
if( j==pTab->iPKey ){ if( j==pTab->iPKey ){
ipkColumn = i; assert( !withoutRowid ); ipkColumn = i; assert( !withoutRowid );
@ -805,7 +880,7 @@ void sqlite3Insert(
if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"cannot INSERT into generated column \"%s\"", "cannot INSERT into generated column \"%s\"",
pTab->aCol[j].zName); pTab->aCol[j].zCnName);
goto insert_cleanup; goto insert_cleanup;
} }
#endif #endif
@ -818,7 +893,7 @@ void sqlite3Insert(
bIdListInOrder = 0; bIdListInOrder = 0;
}else{ }else{
sqlite3ErrorMsg(pParse, "table %S has no column named %s", sqlite3ErrorMsg(pParse, "table %S has no column named %s",
pTabList, 0, pColumn->a[i].zName); pTabList->a, pColumn->a[i].zName);
pParse->checkSchema = 1; pParse->checkSchema = 1;
goto insert_cleanup; goto insert_cleanup;
} }
@ -846,7 +921,9 @@ void sqlite3Insert(
dest.nSdst = pTab->nCol; dest.nSdst = pTab->nCol;
rc = sqlite3Select(pParse, pSelect, &dest); rc = sqlite3Select(pParse, pSelect, &dest);
regFromSelect = dest.iSdst; regFromSelect = dest.iSdst;
if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; assert( db->pParse==pParse );
if( rc || pParse->nErr ) goto insert_cleanup;
assert( db->mallocFailed==0 );
sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeEndCoroutine(v, regYield);
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
assert( pSelect->pEList ); assert( pSelect->pEList );
@ -946,7 +1023,7 @@ void sqlite3Insert(
if( nColumn!=(pTab->nCol-nHidden) ){ if( nColumn!=(pTab->nCol-nHidden) ){
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied", "table %S has %d columns but %d values were supplied",
pTabList, 0, pTab->nCol-nHidden, nColumn); pTabList->a, pTab->nCol-nHidden, nColumn);
goto insert_cleanup; goto insert_cleanup;
} }
} }
@ -990,7 +1067,7 @@ void sqlite3Insert(
pTab->zName); pTab->zName);
goto insert_cleanup; goto insert_cleanup;
} }
if( pTab->pSelect ){ if( IsView(pTab) ){
sqlite3ErrorMsg(pParse, "cannot UPSERT a view"); sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
goto insert_cleanup; goto insert_cleanup;
} }
@ -1089,22 +1166,29 @@ void sqlite3Insert(
}else if( pColumn==0 ){ }else if( pColumn==0 ){
/* Hidden columns that are not explicitly named in the INSERT /* Hidden columns that are not explicitly named in the INSERT
** get there default value */ ** get there default value */
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue; continue;
} }
} }
if( pColumn ){ if( pColumn ){
for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){} assert( pColumn->eU4==EU4_IDX );
for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
if( j>=pColumn->nId ){ if( j>=pColumn->nId ){
/* A column not named in the insert column list gets its /* A column not named in the insert column list gets its
** default value */ ** default value */
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue; continue;
} }
k = j; k = j;
}else if( nColumn==0 ){ }else if( nColumn==0 ){
/* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); sqlite3ExprCodeFactorable(pParse,
sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
iRegStore);
continue; continue;
}else{ }else{
k = i - nHidden; k = i - nHidden;
@ -1117,7 +1201,12 @@ void sqlite3Insert(
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
} }
}else{ }else{
sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); Expr *pX = pList->a[k].pExpr;
int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
if( y!=iRegStore ){
sqlite3VdbeAddOp2(v,
ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
}
} }
} }
@ -1249,12 +1338,14 @@ void sqlite3Insert(
}else }else
#endif #endif
{ {
int isReplace; /* Set to true if constraints may cause a replace */ int isReplace = 0;/* Set to true if constraints may cause a replace */
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
); );
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0); if( db->flags & SQLITE_ForeignKeys ){
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
}
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a ** constraints or (b) there are no triggers and this table is not a
@ -1269,6 +1360,13 @@ void sqlite3Insert(
regIns, aRegIdx, 0, appendFlag, bUseSeek regIns, aRegIdx, 0, appendFlag, bUseSeek
); );
} }
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
}else if( pParse->bReturning ){
/* If there is a RETURNING clause, populate the rowid register with
** constant value -1, in case one or more of the returned expressions
** refer to the "rowid" of the view. */
sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
#endif
} }
/* Update the count of rows that are inserted /* Update the count of rows that are inserted
@ -1322,9 +1420,7 @@ insert_end:
** invoke the callback function. ** invoke the callback function.
*/ */
if( regRowCount ){ if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_ChngCntRow, regRowCount, 1); sqlite3CodeChangeCount(v, regRowCount, "rows inserted");
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
} }
insert_cleanup: insert_cleanup:
@ -1333,7 +1429,7 @@ insert_cleanup:
sqlite3UpsertDelete(db, pUpsert); sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect); sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn); sqlite3IdListDelete(db, pColumn);
sqlite3DbFree(db, aRegIdx); if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
} }
/* Make sure "isView" and other macros defined above are undefined. Otherwise /* Make sure "isView" and other macros defined above are undefined. Otherwise
@ -1612,7 +1708,7 @@ void sqlite3GenerateConstraintChecks(
db = pParse->db; db = pParse->db;
v = pParse->pVdbe; v = pParse->pVdbe;
assert( v!=0 ); assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */ assert( !IsView(pTab) ); /* This table is not a VIEW */
nCol = pTab->nCol; nCol = pTab->nCol;
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for /* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
@ -1663,7 +1759,7 @@ void sqlite3GenerateConstraintChecks(
} }
if( onError==OE_Replace ){ if( onError==OE_Replace ){
if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */
|| pCol->pDflt==0 /* REPLACE is ABORT if no DEFAULT value */ || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */
){ ){
testcase( pCol->colFlags & COLFLAG_VIRTUAL ); testcase( pCol->colFlags & COLFLAG_VIRTUAL );
testcase( pCol->colFlags & COLFLAG_STORED ); testcase( pCol->colFlags & COLFLAG_STORED );
@ -1685,7 +1781,8 @@ void sqlite3GenerateConstraintChecks(
VdbeCoverage(v); VdbeCoverage(v);
assert( (pCol->colFlags & COLFLAG_GENERATED)==0 ); assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
nSeenReplace++; nSeenReplace++;
sqlite3ExprCodeCopy(pParse, pCol->pDflt, iReg); sqlite3ExprCodeCopy(pParse,
sqlite3ColumnExpr(pTab, pCol), iReg);
sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeJumpHere(v, addr1);
break; break;
} }
@ -1695,7 +1792,7 @@ void sqlite3GenerateConstraintChecks(
case OE_Rollback: case OE_Rollback:
case OE_Fail: { case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
pCol->zName); pCol->zCnName);
sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
onError, iReg); onError, iReg);
sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
@ -1948,6 +2045,7 @@ void sqlite3GenerateConstraintChecks(
if( onError==OE_Replace /* IPK rule is REPLACE */ if( onError==OE_Replace /* IPK rule is REPLACE */
&& onError!=overrideError /* Rules for other constraints are different */ && onError!=overrideError /* Rules for other constraints are different */
&& pTab->pIndex /* There exist other constraints */ && pTab->pIndex /* There exist other constraints */
&& !upsertIpkDelay /* IPK check already deferred by UPSERT */
){ ){
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
VdbeComment((v, "defer IPK REPLACE until last")); VdbeComment((v, "defer IPK REPLACE until last"));
@ -2113,7 +2211,7 @@ void sqlite3GenerateConstraintChecks(
testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField );
x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1;
sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
VdbeComment((v, "%s", pTab->aCol[iField].zName)); VdbeComment((v, "%s", pTab->aCol[iField].zCnName));
} }
} }
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
@ -2164,7 +2262,8 @@ void sqlite3GenerateConstraintChecks(
** **
** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row
** must be explicitly deleted in order to ensure any pre-update hook ** must be explicitly deleted in order to ensure any pre-update hook
** is invoked. */ ** is invoked. */
assert( IsOrdinaryTable(pTab) );
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK #ifndef SQLITE_ENABLE_PREUPDATE_HOOK
if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
&& pPk==pIdx /* Condition 2 */ && pPk==pIdx /* Condition 2 */
@ -2172,7 +2271,7 @@ void sqlite3GenerateConstraintChecks(
&& ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
&& ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */ && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */
(0==pTab->pFKey && 0==sqlite3FkReferences(pTab))) (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab)))
){ ){
sqlite3VdbeResolveLabel(v, addrUniqueOk); sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue; continue;
@ -2207,13 +2306,13 @@ void sqlite3GenerateConstraintChecks(
x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName, VdbeComment((v, "%s.%s", pTab->zName,
pTab->aCol[pPk->aiColumn[i]].zName)); pTab->aCol[pPk->aiColumn[i]].zCnName));
} }
} }
if( isUpdate ){ if( isUpdate ){
/* If currently processing the PRIMARY KEY of a WITHOUT ROWID /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
** table, only conflict if the new PRIMARY KEY values are actually ** table, only conflict if the new PRIMARY KEY values are actually
** different from the old. ** different from the old. See TH3 withoutrowid04.test.
** **
** For a UNIQUE index, only conflict if the PRIMARY KEY values ** For a UNIQUE index, only conflict if the PRIMARY KEY values
** of the matched index row are different from the original PRIMARY ** of the matched index row are different from the original PRIMARY
@ -2271,7 +2370,8 @@ void sqlite3GenerateConstraintChecks(
assert( onError==OE_Replace ); assert( onError==OE_Replace );
nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk; nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
assert( nConflictCk>0 ); assert( nConflictCk>0 || db->mallocFailed );
testcase( nConflictCk<=0 );
testcase( nConflictCk>1 ); testcase( nConflictCk>1 );
if( regTrigCnt ){ if( regTrigCnt ){
sqlite3MultiWrite(pParse); sqlite3MultiWrite(pParse);
@ -2354,6 +2454,7 @@ void sqlite3GenerateConstraintChecks(
if( ipkTop ){ if( ipkTop ){
sqlite3VdbeGoto(v, ipkTop); sqlite3VdbeGoto(v, ipkTop);
VdbeComment((v, "Do IPK REPLACE")); VdbeComment((v, "Do IPK REPLACE"));
assert( ipkBottom>0 );
sqlite3VdbeJumpHere(v, ipkBottom); sqlite3VdbeJumpHere(v, ipkBottom);
} }
@ -2406,7 +2507,7 @@ void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
if( pTab->pSchema->file_format<2 ) return; if( pTab->pSchema->file_format<2 ) return;
for(i=pTab->nCol-1; i>0; i--){ for(i=pTab->nCol-1; i>0; i--){
if( pTab->aCol[i].pDflt!=0 ) break; if( pTab->aCol[i].iDflt!=0 ) break;
if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
} }
sqlite3VdbeChangeP5(v, i+1); sqlite3VdbeChangeP5(v, i+1);
@ -2471,7 +2572,7 @@ void sqlite3CompleteInsertion(
v = pParse->pVdbe; v = pParse->pVdbe;
assert( v!=0 ); assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */ assert( !IsView(pTab) ); /* This table is not a VIEW */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
/* All REPLACE indexes are at the end of the list */ /* All REPLACE indexes are at the end of the list */
assert( pIdx->onError!=OE_Replace assert( pIdx->onError!=OE_Replace
@ -2484,7 +2585,6 @@ void sqlite3CompleteInsertion(
} }
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0); pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){ if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
assert( pParse->nested==0 );
pik_flags |= OPFLAG_NCHANGE; pik_flags |= OPFLAG_NCHANGE;
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
if( update_flags==0 ){ if( update_flags==0 ){
@ -2557,8 +2657,9 @@ int sqlite3OpenTableAndIndices(
assert( op==OP_OpenWrite || p5==0 ); assert( op==OP_OpenWrite || p5==0 );
if( IsVirtual(pTab) ){ if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output /* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur uninitialized so that valgrind ** variables *piDataCur and *piIdxCur set to illegal cursor numbers
** can detect if they are used by mistake in the caller. */ ** for improved error detection. */
*piDataCur = *piIdxCur = -999;
return 0; return 0;
} }
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
@ -2699,18 +2800,13 @@ static int xferOptimization(
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
int regData, regRowid; /* Registers holding data and rowid */ int regData, regRowid; /* Registers holding data and rowid */
if( pSelect==0 ){ assert( pSelect!=0 );
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
}
if( pParse->pWith || pSelect->pWith ){ if( pParse->pWith || pSelect->pWith ){
/* Do not attempt to process this query if there are an WITH clauses /* Do not attempt to process this query if there are an WITH clauses
** attached to it. Proceeding may generate a false "no such table: xxx" ** attached to it. Proceeding may generate a false "no such table: xxx"
** error if pSelect reads from a CTE named "xxx". */ ** error if pSelect reads from a CTE named "xxx". */
return 0; return 0;
} }
if( sqlite3TriggerList(pParse, pDest) ){
return 0; /* tab1 must not have triggers */
}
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pDest) ){ if( IsVirtual(pDest) ){
return 0; /* tab1 must not be a virtual table */ return 0; /* tab1 must not be a virtual table */
@ -2773,13 +2869,8 @@ static int xferOptimization(
if( HasRowid(pDest)!=HasRowid(pSrc) ){ if( HasRowid(pDest)!=HasRowid(pSrc) ){
return 0; /* source and destination must both be WITHOUT ROWID or not */ return 0; /* source and destination must both be WITHOUT ROWID or not */
} }
#ifndef SQLITE_OMIT_VIRTUALTABLE if( !IsOrdinaryTable(pSrc) ){
if( IsVirtual(pSrc) ){ return 0; /* tab2 may not be a view or virtual table */
return 0; /* tab2 must not be a virtual table */
}
#endif
if( pSrc->pSelect ){
return 0; /* tab2 may not be a view */
} }
if( pDest->nCol!=pSrc->nCol ){ if( pDest->nCol!=pSrc->nCol ){
return 0; /* Number of columns must be the same in tab1 and tab2 */ return 0; /* Number of columns must be the same in tab1 and tab2 */
@ -2787,6 +2878,9 @@ static int xferOptimization(
if( pDest->iPKey!=pSrc->iPKey ){ if( pDest->iPKey!=pSrc->iPKey ){
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
} }
if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){
return 0; /* Cannot feed from a non-strict into a strict table */
}
for(i=0; i<pDest->nCol; i++){ for(i=0; i<pDest->nCol; i++){
Column *pDestCol = &pDest->aCol[i]; Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i]; Column *pSrcCol = &pSrc->aCol[i];
@ -2823,7 +2917,9 @@ static int xferOptimization(
** This requirement could be relaxed for VIRTUAL columns, I suppose. ** This requirement could be relaxed for VIRTUAL columns, I suppose.
*/ */
if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){
if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ if( sqlite3ExprCompare(0,
sqlite3ColumnExpr(pSrc, pSrcCol),
sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){
testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); testcase( pDestCol->colFlags & COLFLAG_VIRTUAL );
testcase( pDestCol->colFlags & COLFLAG_STORED ); testcase( pDestCol->colFlags & COLFLAG_STORED );
return 0; /* Different generator expressions */ return 0; /* Different generator expressions */
@ -2833,7 +2929,8 @@ static int xferOptimization(
if( pDestCol->affinity!=pSrcCol->affinity ){ if( pDestCol->affinity!=pSrcCol->affinity ){
return 0; /* Affinity must be the same on all columns */ return 0; /* Affinity must be the same on all columns */
} }
if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){ if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol),
sqlite3ColumnColl(pSrcCol))!=0 ){
return 0; /* Collating sequence must be the same on all columns */ return 0; /* Collating sequence must be the same on all columns */
} }
if( pDestCol->notNull && !pSrcCol->notNull ){ if( pDestCol->notNull && !pSrcCol->notNull ){
@ -2841,11 +2938,15 @@ static int xferOptimization(
} }
/* Default values for second and subsequent columns need to match. */ /* Default values for second and subsequent columns need to match. */
if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol);
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol);
if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) assert( pDestExpr==0 || pDestExpr->op==TK_SPAN );
|| (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) );
pSrcCol->pDflt->u.zToken)!=0) assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN );
assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) );
if( (pDestExpr==0)!=(pSrcExpr==0)
|| (pDestExpr!=0 && strcmp(pDestExpr->u.zToken,
pSrcExpr->u.zToken)!=0)
){ ){
return 0; /* Default values must be the same for all columns */ return 0; /* Default values must be the same for all columns */
} }
@ -2882,7 +2983,8 @@ static int xferOptimization(
** the extra complication to make this rule less restrictive is probably ** the extra complication to make this rule less restrictive is probably
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
*/ */
if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ assert( IsOrdinaryTable(pDest) );
if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){
return 0; return 0;
} }
#endif #endif

View file

@ -1,62 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_SQLITE3_INTTYPES_H_
#define COSMOPOLITAN_THIRD_PARTY_SQLITE3_INTTYPES_H_
#include "third_party/sqlite3/sqlite3.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*
** Integers of known sizes. These typedefs might change for architectures
** where the sizes very. Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type. Like this:
**
** cc '-DUINTPTR_TYPE=long long int' ...
*/
#ifndef UINT32_TYPE
#ifdef HAVE_UINT32_T
#define UINT32_TYPE uint32_t
#else
#define UINT32_TYPE unsigned int
#endif
#endif
#ifndef UINT16_TYPE
#ifdef HAVE_UINT16_T
#define UINT16_TYPE uint16_t
#else
#define UINT16_TYPE unsigned short int
#endif
#endif
#ifndef INT16_TYPE
#ifdef HAVE_INT16_T
#define INT16_TYPE int16_t
#else
#define INT16_TYPE short int
#endif
#endif
#ifndef UINT8_TYPE
#ifdef HAVE_UINT8_T
#define UINT8_TYPE uint8_t
#else
#define UINT8_TYPE unsigned char
#endif
#endif
#ifndef INT8_TYPE
#ifdef HAVE_INT8_T
#define INT8_TYPE int8_t
#else
#define INT8_TYPE signed char
#endif
#endif
#ifndef LONGDOUBLE_TYPE
#define LONGDOUBLE_TYPE long double
#endif
typedef sqlite_int64 i64; /* 8-byte signed integer */
typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
typedef INT16_TYPE i16; /* 2-byte signed integer */
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
typedef INT8_TYPE i8; /* 1-byte signed integer */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_SQLITE3_INTTYPES_H_ */

File diff suppressed because it is too large Load diff

1
third_party/sqlite3/json.shell.c vendored Normal file
View file

@ -0,0 +1 @@
#include "third_party/sqlite3/json.c"

View file

@ -1 +0,0 @@
#include "third_party/sqlite3/json1.c"

View file

@ -14,9 +14,8 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
*/ */
/* clang-format off */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* /*
** Execute SQL code. Return one of the SQLITE_ success/failure ** Execute SQL code. Return one of the SQLITE_ success/failure

View file

@ -12,13 +12,12 @@
** This file contains code used to dynamically load extensions into ** This file contains code used to dynamically load extensions into
** the SQLite library. ** the SQLite library.
*/ */
/* clang-format off */
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
#endif #endif
#include "third_party/sqlite3/sqlite3ext.h" #include "third_party/sqlite3/sqlite3ext.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
/* /*
@ -481,6 +480,37 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_database_file_object, sqlite3_database_file_object,
/* Version 3.34.0 and later */ /* Version 3.34.0 and later */
sqlite3_txn_state, sqlite3_txn_state,
/* Version 3.36.1 and later */
sqlite3_changes64,
sqlite3_total_changes64,
/* Version 3.37.0 and later */
sqlite3_autovacuum_pages,
/* Version 3.38.0 and later */
sqlite3_error_offset,
#ifndef SQLITE_OMIT_VIRTUALTABLE
sqlite3_vtab_rhs_value,
sqlite3_vtab_distinct,
sqlite3_vtab_in,
sqlite3_vtab_in_first,
sqlite3_vtab_in_next,
#else
0,
0,
0,
0,
0,
#endif
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
sqlite3_deserialize,
sqlite3_serialize,
#else
0,
0,
#endif
sqlite3_db_name,
/* Version 3.40.0 and later */
sqlite3_value_type
}; };
/* True if x is the directory separator character /* True if x is the directory separator character
@ -516,7 +546,7 @@ static int sqlite3LoadExtension(
const char *zEntry; const char *zEntry;
char *zAltEntry = 0; char *zAltEntry = 0;
void **aHandle; void **aHandle;
u64 nMsg = 300 + sqlite3Strlen30(zFile); u64 nMsg = strlen(zFile);
int ii; int ii;
int rc; int rc;
@ -550,6 +580,12 @@ static int sqlite3LoadExtension(
zEntry = zProc ? zProc : "sqlite3_extension_init"; zEntry = zProc ? zProc : "sqlite3_extension_init";
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
** https://sqlite.org/forum/forumpost/08a0d6d9bf */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
handle = sqlite3OsDlOpen(pVfs, zFile); handle = sqlite3OsDlOpen(pVfs, zFile);
#if SQLITE_OS_UNIX || SQLITE_OS_WIN #if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){ for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
@ -559,17 +595,7 @@ static int sqlite3LoadExtension(
sqlite3_free(zAltFile); sqlite3_free(zAltFile);
} }
#endif #endif
if( handle==0 ){ if( handle==0 ) goto extension_not_found;
if( pzErrMsg ){
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
}
}
return SQLITE_ERROR;
}
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
/* If no entry point was specified and the default legacy /* If no entry point was specified and the default legacy
@ -606,10 +632,11 @@ static int sqlite3LoadExtension(
} }
if( xInit==0 ){ if( xInit==0 ){
if( pzErrMsg ){ if( pzErrMsg ){
nMsg += sqlite3Strlen30(zEntry); nMsg += strlen(zEntry) + 300;
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){ if( zErrmsg ){
sqlite3_snprintf(nMsg, zErrmsg, assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
sqlite3_snprintf((int)nMsg, zErrmsg,
"no entry point [%s] in shared library [%s]", zEntry, zFile); "no entry point [%s] in shared library [%s]", zEntry, zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
} }
@ -643,6 +670,19 @@ static int sqlite3LoadExtension(
db->aExtension[db->nExtension++] = handle; db->aExtension[db->nExtension++] = handle;
return SQLITE_OK; return SQLITE_OK;
extension_not_found:
if( pzErrMsg ){
nMsg += 300;
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){
assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
sqlite3_snprintf((int)nMsg, zErrmsg,
"unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
}
}
return SQLITE_ERROR;
} }
int sqlite3_load_extension( int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */ sqlite3 *db, /* Load the extension into this database connection */

View file

@ -14,17 +14,16 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifdef SQLITE_ENABLE_FTS3 #ifdef SQLITE_ENABLE_FTS3
#include "third_party/sqlite3/fts3.inc" # include "third_party/sqlite3/fts3.h"
#endif #endif
#ifdef SQLITE_ENABLE_RTREE #ifdef SQLITE_ENABLE_RTREE
#include "third_party/sqlite3/rtree.inc" # include "third_party/sqlite3/rtree.h"
#endif #endif
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
#include "third_party/sqlite3/sqliteicu.inc" # include "third_party/sqlite3/sqliteicu.h"
#endif #endif
/* /*
@ -51,9 +50,6 @@ int sqlite3Fts2Init(sqlite3*);
#ifdef SQLITE_ENABLE_FTS5 #ifdef SQLITE_ENABLE_FTS5
int sqlite3Fts5Init(sqlite3*); int sqlite3Fts5Init(sqlite3*);
#endif #endif
#ifdef SQLITE_ENABLE_JSON1
int sqlite3Json1Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB #ifdef SQLITE_ENABLE_STMTVTAB
int sqlite3StmtVtabInit(sqlite3*); int sqlite3StmtVtabInit(sqlite3*);
#endif #endif
@ -88,8 +84,8 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
sqlite3DbstatRegister, sqlite3DbstatRegister,
#endif #endif
sqlite3TestExtInit, sqlite3TestExtInit,
#ifdef SQLITE_ENABLE_JSON1 #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
sqlite3Json1Init, sqlite3JsonTableFunctions,
#endif #endif
#ifdef SQLITE_ENABLE_STMTVTAB #ifdef SQLITE_ENABLE_STMTVTAB
sqlite3StmtVtabInit, sqlite3StmtVtabInit,
@ -306,7 +302,7 @@ int sqlite3_initialize(void){
sqlite3GlobalConfig.isPCacheInit = 1; sqlite3GlobalConfig.isPCacheInit = 1;
rc = sqlite3OsInit(); rc = sqlite3OsInit();
} }
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3MemdbInit(); rc = sqlite3MemdbInit();
} }
@ -721,12 +717,12 @@ int sqlite3_config(int op, ...){
} }
#endif /* SQLITE_ENABLE_SORTER_REFERENCES */ #endif /* SQLITE_ENABLE_SORTER_REFERENCES */
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
case SQLITE_CONFIG_MEMDB_MAXSIZE: { case SQLITE_CONFIG_MEMDB_MAXSIZE: {
sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64);
break; break;
} }
#endif /* SQLITE_ENABLE_DESERIALIZE */ #endif /* SQLITE_OMIT_DESERIALIZE */
default: { default: {
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
@ -828,18 +824,19 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.bMalloced = pBuf==0 ?1:0; db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm; db->lookaside.nSlot = nBig+nSm;
}else{ }else{
db->lookaside.pStart = db; db->lookaside.pStart = 0;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
db->lookaside.pSmallInit = 0; db->lookaside.pSmallInit = 0;
db->lookaside.pSmallFree = 0; db->lookaside.pSmallFree = 0;
db->lookaside.pMiddle = db; db->lookaside.pMiddle = 0;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
db->lookaside.pEnd = db; db->lookaside.pEnd = 0;
db->lookaside.bDisable = 1; db->lookaside.bDisable = 1;
db->lookaside.sz = 0; db->lookaside.sz = 0;
db->lookaside.bMalloced = 0; db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0; db->lookaside.nSlot = 0;
} }
db->lookaside.pTrueEnd = db->lookaside.pEnd;
assert( sqlite3LookasideUsed(db,0)==0 ); assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */ #endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK; return SQLITE_OK;
@ -918,6 +915,7 @@ int sqlite3_db_cacheflush(sqlite3 *db){
int sqlite3_db_config(sqlite3 *db, int op, ...){ int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap; va_list ap;
int rc; int rc;
sqlite3_mutex_enter(db->mutex);
va_start(ap, op); va_start(ap, op);
switch( op ){ switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: { case SQLITE_DBCONFIG_MAINDBNAME: {
@ -983,6 +981,7 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
} }
} }
va_end(ap); va_end(ap);
sqlite3_mutex_leave(db->mutex);
return rc; return rc;
} }
@ -1087,7 +1086,7 @@ void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
/* /*
** Return the number of changes in the most recent call to sqlite3_exec(). ** Return the number of changes in the most recent call to sqlite3_exec().
*/ */
int sqlite3_changes(sqlite3 *db){ sqlite3_int64 sqlite3_changes64(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR #ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){ if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT; (void)SQLITE_MISUSE_BKPT;
@ -1096,11 +1095,14 @@ int sqlite3_changes(sqlite3 *db){
#endif #endif
return db->nChange; return db->nChange;
} }
int sqlite3_changes(sqlite3 *db){
return (int)sqlite3_changes64(db);
}
/* /*
** Return the number of changes since the database handle was opened. ** Return the number of changes since the database handle was opened.
*/ */
int sqlite3_total_changes(sqlite3 *db){ sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR #ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){ if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT; (void)SQLITE_MISUSE_BKPT;
@ -1109,6 +1111,9 @@ int sqlite3_total_changes(sqlite3 *db){
#endif #endif
return db->nTotalChange; return db->nTotalChange;
} }
int sqlite3_total_changes(sqlite3 *db){
return (int)sqlite3_total_changes64(db);
}
/* /*
** Close all open savepoints. This function only manipulates fields of the ** Close all open savepoints. This function only manipulates fields of the
@ -1133,7 +1138,9 @@ void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding. ** with SQLITE_ANY as the encoding.
*/ */
static void functionDestroy(sqlite3 *db, FuncDef *p){ static void functionDestroy(sqlite3 *db, FuncDef *p){
FuncDestructor *pDestructor = p->u.pDestructor; FuncDestructor *pDestructor;
assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 );
pDestructor = p->u.pDestructor;
if( pDestructor ){ if( pDestructor ){
pDestructor->nRef--; pDestructor->nRef--;
if( pDestructor->nRef==0 ){ if( pDestructor->nRef==0 ){
@ -1237,7 +1244,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
/* Convert the connection into a zombie and then close it. /* Convert the connection into a zombie and then close it.
*/ */
db->magic = SQLITE_MAGIC_ZOMBIE; db->eOpenState = SQLITE_STATE_ZOMBIE;
sqlite3LeaveMutexAndCloseZombie(db); sqlite3LeaveMutexAndCloseZombie(db);
return SQLITE_OK; return SQLITE_OK;
} }
@ -1275,7 +1282,7 @@ int sqlite3_txn_state(sqlite3 *db, const char *zSchema){
/* /*
** Two variations on the public interface for closing a database ** Two variations on the public interface for closing a database
** connection. The sqlite3_close() version returns SQLITE_BUSY and ** connection. The sqlite3_close() version returns SQLITE_BUSY and
** leaves the connection option if there are unfinalized prepared ** leaves the connection open if there are unfinalized prepared
** statements or unfinished sqlite3_backups. The sqlite3_close_v2() ** statements or unfinished sqlite3_backups. The sqlite3_close_v2()
** version forces the connection to become a zombie if there are ** version forces the connection to become a zombie if there are
** unclosed resources, and arranges for deallocation when the last ** unclosed resources, and arranges for deallocation when the last
@ -1301,7 +1308,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
** or if the connection has not yet been closed by sqlite3_close_v2(), ** or if the connection has not yet been closed by sqlite3_close_v2(),
** then just leave the mutex and return. ** then just leave the mutex and return.
*/ */
if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
return; return;
} }
@ -1387,7 +1394,7 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3_free(db->auth.zAuthPW); sqlite3_free(db->auth.zAuthPW);
#endif #endif
db->magic = SQLITE_MAGIC_ERROR; db->eOpenState = SQLITE_STATE_ERROR;
/* The temp-database schema is allocated differently from the other schema /* The temp-database schema is allocated differently from the other schema
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
@ -1396,8 +1403,11 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
** structure? ** structure?
*/ */
sqlite3DbFree(db, db->aDb[1].pSchema); sqlite3DbFree(db, db->aDb[1].pSchema);
if( db->xAutovacDestr ){
db->xAutovacDestr(db->pAutovacPagesArg);
}
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED; db->eOpenState = SQLITE_STATE_CLOSED;
sqlite3_mutex_free(db->mutex); sqlite3_mutex_free(db->mutex);
assert( sqlite3LookasideUsed(db,0)==0 ); assert( sqlite3LookasideUsed(db,0)==0 );
if( db->lookaside.bMalloced ){ if( db->lookaside.bMalloced ){
@ -1450,7 +1460,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
/* Any deferred constraint violations have now been resolved. */ /* Any deferred constraint violations have now been resolved. */
db->nDeferredCons = 0; db->nDeferredCons = 0;
db->nDeferredImmCons = 0; db->nDeferredImmCons = 0;
db->flags &= ~(u64)SQLITE_DeferFKs; db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly);
/* If one has been configured, invoke the rollback-hook callback */ /* If one has been configured, invoke the rollback-hook callback */
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
@ -1785,7 +1795,7 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
*/ */
void sqlite3_interrupt(sqlite3 *db){ void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR #ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){ if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){
(void)SQLITE_MISUSE_BKPT; (void)SQLITE_MISUSE_BKPT;
return; return;
} }
@ -1814,7 +1824,6 @@ int sqlite3CreateFunc(
FuncDestructor *pDestructor FuncDestructor *pDestructor
){ ){
FuncDef *p; FuncDef *p;
int nName;
int extraFlags; int extraFlags;
assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3_mutex_held(db->mutex) );
@ -1824,7 +1833,7 @@ int sqlite3CreateFunc(
|| ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */ || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
|| ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */ || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
|| (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
|| (255<(nName = sqlite3Strlen30( zFunctionName))) || (255<sqlite3Strlen30(zFunctionName))
){ ){
return SQLITE_MISUSE_BKPT; return SQLITE_MISUSE_BKPT;
} }
@ -1849,22 +1858,33 @@ int sqlite3CreateFunc(
** If SQLITE_ANY is specified, add three versions of the function ** If SQLITE_ANY is specified, add three versions of the function
** to the hash table. ** to the hash table.
*/ */
if( enc==SQLITE_UTF16 ){ switch( enc ){
enc = SQLITE_UTF16NATIVE; case SQLITE_UTF16:
}else if( enc==SQLITE_ANY ){ enc = SQLITE_UTF16NATIVE;
int rc; break;
rc = sqlite3CreateFunc(db, zFunctionName, nArg, case SQLITE_ANY: {
(SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, int rc;
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg, rc = sqlite3CreateFunc(db, zFunctionName, nArg,
(SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
(SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
}
enc = SQLITE_UTF16BE;
break;
} }
if( rc!=SQLITE_OK ){ case SQLITE_UTF8:
return rc; case SQLITE_UTF16LE:
} case SQLITE_UTF16BE:
enc = SQLITE_UTF16BE; break;
default:
enc = SQLITE_UTF8;
break;
} }
#else #else
enc = SQLITE_UTF8; enc = SQLITE_UTF8;
@ -1885,6 +1905,10 @@ int sqlite3CreateFunc(
}else{ }else{
sqlite3ExpirePreparedStatements(db, 0); sqlite3ExpirePreparedStatements(db, 0);
} }
}else if( xSFunc==0 && xFinal==0 ){
/* Trying to delete a function that does not exist. This is a no-op.
** https://sqlite.org/forum/forumpost/726219164b */
return SQLITE_OK;
} }
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1); p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
@ -1957,7 +1981,7 @@ static int createFunctionApi(
xSFunc, xStep, xFinal, xValue, xInverse, pArg xSFunc, xStep, xFinal, xValue, xInverse, pArg
); );
if( pArg && pArg->nRef==0 ){ if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK ); assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) );
xDestroy(p); xDestroy(p);
sqlite3_free(pArg); sqlite3_free(pArg);
} }
@ -2283,6 +2307,34 @@ void *sqlite3_preupdate_hook(
} }
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
/*
** Register a function to be invoked prior to each autovacuum that
** determines the number of pages to vacuum.
*/
int sqlite3_autovacuum_pages(
sqlite3 *db, /* Attach the hook to this database */
unsigned int (*xCallback)(void*,const char*,u32,u32,u32),
void *pArg, /* Argument to the function */
void (*xDestructor)(void*) /* Destructor for pArg */
){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
if( xDestructor ) xDestructor(pArg);
return SQLITE_MISUSE_BKPT;
}
#endif
sqlite3_mutex_enter(db->mutex);
if( db->xAutovacDestr ){
db->xAutovacDestr(db->pAutovacPagesArg);
}
db->xAutovacPages = xCallback;
db->pAutovacPagesArg = pArg;
db->xAutovacDestr = xDestructor;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
/* /*
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint(). ** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
@ -2545,6 +2597,19 @@ const char *sqlite3_errmsg(sqlite3 *db){
return z; return z;
} }
/*
** Return the byte offset of the most recent error
*/
int sqlite3_error_offset(sqlite3 *db){
int iOffset = -1;
if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){
sqlite3_mutex_enter(db->mutex);
iOffset = db->errByteOffset;
sqlite3_mutex_leave(db->mutex);
}
return iOffset;
}
#ifndef SQLITE_OMIT_UTF16 #ifndef SQLITE_OMIT_UTF16
/* /*
** Return UTF-16 encoded English language explanation of the most recent ** Return UTF-16 encoded English language explanation of the most recent
@ -2805,6 +2870,8 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>=0 ){ /* IMP: R-52476-28732 */
if( newLimit>aHardLimit[limitId] ){ if( newLimit>aHardLimit[limitId] ){
newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
}else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
newLimit = 1;
} }
db->aLimit[limitId] = newLimit; db->aLimit[limitId] = newLimit;
} }
@ -3076,7 +3143,7 @@ int sqlite3ParseUri(
*/ */
static const char *uriParameter(const char *zFilename, const char *zParam){ static const char *uriParameter(const char *zFilename, const char *zParam){
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){ while( ALWAYS(zFilename!=0) && zFilename[0] ){
int x = strcmp(zFilename, zParam); int x = strcmp(zFilename, zParam);
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
if( x==0 ) return zFilename; if( x==0 ) return zFilename;
@ -3136,8 +3203,8 @@ static int openDatabase(
** dealt with in the previous code block. Besides these, the only ** dealt with in the previous code block. Besides these, the only
** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY, ** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY,
** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE, ** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE,
** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved
** off all other flags. ** bits. Silently mask off all other flags.
*/ */
flags &= ~( SQLITE_OPEN_DELETEONCLOSE | flags &= ~( SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_EXCLUSIVE |
@ -3172,9 +3239,9 @@ static int openDatabase(
} }
} }
sqlite3_mutex_enter(db->mutex); sqlite3_mutex_enter(db->mutex);
db->errMask = 0xff; db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff;
db->nDb = 2; db->nDb = 2;
db->magic = SQLITE_MAGIC_BUSY; db->eOpenState = SQLITE_STATE_BUSY;
db->aDb = db->aDbStatic; db->aDb = db->aDbStatic;
db->lookaside.bDisable = 1; db->lookaside.bDisable = 1;
db->lookaside.sz = 0; db->lookaside.sz = 0;
@ -3186,7 +3253,15 @@ static int openDatabase(
db->nextAutovac = -1; db->nextAutovac = -1;
db->szMmap = sqlite3GlobalConfig.szMmap; db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0; db->nextPagesize = 0;
db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
#ifdef SQLITE_ENABLE_SORTER_MMAP
/* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map
** the temporary files used to do external sorts (see code in vdbesort.c)
** is disabled. It can still be used either by defining
** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the
** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */
db->nMaxSorterMmap = 0x7FFFFFFF; db->nMaxSorterMmap = 0x7FFFFFFF;
#endif
db->flags |= SQLITE_ShortColNames db->flags |= SQLITE_ShortColNames
| SQLITE_EnableTrigger | SQLITE_EnableTrigger
| SQLITE_EnableView | SQLITE_EnableView
@ -3277,6 +3352,19 @@ static int openDatabase(
goto opendb_out; goto opendb_out;
} }
#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
/* Process magic filenames ":localStorage:" and ":sessionStorage:" */
if( zFilename && zFilename[0]==':' ){
if( strcmp(zFilename, ":localStorage:")==0 ){
zFilename = "file:local?vfs=kvvfs";
flags |= SQLITE_OPEN_URI;
}else if( strcmp(zFilename, ":sessionStorage:")==0 ){
zFilename = "file:session?vfs=kvvfs";
flags |= SQLITE_OPEN_URI;
}
}
#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
/* Parse the filename/URI argument /* Parse the filename/URI argument
** **
** Only allow sensible combinations of bits in the flags argument. ** Only allow sensible combinations of bits in the flags argument.
@ -3307,6 +3395,12 @@ static int openDatabase(
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
goto opendb_out; goto opendb_out;
} }
assert( db->pVfs!=0 );
#if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL)
if( sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){
db->temp_store = 2;
}
#endif
/* Open the backend database driver */ /* Open the backend database driver */
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
@ -3334,7 +3428,7 @@ static int openDatabase(
db->aDb[1].zDbSName = "temp"; db->aDb[1].zDbSName = "temp";
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF; db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
db->magic = SQLITE_MAGIC_OPEN; db->eOpenState = SQLITE_STATE_OPEN;
if( db->mallocFailed ){ if( db->mallocFailed ){
goto opendb_out; goto opendb_out;
} }
@ -3396,12 +3490,12 @@ opendb_out:
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
} }
rc = sqlite3_errcode(db); rc = sqlite3_errcode(db);
assert( db!=0 || rc==SQLITE_NOMEM ); assert( db!=0 || (rc&0xff)==SQLITE_NOMEM );
if( rc==SQLITE_NOMEM ){ if( (rc&0xff)==SQLITE_NOMEM ){
sqlite3_close(db); sqlite3_close(db);
db = 0; db = 0;
}else if( rc!=SQLITE_OK ){ }else if( rc!=SQLITE_OK ){
db->magic = SQLITE_MAGIC_SICK; db->eOpenState = SQLITE_STATE_SICK;
} }
*ppDb = db; *ppDb = db;
#ifdef SQLITE_ENABLE_SQLLOG #ifdef SQLITE_ENABLE_SQLLOG
@ -3412,7 +3506,7 @@ opendb_out:
} }
#endif #endif
sqlite3_free_filename(zOpen); sqlite3_free_filename(zOpen);
return rc & 0xff; return rc;
} }
@ -3712,7 +3806,7 @@ int sqlite3_table_column_metadata(
/* Locate the table in question */ /* Locate the table in question */
pTab = sqlite3FindTable(db, zTableName, zDbName); pTab = sqlite3FindTable(db, zTableName, zDbName);
if( !pTab || pTab->pSelect ){ if( !pTab || IsView(pTab) ){
pTab = 0; pTab = 0;
goto error_out; goto error_out;
} }
@ -3723,7 +3817,7 @@ int sqlite3_table_column_metadata(
}else{ }else{
for(iCol=0; iCol<pTab->nCol; iCol++){ for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol]; pCol = &pTab->aCol[iCol];
if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){ if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){
break; break;
} }
} }
@ -3750,7 +3844,7 @@ int sqlite3_table_column_metadata(
*/ */
if( pCol ){ if( pCol ){
zDataType = sqlite3ColumnType(pCol,0); zDataType = sqlite3ColumnType(pCol,0);
zCollSeq = pCol->zColl; zCollSeq = sqlite3ColumnColl(pCol);
notnull = pCol->notNull!=0; notnull = pCol->notNull!=0;
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0;
@ -3957,12 +4051,16 @@ int sqlite3_test_control(int op, ...){
** sqlite3_test_control(). ** sqlite3_test_control().
*/ */
case SQLITE_TESTCTRL_FAULT_INSTALL: { case SQLITE_TESTCTRL_FAULT_INSTALL: {
/* MSVC is picky about pulling func ptrs from va lists. /* A bug in MSVC prevents it from understanding pointers to functions
** http://support.microsoft.com/kb/47961 ** types in the second argument to va_arg(). Work around the problem
** using a typedef.
** http://support.microsoft.com/kb/47961 <-- dead hyperlink
** Search at http://web.archive.org/ to find the 2015-03-16 archive
** of the link above to see the original text.
** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int));
*/ */
typedef int(*TESTCALLBACKFUNC_t)(int); typedef int(*sqlite3FaultFuncType)(int);
sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); sqlite3GlobalConfig.xTestCallback = va_arg(ap, sqlite3FaultFuncType);
rc = sqlite3FaultSim(0); rc = sqlite3FaultSim(0);
break; break;
} }
@ -4021,6 +4119,28 @@ int sqlite3_test_control(int op, ...){
volatile int x = 0; volatile int x = 0;
assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
rc = x; rc = x;
#if defined(SQLITE_DEBUG)
/* Invoke these debugging routines so that the compiler does not
** issue "defined but not used" warnings. */
if( x==9999 ){
sqlite3ShowExpr(0);
sqlite3ShowExpr(0);
sqlite3ShowExprList(0);
sqlite3ShowIdList(0);
sqlite3ShowSrcList(0);
sqlite3ShowWith(0);
sqlite3ShowUpsert(0);
sqlite3ShowTriggerStep(0);
sqlite3ShowTriggerStepList(0);
sqlite3ShowTrigger(0);
sqlite3ShowTriggerList(0);
#ifndef SQLITE_OMIT_WINDOWFUNC
sqlite3ShowWindow(0);
sqlite3ShowWinFunc(0);
#endif
sqlite3ShowSelect(0);
}
#endif
break; break;
} }
@ -4089,13 +4209,27 @@ int sqlite3_test_control(int op, ...){
break; break;
} }
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff); /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
** **
** If parameter onoff is non-zero, subsequent calls to localtime() ** If parameter onoff is 1, subsequent calls to localtime() fail.
** and its variants fail. If onoff is zero, undo this setting. ** If 2, then invoke xAlt() instead of localtime(). If 0, normal
** processing.
**
** xAlt arguments are void pointers, but they really want to be:
**
** int xAlt(const time_t*, struct tm*);
**
** xAlt should write results in to struct tm object of its 2nd argument
** and return zero on success, or return non-zero on failure.
*/ */
case SQLITE_TESTCTRL_LOCALTIME_FAULT: { case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int); sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
if( sqlite3GlobalConfig.bLocaltimeFault==2 ){
typedef int(*sqlite3LocaltimeType)(const void*,void*);
sqlite3GlobalConfig.xAltLocaltime = va_arg(ap, sqlite3LocaltimeType);
}else{
sqlite3GlobalConfig.xAltLocaltime = 0;
}
break; break;
} }
@ -4200,12 +4334,16 @@ int sqlite3_test_control(int op, ...){
*/ */
case SQLITE_TESTCTRL_IMPOSTER: { case SQLITE_TESTCTRL_IMPOSTER: {
sqlite3 *db = va_arg(ap, sqlite3*); sqlite3 *db = va_arg(ap, sqlite3*);
int iDb;
sqlite3_mutex_enter(db->mutex); sqlite3_mutex_enter(db->mutex);
db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
db->init.busy = db->init.imposterTable = va_arg(ap,int); if( iDb>=0 ){
db->init.newTnum = va_arg(ap,int); db->init.iDb = iDb;
if( db->init.busy==0 && db->init.newTnum>0 ){ db->init.busy = db->init.imposterTable = va_arg(ap,int);
sqlite3ResetAllSchemasOfConnection(db); db->init.newTnum = va_arg(ap,int);
if( db->init.busy==0 && db->init.newTnum>0 ){
sqlite3ResetAllSchemasOfConnection(db);
}
} }
sqlite3_mutex_leave(db->mutex); sqlite3_mutex_leave(db->mutex);
break; break;
@ -4264,8 +4402,8 @@ int sqlite3_test_control(int op, ...){
** **
** "ptr" is a pointer to a u32. ** "ptr" is a pointer to a u32.
** **
** op==0 Store the current sqlite3SelectTrace in *ptr ** op==0 Store the current sqlite3TreeTrace in *ptr
** op==1 Set sqlite3SelectTrace to the value *ptr ** op==1 Set sqlite3TreeTrace to the value *ptr
** op==3 Store the current sqlite3WhereTrace in *ptr ** op==3 Store the current sqlite3WhereTrace in *ptr
** op==3 Set sqlite3WhereTrace to the value *ptr ** op==3 Set sqlite3WhereTrace to the value *ptr
*/ */
@ -4273,13 +4411,65 @@ int sqlite3_test_control(int op, ...){
int opTrace = va_arg(ap, int); int opTrace = va_arg(ap, int);
u32 *ptr = va_arg(ap, u32*); u32 *ptr = va_arg(ap, u32*);
switch( opTrace ){ switch( opTrace ){
case 0: *ptr = sqlite3SelectTrace; break; case 0: *ptr = sqlite3TreeTrace; break;
case 1: sqlite3SelectTrace = *ptr; break; case 1: sqlite3TreeTrace = *ptr; break;
case 2: *ptr = sqlite3WhereTrace; break; case 2: *ptr = sqlite3WhereTrace; break;
case 3: sqlite3WhereTrace = *ptr; break; case 3: sqlite3WhereTrace = *ptr; break;
} }
break; break;
} }
/* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST,
** double fIn, // Input value
** int *pLogEst, // sqlite3LogEstFromDouble(fIn)
** u64 *pInt, // sqlite3LogEstToInt(*pLogEst)
** int *pLogEst2 // sqlite3LogEst(*pInt)
** );
**
** Test access for the LogEst conversion routines.
*/
case SQLITE_TESTCTRL_LOGEST: {
double rIn = va_arg(ap, double);
LogEst rLogEst = sqlite3LogEstFromDouble(rIn);
int *pI1 = va_arg(ap,int*);
u64 *pU64 = va_arg(ap,u64*);
int *pI2 = va_arg(ap,int*);
*pI1 = rLogEst;
*pU64 = sqlite3LogEstToInt(rLogEst);
*pI2 = sqlite3LogEst(*pU64);
break;
}
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
**
** If "id" is an integer between 1 and SQLITE_NTUNE then set the value
** of the id-th tuning parameter to *piValue. If "id" is between -1
** and -SQLITE_NTUNE, then write the current value of the (-id)-th
** tuning parameter into *piValue.
**
** Tuning parameters are for use during transient development builds,
** to help find the best values for constants in the query planner.
** Access tuning parameters using the Tuning(ID) macro. Set the
** parameters in the CLI using ".testctrl tune ID VALUE".
**
** Transient use only. Tuning parameters should not be used in
** checked-in code.
*/
case SQLITE_TESTCTRL_TUNE: {
int id = va_arg(ap, int);
int *piValue = va_arg(ap, int*);
if( id>0 && id<=SQLITE_NTUNE ){
Tuning(id) = *piValue;
}else if( id<0 && id>=-SQLITE_NTUNE ){
*piValue = Tuning(-id);
}else{
rc = SQLITE_NOTFOUND;
}
break;
}
#endif
} }
va_end(ap); va_end(ap);
#endif /* SQLITE_UNTESTABLE */ #endif /* SQLITE_UNTESTABLE */
@ -4320,7 +4510,7 @@ static char *appendText(char *p, const char *z){
** Memory layout must be compatible with that generated by the pager ** Memory layout must be compatible with that generated by the pager
** and expected by sqlite3_uri_parameter() and databaseName(). ** and expected by sqlite3_uri_parameter() and databaseName().
*/ */
char *sqlite3_create_filename( const char *sqlite3_create_filename(
const char *zDatabase, const char *zDatabase,
const char *zJournal, const char *zJournal,
const char *zWal, const char *zWal,
@ -4356,10 +4546,10 @@ char *sqlite3_create_filename(
** error to call this routine with any parameter other than a pointer ** error to call this routine with any parameter other than a pointer
** previously obtained from sqlite3_create_filename() or a NULL pointer. ** previously obtained from sqlite3_create_filename() or a NULL pointer.
*/ */
void sqlite3_free_filename(char *p){ void sqlite3_free_filename(const char *p){
if( p==0 ) return; if( p==0 ) return;
p = (char*)databaseName(p); p = databaseName(p);
sqlite3_free(p - 4); sqlite3_free((char*)p - 4);
} }
@ -4387,7 +4577,7 @@ const char *sqlite3_uri_key(const char *zFilename, int N){
if( zFilename==0 || N<0 ) return 0; if( zFilename==0 || N<0 ) return 0;
zFilename = databaseName(zFilename); zFilename = databaseName(zFilename);
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] && (N--)>0 ){ while( ALWAYS(zFilename) && zFilename[0] && (N--)>0 ){
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
} }
@ -4430,12 +4620,14 @@ sqlite3_int64 sqlite3_uri_int64(
** corruption. ** corruption.
*/ */
const char *sqlite3_filename_database(const char *zFilename){ const char *sqlite3_filename_database(const char *zFilename){
if( zFilename==0 ) return 0;
return databaseName(zFilename); return databaseName(zFilename);
} }
const char *sqlite3_filename_journal(const char *zFilename){ const char *sqlite3_filename_journal(const char *zFilename){
if( zFilename==0 ) return 0;
zFilename = databaseName(zFilename); zFilename = databaseName(zFilename);
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){ while( ALWAYS(zFilename) && zFilename[0] ){
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
zFilename += sqlite3Strlen30(zFilename) + 1; zFilename += sqlite3Strlen30(zFilename) + 1;
} }
@ -4446,7 +4638,7 @@ const char *sqlite3_filename_wal(const char *zFilename){
return 0; return 0;
#else #else
zFilename = sqlite3_filename_journal(zFilename); zFilename = sqlite3_filename_journal(zFilename);
zFilename += sqlite3Strlen30(zFilename) + 1; if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1;
return zFilename; return zFilename;
#endif #endif
} }
@ -4459,6 +4651,24 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
return iDb<0 ? 0 : db->aDb[iDb].pBt; return iDb<0 ? 0 : db->aDb[iDb].pBt;
} }
/*
** Return the name of the N-th database schema. Return NULL if N is out
** of range.
*/
const char *sqlite3_db_name(sqlite3 *db, int N){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
if( N<0 || N>=db->nDb ){
return 0;
}else{
return db->aDb[N].zDbSName;
}
}
/* /*
** Return the filename of the database associated with a database ** Return the filename of the database associated with a database
** connection. ** connection.
@ -4590,8 +4800,8 @@ int sqlite3_snapshot_open(
*/ */
int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR; int rc = SQLITE_ERROR;
int iDb;
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR #ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){ if( !sqlite3SafetyCheckOk(db) ){

View file

@ -12,9 +12,7 @@
** **
** Memory allocation functions used throughout sqlite. ** Memory allocation functions used throughout sqlite.
*/ */
/* clang-format off */ #include "third_party/sqlite3/sqliteInt.h"
#include "third_party/sqlite3/sqliteInt.inc"
/* /*
** Attempt to release up to n bytes of non-essential memory currently ** Attempt to release up to n bytes of non-essential memory currently
@ -162,7 +160,6 @@ int sqlite3MallocInit(void){
if( sqlite3GlobalConfig.m.xMalloc==0 ){ if( sqlite3GlobalConfig.m.xMalloc==0 ){
sqlite3MemSetDefault(); sqlite3MemSetDefault();
} }
memset(&mem0, 0, sizeof(mem0));
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512 if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|| sqlite3GlobalConfig.nPage<=0 ){ || sqlite3GlobalConfig.nPage<=0 ){
@ -272,18 +269,34 @@ static void mallocWithAlarm(int n, void **pp){
*pp = p; *pp = p;
} }
/*
** Maximum size of any single memory allocation.
**
** This is not a limit on the total amount of memory used. This is
** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
**
** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
** This provides a 256-byte safety margin for defense against 32-bit
** signed integer overflow bugs when computing memory allocation sizes.
** Parnoid applications might want to reduce the maximum allocation size
** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
** or even smaller would be reasonable upper bounds on the size of a memory
** allocations for most applications.
*/
#ifndef SQLITE_MAX_ALLOCATION_SIZE
# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
#endif
#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
#endif
/* /*
** Allocate memory. This routine is like sqlite3_malloc() except that it ** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized. ** assumes the memory subsystem has already been initialized.
*/ */
void *sqlite3Malloc(u64 n){ void *sqlite3Malloc(u64 n){
void *p; void *p;
if( n==0 || n>=0x7fffff00 ){ if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
/* A memory allocation of a number of bytes which is near the maximum
** signed integer value might cause an integer overflow inside of the
** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
** 255 bytes of overhead. SQLite itself will never use anything near
** this amount. The only way to reach the limit is with sqlite3_malloc() */
p = 0; p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){ }else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex); sqlite3_mutex_enter(mem0.mutex);
@ -318,8 +331,8 @@ void *sqlite3_malloc64(sqlite3_uint64 n){
** TRUE if p is a lookaside memory allocation from db ** TRUE if p is a lookaside memory allocation from db
*/ */
#ifndef SQLITE_OMIT_LOOKASIDE #ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, void *p){ static int isLookaside(sqlite3 *db, const void *p){
return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd); return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
} }
#else #else
#define isLookaside(A,B) 0 #define isLookaside(A,B) 0
@ -329,32 +342,30 @@ static int isLookaside(sqlite3 *db, void *p){
** Return the size of a memory allocation previously obtained from ** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc(). ** sqlite3Malloc() or sqlite3_malloc().
*/ */
int sqlite3MallocSize(void *p){ int sqlite3MallocSize(const void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p); return sqlite3GlobalConfig.m.xSize((void*)p);
} }
static int lookasideMallocSize(sqlite3 *db, void *p){ static int lookasideMallocSize(sqlite3 *db, const void *p){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL; return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
#else #else
return db->lookaside.szTrue; return db->lookaside.szTrue;
#endif #endif
} }
int sqlite3DbMallocSize(sqlite3 *db, void *p){ int sqlite3DbMallocSize(sqlite3 *db, const void *p){
assert( p!=0 ); assert( p!=0 );
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
if( db==0 || !isLookaside(db,p) ){ if( db==0 ){
if( db==0 ){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); }else if( !isLookaside(db,p) ){
}else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
} }
#endif #endif
if( db ){ if( db ){
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3_mutex_held(db->mutex) );
@ -367,7 +378,7 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
} }
} }
} }
return sqlite3GlobalConfig.m.xSize(p); return sqlite3GlobalConfig.m.xSize((void*)p);
} }
sqlite3_uint64 sqlite3_msize(void *p){ sqlite3_uint64 sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
@ -410,14 +421,11 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( p!=0 ); assert( p!=0 );
if( db ){ if( db ){
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p; LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif #endif
@ -428,6 +436,7 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */ #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p; LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif #endif
@ -436,6 +445,10 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
return; return;
} }
} }
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
} }
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@ -443,6 +456,43 @@ void sqlite3DbFreeNN(sqlite3 *db, void *p){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP); sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p); sqlite3_free(p);
} }
void sqlite3DbNNFreeNN(sqlite3 *db, void *p){
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pSmallFree;
db->lookaside.pSmallFree = pBuf;
return;
}
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf;
return;
}
}
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
void sqlite3DbFree(sqlite3 *db, void *p){ void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p ) sqlite3DbFreeNN(db, p); if( p ) sqlite3DbFreeNN(db, p);
@ -752,8 +802,9 @@ char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
** Free any prior content in *pz and replace it with a copy of zNew. ** Free any prior content in *pz and replace it with a copy of zNew.
*/ */
void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
char *z = sqlite3DbStrDup(db, zNew);
sqlite3DbFree(db, *pz); sqlite3DbFree(db, *pz);
*pz = sqlite3DbStrDup(db, zNew); *pz = z;
} }
/* /*
@ -761,8 +812,15 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
** has happened. This routine will set db->mallocFailed, and also ** has happened. This routine will set db->mallocFailed, and also
** temporarily disable the lookaside memory allocator and interrupt ** temporarily disable the lookaside memory allocator and interrupt
** any running VDBEs. ** any running VDBEs.
**
** Always return a NULL pointer so that this routine can be invoked using
**
** return sqlite3OomFault(db);
**
** and thereby avoid unnecessary stack frame allocations for the overwhelmingly
** common case where no OOM occurs.
*/ */
void sqlite3OomFault(sqlite3 *db){ void *sqlite3OomFault(sqlite3 *db){
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
db->mallocFailed = 1; db->mallocFailed = 1;
if( db->nVdbeExec>0 ){ if( db->nVdbeExec>0 ){
@ -770,9 +828,16 @@ void sqlite3OomFault(sqlite3 *db){
} }
DisableLookaside; DisableLookaside;
if( db->pParse ){ if( db->pParse ){
Parse *pParse;
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT; db->pParse->rc = SQLITE_NOMEM_BKPT;
for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
pParse->nErr++;
pParse->rc = SQLITE_NOMEM;
}
} }
} }
return 0;
} }
/* /*

View file

@ -16,8 +16,7 @@
** are merely placeholders. Real drivers must be substituted using ** are merely placeholders. Real drivers must be substituted using
** sqlite3_config() before SQLite will operate. ** sqlite3_config() before SQLite will operate.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** This version of the memory allocator is the default. It is ** This version of the memory allocator is the default. It is

View file

@ -41,8 +41,7 @@
** be necessary when compiling for Delphi, ** be necessary when compiling for Delphi,
** for example. ** for example.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** This version of the memory allocator is the default. It is ** This version of the memory allocator is the default. It is
@ -104,16 +103,16 @@ static malloc_zone_t* _sqliteZone_;
** the macro SQLITE_MALLOCSIZE to the desired function name. ** the macro SQLITE_MALLOCSIZE to the desired function name.
*/ */
#if defined(SQLITE_USE_MALLOC_H) #if defined(SQLITE_USE_MALLOC_H)
#include "libc/mem/mem.h" # include <malloc.h>
#if defined(SQLITE_USE_MALLOC_USABLE_SIZE) # if defined(SQLITE_USE_MALLOC_USABLE_SIZE)
#if !defined(SQLITE_MALLOCSIZE) # if !defined(SQLITE_MALLOCSIZE)
#define SQLITE_MALLOCSIZE(x) malloc_usable_size(x) # define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)
#endif # endif
#elif defined(SQLITE_USE_MSIZE) # elif defined(SQLITE_USE_MSIZE)
#if !defined(SQLITE_MALLOCSIZE) # if !defined(SQLITE_MALLOCSIZE)
#define SQLITE_MALLOCSIZE _msize # define SQLITE_MALLOCSIZE _msize
#endif # endif
#endif # endif
#endif /* defined(SQLITE_USE_MALLOC_H) */ #endif /* defined(SQLITE_USE_MALLOC_H) */
#endif /* __APPLE__ or not __APPLE__ */ #endif /* __APPLE__ or not __APPLE__ */

View file

@ -19,8 +19,7 @@
** This file contains implementations of the low-level memory allocation ** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object. ** routines specified in the sqlite3_mem_methods object.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** This version of the memory allocator is used only if the ** This version of the memory allocator is used only if the
@ -38,7 +37,7 @@
# define backtrace(A,B) 1 # define backtrace(A,B) 1
# define backtrace_symbols_fd(A,B,C) # define backtrace_symbols_fd(A,B,C)
#endif #endif
#include "libc/stdio/stdio.h" #include <stdio.h>
/* /*
** Each memory allocation looks like this: ** Each memory allocation looks like this:
@ -150,7 +149,7 @@ static void adjustStats(int iSize, int increment){
** This routine checks the guards at either end of the allocation and ** This routine checks the guards at either end of the allocation and
** if they are incorrect it asserts. ** if they are incorrect it asserts.
*/ */
static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){ static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){
struct MemBlockHdr *p; struct MemBlockHdr *p;
int *pInt; int *pInt;
u8 *pU8; u8 *pU8;
@ -397,7 +396,7 @@ void sqlite3MemdebugSetType(void *p, u8 eType){
** **
** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); ** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
*/ */
int sqlite3MemdebugHasType(void *p, u8 eType){ int sqlite3MemdebugHasType(const void *p, u8 eType){
int rc = 1; int rc = 1;
if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr; struct MemBlockHdr *pHdr;
@ -419,7 +418,7 @@ int sqlite3MemdebugHasType(void *p, u8 eType){
** **
** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) ); ** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
*/ */
int sqlite3MemdebugNoType(void *p, u8 eType){ int sqlite3MemdebugNoType(const void *p, u8 eType){
int rc = 1; int rc = 1;
if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr; struct MemBlockHdr *pHdr;

View file

@ -10,12 +10,12 @@
** **
************************************************************************* *************************************************************************
** This file contains the C functions that implement a memory ** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. ** allocation subsystem for use by SQLite.
** **
** This version of the memory allocation subsystem omits all ** This version of the memory allocation subsystem omits all
** use of malloc(). The SQLite user supplies a block of memory ** use of malloc(). The SQLite user supplies a block of memory
** before calling sqlite3_initialize() from which allocations ** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc() ** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called, ** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot ** the amount of memory available to SQLite is fixed and cannot
** be changed. ** be changed.
@ -23,8 +23,7 @@
** This version of the memory allocation subsystem is included ** This version of the memory allocation subsystem is included
** in the build only if SQLITE_ENABLE_MEMSYS3 is defined. ** in the build only if SQLITE_ENABLE_MEMSYS3 is defined.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** This version of the memory allocator is only built into the library ** This version of the memory allocator is only built into the library

View file

@ -10,12 +10,12 @@
** **
************************************************************************* *************************************************************************
** This file contains the C functions that implement a memory ** This file contains the C functions that implement a memory
** allocation subsystem for use by SQLite. ** allocation subsystem for use by SQLite.
** **
** This version of the memory allocation subsystem omits all ** This version of the memory allocation subsystem omits all
** use of malloc(). The application gives SQLite a block of memory ** use of malloc(). The application gives SQLite a block of memory
** before calling sqlite3_initialize() from which allocations ** before calling sqlite3_initialize() from which allocations
** are made and returned by the xMalloc() and xRealloc() ** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called, ** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot ** the amount of memory available to SQLite is fixed and cannot
** be changed. ** be changed.
@ -35,12 +35,12 @@
** This algorithm is described in: J. M. Robson. "Bounds for Some Functions ** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
** Concerning Dynamic Storage Allocation". Journal of the Association for ** Concerning Dynamic Storage Allocation". Journal of the Association for
** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. ** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
** **
** Let n be the size of the largest allocation divided by the minimum ** Let n be the size of the largest allocation divided by the minimum
** allocation size (after rounding all sizes up to a power of 2.) Let M ** allocation size (after rounding all sizes up to a power of 2.) Let M
** be the maximum amount of memory ever outstanding at one time. Let ** be the maximum amount of memory ever outstanding at one time. Let
** N be the total amount of memory available for allocation. Robson ** N be the total amount of memory available for allocation. Robson
** proved that this memory allocator will never breakdown due to ** proved that this memory allocator will never breakdown due to
** fragmentation as long as the following constraint holds: ** fragmentation as long as the following constraint holds:
** **
** N >= M*(1 + log2(n)/2) - n + 1 ** N >= M*(1 + log2(n)/2) - n + 1
@ -48,8 +48,7 @@
** The sqlite3_status() logic tracks the maximum values of n and M so ** The sqlite3_status() logic tracks the maximum values of n and M so
** that an application can, at any time, verify this constraint. ** that an application can, at any time, verify this constraint.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** This version of the memory allocator is used only when ** This version of the memory allocator is used only when
@ -421,8 +420,13 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
*/ */
static int memsys5Roundup(int n){ static int memsys5Roundup(int n){
int iFullSz; int iFullSz;
if( n > 0x40000000 ) return 0; if( n<=mem5.szAtom*2 ){
for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2); if( n<=mem5.szAtom ) return mem5.szAtom;
return mem5.szAtom*2;
}
if( n>0x40000000 ) return 0;
for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
if( (iFullSz/2)>=n ) return iFullSz/2;
return iFullSz; return iFullSz;
} }

View file

@ -16,33 +16,89 @@
** This file also implements interface sqlite3_serialize() and ** This file also implements interface sqlite3_serialize() and
** sqlite3_deserialize(). ** sqlite3_deserialize().
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
/* clang-format off */
/* /*
** Forward declaration of objects used by this utility ** Forward declaration of objects used by this utility
*/ */
typedef struct sqlite3_vfs MemVfs; typedef struct sqlite3_vfs MemVfs;
typedef struct MemFile MemFile; typedef struct MemFile MemFile;
typedef struct MemStore MemStore;
/* Access to a lower-level VFS that (might) implement dynamic loading, /* Access to a lower-level VFS that (might) implement dynamic loading,
** access to randomness, etc. ** access to randomness, etc.
*/ */
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
/* An open file */ /* Storage for a memdb file.
struct MemFile { **
sqlite3_file base; /* IO methods */ ** An memdb object can be shared or separate. Shared memdb objects can be
** used by more than one database connection. Mutexes are used by shared
** memdb objects to coordinate access. Separate memdb objects are only
** connected to a single database connection and do not require additional
** mutexes.
**
** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created
** using "file:/name?vfs=memdb". The first character of the name must be
** "/" or else the object will be a separate memdb object. All shared
** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order.
**
** Separate memdb objects are created using a name that does not begin
** with "/" or using sqlite3_deserialize().
**
** Access rules for shared MemStore objects:
**
** * .zFName is initialized when the object is created and afterwards
** is unchanged until the object is destroyed. So it can be accessed
** at any time as long as we know the object is not being destroyed,
** which means while either the SQLITE_MUTEX_STATIC_VFS1 or
** .pMutex is held or the object is not part of memdb_g.apMemStore[].
**
** * Can .pMutex can only be changed while holding the
** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part
** of memdb_g.apMemStore[].
**
** * Other fields can only be changed while holding the .pMutex mutex
** or when the .nRef is less than zero and the object is not part of
** memdb_g.apMemStore[].
**
** * The .aData pointer has the added requirement that it can can only
** be changed (for resizing) when nMmap is zero.
**
*/
struct MemStore {
sqlite3_int64 sz; /* Size of the file */ sqlite3_int64 sz; /* Size of the file */
sqlite3_int64 szAlloc; /* Space allocated to aData */ sqlite3_int64 szAlloc; /* Space allocated to aData */
sqlite3_int64 szMax; /* Maximum allowed size of the file */ sqlite3_int64 szMax; /* Maximum allowed size of the file */
unsigned char *aData; /* content of the file */ unsigned char *aData; /* content of the file */
sqlite3_mutex *pMutex; /* Used by shared stores only */
int nMmap; /* Number of memory mapped pages */ int nMmap; /* Number of memory mapped pages */
unsigned mFlags; /* Flags */ unsigned mFlags; /* Flags */
int nRdLock; /* Number of readers */
int nWrLock; /* Number of writers. (Always 0 or 1) */
int nRef; /* Number of users of this MemStore */
char *zFName; /* The filename for shared stores */
};
/* An open file */
struct MemFile {
sqlite3_file base; /* IO methods */
MemStore *pStore; /* The storage */
int eLock; /* Most recent lock against this file */ int eLock; /* Most recent lock against this file */
}; };
/*
** File-scope variables for holding the memdb files that are accessible
** to multiple database connections in separate threads.
**
** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object.
*/
static struct MemFS {
int nMemStore; /* Number of shared MemStore objects */
MemStore **apMemStore; /* Array of all shared MemStore objects */
} memdb_g;
/* /*
** Methods for MemFile ** Methods for MemFile
*/ */
@ -96,7 +152,10 @@ static sqlite3_vfs memdb_vfs = {
memdbSleep, /* xSleep */ memdbSleep, /* xSleep */
0, /* memdbCurrentTime, */ /* xCurrentTime */ 0, /* memdbCurrentTime, */ /* xCurrentTime */
memdbGetLastError, /* xGetLastError */ memdbGetLastError, /* xGetLastError */
memdbCurrentTimeInt64 /* xCurrentTimeInt64 */ memdbCurrentTimeInt64, /* xCurrentTimeInt64 */
0, /* xSetSystemCall */
0, /* xGetSystemCall */
0, /* xNextSystemCall */
}; };
static const sqlite3_io_methods memdb_io_methods = { static const sqlite3_io_methods memdb_io_methods = {
@ -121,19 +180,67 @@ static const sqlite3_io_methods memdb_io_methods = {
memdbUnfetch /* xUnfetch */ memdbUnfetch /* xUnfetch */
}; };
/*
** Enter/leave the mutex on a MemStore
*/
#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
static void memdbEnter(MemStore *p){
UNUSED_PARAMETER(p);
}
static void memdbLeave(MemStore *p){
UNUSED_PARAMETER(p);
}
#else
static void memdbEnter(MemStore *p){
sqlite3_mutex_enter(p->pMutex);
}
static void memdbLeave(MemStore *p){
sqlite3_mutex_leave(p->pMutex);
}
#endif
/* /*
** Close an memdb-file. ** Close an memdb-file.
** ** Free the underlying MemStore object when its refcount drops to zero
** The pData pointer is owned by the application, so there is nothing ** or less.
** to free. Unless the SQLITE_DESERIALIZE_FREEONCLOSE flag is set,
** in which case we own the pData pointer and need to free it.
*/ */
static int memdbClose(sqlite3_file *pFile){ static int memdbClose(sqlite3_file *pFile){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ if( p->zFName ){
sqlite3_free(p->aData); int i;
#ifndef SQLITE_MUTEX_OMIT
sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
sqlite3_mutex_enter(pVfsMutex);
for(i=0; ALWAYS(i<memdb_g.nMemStore); i++){
if( memdb_g.apMemStore[i]==p ){
memdbEnter(p);
if( p->nRef==1 ){
memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore];
if( memdb_g.nMemStore==0 ){
sqlite3_free(memdb_g.apMemStore);
memdb_g.apMemStore = 0;
}
}
break;
}
}
sqlite3_mutex_leave(pVfsMutex);
}else{
memdbEnter(p);
}
p->nRef--;
if( p->nRef<=0 ){
if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){
sqlite3_free(p->aData);
}
memdbLeave(p);
sqlite3_mutex_free(p->pMutex);
sqlite3_free(p);
}else{
memdbLeave(p);
} }
return SQLITE_OK; return SQLITE_OK;
} }
@ -147,22 +254,25 @@ static int memdbRead(
int iAmt, int iAmt,
sqlite_int64 iOfst sqlite_int64 iOfst
){ ){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
memdbEnter(p);
if( iOfst+iAmt>p->sz ){ if( iOfst+iAmt>p->sz ){
memset(zBuf, 0, iAmt); memset(zBuf, 0, iAmt);
if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
memdbLeave(p);
return SQLITE_IOERR_SHORT_READ; return SQLITE_IOERR_SHORT_READ;
} }
memcpy(zBuf, p->aData+iOfst, iAmt); memcpy(zBuf, p->aData+iOfst, iAmt);
memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
/* /*
** Try to enlarge the memory allocation to hold at least sz bytes ** Try to enlarge the memory allocation to hold at least sz bytes
*/ */
static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){ static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){
unsigned char *pNew; unsigned char *pNew;
if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){
return SQLITE_FULL; return SQLITE_FULL;
} }
if( newSz>p->szMax ){ if( newSz>p->szMax ){
@ -171,7 +281,7 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
newSz *= 2; newSz *= 2;
if( newSz>p->szMax ) newSz = p->szMax; if( newSz>p->szMax ) newSz = p->szMax;
pNew = sqlite3Realloc(p->aData, newSz); pNew = sqlite3Realloc(p->aData, newSz);
if( pNew==0 ) return SQLITE_NOMEM; if( pNew==0 ) return SQLITE_IOERR_NOMEM;
p->aData = pNew; p->aData = pNew;
p->szAlloc = newSz; p->szAlloc = newSz;
return SQLITE_OK; return SQLITE_OK;
@ -186,19 +296,27 @@ static int memdbWrite(
int iAmt, int iAmt,
sqlite_int64 iOfst sqlite_int64 iOfst
){ ){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY; memdbEnter(p);
if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
/* Can't happen: memdbLock() will return SQLITE_READONLY before
** reaching this point */
memdbLeave(p);
return SQLITE_IOERR_WRITE;
}
if( iOfst+iAmt>p->sz ){ if( iOfst+iAmt>p->sz ){
int rc; int rc;
if( iOfst+iAmt>p->szAlloc if( iOfst+iAmt>p->szAlloc
&& (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK
){ ){
memdbLeave(p);
return rc; return rc;
} }
if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz); if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
p->sz = iOfst+iAmt; p->sz = iOfst+iAmt;
} }
memcpy(p->aData+iOfst, z, iAmt); memcpy(p->aData+iOfst, z, iAmt);
memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
@ -210,16 +328,25 @@ static int memdbWrite(
** the size of a file, never to increase the size. ** the size of a file, never to increase the size.
*/ */
static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){ static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
if( NEVER(size>p->sz) ) return SQLITE_FULL; int rc = SQLITE_OK;
p->sz = size; memdbEnter(p);
return SQLITE_OK; if( size>p->sz ){
/* This can only happen with a corrupt wal mode db */
rc = SQLITE_CORRUPT;
}else{
p->sz = size;
}
memdbLeave(p);
return rc;
} }
/* /*
** Sync an memdb-file. ** Sync an memdb-file.
*/ */
static int memdbSync(sqlite3_file *pFile, int flags){ static int memdbSync(sqlite3_file *pFile, int flags){
UNUSED_PARAMETER(pFile);
UNUSED_PARAMETER(flags);
return SQLITE_OK; return SQLITE_OK;
} }
@ -227,8 +354,10 @@ static int memdbSync(sqlite3_file *pFile, int flags){
** Return the current file-size of an memdb-file. ** Return the current file-size of an memdb-file.
*/ */
static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
memdbEnter(p);
*pSize = p->sz; *pSize = p->sz;
memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
@ -236,19 +365,48 @@ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
** Lock an memdb-file. ** Lock an memdb-file.
*/ */
static int memdbLock(sqlite3_file *pFile, int eLock){ static int memdbLock(sqlite3_file *pFile, int eLock){
MemFile *p = (MemFile *)pFile; MemFile *pThis = (MemFile*)pFile;
if( eLock>SQLITE_LOCK_SHARED MemStore *p = pThis->pStore;
&& (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0 int rc = SQLITE_OK;
){ if( eLock==pThis->eLock ) return SQLITE_OK;
return SQLITE_READONLY; memdbEnter(p);
if( eLock>SQLITE_LOCK_SHARED ){
if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){
rc = SQLITE_READONLY;
}else if( pThis->eLock<=SQLITE_LOCK_SHARED ){
if( p->nWrLock ){
rc = SQLITE_BUSY;
}else{
p->nWrLock = 1;
}
}
}else if( eLock==SQLITE_LOCK_SHARED ){
if( pThis->eLock > SQLITE_LOCK_SHARED ){
assert( p->nWrLock==1 );
p->nWrLock = 0;
}else if( p->nWrLock ){
rc = SQLITE_BUSY;
}else{
p->nRdLock++;
}
}else{
assert( eLock==SQLITE_LOCK_NONE );
if( pThis->eLock>SQLITE_LOCK_SHARED ){
assert( p->nWrLock==1 );
p->nWrLock = 0;
}
assert( p->nRdLock>0 );
p->nRdLock--;
} }
p->eLock = eLock; if( rc==SQLITE_OK ) pThis->eLock = eLock;
return SQLITE_OK; memdbLeave(p);
return rc;
} }
#if 0 /* Never used because memdbAccess() always returns false */ #if 0
/* /*
** Check if another file-handle holds a RESERVED lock on an memdb-file. ** This interface is only used for crash recovery, which does not
** occur on an in-memory database.
*/ */
static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
*pResOut = 0; *pResOut = 0;
@ -256,12 +414,14 @@ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
} }
#endif #endif
/* /*
** File control method. For custom operations on an memdb-file. ** File control method. For custom operations on an memdb-file.
*/ */
static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
int rc = SQLITE_NOTFOUND; int rc = SQLITE_NOTFOUND;
memdbEnter(p);
if( op==SQLITE_FCNTL_VFSNAME ){ if( op==SQLITE_FCNTL_VFSNAME ){
*(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz); *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
rc = SQLITE_OK; rc = SQLITE_OK;
@ -279,6 +439,7 @@ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
*(sqlite3_int64*)pArg = iLimit; *(sqlite3_int64*)pArg = iLimit;
rc = SQLITE_OK; rc = SQLITE_OK;
} }
memdbLeave(p);
return rc; return rc;
} }
@ -295,6 +456,7 @@ static int memdbSectorSize(sqlite3_file *pFile){
** Return the device characteristic flags supported by an memdb-file. ** Return the device characteristic flags supported by an memdb-file.
*/ */
static int memdbDeviceCharacteristics(sqlite3_file *pFile){ static int memdbDeviceCharacteristics(sqlite3_file *pFile){
UNUSED_PARAMETER(pFile);
return SQLITE_IOCAP_ATOMIC | return SQLITE_IOCAP_ATOMIC |
SQLITE_IOCAP_POWERSAFE_OVERWRITE | SQLITE_IOCAP_POWERSAFE_OVERWRITE |
SQLITE_IOCAP_SAFE_APPEND | SQLITE_IOCAP_SAFE_APPEND |
@ -308,20 +470,26 @@ static int memdbFetch(
int iAmt, int iAmt,
void **pp void **pp
){ ){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
if( iOfst+iAmt>p->sz ){ memdbEnter(p);
if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){
*pp = 0; *pp = 0;
}else{ }else{
p->nMmap++; p->nMmap++;
*pp = (void*)(p->aData + iOfst); *pp = (void*)(p->aData + iOfst);
} }
memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
/* Release a memory-mapped page */ /* Release a memory-mapped page */
static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
MemFile *p = (MemFile *)pFile; MemStore *p = ((MemFile*)pFile)->pStore;
UNUSED_PARAMETER(iOfst);
UNUSED_PARAMETER(pPage);
memdbEnter(p);
p->nMmap--; p->nMmap--;
memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
@ -331,20 +499,79 @@ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
static int memdbOpen( static int memdbOpen(
sqlite3_vfs *pVfs, sqlite3_vfs *pVfs,
const char *zName, const char *zName,
sqlite3_file *pFile, sqlite3_file *pFd,
int flags, int flags,
int *pOutFlags int *pOutFlags
){ ){
MemFile *p = (MemFile*)pFile; MemFile *pFile = (MemFile*)pFd;
if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ MemStore *p = 0;
return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags); int szName;
UNUSED_PARAMETER(pVfs);
memset(pFile, 0, sizeof(*pFile));
szName = sqlite3Strlen30(zName);
if( szName>1 && zName[0]=='/' ){
int i;
#ifndef SQLITE_MUTEX_OMIT
sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
sqlite3_mutex_enter(pVfsMutex);
for(i=0; i<memdb_g.nMemStore; i++){
if( strcmp(memdb_g.apMemStore[i]->zFName,zName)==0 ){
p = memdb_g.apMemStore[i];
break;
}
}
if( p==0 ){
MemStore **apNew;
p = sqlite3Malloc( sizeof(*p) + szName + 3 );
if( p==0 ){
sqlite3_mutex_leave(pVfsMutex);
return SQLITE_NOMEM;
}
apNew = sqlite3Realloc(memdb_g.apMemStore,
sizeof(apNew[0])*(memdb_g.nMemStore+1) );
if( apNew==0 ){
sqlite3_free(p);
sqlite3_mutex_leave(pVfsMutex);
return SQLITE_NOMEM;
}
apNew[memdb_g.nMemStore++] = p;
memdb_g.apMemStore = apNew;
memset(p, 0, sizeof(*p));
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE;
p->szMax = sqlite3GlobalConfig.mxMemdbSize;
p->zFName = (char*)&p[1];
memcpy(p->zFName, zName, szName+1);
p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( p->pMutex==0 ){
memdb_g.nMemStore--;
sqlite3_free(p);
sqlite3_mutex_leave(pVfsMutex);
return SQLITE_NOMEM;
}
p->nRef = 1;
memdbEnter(p);
}else{
memdbEnter(p);
p->nRef++;
}
sqlite3_mutex_leave(pVfsMutex);
}else{
p = sqlite3Malloc( sizeof(*p) );
if( p==0 ){
return SQLITE_NOMEM;
}
memset(p, 0, sizeof(*p));
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
p->szMax = sqlite3GlobalConfig.mxMemdbSize;
} }
memset(p, 0, sizeof(*p)); pFile->pStore = p;
p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; if( pOutFlags!=0 ){
assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ *pOutFlags = flags | SQLITE_OPEN_MEMORY;
*pOutFlags = flags | SQLITE_OPEN_MEMORY; }
pFile->pMethods = &memdb_io_methods; pFd->pMethods = &memdb_io_methods;
p->szMax = sqlite3GlobalConfig.mxMemdbSize; memdbLeave(p);
return SQLITE_OK; return SQLITE_OK;
} }
@ -372,6 +599,9 @@ static int memdbAccess(
int flags, int flags,
int *pResOut int *pResOut
){ ){
UNUSED_PARAMETER(pVfs);
UNUSED_PARAMETER(zPath);
UNUSED_PARAMETER(flags);
*pResOut = 0; *pResOut = 0;
return SQLITE_OK; return SQLITE_OK;
} }
@ -387,6 +617,7 @@ static int memdbFullPathname(
int nOut, int nOut,
char *zOut char *zOut
){ ){
UNUSED_PARAMETER(pVfs);
sqlite3_snprintf(nOut, zOut, "%s", zPath); sqlite3_snprintf(nOut, zOut, "%s", zPath);
return SQLITE_OK; return SQLITE_OK;
} }
@ -459,9 +690,14 @@ static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
*/ */
static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
MemFile *p = 0; MemFile *p = 0;
MemStore *pStore;
int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p); int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
if( rc ) return 0; if( rc ) return 0;
if( p->base.pMethods!=&memdb_io_methods ) return 0; if( p->base.pMethods!=&memdb_io_methods ) return 0;
pStore = p->pStore;
memdbEnter(pStore);
if( pStore->zFName!=0 ) p = 0;
memdbLeave(pStore);
return p; return p;
} }
@ -497,12 +733,14 @@ unsigned char *sqlite3_serialize(
if( piSize ) *piSize = -1; if( piSize ) *piSize = -1;
if( iDb<0 ) return 0; if( iDb<0 ) return 0;
if( p ){ if( p ){
if( piSize ) *piSize = p->sz; MemStore *pStore = p->pStore;
assert( pStore->pMutex==0 );
if( piSize ) *piSize = pStore->sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = p->aData; pOut = pStore->aData;
}else{ }else{
pOut = sqlite3_malloc64( p->sz ); pOut = sqlite3_malloc64( pStore->sz );
if( pOut ) memcpy(pOut, p->aData, p->sz); if( pOut ) memcpy(pOut, pStore->aData, pStore->sz);
} }
return pOut; return pOut;
} }
@ -572,10 +810,11 @@ int sqlite3_deserialize(
sqlite3_mutex_enter(db->mutex); sqlite3_mutex_enter(db->mutex);
if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
iDb = sqlite3FindDbName(db, zSchema); iDb = sqlite3FindDbName(db, zSchema);
if( iDb<0 ){ testcase( iDb==1 );
if( iDb<2 && iDb!=0 ){
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
goto end_deserialize; goto end_deserialize;
} }
zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
if( zSql==0 ){ if( zSql==0 ){
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
@ -596,15 +835,16 @@ int sqlite3_deserialize(
if( p==0 ){ if( p==0 ){
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
p->aData = pData; MemStore *pStore = p->pStore;
pStore->aData = pData;
pData = 0; pData = 0;
p->sz = szDb; pStore->sz = szDb;
p->szAlloc = szBuf; pStore->szAlloc = szBuf;
p->szMax = szBuf; pStore->szMax = szBuf;
if( p->szMax<sqlite3GlobalConfig.mxMemdbSize ){ if( pStore->szMax<sqlite3GlobalConfig.mxMemdbSize ){
p->szMax = sqlite3GlobalConfig.mxMemdbSize; pStore->szMax = sqlite3GlobalConfig.mxMemdbSize;
} }
p->mFlags = mFlags; pStore->mFlags = mFlags;
rc = SQLITE_OK; rc = SQLITE_OK;
} }
@ -623,7 +863,9 @@ end_deserialize:
*/ */
int sqlite3MemdbInit(void){ int sqlite3MemdbInit(void){
sqlite3_vfs *pLower = sqlite3_vfs_find(0); sqlite3_vfs *pLower = sqlite3_vfs_find(0);
int sz = pLower->szOsFile; unsigned int sz;
if( NEVER(pLower==0) ) return SQLITE_ERROR;
sz = pLower->szOsFile;
memdb_vfs.pAppData = pLower; memdb_vfs.pAppData = pLower;
/* The following conditional can only be true when compiled for /* The following conditional can only be true when compiled for
** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
@ -633,4 +875,4 @@ int sqlite3MemdbInit(void){
memdb_vfs.szOsFile = sz; memdb_vfs.szOsFile = sz;
return sqlite3_vfs_register(&memdb_vfs, 0); return sqlite3_vfs_register(&memdb_vfs, 0);
} }
#endif /* SQLITE_ENABLE_DESERIALIZE */ #endif /* SQLITE_OMIT_DESERIALIZE */

View file

@ -23,8 +23,7 @@
** in the common case, they are usually small and no file I/O needs to ** in the common case, they are usually small and no file I/O needs to
** occur. ** occur.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* Forward references to internal structures */ /* Forward references to internal structures */
typedef struct MemJournal MemJournal; typedef struct MemJournal MemJournal;
@ -179,6 +178,9 @@ static int memjrnlCreateFile(MemJournal *p){
} }
/* Forward reference */
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size);
/* /*
** Write data to the file. ** Write data to the file.
*/ */
@ -208,23 +210,21 @@ static int memjrnlWrite(
** access writes are not required. The only exception to this is when ** access writes are not required. The only exception to this is when
** the in-memory journal is being used by a connection using the ** the in-memory journal is being used by a connection using the
** atomic-write optimization. In this case the first 28 bytes of the ** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */ ** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 ); assert( iOfst<=p->endpoint.iOffset );
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ if( iOfst>0 && iOfst!=p->endpoint.iOffset ){
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) memjrnlTruncate(pJfd, iOfst);
}
if( iOfst==0 && p->pFirst ){ if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt ); assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
}else }else{
#else
assert( iOfst>0 || p->pFirst==0 );
#endif
{
while( nWrite>0 ){ while( nWrite>0 ){
FileChunk *pChunk = p->endpoint.pChunk; FileChunk *pChunk = p->endpoint.pChunk;
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
assert( pChunk!=0 || iChunkOffset==0 );
if( iChunkOffset==0 ){ if( iChunkOffset==0 ){
/* New chunk is required to extend the file. */ /* New chunk is required to extend the file. */
FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
@ -239,10 +239,11 @@ static int memjrnlWrite(
assert( !p->pFirst ); assert( !p->pFirst );
p->pFirst = pNew; p->pFirst = pNew;
} }
p->endpoint.pChunk = pNew; pChunk = p->endpoint.pChunk = pNew;
} }
memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); assert( pChunk!=0 );
memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace);
zWrite += iSpace; zWrite += iSpace;
nWrite -= iSpace; nWrite -= iSpace;
p->endpoint.iOffset += iSpace; p->endpoint.iOffset += iSpace;
@ -258,26 +259,28 @@ static int memjrnlWrite(
*/ */
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd; MemJournal *p = (MemJournal *)pJfd;
FileChunk *pIter = 0; assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 );
if( size<p->endpoint.iOffset ){
FileChunk *pIter = 0;
if( size==0 ){
memjrnlFreeChunks(p->pFirst);
p->pFirst = 0;
}else{
i64 iOff = p->nChunkSize;
for(pIter=p->pFirst; ALWAYS(pIter) && iOff<size; pIter=pIter->pNext){
iOff += p->nChunkSize;
}
if( ALWAYS(pIter) ){
memjrnlFreeChunks(pIter->pNext);
pIter->pNext = 0;
}
}
if( size==0 ){ p->endpoint.pChunk = pIter;
memjrnlFreeChunks(p->pFirst); p->endpoint.iOffset = size;
p->pFirst = 0; p->readpoint.pChunk = 0;
}else{ p->readpoint.iOffset = 0;
i64 iOff = p->nChunkSize;
for(pIter=p->pFirst; ALWAYS(pIter) && iOff<=size; pIter=pIter->pNext){
iOff += p->nChunkSize;
}
if( ALWAYS(pIter) ){
memjrnlFreeChunks(pIter->pNext);
pIter->pNext = 0;
}
} }
p->endpoint.pChunk = pIter;
p->endpoint.iOffset = size;
p->readpoint.pChunk = 0;
p->readpoint.iOffset = 0;
return SQLITE_OK; return SQLITE_OK;
} }
@ -356,6 +359,8 @@ int sqlite3JournalOpen(
){ ){
MemJournal *p = (MemJournal*)pJfd; MemJournal *p = (MemJournal*)pJfd;
assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
/* Zero the file-handle object. If nSpill was passed zero, initialize /* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this ** 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 ** case none of the code in this module is executed as a result of calls

View file

@ -14,7 +14,6 @@
*/ */
#ifndef SQLITE_MSVC_H #ifndef SQLITE_MSVC_H
#define SQLITE_MSVC_H #define SQLITE_MSVC_H
/* clang-format off */
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(disable : 4054) #pragma warning(disable : 4054)

View file

@ -13,8 +13,7 @@
** **
** This file contains code that is common across all mutex implementations. ** This file contains code that is common across all mutex implementations.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) #if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT)
/* /*

View file

@ -19,7 +19,6 @@
** Source files should #include the sqliteInt.h file and let that file ** Source files should #include the sqliteInt.h file and let that file
** include this one indirectly. ** include this one indirectly.
*/ */
/* clang-format off */
/* /*

View file

@ -25,8 +25,7 @@
** that does error checking on mutexes to make sure they are being ** that does error checking on mutexes to make sure they are being
** called correctly. ** called correctly.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#ifndef SQLITE_MUTEX_OMIT #ifndef SQLITE_MUTEX_OMIT

View file

@ -11,9 +11,7 @@
************************************************************************* *************************************************************************
** This file contains the C functions that implement mutexes for pthreads ** This file contains the C functions that implement mutexes for pthreads
*/ */
#include "libc/thread/thread.h" #include "third_party/sqlite3/sqliteInt.h"
#include "third_party/sqlite3/sqliteInt.inc"
/* clang-format off */
/* /*
** The code in this file is only used if we are compiling threadsafe ** The code in this file is only used if we are compiling threadsafe
@ -24,6 +22,8 @@
*/ */
#ifdef SQLITE_MUTEX_PTHREADS #ifdef SQLITE_MUTEX_PTHREADS
#include "libc/thread/thread.h"
/* /*
** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields ** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
** are necessary under two condidtions: (1) Debug builds and (2) using ** are necessary under two condidtions: (1) Debug builds and (2) using

View file

@ -13,9 +13,8 @@
** This file contains the implementation of the sqlite3_unlock_notify() ** This file contains the implementation of the sqlite3_unlock_notify()
** API method and its associated functionality. ** API method and its associated functionality.
*/ */
#include "third_party/sqlite3/btreeInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/btreeInt.h"
/* clang-format off */
/* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */ /* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY

View file

@ -1,4 +1,3 @@
/* clang-format off */
/* Automatically generated. Do not edit */ /* Automatically generated. Do not edit */
/* See the tool/mkopcodec.tcl script for details. */ /* See the tool/mkopcodec.tcl script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) \ #if !defined(SQLITE_OMIT_EXPLAIN) \
@ -14,53 +13,53 @@ const char *sqlite3OpcodeName(int i){
/* 0 */ "Savepoint" OpHelp(""), /* 0 */ "Savepoint" OpHelp(""),
/* 1 */ "AutoCommit" OpHelp(""), /* 1 */ "AutoCommit" OpHelp(""),
/* 2 */ "Transaction" OpHelp(""), /* 2 */ "Transaction" OpHelp(""),
/* 3 */ "SorterNext" OpHelp(""), /* 3 */ "Checkpoint" OpHelp(""),
/* 4 */ "Prev" OpHelp(""), /* 4 */ "JournalMode" OpHelp(""),
/* 5 */ "Next" OpHelp(""), /* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "Checkpoint" OpHelp(""), /* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "JournalMode" OpHelp(""), /* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
/* 8 */ "Vacuum" OpHelp(""), /* 8 */ "Init" OpHelp("Start at P2"),
/* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"), /* 9 */ "Goto" OpHelp(""),
/* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"), /* 10 */ "Gosub" OpHelp(""),
/* 11 */ "Goto" OpHelp(""), /* 11 */ "InitCoroutine" OpHelp(""),
/* 12 */ "Gosub" OpHelp(""), /* 12 */ "Yield" OpHelp(""),
/* 13 */ "InitCoroutine" OpHelp(""), /* 13 */ "MustBeInt" OpHelp(""),
/* 14 */ "Yield" OpHelp(""), /* 14 */ "Jump" OpHelp(""),
/* 15 */ "MustBeInt" OpHelp(""), /* 15 */ "Once" OpHelp(""),
/* 16 */ "Jump" OpHelp(""), /* 16 */ "If" OpHelp(""),
/* 17 */ "Once" OpHelp(""), /* 17 */ "IfNot" OpHelp(""),
/* 18 */ "If" OpHelp(""), /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"), /* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
/* 20 */ "IfNot" OpHelp(""), /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
/* 21 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"), /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
/* 22 */ "SeekLT" OpHelp("key=r[P3@P4]"), /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
/* 23 */ "SeekLE" OpHelp("key=r[P3@P4]"), /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
/* 24 */ "SeekGE" OpHelp("key=r[P3@P4]"), /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
/* 25 */ "SeekGT" OpHelp("key=r[P3@P4]"), /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
/* 26 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"), /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
/* 27 */ "IfNoHope" OpHelp("key=r[P3@P4]"), /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
/* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"), /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"),
/* 29 */ "NotFound" OpHelp("key=r[P3@P4]"), /* 29 */ "Found" OpHelp("key=r[P3@P4]"),
/* 30 */ "Found" OpHelp("key=r[P3@P4]"), /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
/* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"), /* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
/* 32 */ "NotExists" OpHelp("intkey=r[P3]"), /* 32 */ "Last" OpHelp(""),
/* 33 */ "Last" OpHelp(""), /* 33 */ "IfSmaller" OpHelp(""),
/* 34 */ "IfSmaller" OpHelp(""), /* 34 */ "SorterSort" OpHelp(""),
/* 35 */ "SorterSort" OpHelp(""), /* 35 */ "Sort" OpHelp(""),
/* 36 */ "Sort" OpHelp(""), /* 36 */ "Rewind" OpHelp(""),
/* 37 */ "Rewind" OpHelp(""), /* 37 */ "SorterNext" OpHelp(""),
/* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"), /* 38 */ "Prev" OpHelp(""),
/* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"), /* 39 */ "Next" OpHelp(""),
/* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
/* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"), /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
/* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"), /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
/* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
/* 46 */ "Program" OpHelp(""), /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
/* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
/* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), /* 48 */ "Program" OpHelp(""),
/* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
@ -69,50 +68,50 @@ const char *sqlite3OpcodeName(int i){
/* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"), /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"), /* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"), /* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
/* 58 */ "ElseNotEq" OpHelp(""), /* 58 */ "ElseEq" OpHelp(""),
/* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
/* 60 */ "IncrVacuum" OpHelp(""), /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
/* 61 */ "VNext" OpHelp(""), /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
/* 62 */ "Init" OpHelp("Start at P2"), /* 62 */ "IncrVacuum" OpHelp(""),
/* 63 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), /* 63 */ "VNext" OpHelp(""),
/* 64 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "Return" OpHelp(""), /* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
/* 66 */ "EndCoroutine" OpHelp(""), /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
/* 67 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), /* 67 */ "Return" OpHelp(""),
/* 68 */ "Halt" OpHelp(""), /* 68 */ "EndCoroutine" OpHelp(""),
/* 69 */ "Integer" OpHelp("r[P2]=P1"), /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
/* 70 */ "Int64" OpHelp("r[P2]=P4"), /* 70 */ "Halt" OpHelp(""),
/* 71 */ "String" OpHelp("r[P2]='P4' (len=P1)"), /* 71 */ "Integer" OpHelp("r[P2]=P1"),
/* 72 */ "Null" OpHelp("r[P2..P3]=NULL"), /* 72 */ "Int64" OpHelp("r[P2]=P4"),
/* 73 */ "SoftNull" OpHelp("r[P1]=NULL"), /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
/* 74 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"),
/* 75 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"),
/* 76 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"),
/* 77 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
/* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"), /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
/* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"), /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
/* 80 */ "ChngCntRow" OpHelp("output=r[P1]"), /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
/* 81 */ "ResultRow" OpHelp("output=r[P1@P2]"), /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"),
/* 82 */ "CollSeq" OpHelp(""), /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
/* 83 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), /* 83 */ "FkCheck" OpHelp(""),
/* 84 */ "RealAffinity" OpHelp(""), /* 84 */ "ResultRow" OpHelp("output=r[P1@P2]"),
/* 85 */ "Cast" OpHelp("affinity(r[P1])"), /* 85 */ "CollSeq" OpHelp(""),
/* 86 */ "Permutation" OpHelp(""), /* 86 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
/* 87 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), /* 87 */ "RealAffinity" OpHelp(""),
/* 88 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), /* 88 */ "Cast" OpHelp("affinity(r[P1])"),
/* 89 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), /* 89 */ "Permutation" OpHelp(""),
/* 90 */ "Column" OpHelp("r[P3]=PX"), /* 90 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
/* 91 */ "Affinity" OpHelp("affinity(r[P1@P2])"), /* 91 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
/* 92 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), /* 92 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"),
/* 93 */ "Count" OpHelp("r[P2]=count()"), /* 93 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"),
/* 94 */ "ReadCookie" OpHelp(""), /* 94 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"),
/* 95 */ "SetCookie" OpHelp(""), /* 95 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"),
/* 96 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
/* 97 */ "OpenRead" OpHelp("root=P2 iDb=P3"), /* 97 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
/* 98 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), /* 98 */ "Count" OpHelp("r[P2]=count()"),
/* 99 */ "OpenDup" OpHelp(""), /* 99 */ "ReadCookie" OpHelp(""),
/* 100 */ "OpenAutoindex" OpHelp("nColumn=P2"), /* 100 */ "SetCookie" OpHelp(""),
/* 101 */ "OpenEphemeral" OpHelp("nColumn=P2"), /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
/* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
/* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
/* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"), /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
@ -123,73 +122,81 @@ const char *sqlite3OpcodeName(int i){
/* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
/* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
/* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
/* 112 */ "SorterOpen" OpHelp(""), /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
/* 113 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
/* 114 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
/* 115 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), /* 115 */ "OpenDup" OpHelp(""),
/* 116 */ "String8" OpHelp("r[P2]='P4'"), /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"),
/* 117 */ "Close" OpHelp(""), /* 117 */ "String8" OpHelp("r[P2]='P4'"),
/* 118 */ "ColumnsUsed" OpHelp(""), /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"),
/* 119 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"), /* 119 */ "SorterOpen" OpHelp(""),
/* 120 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"), /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
/* 121 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
/* 122 */ "NewRowid" OpHelp("r[P2]=rowid"), /* 122 */ "Close" OpHelp(""),
/* 123 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), /* 123 */ "ColumnsUsed" OpHelp(""),
/* 124 */ "RowCell" OpHelp(""), /* 124 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"),
/* 125 */ "Delete" OpHelp(""), /* 125 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"),
/* 126 */ "ResetCount" OpHelp(""), /* 126 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
/* 127 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), /* 127 */ "NewRowid" OpHelp("r[P2]=rowid"),
/* 128 */ "SorterData" OpHelp("r[P2]=data"), /* 128 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
/* 129 */ "RowData" OpHelp("r[P2]=data"), /* 129 */ "RowCell" OpHelp(""),
/* 130 */ "Rowid" OpHelp("r[P2]=rowid"), /* 130 */ "Delete" OpHelp(""),
/* 131 */ "NullRow" OpHelp(""), /* 131 */ "ResetCount" OpHelp(""),
/* 132 */ "SeekEnd" OpHelp(""), /* 132 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
/* 133 */ "IdxInsert" OpHelp("key=r[P2]"), /* 133 */ "SorterData" OpHelp("r[P2]=data"),
/* 134 */ "SorterInsert" OpHelp("key=r[P2]"), /* 134 */ "RowData" OpHelp("r[P2]=data"),
/* 135 */ "IdxDelete" OpHelp("key=r[P2@P3]"), /* 135 */ "Rowid" OpHelp("r[P2]=PX rowid of P1"),
/* 136 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"), /* 136 */ "NullRow" OpHelp(""),
/* 137 */ "IdxRowid" OpHelp("r[P2]=rowid"), /* 137 */ "SeekEnd" OpHelp(""),
/* 138 */ "FinishSeek" OpHelp(""), /* 138 */ "IdxInsert" OpHelp("key=r[P2]"),
/* 139 */ "Destroy" OpHelp(""), /* 139 */ "SorterInsert" OpHelp("key=r[P2]"),
/* 140 */ "Clear" OpHelp(""), /* 140 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
/* 141 */ "ResetSorter" OpHelp(""), /* 141 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
/* 142 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), /* 142 */ "IdxRowid" OpHelp("r[P2]=rowid"),
/* 143 */ "SqlExec" OpHelp(""), /* 143 */ "FinishSeek" OpHelp(""),
/* 144 */ "ParseSchema" OpHelp(""), /* 144 */ "Destroy" OpHelp(""),
/* 145 */ "LoadAnalysis" OpHelp(""), /* 145 */ "Clear" OpHelp(""),
/* 146 */ "DropTable" OpHelp(""), /* 146 */ "ResetSorter" OpHelp(""),
/* 147 */ "DropIndex" OpHelp(""), /* 147 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"),
/* 148 */ "DropTrigger" OpHelp(""), /* 148 */ "SqlExec" OpHelp(""),
/* 149 */ "IntegrityCk" OpHelp(""), /* 149 */ "ParseSchema" OpHelp(""),
/* 150 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), /* 150 */ "LoadAnalysis" OpHelp(""),
/* 151 */ "Param" OpHelp(""), /* 151 */ "DropTable" OpHelp(""),
/* 152 */ "Real" OpHelp("r[P2]=P4"), /* 152 */ "DropIndex" OpHelp(""),
/* 153 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), /* 153 */ "Real" OpHelp("r[P2]=P4"),
/* 154 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), /* 154 */ "DropTrigger" OpHelp(""),
/* 155 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), /* 155 */ "IntegrityCk" OpHelp(""),
/* 156 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
/* 157 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), /* 157 */ "Param" OpHelp(""),
/* 158 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
/* 159 */ "AggValue" OpHelp("r[P3]=value N=P2"), /* 159 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
/* 160 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), /* 160 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
/* 161 */ "Expire" OpHelp(""), /* 161 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"),
/* 162 */ "CursorLock" OpHelp(""), /* 162 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
/* 163 */ "CursorUnlock" OpHelp(""), /* 163 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"),
/* 164 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), /* 164 */ "AggValue" OpHelp("r[P3]=value N=P2"),
/* 165 */ "VBegin" OpHelp(""), /* 165 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
/* 166 */ "VCreate" OpHelp(""), /* 166 */ "Expire" OpHelp(""),
/* 167 */ "VDestroy" OpHelp(""), /* 167 */ "CursorLock" OpHelp(""),
/* 168 */ "VOpen" OpHelp(""), /* 168 */ "CursorUnlock" OpHelp(""),
/* 169 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), /* 169 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
/* 170 */ "VRename" OpHelp(""), /* 170 */ "VBegin" OpHelp(""),
/* 171 */ "Pagecount" OpHelp(""), /* 171 */ "VCreate" OpHelp(""),
/* 172 */ "MaxPgcnt" OpHelp(""), /* 172 */ "VDestroy" OpHelp(""),
/* 173 */ "Trace" OpHelp(""), /* 173 */ "VOpen" OpHelp(""),
/* 174 */ "CursorHint" OpHelp(""), /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
/* 175 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
/* 176 */ "Noop" OpHelp(""), /* 176 */ "VRename" OpHelp(""),
/* 177 */ "Explain" OpHelp(""), /* 177 */ "Pagecount" OpHelp(""),
/* 178 */ "Abortable" OpHelp(""), /* 178 */ "MaxPgcnt" OpHelp(""),
/* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
/* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
/* 181 */ "Trace" OpHelp(""),
/* 182 */ "CursorHint" OpHelp(""),
/* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
/* 184 */ "Noop" OpHelp(""),
/* 185 */ "Explain" OpHelp(""),
/* 186 */ "Abortable" OpHelp(""),
}; };
return azName[i]; return azName[i];
} }

233
third_party/sqlite3/opcodes.h vendored Normal file
View file

@ -0,0 +1,233 @@
/* Automatically generated. Do not edit */
/* See the tool/mkopcodeh.tcl script for details */
#define OP_Savepoint 0
#define OP_AutoCommit 1
#define OP_Transaction 2
#define OP_Checkpoint 3
#define OP_JournalMode 4
#define OP_Vacuum 5
#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
#define OP_Init 8 /* jump, synopsis: Start at P2 */
#define OP_Goto 9 /* jump */
#define OP_Gosub 10 /* jump */
#define OP_InitCoroutine 11 /* jump */
#define OP_Yield 12 /* jump */
#define OP_MustBeInt 13 /* jump */
#define OP_Jump 14 /* jump */
#define OP_Once 15 /* jump */
#define OP_If 16 /* jump */
#define OP_IfNot 17 /* jump */
#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */
#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */
#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
#define OP_Last 32 /* jump */
#define OP_IfSmaller 33 /* jump */
#define OP_SorterSort 34 /* jump */
#define OP_Sort 35 /* jump */
#define OP_Rewind 36 /* jump */
#define OP_SorterNext 37 /* jump */
#define OP_Prev 38 /* jump */
#define OP_Next 39 /* jump */
#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */
#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */
#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program 48 /* jump */
#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
#define OP_IncrVacuum 62 /* jump */
#define OP_VNext 63 /* jump */
#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Return 67
#define OP_EndCoroutine 68
#define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */
#define OP_Halt 70
#define OP_Integer 71 /* synopsis: r[P2]=P1 */
#define OP_Int64 72 /* synopsis: r[P2]=P4 */
#define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */
#define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */
#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */
#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */
#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */
#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */
#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */
#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */
#define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */
#define OP_FkCheck 83
#define OP_ResultRow 84 /* synopsis: output=r[P1@P2] */
#define OP_CollSeq 85
#define OP_AddImm 86 /* synopsis: r[P1]=r[P1]+P2 */
#define OP_RealAffinity 87
#define OP_Cast 88 /* synopsis: affinity(r[P1]) */
#define OP_Permutation 89
#define OP_Compare 90 /* synopsis: r[P1@P3] <-> r[P2@P3] */
#define OP_IsTrue 91 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_ZeroOrNull 92 /* synopsis: r[P2] = 0 OR NULL */
#define OP_Offset 93 /* synopsis: r[P3] = sqlite_offset(P1) */
#define OP_Column 94 /* synopsis: r[P3]=PX cursor P1 column P2 */
#define OP_TypeCheck 95 /* synopsis: typecheck(r[P1@P2]) */
#define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */
#define OP_MakeRecord 97 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
#define OP_Count 98 /* synopsis: r[P2]=count() */
#define OP_ReadCookie 99
#define OP_SetCookie 100
#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */
#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight 105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */
#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_OpenDup 115
#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */
#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */
#define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */
#define OP_SorterOpen 119
#define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */
#define OP_Close 122
#define OP_ColumnsUsed 123
#define OP_SeekScan 124 /* synopsis: Scan-ahead up to P1 rows */
#define OP_SeekHit 125 /* synopsis: set P2<=seekHit<=P3 */
#define OP_Sequence 126 /* synopsis: r[P2]=cursor[P1].ctr++ */
#define OP_NewRowid 127 /* synopsis: r[P2]=rowid */
#define OP_Insert 128 /* synopsis: intkey=r[P3] data=r[P2] */
#define OP_RowCell 129
#define OP_Delete 130
#define OP_ResetCount 131
#define OP_SorterCompare 132 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_SorterData 133 /* synopsis: r[P2]=data */
#define OP_RowData 134 /* synopsis: r[P2]=data */
#define OP_Rowid 135 /* synopsis: r[P2]=PX rowid of P1 */
#define OP_NullRow 136
#define OP_SeekEnd 137
#define OP_IdxInsert 138 /* synopsis: key=r[P2] */
#define OP_SorterInsert 139 /* synopsis: key=r[P2] */
#define OP_IdxDelete 140 /* synopsis: key=r[P2@P3] */
#define OP_DeferredSeek 141 /* synopsis: Move P3 to P1.rowid if needed */
#define OP_IdxRowid 142 /* synopsis: r[P2]=rowid */
#define OP_FinishSeek 143
#define OP_Destroy 144
#define OP_Clear 145
#define OP_ResetSorter 146
#define OP_CreateBtree 147 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
#define OP_SqlExec 148
#define OP_ParseSchema 149
#define OP_LoadAnalysis 150
#define OP_DropTable 151
#define OP_DropIndex 152
#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
#define OP_DropTrigger 154
#define OP_IntegrityCk 155
#define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */
#define OP_Param 157
#define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */
#define OP_MemMax 159 /* synopsis: r[P1]=max(r[P1],r[P2]) */
#define OP_OffsetLimit 160 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_AggInverse 161 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */
#define OP_AggStep 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */
#define OP_AggStep1 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */
#define OP_AggValue 164 /* synopsis: r[P3]=value N=P2 */
#define OP_AggFinal 165 /* synopsis: accum=r[P1] N=P2 */
#define OP_Expire 166
#define OP_CursorLock 167
#define OP_CursorUnlock 168
#define OP_TableLock 169 /* synopsis: iDb=P1 root=P2 write=P3 */
#define OP_VBegin 170
#define OP_VCreate 171
#define OP_VDestroy 172
#define OP_VOpen 173
#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */
#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */
#define OP_VRename 176
#define OP_Pagecount 177
#define OP_MaxPgcnt 178
#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */
#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */
#define OP_Trace 181
#define OP_CursorHint 182
#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */
#define OP_Noop 184
#define OP_Explain 185
#define OP_Abortable 186
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */
#define OPFLG_IN1 0x02 /* in1: P1 is an input */
#define OPFLG_IN2 0x04 /* in2: P2 is an input */
#define OPFLG_IN3 0x08 /* in3: P3 is an input */
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x09, 0x09, 0x09,\
/* 24 */ 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x01, 0x23, 0x0b,\
/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00,\
/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\
/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
/* 136 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\
/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
/* 184 */ 0x00, 0x00, 0x00,}
/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */

View file

@ -1,232 +0,0 @@
/* Automatically generated. Do not edit */
/* See the tool/mkopcodeh.tcl script for details */
#define OP_Savepoint 0
#define OP_AutoCommit 1
#define OP_Transaction 2
#define OP_SorterNext 3 /* jump */
#define OP_Prev 4 /* jump */
#define OP_Next 5 /* jump */
#define OP_Checkpoint 6
#define OP_JournalMode 7
#define OP_Vacuum 8
#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */
#define OP_Goto 11 /* jump */
#define OP_Gosub 12 /* jump */
#define OP_InitCoroutine 13 /* jump */
#define OP_Yield 14 /* jump */
#define OP_MustBeInt 15 /* jump */
#define OP_Jump 16 /* jump */
#define OP_Once 17 /* jump */
#define OP_If 18 /* jump */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
#define OP_IfNot 20 /* jump */
#define OP_IfNullRow \
21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT 22 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekLE 23 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekGE 24 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekGT 25 /* jump, synopsis: key=r[P3@P4] */
#define OP_IfNotOpen 26 /* jump, synopsis: if( !csr[P1] ) goto P2 */
#define OP_IfNoHope 27 /* jump, synopsis: key=r[P3@P4] */
#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */
#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */
#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */
#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */
#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */
#define OP_Last 33 /* jump */
#define OP_IfSmaller 34 /* jump */
#define OP_SorterSort 35 /* jump */
#define OP_Sort 36 /* jump */
#define OP_Rewind 37 /* jump */
#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */
#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */
#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */
#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */
#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program 46 /* jump */
#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 \
*/
#define OP_IsNull \
50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull \
51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */
#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */
#define OP_IncrVacuum 60 /* jump */
#define OP_VNext 61 /* jump */
#define OP_Init 62 /* jump, synopsis: Start at P2 */
#define OP_PureFunc 63 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Function 64 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Return 65
#define OP_EndCoroutine 66
#define OP_HaltIfNull 67 /* synopsis: if r[P3]=null halt */
#define OP_Halt 68
#define OP_Integer 69 /* synopsis: r[P2]=P1 */
#define OP_Int64 70 /* synopsis: r[P2]=P4 */
#define OP_String 71 /* synopsis: r[P2]='P4' (len=P1) */
#define OP_Null 72 /* synopsis: r[P2..P3]=NULL */
#define OP_SoftNull 73 /* synopsis: r[P1]=NULL */
#define OP_Blob 74 /* synopsis: r[P2]=P4 (len=P1) */
#define OP_Variable 75 /* synopsis: r[P2]=parameter(P1,P4) */
#define OP_Move 76 /* synopsis: r[P2@P3]=r[P1@P3] */
#define OP_Copy 77 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
#define OP_SCopy 78 /* synopsis: r[P2]=r[P1] */
#define OP_IntCopy 79 /* synopsis: r[P2]=r[P1] */
#define OP_ChngCntRow 80 /* synopsis: output=r[P1] */
#define OP_ResultRow 81 /* synopsis: output=r[P1@P2] */
#define OP_CollSeq 82
#define OP_AddImm 83 /* synopsis: r[P1]=r[P1]+P2 */
#define OP_RealAffinity 84
#define OP_Cast 85 /* synopsis: affinity(r[P1]) */
#define OP_Permutation 86
#define OP_Compare 87 /* synopsis: r[P1@P3] <-> r[P2@P3] */
#define OP_IsTrue 88 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_Offset 89 /* synopsis: r[P3] = sqlite_offset(P1) */
#define OP_Column 90 /* synopsis: r[P3]=PX */
#define OP_Affinity 91 /* synopsis: affinity(r[P1@P2]) */
#define OP_MakeRecord 92 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
#define OP_Count 93 /* synopsis: r[P2]=count() */
#define OP_ReadCookie 94
#define OP_SetCookie 95
#define OP_ReopenIdx 96 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenRead 97 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenWrite 98 /* synopsis: root=P2 iDb=P3 */
#define OP_OpenDup 99
#define OP_OpenAutoindex 100 /* synopsis: nColumn=P2 */
#define OP_OpenEphemeral 101 /* synopsis: nColumn=P2 */
#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight 105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] \
*/
#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_SorterOpen 112
#define OP_BitNot 113 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_SequenceTest 114 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
#define OP_OpenPseudo 115 /* synopsis: P3 columns in r[P2] */
#define OP_String8 116 /* same as TK_STRING, synopsis: r[P2]='P4' */
#define OP_Close 117
#define OP_ColumnsUsed 118
#define OP_SeekScan 119 /* synopsis: Scan-ahead up to P1 rows */
#define OP_SeekHit 120 /* synopsis: set P2<=seekHit<=P3 */
#define OP_Sequence 121 /* synopsis: r[P2]=cursor[P1].ctr++ */
#define OP_NewRowid 122 /* synopsis: r[P2]=rowid */
#define OP_Insert 123 /* synopsis: intkey=r[P3] data=r[P2] */
#define OP_RowCell 124
#define OP_Delete 125
#define OP_ResetCount 126
#define OP_SorterCompare 127 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 \
*/
#define OP_SorterData 128 /* synopsis: r[P2]=data */
#define OP_RowData 129 /* synopsis: r[P2]=data */
#define OP_Rowid 130 /* synopsis: r[P2]=rowid */
#define OP_NullRow 131
#define OP_SeekEnd 132
#define OP_IdxInsert 133 /* synopsis: key=r[P2] */
#define OP_SorterInsert 134 /* synopsis: key=r[P2] */
#define OP_IdxDelete 135 /* synopsis: key=r[P2@P3] */
#define OP_DeferredSeek 136 /* synopsis: Move P3 to P1.rowid if needed */
#define OP_IdxRowid 137 /* synopsis: r[P2]=rowid */
#define OP_FinishSeek 138
#define OP_Destroy 139
#define OP_Clear 140
#define OP_ResetSorter 141
#define OP_CreateBtree 142 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
#define OP_SqlExec 143
#define OP_ParseSchema 144
#define OP_LoadAnalysis 145
#define OP_DropTable 146
#define OP_DropIndex 147
#define OP_DropTrigger 148
#define OP_IntegrityCk 149
#define OP_RowSetAdd 150 /* synopsis: rowset(P1)=r[P2] */
#define OP_Param 151
#define OP_Real 152 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
#define OP_FkCounter 153 /* synopsis: fkctr[P1]+=P2 */
#define OP_MemMax 154 /* synopsis: r[P1]=max(r[P1],r[P2]) */
#define OP_OffsetLimit \
155 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_AggInverse 156 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */
#define OP_AggStep 157 /* synopsis: accum=r[P3] step(r[P2@P5]) */
#define OP_AggStep1 158 /* synopsis: accum=r[P3] step(r[P2@P5]) */
#define OP_AggValue 159 /* synopsis: r[P3]=value N=P2 */
#define OP_AggFinal 160 /* synopsis: accum=r[P1] N=P2 */
#define OP_Expire 161
#define OP_CursorLock 162
#define OP_CursorUnlock 163
#define OP_TableLock 164 /* synopsis: iDb=P1 root=P2 write=P3 */
#define OP_VBegin 165
#define OP_VCreate 166
#define OP_VDestroy 167
#define OP_VOpen 168
#define OP_VColumn 169 /* synopsis: r[P3]=vcolumn(P2) */
#define OP_VRename 170
#define OP_Pagecount 171
#define OP_MaxPgcnt 172
#define OP_Trace 173
#define OP_CursorHint 174
#define OP_ReleaseReg 175 /* synopsis: release r[P1@P2] mask P3 */
#define OP_Noop 176
#define OP_Explain 177
#define OP_Abortable 178
/* clang-format off */
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */
#define OPFLG_IN1 0x02 /* in1: P1 is an input */
#define OPFLG_IN2 0x04 /* in2: P2 is an input */
#define OPFLG_IN3 0x08 /* in3: P3 is an input */
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
/* 24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\
/* 64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
/* 72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
/* 80 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\
/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\
/* 120 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 128 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04, 0x00,\
/* 136 */ 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00,\
/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10,\
/* 152 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\
/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\
/* 176 */ 0x00, 0x00, 0x00,}
/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */

View file

@ -13,8 +13,7 @@
** This file contains OS interface code that is common to all ** This file contains OS interface code that is common to all
** architectures. ** architectures.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** If we compile with the SQLITE_TEST macro set, then the following block ** If we compile with the SQLITE_TEST macro set, then the following block
@ -107,9 +106,11 @@ int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
} }
int sqlite3OsLock(sqlite3_file *id, int lockType){ int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id); DO_OS_MALLOC_TEST(id);
assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
return id->pMethods->xLock(id, lockType); return id->pMethods->xLock(id, lockType);
} }
int sqlite3OsUnlock(sqlite3_file *id, int lockType){ int sqlite3OsUnlock(sqlite3_file *id, int lockType){
assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
return id->pMethods->xUnlock(id, lockType); return id->pMethods->xUnlock(id, lockType);
} }
int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
@ -162,6 +163,7 @@ int sqlite3OsSectorSize(sqlite3_file *id){
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE); return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
} }
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){ int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
if( NEVER(id->pMethods==0) ) return 0;
return id->pMethods->xDeviceCharacteristics(id); return id->pMethods->xDeviceCharacteristics(id);
} }
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
@ -223,6 +225,7 @@ int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example, ** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */ ** reaching the VFS. */
assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut); rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 ); assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc; return rc;
@ -230,7 +233,7 @@ int sqlite3OsOpen(
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
DO_OS_MALLOC_TEST(0); DO_OS_MALLOC_TEST(0);
assert( dirSync==0 || dirSync==1 ); assert( dirSync==0 || dirSync==1 );
return pVfs->xDelete(pVfs, zPath, dirSync); return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK;
} }
int sqlite3OsAccess( int sqlite3OsAccess(
sqlite3_vfs *pVfs, sqlite3_vfs *pVfs,
@ -253,6 +256,8 @@ int sqlite3OsFullPathname(
} }
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){ void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
assert( zPath!=0 );
assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */
return pVfs->xDlOpen(pVfs, zPath); return pVfs->xDlOpen(pVfs, zPath);
} }
void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
@ -314,12 +319,15 @@ int sqlite3OsOpenMalloc(
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags); rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3_free(pFile); sqlite3_free(pFile);
*ppFile = 0;
}else{ }else{
*ppFile = pFile; *ppFile = pFile;
} }
}else{ }else{
*ppFile = 0;
rc = SQLITE_NOMEM_BKPT; rc = SQLITE_NOMEM_BKPT;
} }
assert( *ppFile!=0 || rc!=SQLITE_OK );
return rc; return rc;
} }
void sqlite3OsCloseFree(sqlite3_file *pFile){ void sqlite3OsCloseFree(sqlite3_file *pFile){

View file

@ -19,13 +19,12 @@
*/ */
#ifndef _SQLITE_OS_H_ #ifndef _SQLITE_OS_H_
#define _SQLITE_OS_H_ #define _SQLITE_OS_H_
/* clang-format off */
/* /*
** Attempt to automatically detect the operating system and setup the ** Attempt to automatically detect the operating system and setup the
** necessary pre-processor macros for it. ** necessary pre-processor macros for it.
*/ */
#include "third_party/sqlite3/os_setup.inc" #include "third_party/sqlite3/os_setup.h"
/* If the SET_FULLSYNC macro is not defined above, then make it /* If the SET_FULLSYNC macro is not defined above, then make it
** a no-op ** a no-op
@ -34,6 +33,19 @@
# define SET_FULLSYNC(x,y) # define SET_FULLSYNC(x,y)
#endif #endif
/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
*/
#ifndef SQLITE_MAX_PATHLEN
# define SQLITE_MAX_PATHLEN FILENAME_MAX
#endif
/* Maximum number of symlinks that will be resolved while trying to
** expand a filename in xFullPathname() in the VFS.
*/
#ifndef SQLITE_MAX_SYMLINK
# define SQLITE_MAX_SYMLINK 200
#endif
/* /*
** The default size of a disk sector ** The default size of a disk sector
*/ */

View file

@ -19,7 +19,6 @@
*/ */
#ifndef _OS_COMMON_H_ #ifndef _OS_COMMON_H_
#define _OS_COMMON_H_ #define _OS_COMMON_H_
/* clang-format off */
/* /*
** At least two bugs have slipped in because we changed the MEMORY_DEBUG ** At least two bugs have slipped in because we changed the MEMORY_DEBUG

971
third_party/sqlite3/os_kv.c vendored Normal file
View file

@ -0,0 +1,971 @@
/*
** 2022-09-06
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file contains an experimental VFS layer that operates on a
** Key/Value storage engine where both keys and values must be pure
** text.
*/
#include "third_party/sqlite3/sqliteInt.h"
#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
/*****************************************************************************
** Debugging logic
*/
/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
#if 0
#define SQLITE_KV_TRACE(X) printf X
#else
#define SQLITE_KV_TRACE(X)
#endif
/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
#if 0
#define SQLITE_KV_LOG(X) printf X
#else
#define SQLITE_KV_LOG(X)
#endif
/*
** Forward declaration of objects used by this VFS implementation
*/
typedef struct KVVfsFile KVVfsFile;
/* A single open file. There are only two files represented by this
** VFS - the database and the rollback journal.
*/
struct KVVfsFile {
sqlite3_file base; /* IO methods */
const char *zClass; /* Storage class */
int isJournal; /* True if this is a journal file */
unsigned int nJrnl; /* Space allocated for aJrnl[] */
char *aJrnl; /* Journal content */
int szPage; /* Last known page size */
sqlite3_int64 szDb; /* Database file size. -1 means unknown */
};
/*
** Methods for KVVfsFile
*/
static int kvvfsClose(sqlite3_file*);
static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
static int kvvfsSyncDb(sqlite3_file*, int flags);
static int kvvfsSyncJrnl(sqlite3_file*, int flags);
static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
static int kvvfsLock(sqlite3_file*, int);
static int kvvfsUnlock(sqlite3_file*, int);
static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
static int kvvfsSectorSize(sqlite3_file*);
static int kvvfsDeviceCharacteristics(sqlite3_file*);
/*
** Methods for sqlite3_vfs
*/
static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int kvvfsSleep(sqlite3_vfs*, int microseconds);
static int kvvfsCurrentTime(sqlite3_vfs*, double*);
static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static sqlite3_vfs sqlite3OsKvvfsObject = {
1, /* iVersion */
sizeof(KVVfsFile), /* szOsFile */
1024, /* mxPathname */
0, /* pNext */
"kvvfs", /* zName */
0, /* pAppData */
kvvfsOpen, /* xOpen */
kvvfsDelete, /* xDelete */
kvvfsAccess, /* xAccess */
kvvfsFullPathname, /* xFullPathname */
kvvfsDlOpen, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
kvvfsRandomness, /* xRandomness */
kvvfsSleep, /* xSleep */
kvvfsCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
};
/* Methods for sqlite3_file objects referencing a database file
*/
static sqlite3_io_methods kvvfs_db_io_methods = {
1, /* iVersion */
kvvfsClose, /* xClose */
kvvfsReadDb, /* xRead */
kvvfsWriteDb, /* xWrite */
kvvfsTruncateDb, /* xTruncate */
kvvfsSyncDb, /* xSync */
kvvfsFileSizeDb, /* xFileSize */
kvvfsLock, /* xLock */
kvvfsUnlock, /* xUnlock */
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControlDb, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/* Methods for sqlite3_file objects referencing a rollback journal
*/
static sqlite3_io_methods kvvfs_jrnl_io_methods = {
1, /* iVersion */
kvvfsClose, /* xClose */
kvvfsReadJrnl, /* xRead */
kvvfsWriteJrnl, /* xWrite */
kvvfsTruncateJrnl, /* xTruncate */
kvvfsSyncJrnl, /* xSync */
kvvfsFileSizeJrnl, /* xFileSize */
kvvfsLock, /* xLock */
kvvfsUnlock, /* xUnlock */
kvvfsCheckReservedLock, /* xCheckReservedLock */
kvvfsFileControlJrnl, /* xFileControl */
kvvfsSectorSize, /* xSectorSize */
kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmMap */
0, /* xShmLock */
0, /* xShmBarrier */
0, /* xShmUnmap */
0, /* xFetch */
0 /* xUnfetch */
};
/****** Storage subsystem **************************************************/
#include "libc/isystem/sys/types.h"
#include "libc/isystem/sys/stat.h"
/* Forward declarations for the low-level storage engine
*/
static int kvstorageWrite(const char*, const char *zKey, const char *zData);
static int kvstorageDelete(const char*, const char *zKey);
static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
#define KVSTORAGE_KEY_SZ 32
/* Expand the key name with an appropriate prefix and put the result
** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
** KVSTORAGE_KEY_SZ bytes.
*/
static void kvstorageMakeKey(
const char *zClass,
const char *zKeyIn,
char *zKeyOut
){
sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
}
/* Write content into a key. zClass is the particular namespace of the
** underlying key/value store to use - either "local" or "session".
**
** Both zKey and zData are zero-terminated pure text strings.
**
** Return the number of errors.
*/
static int kvstorageWrite(
const char *zClass,
const char *zKey,
const char *zData
){
FILE *fd;
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
fd = fopen(zXKey, "wb");
if( fd ){
SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
(int)strlen(zData), zData,
strlen(zData)>50 ? "..." : ""));
fputs(zData, fd);
fclose(fd);
return 0;
}else{
return 1;
}
}
/* Delete a key (with its corresponding data) from the key/value
** namespace given by zClass. If the key does not previously exist,
** this routine is a no-op.
*/
static int kvstorageDelete(const char *zClass, const char *zKey){
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
unlink(zXKey);
SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
return 0;
}
/* Read the value associated with a zKey from the key/value namespace given
** by zClass and put the text data associated with that key in the first
** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
** enough to hold it all. The value put into zBuf must always be zero
** terminated, even if it gets truncated because nBuf is not large enough.
**
** Return the total number of bytes in the data, without truncation, and
** not counting the final zero terminator. Return -1 if the key does
** not exist.
**
** If nBuf<=0 then this routine simply returns the size of the data without
** actually reading it.
*/
static int kvstorageRead(
const char *zClass,
const char *zKey,
char *zBuf,
int nBuf
){
FILE *fd;
struct stat buf;
char zXKey[KVSTORAGE_KEY_SZ];
kvstorageMakeKey(zClass, zKey, zXKey);
if( access(zXKey, R_OK)!=0
|| stat(zXKey, &buf)!=0
|| !S_ISREG(buf.st_mode)
){
SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}
if( nBuf<=0 ){
return (int)buf.st_size;
}else if( nBuf==1 ){
zBuf[0] = 0;
SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
(int)buf.st_size));
return (int)buf.st_size;
}
if( nBuf > buf.st_size + 1 ){
nBuf = buf.st_size + 1;
}
fd = fopen(zXKey, "rb");
if( fd==0 ){
SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
return -1;
}else{
sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
fclose(fd);
zBuf[n] = 0;
SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
n, zBuf, n>50 ? "..." : ""));
return (int)n;
}
}
/*
** An internal level of indirection which enables us to replace the
** kvvfs i/o methods with JavaScript implementations in WASM builds.
** Maintenance reminder: if this struct changes in any way, the JSON
** rendering of its structure must be updated in
** sqlite3_wasm_enum_json(). There are no binary compatibility
** concerns, so it does not need an iVersion member. This file is
** necessarily always compiled together with sqlite3_wasm_enum_json(),
** and JS code dynamically creates the mapping of members based on
** that JSON description.
*/
typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
struct sqlite3_kvvfs_methods {
int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
int (*xDelete)(const char *zClass, const char *zKey);
const int nKeySize;
};
/*
** This object holds the kvvfs I/O methods which may be swapped out
** for JavaScript-side implementations in WASM builds. In such builds
** it cannot be const, but in native builds it should be so that
** the compiler can hopefully optimize this level of indirection out.
** That said, kvvfs is intended primarily for use in WASM builds.
**
** Note that this is not explicitly flagged as static because the
** amalgamation build will tag it with SQLITE_PRIVATE.
*/
#ifndef SQLITE_WASM
const
#endif
sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
kvstorageRead,
kvstorageWrite,
kvstorageDelete,
KVSTORAGE_KEY_SZ
};
/****** Utility subroutines ************************************************/
/*
** Encode binary into the text encoded used to persist on disk.
** The output text is stored in aOut[], which must be at least
** nData+1 bytes in length.
**
** Return the actual length of the encoded text, not counting the
** zero terminator at the end.
**
** Encoding format
** ---------------
**
** * Non-zero bytes are encoded as upper-case hexadecimal
**
** * A sequence of one or more zero-bytes that are not at the
** beginning of the buffer are encoded as a little-endian
** base-26 number using a..z. "a" means 0. "b" means 1,
** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
**
** * Because there is no overlap between the encoding characters
** of hexadecimal and base-26 numbers, it is always clear where
** one stops and the next begins.
*/
static int kvvfsEncode(const char *aData, int nData, char *aOut){
int i, j;
const unsigned char *a = (const unsigned char*)aData;
for(i=j=0; i<nData; i++){
unsigned char c = a[i];
if( c!=0 ){
aOut[j++] = "0123456789ABCDEF"[c>>4];
aOut[j++] = "0123456789ABCDEF"[c&0xf];
}else{
/* A sequence of 1 or more zeros is stored as a little-endian
** base-26 number using a..z as the digits. So one zero is "b".
** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
** and so forth.
*/
int k;
for(k=1; i+k<nData && a[i+k]==0; k++){}
i += k-1;
while( k>0 ){
aOut[j++] = 'a'+(k%26);
k /= 26;
}
}
}
aOut[j] = 0;
return j;
}
static const signed char kvvfsHexValue[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
/*
** Decode the text encoding back to binary. The binary content is
** written into pOut, which must be at least nOut bytes in length.
**
** The return value is the number of bytes actually written into aOut[].
*/
static int kvvfsDecode(const char *a, char *aOut, int nOut){
int i, j;
int c;
const unsigned char *aIn = (const unsigned char*)a;
i = 0;
j = 0;
while( 1 ){
c = kvvfsHexValue[aIn[i]];
if( c<0 ){
int n = 0;
int mult = 1;
c = aIn[i];
if( c==0 ) break;
while( c>='a' && c<='z' ){
n += (c - 'a')*mult;
mult *= 26;
c = aIn[++i];
}
if( j+n>nOut ) return -1;
memset(&aOut[j], 0, n);
j += n;
c = aIn[i];
if( c==0 ) break;
}else{
aOut[j] = c<<4;
c = kvvfsHexValue[aIn[++i]];
if( c<0 ) break;
aOut[j++] += c;
i++;
}
}
return j;
}
/*
** Decode a complete journal file. Allocate space in pFile->aJrnl
** and store the decoding there. Or leave pFile->aJrnl set to NULL
** if an error is encountered.
**
** The first few characters of the text encoding will be a little-endian
** base-26 number (digits a..z) that is the total number of bytes
** in the decoded journal file image. This base-26 number is followed
** by a single space, then the encoding of the journal. The space
** separator is required to act as a terminator for the base-26 number.
*/
static void kvvfsDecodeJournal(
KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
const char *zTxt, /* Text encoding. Zero-terminated */
int nTxt /* Bytes in zTxt, excluding zero terminator */
){
unsigned int n = 0;
int c, i, mult;
i = 0;
mult = 1;
while( (c = zTxt[i++])>='a' && c<='z' ){
n += (zTxt[i] - 'a')*mult;
mult *= 26;
}
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = sqlite3_malloc64( n );
if( pFile->aJrnl==0 ){
pFile->nJrnl = 0;
return;
}
pFile->nJrnl = n;
n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
if( n<pFile->nJrnl ){
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = 0;
pFile->nJrnl = 0;
}
}
/*
** Read or write the "sz" element, containing the database file size.
*/
static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
char zData[50];
zData[0] = 0;
sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
return strtoll(zData, 0, 0);
}
static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
char zData[50];
sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
}
/****** sqlite3_io_methods methods ******************************************/
/*
** Close an kvvfs-file.
*/
static int kvvfsClose(sqlite3_file *pProtoFile){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
pFile->isJournal ? "journal" : "db"));
sqlite3_free(pFile->aJrnl);
return SQLITE_OK;
}
/*
** Read from the -journal file.
*/
static int kvvfsReadJrnl(
sqlite3_file *pProtoFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
assert( pFile->isJournal );
SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( pFile->aJrnl==0 ){
int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
char *aTxt;
if( szTxt<=4 ){
return SQLITE_IOERR;
}
aTxt = sqlite3_malloc64( szTxt+1 );
if( aTxt==0 ) return SQLITE_NOMEM;
kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
kvvfsDecodeJournal(pFile, aTxt, szTxt);
sqlite3_free(aTxt);
if( pFile->aJrnl==0 ) return SQLITE_IOERR;
}
if( iOfst+iAmt>pFile->nJrnl ){
return SQLITE_IOERR_SHORT_READ;
}
memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
return SQLITE_OK;
}
/*
** Read from the database file.
*/
static int kvvfsReadDb(
sqlite3_file *pProtoFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
unsigned int pgno;
int got, n;
char zKey[30];
char aData[133073];
assert( iOfst>=0 );
assert( iAmt>=0 );
SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iOfst+iAmt>=512 ){
if( (iOfst % iAmt)!=0 ){
return SQLITE_IOERR_READ;
}
if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
return SQLITE_IOERR_READ;
}
pFile->szPage = iAmt;
pgno = 1 + iOfst/iAmt;
}else{
pgno = 1;
}
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, aData, sizeof(aData)-1);
if( got<0 ){
n = 0;
}else{
aData[got] = 0;
if( iOfst+iAmt<512 ){
int k = iOfst+iAmt;
aData[k*2] = 0;
n = kvvfsDecode(aData, &aData[2000], sizeof(aData)-2000);
if( n>=iOfst+iAmt ){
memcpy(zBuf, &aData[2000+iOfst], iAmt);
n = iAmt;
}else{
n = 0;
}
}else{
n = kvvfsDecode(aData, zBuf, iAmt);
}
}
if( n<iAmt ){
memset(zBuf+n, 0, iAmt-n);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
/*
** Write into the -journal file.
*/
static int kvvfsWriteJrnl(
sqlite3_file *pProtoFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
sqlite3_int64 iEnd = iOfst+iAmt;
SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
if( iEnd>=0x10000000 ) return SQLITE_FULL;
if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
if( aNew==0 ){
return SQLITE_IOERR_NOMEM;
}
pFile->aJrnl = aNew;
if( pFile->nJrnl<iOfst ){
memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
}
pFile->nJrnl = iEnd;
}
memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
return SQLITE_OK;
}
/*
** Write into the database file.
*/
static int kvvfsWriteDb(
sqlite3_file *pProtoFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
unsigned int pgno;
char zKey[30];
char aData[131073];
SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
assert( iAmt>=512 && iAmt<=65536 );
assert( (iAmt & (iAmt-1))==0 );
assert( pFile->szPage<0 || pFile->szPage==iAmt );
pFile->szPage = iAmt;
pgno = 1 + iOfst/iAmt;
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
kvvfsEncode(zBuf, iAmt, aData);
if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
return SQLITE_IOERR;
}
if( iOfst+iAmt > pFile->szDb ){
pFile->szDb = iOfst + iAmt;
}
return SQLITE_OK;
}
/*
** Truncate an kvvfs-file.
*/
static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
assert( size==0 );
sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
sqlite3_free(pFile->aJrnl);
pFile->aJrnl = 0;
pFile->nJrnl = 0;
return SQLITE_OK;
}
static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
if( pFile->szDb>size
&& pFile->szPage>0
&& (size % pFile->szPage)==0
){
char zKey[50];
unsigned int pgno, pgnoMax;
SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
pgno = 1 + size/pFile->szPage;
pgnoMax = 2 + pFile->szDb/pFile->szPage;
while( pgno<=pgnoMax ){
sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
pgno++;
}
pFile->szDb = size;
return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
}
return SQLITE_IOERR;
}
/*
** Sync an kvvfs-file.
*/
static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
int i, n;
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
char *zOut;
SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
if( pFile->nJrnl<=0 ){
return kvvfsTruncateJrnl(pProtoFile, 0);
}
zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
if( zOut==0 ){
return SQLITE_IOERR_NOMEM;
}
n = pFile->nJrnl;
i = 0;
do{
zOut[i++] = 'a' + (n%26);
n /= 26;
}while( n>0 );
zOut[i++] = ' ';
kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
sqlite3_free(zOut);
return i ? SQLITE_IOERR : SQLITE_OK;
}
static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
return SQLITE_OK;
}
/*
** Return the current file-size of an kvvfs-file.
*/
static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
*pSize = pFile->nJrnl;
return SQLITE_OK;
}
static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
if( pFile->szDb>=0 ){
*pSize = pFile->szDb;
}else{
*pSize = kvvfsReadFileSize(pFile);
}
return SQLITE_OK;
}
/*
** Lock an kvvfs-file.
*/
static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
if( eLock!=SQLITE_LOCK_NONE ){
pFile->szDb = kvvfsReadFileSize(pFile);
}
return SQLITE_OK;
}
/*
** Unlock an kvvfs-file.
*/
static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
assert( !pFile->isJournal );
SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
if( eLock==SQLITE_LOCK_NONE ){
pFile->szDb = -1;
}
return SQLITE_OK;
}
/*
** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
*/
static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
SQLITE_KV_LOG(("xCheckReservedLock\n"));
*pResOut = 0;
return SQLITE_OK;
}
/*
** File control method. For custom operations on an kvvfs-file.
*/
static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
return SQLITE_NOTFOUND;
}
static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
if( op==SQLITE_FCNTL_SYNC ){
KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
int rc = SQLITE_OK;
SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
rc = SQLITE_IOERR;
}
return rc;
}
return SQLITE_NOTFOUND;
}
/*
** Return the sector-size in bytes for an kvvfs-file.
*/
static int kvvfsSectorSize(sqlite3_file *pFile){
return 512;
}
/*
** Return the device characteristic flags supported by an kvvfs-file.
*/
static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
return 0;
}
/****** sqlite3_vfs methods *************************************************/
/*
** Open an kvvfs file handle.
*/
static int kvvfsOpen(
sqlite3_vfs *pProtoVfs,
const char *zName,
sqlite3_file *pProtoFile,
int flags,
int *pOutFlags
){
KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
if( zName==0 ) zName = "";
SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
if( strcmp(zName, "local")==0
|| strcmp(zName, "session")==0
){
pFile->isJournal = 0;
pFile->base.pMethods = &kvvfs_db_io_methods;
}else
if( strcmp(zName, "local-journal")==0
|| strcmp(zName, "session-journal")==0
){
pFile->isJournal = 1;
pFile->base.pMethods = &kvvfs_jrnl_io_methods;
}else{
return SQLITE_CANTOPEN;
}
if( zName[0]=='s' ){
pFile->zClass = "session";
}else{
pFile->zClass = "local";
}
pFile->aJrnl = 0;
pFile->nJrnl = 0;
pFile->szPage = -1;
pFile->szDb = -1;
return SQLITE_OK;
}
/*
** Delete the file located at zPath. If the dirSync argument is true,
** ensure the file-system modifications are synced to disk before
** returning.
*/
static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
if( strcmp(zPath, "local-journal")==0 ){
sqlite3KvvfsMethods.xDelete("local", "jrnl");
}else
if( strcmp(zPath, "session-journal")==0 ){
sqlite3KvvfsMethods.xDelete("session", "jrnl");
}
return SQLITE_OK;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int kvvfsAccess(
sqlite3_vfs *pProtoVfs,
const char *zPath,
int flags,
int *pResOut
){
SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
if( strcmp(zPath, "local-journal")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
}else
if( strcmp(zPath, "session-journal")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
}else
if( strcmp(zPath, "local")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
}else
if( strcmp(zPath, "session")==0 ){
*pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
}else
{
*pResOut = 0;
}
SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
return SQLITE_OK;
}
/*
** Populate buffer zOut with the full canonical pathname corresponding
** to the pathname in zPath. zOut is guaranteed to point to a buffer
** of at least (INST_MAX_PATHNAME+1) bytes.
*/
static int kvvfsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
size_t nPath;
#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
zPath = "local";
#endif
nPath = strlen(zPath);
SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
if( nOut<nPath+1 ) nPath = nOut - 1;
memcpy(zOut, zPath, nPath);
zOut[nPath] = 0;
return SQLITE_OK;
}
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return 0;
}
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
memset(zBufOut, 0, nByte);
return nByte;
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
return SQLITE_OK;
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
sqlite3_int64 i = 0;
int rc;
rc = kvvfsCurrentTimeInt64(0, &i);
*pTimeOut = i/86400000.0;
return rc;
}
#include <sys/time.h>
static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
struct timeval sNow;
(void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
*pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
return SQLITE_OK;
}
#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
#if SQLITE_OS_KV
/*
** This routine is called initialize the KV-vfs as the default VFS.
*/
int sqlite3_os_init(void){
return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
}
int sqlite3_os_end(void){
return SQLITE_OK;
}
#endif /* SQLITE_OS_KV */
#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
int sqlite3KvvfsInit(void){
return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
}
#endif

91
third_party/sqlite3/os_setup.h vendored Normal file
View file

@ -0,0 +1,91 @@
/*
** 2013 November 25
**
** 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 pre-processor directives related to operating system
** detection and/or setup.
*/
#ifndef SQLITE_OS_SETUP_H
#define SQLITE_OS_SETUP_H
/*
** Figure out if we are dealing with Unix, Windows, or some other operating
** system.
**
** After the following block of preprocess macros, all of
**
** SQLITE_OS_KV
** SQLITE_OS_OTHER
** SQLITE_OS_UNIX
** SQLITE_OS_WIN
**
** will defined to either 1 or 0. One of them will be 1. The others will be 0.
** If none of the macros are initially defined, then select either
** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
**
** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
** must provide its own VFS implementation together with sqlite3_os_init()
** and sqlite3_os_end() routines.
*/
#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
!defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
defined(__MINGW32__) || defined(__BORLANDC__)
# define SQLITE_OS_WIN 1
# define SQLITE_OS_UNIX 0
# else
# define SQLITE_OS_WIN 0
# define SQLITE_OS_UNIX 1
# endif
#endif
#if SQLITE_OS_OTHER+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
#endif
#if SQLITE_OS_KV+1>1
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
# define SQLITE_OMIT_LOAD_EXTENSION 1
# define SQLITE_OMIT_WAL 1
# define SQLITE_OMIT_DEPRECATED 1
# undef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
# define SQLITE_DQS 0
# define SQLITE_OMIT_SHARED_CACHE 1
# define SQLITE_OMIT_AUTOINIT 1
#endif
#if SQLITE_OS_UNIX+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
#endif
#if SQLITE_OS_WIN+1>1
# undef SQLITE_OS_KV
# define SQLITE_OS_KV 0
# undef SQLITE_OS_OTHER
# define SQLITE_OS_OTHER 0
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
#endif
#endif /* SQLITE_OS_SETUP_H */

View file

@ -1,58 +0,0 @@
/*
** 2013 November 25
**
** 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 pre-processor directives related to operating system
** detection and/or setup.
*/
#ifndef SQLITE_OS_SETUP_H
#define SQLITE_OS_SETUP_H
/* clang-format off */
/*
** Figure out if we are dealing with Unix, Windows, or some other operating
** system.
**
** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
** the three will be 1. The other two will be 0.
*/
#if defined(SQLITE_OS_OTHER)
# if SQLITE_OS_OTHER==1
# undef SQLITE_OS_UNIX
# define SQLITE_OS_UNIX 0
# undef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
# else
# undef SQLITE_OS_OTHER
# endif
#endif
#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
# define SQLITE_OS_OTHER 0
# ifndef SQLITE_OS_WIN
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
defined(__MINGW32__) || defined(__BORLANDC__)
# define SQLITE_OS_WIN 1
# define SQLITE_OS_UNIX 0
# else
# define SQLITE_OS_WIN 0
# define SQLITE_OS_UNIX 1
# endif
# else
# define SQLITE_OS_UNIX 0
# endif
#else
# ifndef SQLITE_OS_WIN
# define SQLITE_OS_WIN 0
# endif
#endif
#endif /* SQLITE_OS_SETUP_H */

View file

@ -46,16 +46,9 @@
*/ */
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/sysv/consts/lock.h" #include "libc/sysv/consts/lock.h"
#include "libc/calls/struct/stat.h" #include "third_party/sqlite3/sqliteInt.h"
#include "libc/sysv/consts/s.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/struct/timeval.h"
#include "third_party/sqlite3/sqlite3.h"
#include "third_party/sqlite3/mutex.internal.h"
#include "third_party/sqlite3/mutex.internal.h"
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "third_party/sqlite3/sqliteInt.inc"
#if SQLITE_OS_UNIX /* This file is used on unix only */ #if SQLITE_OS_UNIX /* This file is used on unix only */
/* /*
@ -101,10 +94,14 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/flock.h" #include "libc/calls/struct/flock.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/weirdtypes.h" #include "libc/calls/weirdtypes.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/runtime/sysconf.h" #include "libc/runtime/sysconf.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/mremap.h" #include "libc/sysv/consts/mremap.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
@ -114,6 +111,16 @@
#include "libc/time/time.h" #include "libc/time/time.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
#include "libc/isystem/sys/mman.h"
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
# include "libc/isystem/sys/ioctl.h"
# include "libc/isystem/sys/file.h"
# include "libc/isystem/sys/param.h"
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/* /*
** Try to determine if gethostuuid() is available based on standard ** Try to determine if gethostuuid() is available based on standard
** macros. This might sometimes compute the wrong value for some ** macros. This might sometimes compute the wrong value for some
@ -143,14 +150,13 @@
#if OS_VXWORKS #if OS_VXWORKS
#include <semaphore.h> # include <sys/ioctl.h>
#include <sys/ioctl.h> # include <semaphore.h>
# include "libc/limits.h"
#include "libc/limits.h"
#endif /* OS_VXWORKS */ #endif /* OS_VXWORKS */
#ifdef HAVE_UTIME #ifdef HAVE_UTIME
#include "libc/time/time.h" # include "libc/time/time.h"
#endif #endif
/* /*
@ -296,7 +302,7 @@ static pid_t randomnessPid = 0;
/* /*
** Include code that is common to all os_*.c files ** Include code that is common to all os_*.c files
*/ */
#include "third_party/sqlite3/os_common.inc" #include "os_common.h"
/* /*
** Define various macros that are missing from some systems. ** Define various macros that are missing from some systems.
@ -854,20 +860,20 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
*/ */
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) { static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
assert((sqliteIOErr == SQLITE_IOERR_LOCK) || assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
(sqliteIOErr == SQLITE_IOERR_UNLOCK) || (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
(sqliteIOErr == SQLITE_IOERR_RDLOCK) || (sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK)); (sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
// changed switch to if-else // changed switch to if-else
if (posixError == EACCES || posixError == EAGAIN || posixError == ETIMEDOUT || if (posixError == EACCES || posixError == EAGAIN || posixError == ETIMEDOUT ||
posixError == EBUSY || posixError == EINTR || posixError == ENOLCK) posixError == EBUSY || posixError == EINTR || posixError == ENOLCK)
/* random NFS retry error, unless during file system support /* random NFS retry error, unless during file system support
* introspection, in which it actually means what it says */ * introspection, in which it actually means what it says */
return SQLITE_BUSY; return SQLITE_BUSY;
else if (posixError == EPERM) else if (posixError == EPERM)
return SQLITE_PERM; return SQLITE_PERM;
else else
return sqliteIOErr; return sqliteIOErr;
} }
@ -3541,6 +3547,16 @@ int sqlite3_sync_count = 0;
int sqlite3_fullsync_count = 0; int sqlite3_fullsync_count = 0;
#endif #endif
/*
** We do not trust systems to provide a working fdatasync(). Some do.
** Others do no. To be safe, we will stick with the (slightly slower)
** fsync(). If you know that your system does support fdatasync() correctly,
** then simply compile with -Dfdatasync=fdatasync or -DHAVE_FDATASYNC
*/
#if !defined(fdatasync) && !HAVE_FDATASYNC
# define fdatasync fsync
#endif
/* /*
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently ** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently
@ -3936,6 +3952,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
/* Forward declaration */ /* Forward declaration */
static int unixGetTempname(int nBuf, char *zBuf); static int unixGetTempname(int nBuf, char *zBuf);
#ifndef SQLITE_OMIT_WAL
static int unixFcntlExternalReader(unixFile*, int*);
#endif
/* /*
** Information and control of an open file handle. ** Information and control of an open file handle.
@ -4052,6 +4071,15 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return proxyFileControl(id,op,pArg); return proxyFileControl(id,op,pArg);
} }
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */ #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
case SQLITE_FCNTL_EXTERNAL_READER: {
#ifndef SQLITE_OMIT_WAL
return unixFcntlExternalReader((unixFile*)id, (int*)pArg);
#else
*(int*)pArg = 0;
return SQLITE_OK;
#endif
}
} }
return SQLITE_NOTFOUND; return SQLITE_NOTFOUND;
} }
@ -4297,6 +4325,40 @@ struct unixShm {
#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
/*
** Use F_GETLK to check whether or not there are any readers with open
** wal-mode transactions in other processes on database file pFile. If
** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are
** such transactions, or 0 otherwise. If an error occurs, return an
** SQLite error code. The final value of *piOut is undefined in this
** case.
*/
static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
int rc = SQLITE_OK;
*piOut = 0;
if( pFile->pShm){
unixShmNode *pShmNode = pFile->pShm->pShmNode;
struct flock f;
memset(&f, 0, sizeof(f));
f.l_type = F_WRLCK;
f.l_whence = SEEK_SET;
f.l_start = UNIX_SHM_BASE + 3;
f.l_len = SQLITE_SHM_NLOCK - 3;
sqlite3_mutex_enter(pShmNode->pShmMutex);
if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){
rc = SQLITE_IOERR_LOCK;
}else{
*piOut = (f.l_type!=F_UNLCK);
}
sqlite3_mutex_leave(pShmNode->pShmMutex);
}
return rc;
}
/* /*
** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
** **
@ -4849,11 +4911,17 @@ static int unixShmLock(
int flags /* What to do with the lock */ int flags /* What to do with the lock */
){ ){
unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
unixShm *p = pDbFd->pShm; /* The shared memory being locked */ unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */ int rc = SQLITE_OK; /* Result code */
u16 mask; /* Mask of locks to take or release */ u16 mask; /* Mask of locks to take or release */
int *aLock = pShmNode->aLock; int *aLock;
p = pDbFd->pShm;
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
pShmNode = p->pShmNode;
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
aLock = pShmNode->aLock;
assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode==pDbFd->pInode->pShmNode );
assert( pShmNode->pInode==pDbFd->pInode ); assert( pShmNode->pInode==pDbFd->pInode );
@ -5737,25 +5805,35 @@ static int fillInUnixFile(
return rc; return rc;
} }
/*
** Directories to consider for temp files.
*/
static const char *azTempDirs[] = {
0,
0,
"/var/tmp",
"/usr/tmp",
"/tmp",
"."
};
/*
** Initialize first two members of azTempDirs[] array.
*/
static void unixTempFileInit(void){
azTempDirs[0] = getenv("SQLITE_TMPDIR");
azTempDirs[1] = getenv("TMPDIR");
}
/* /*
** Return the name of a directory in which to put temporary files. ** Return the name of a directory in which to put temporary files.
** If no suitable temporary file directory can be found, return NULL. ** If no suitable temporary file directory can be found, return NULL.
*/ */
static const char *unixTempFileDir(void){ static const char *unixTempFileDir(void){
static const char *azDirs[] = {
0,
0,
"/var/tmp",
"/usr/tmp",
"/tmp",
"."
};
unsigned int i = 0; unsigned int i = 0;
struct stat buf; struct stat buf;
const char *zDir = sqlite3_temp_directory; const char *zDir = sqlite3_temp_directory;
if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
while(1){ while(1){
if( zDir!=0 if( zDir!=0
&& osStat(zDir, &buf)==0 && osStat(zDir, &buf)==0
@ -5764,8 +5842,8 @@ static const char *unixTempFileDir(void){
){ ){
return zDir; return zDir;
} }
if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break;
zDir = azDirs[i++]; zDir = azTempDirs[i++];
} }
return 0; return 0;
} }
@ -5778,6 +5856,7 @@ static const char *unixTempFileDir(void){
static int unixGetTempname(int nBuf, char *zBuf){ static int unixGetTempname(int nBuf, char *zBuf){
const char *zDir; const char *zDir;
int iLimit = 0; int iLimit = 0;
int rc = SQLITE_OK;
int e = errno; // [jart] don't pollute strace logs int e = errno; // [jart] don't pollute strace logs
/* It's odd to simulate an io-error here, but really this is just /* It's odd to simulate an io-error here, but really this is just
@ -5787,19 +5866,27 @@ static int unixGetTempname(int nBuf, char *zBuf){
zBuf[0] = 0; zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR ); SimulateIOError( return SQLITE_IOERR );
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
zDir = unixTempFileDir(); zDir = unixTempFileDir();
if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH; if( zDir==0 ){
do{ rc = SQLITE_IOERR_GETTEMPPATH;
u64 r; }else{
sqlite3_randomness(sizeof(r), &r); do{
assert( nBuf>2 ); u64 r;
zBuf[nBuf-2] = 0; sqlite3_randomness(sizeof(r), &r);
sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c", assert( nBuf>2 );
zDir, r, 0); zBuf[nBuf-2] = 0;
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR; sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
}while( osAccess(zBuf,0)==0 ); zDir, r, 0);
if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
rc = SQLITE_ERROR;
break;
}
}while( osAccess(zBuf,0)==0 );
}
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
errno = e; // [jart] don't pollute strace logs errno = e; // [jart] don't pollute strace logs
return SQLITE_OK; return rc;
} }
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
@ -5942,20 +6029,23 @@ static int findCreateFileMode(
** **
** where NN is a decimal number. The NN naming schemes are ** where NN is a decimal number. The NN naming schemes are
** used by the test_multiplex.c module. ** used by the test_multiplex.c module.
**
** In normal operation, the journal file name will always contain
** a '-' character. However in 8+3 filename mode, or if a corrupt
** rollback journal specifies a super-journal with a goofy name, then
** the '-' might be missing or the '-' might be the first character in
** the filename. In that case, just return SQLITE_OK with *pMode==0.
*/ */
nDb = sqlite3Strlen30(zPath) - 1; nDb = sqlite3Strlen30(zPath) - 1;
while( zPath[nDb]!='-' ){ while( nDb>0 && zPath[nDb]!='.' ){
/* In normal operation, the journal file name will always contain if( zPath[nDb]=='-' ){
** a '-' character. However in 8+3 filename mode, or if a corrupt memcpy(zDb, zPath, nDb);
** rollback journal specifies a super-journal with a goofy name, then zDb[nDb] = '\0';
** the '-' might be missing. */ rc = getFileMode(zDb, pMode, pUid, pGid);
if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; break;
}
nDb--; nDb--;
} }
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
rc = getFileMode(zDb, pMode, pUid, pGid);
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600; *pMode = 0600;
}else if( flags & SQLITE_OPEN_URI ){ }else if( flags & SQLITE_OPEN_URI ){
@ -6073,6 +6163,11 @@ static int unixOpen(
} }
bzero(p, sizeof(unixFile)); bzero(p, sizeof(unixFile));
#ifdef SQLITE_ASSERT_NO_FILES
/* Applications that never read or write a persistent disk files */
assert( zName==0 );
#endif
if( eType==SQLITE_OPEN_MAIN_DB ){ if( eType==SQLITE_OPEN_MAIN_DB ){
UnixUnusedFd *pUnused; UnixUnusedFd *pUnused;
pUnused = findReusableFd(zName, flags); pUnused = findReusableFd(zName, flags);
@ -6342,86 +6437,99 @@ static int unixAccess(
} }
/* /*
** If the last component of the pathname in z[0]..z[j-1] is something ** A pathname under construction
** other than ".." then back it out and return true. If the last
** component is empty or if it is ".." then return false.
*/ */
static int unixBackupDir(const char *z, int *pJ){ typedef struct DbPath DbPath;
int j = *pJ; struct DbPath {
int i; int rc; /* Non-zero following any error */
if( j<=0 ) return 0; int nSymlink; /* Number of symlinks resolved */
for(i=j-1; i>0 && z[i-1]!='/'; i--){} char *zOut; /* Write the pathname here */
if( i==0 ) return 0; int nOut; /* Bytes of space available to zOut[] */
if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; int nUsed; /* Bytes of zOut[] currently being used */
*pJ = i-1; };
return 1;
/* Forward reference */
static void appendAllPathElements(DbPath*,const char*);
/*
** Append a single path element to the DbPath under construction
*/
static void appendOnePathElement(
DbPath *pPath, /* Path under construction, to which to append zName */
const char *zName, /* Name to append to pPath. Not zero-terminated */
int nName /* Number of significant bytes in zName */
){
assert( nName>0 );
assert( zName!=0 );
if( zName[0]=='.' ){
if( nName==1 ) return;
if( zName[1]=='.' && nName==2 ){
if( pPath->nUsed<=1 ){
pPath->rc = SQLITE_ERROR;
return;
}
assert( pPath->zOut[0]=='/' );
while( pPath->zOut[--pPath->nUsed]!='/' ){}
return;
}
}
if( pPath->nUsed + nName + 2 >= pPath->nOut ){
pPath->rc = SQLITE_ERROR;
return;
}
pPath->zOut[pPath->nUsed++] = '/';
memcpy(&pPath->zOut[pPath->nUsed], zName, nName);
pPath->nUsed += nName;
#if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
if( pPath->rc==SQLITE_OK ){
const char *zIn;
struct stat buf;
pPath->zOut[pPath->nUsed] = 0;
zIn = pPath->zOut;
if( osLstat(zIn, &buf)!=0 ){
if( errno!=ENOENT ){
pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
}
}else if( S_ISLNK(buf.st_mode) ){
ssize_t got;
char zLnk[SQLITE_MAX_PATHLEN+2];
if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){
pPath->rc = SQLITE_CANTOPEN_BKPT;
return;
}
got = osReadlink(zIn, zLnk, sizeof(zLnk)-2);
if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){
pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
return;
}
zLnk[got] = 0;
if( zLnk[0]=='/' ){
pPath->nUsed = 0;
}else{
pPath->nUsed -= nName + 1;
}
appendAllPathElements(pPath, zLnk);
}
}
#endif
} }
/* /*
** Convert a relative pathname into a full pathname. Also ** Append all path elements in zPath to the DbPath under construction.
** simplify the pathname as follows:
**
** Remove all instances of /./
** Remove all isntances of /X/../ for any X
*/ */
static int mkFullPathname( static void appendAllPathElements(
const char *zPath, /* Input path */ DbPath *pPath, /* Path under construction, to which to append zName */
char *zOut, /* Output buffer */ const char *zPath /* Path to append to pPath. Is zero-terminated */
int nOut /* Allocated size of buffer zOut */
){ ){
int nPath = sqlite3Strlen30(zPath); int i = 0;
int iOff = 0; int j = 0;
int i, j; do{
if( zPath[0]!='/' ){ while( zPath[i] && zPath[i]!='/' ){ i++; }
if( osGetcwd(zOut, nOut-2)==0 ){ if( i>j ){
return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); appendOnePathElement(pPath, &zPath[j], i-j);
} }
iOff = sqlite3Strlen30(zOut); j = i+1;
zOut[iOff++] = '/'; }while( zPath[i++] );
}
if( (iOff+nPath+1)>nOut ){
/* SQLite assumes that xFullPathname() nul-terminates the output buffer
** even if it returns an error. */
zOut[iOff] = '\0';
return SQLITE_CANTOPEN_BKPT;
}
sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
/* Remove duplicate '/' characters. Except, two // at the beginning
** of a pathname is allowed since this is important on windows. */
for(i=j=1; zOut[i]; i++){
zOut[j++] = zOut[i];
while( zOut[i]=='/' && zOut[i+1]=='/' ) i++;
}
zOut[j] = 0;
assert( zOut[0]=='/' );
for(i=j=0; zOut[i]; i++){
if( zOut[i]=='/' ){
/* Skip over internal "/." directory components */
if( zOut[i+1]=='.' && zOut[i+2]=='/' ){
i += 1;
continue;
}
/* If this is a "/.." directory component then back out the
** previous term of the directory if it is something other than "..".
*/
if( zOut[i+1]=='.'
&& zOut[i+2]=='.'
&& zOut[i+3]=='/'
&& unixBackupDir(zOut, &j)
){
i += 2;
continue;
}
}
if( ALWAYS(j>=0) ) zOut[j] = zOut[i];
j++;
}
if( NEVER(j==0) ) zOut[j++] = '/';
zOut[j] = 0;
return SQLITE_OK;
} }
/* /*
@ -6439,86 +6547,27 @@ static int unixFullPathname(
int nOut, /* Size of output buffer in bytes */ int nOut, /* Size of output buffer in bytes */
char *zOut /* Output buffer */ char *zOut /* Output buffer */
){ ){
#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) DbPath path;
return mkFullPathname(zPath, zOut, nOut);
#else
int rc = SQLITE_OK;
int nByte;
int nLink = 0; /* Number of symbolic links followed so far */
const char *zIn = zPath; /* Input path for each iteration of loop */
char *zDel = 0;
assert( pVfs->mxPathname==MAX_PATHNAME );
UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(pVfs);
path.rc = 0;
/* It's odd to simulate an io-error here, but really this is just path.nUsed = 0;
** using the io-error infrastructure to test that SQLite handles this path.nSymlink = 0;
** function failing. This function could fail if, for example, the path.nOut = nOut;
** current working directory has been unlinked. path.zOut = zOut;
*/ if( zPath[0]!='/' ){
SimulateIOError( return SQLITE_ERROR ); char zPwd[SQLITE_MAX_PATHLEN+2];
if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){
do { return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
/* Call stat() on path zIn. Set bLink to true if the path is a symbolic
** link, or false otherwise. */
int bLink = 0;
struct stat buf;
if( osLstat(zIn, &buf)!=0 ){
if( errno!=ENOENT ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
}
}else{
bLink = S_ISLNK(buf.st_mode);
} }
appendAllPathElements(&path, zPwd);
if( bLink ){ }
nLink++; appendAllPathElements(&path, zPath);
if( zDel==0 ){ zOut[path.nUsed] = 0;
zDel = sqlite3_malloc(nOut); if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT;
if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; if( path.nSymlink ) return SQLITE_OK_SYMLINK;
}else if( nLink>=SQLITE_MAX_SYMLINKS ){ return SQLITE_OK;
rc = SQLITE_CANTOPEN_BKPT;
}
if( rc==SQLITE_OK ){
nByte = osReadlink(zIn, zDel, nOut-1);
if( nByte<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
}else{
if( zDel[0]!='/' ){
int n;
for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
if( nByte+n+1>nOut ){
rc = SQLITE_CANTOPEN_BKPT;
}else{
memmove(&zDel[n], zDel, nByte+1);
memcpy(zDel, zIn, n);
nByte += n;
}
}
zDel[nByte] = '\0';
}
}
zIn = zDel;
}
assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
if( rc==SQLITE_OK && zIn!=zOut ){
rc = mkFullPathname(zIn, zOut, nOut);
}
if( bLink==0 ) break;
zIn = zOut;
}while( rc==SQLITE_OK );
sqlite3_free(zDel);
if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
return rc;
#endif /* HAVE_READLINK && HAVE_LSTAT */
} }
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
/* /*
** Interfaces for opening a shared library, finding entry points ** Interfaces for opening a shared library, finding entry points
@ -7983,9 +8032,39 @@ int sqlite3_os_init(void){
/* Register all VFSes defined in the aVfs[] array */ /* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
#ifdef SQLITE_DEFAULT_UNIX_VFS
sqlite3_vfs_register(&aVfs[i],
0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
#else
sqlite3_vfs_register(&aVfs[i], i==0); sqlite3_vfs_register(&aVfs[i], i==0);
#endif
} }
#ifdef SQLITE_OS_KV_OPTIONAL
sqlite3KvvfsInit();
#endif
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1); unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
/* Validate lock assumptions */
assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */
assert( UNIX_SHM_BASE==120 ); /* Start of locking area */
/* Locks:
** WRITE UNIX_SHM_BASE 120
** CKPT UNIX_SHM_BASE+1 121
** RECOVER UNIX_SHM_BASE+2 122
** READ-0 UNIX_SHM_BASE+3 123
** READ-1 UNIX_SHM_BASE+4 124
** READ-2 UNIX_SHM_BASE+5 125
** READ-3 UNIX_SHM_BASE+6 126
** READ-4 UNIX_SHM_BASE+7 127
** DMS UNIX_SHM_BASE+8 128
*/
assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */
#endif
/* Initialize temp file dir array. */
unixTempFileInit();
return SQLITE_OK; return SQLITE_OK;
} }

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
#include "third_party/sqlite3/os_win.c"

View file

@ -10,7 +10,7 @@
** **
************************************************************************* *************************************************************************
** This is the implementation of the page cache subsystem or "pager". ** This is the implementation of the page cache subsystem or "pager".
** **
** The pager is used to access a database disk file. It implements ** The pager is used to access a database disk file. It implements
** atomic commit and rollback through the use of a journal file that ** atomic commit and rollback through the use of a journal file that
** is separate from the database file. The pager also implements file ** is separate from the database file. The pager also implements file
@ -19,9 +19,8 @@
** another is writing. ** another is writing.
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
#include "third_party/sqlite3/wal.inc" #include "third_party/sqlite3/wal.h"
/* clang-format off */
/******************* NOTES ON THE DESIGN OF THE PAGER ************************ /******************* NOTES ON THE DESIGN OF THE PAGER ************************
@ -631,6 +630,7 @@ struct Pager {
u8 noLock; /* Do not lock (except in WAL mode) */ u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */ u8 readOnly; /* True for a read-only database */
u8 memDb; /* True to inhibit all file I/O */ u8 memDb; /* True to inhibit all file I/O */
u8 memVfs; /* VFS-implemented memory database */
/************************************************************************** /**************************************************************************
** The following block contains those class members that change during ** The following block contains those class members that change during
@ -680,8 +680,9 @@ struct Pager {
i16 nReserve; /* Number of unused bytes at end of each page */ i16 nReserve; /* Number of unused bytes at end of each page */
u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
u32 sectorSize; /* Assumed sector size during rollback */ u32 sectorSize; /* Assumed sector size during rollback */
int pageSize; /* Number of bytes in a page */
Pgno mxPgno; /* Maximum allowed size of the database */ Pgno mxPgno; /* Maximum allowed size of the database */
Pgno lckPgno; /* Page number for the locking page */
i64 pageSize; /* Number of bytes in a page */
i64 journalSizeLimit; /* Size limit for persistent journal files */ i64 journalSizeLimit; /* Size limit for persistent journal files */
char *zFilename; /* Name of the database file */ char *zFilename; /* Name of the database file */
char *zJournal; /* Name of the journal file */ char *zJournal; /* Name of the journal file */
@ -1667,7 +1668,7 @@ static int readJournalHdr(
** journal file descriptor is advanced to the next sector boundary before ** journal file descriptor is advanced to the next sector boundary before
** anything is written. The format is: ** anything is written. The format is:
** **
** + 4 bytes: PAGER_MJ_PGNO. ** + 4 bytes: PAGER_SJ_PGNO.
** + N bytes: super-journal filename in utf-8. ** + N bytes: super-journal filename in utf-8.
** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator). ** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
** + 4 bytes: super-journal name checksum. ** + 4 bytes: super-journal name checksum.
@ -1715,7 +1716,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){
/* Write the super-journal data to the end of the journal file. If /* Write the super-journal data to the end of the journal file. If
** an error occurs, return the error code to the caller. ** an error occurs, return the error code to the caller.
*/ */
if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager)))) if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_SJ_PGNO(pPager))))
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
|| (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
@ -2225,7 +2226,7 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** corrupted, SQLITE_DONE is returned. Data is considered corrupted in
** two circumstances: ** two circumstances:
** **
** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or ** * If the record page-number is illegal (0 or PAGER_SJ_PGNO), or
** * If the record is being rolled back from the main journal file ** * If the record is being rolled back from the main journal file
** and the checksum field does not match the record content. ** and the checksum field does not match the record content.
** **
@ -2285,7 +2286,7 @@ static int pager_playback_one_page(
** it could cause invalid data to be written into the journal. We need to ** it could cause invalid data to be written into the journal. We need to
** detect this invalid data (with high probability) and ignore it. ** detect this invalid data (with high probability) and ignore it.
*/ */
if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ if( pgno==0 || pgno==PAGER_SJ_PGNO(pPager) ){
assert( !isSavepnt ); assert( !isSavepnt );
return SQLITE_DONE; return SQLITE_DONE;
} }
@ -2622,6 +2623,7 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
memset(pTmp, 0, szPage); memset(pTmp, 0, szPage);
testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) == currentSize );
testcase( (newSize-szPage) > currentSize ); testcase( (newSize-szPage) > currentSize );
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &newSize);
rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -2844,6 +2846,9 @@ static int pager_playback(Pager *pPager, int isHot){
goto end_playback; goto end_playback;
} }
pPager->dbSize = mxPg; pPager->dbSize = mxPg;
if( pPager->mxPgno<mxPg ){
pPager->mxPgno = mxPg;
}
} }
/* Copy original pages out of the journal and back into the /* Copy original pages out of the journal and back into the
@ -3025,6 +3030,7 @@ static int readDbPage(PgHdr *pPg){
*/ */
static void pager_write_changecounter(PgHdr *pPg){ static void pager_write_changecounter(PgHdr *pPg){
u32 change_counter; u32 change_counter;
if( NEVER(pPg==0) ) return;
/* Increment the value just read and write it back to byte 24. */ /* Increment the value just read and write it back to byte 24. */
change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1; change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
@ -3739,6 +3745,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
pPager->pTmpSpace = pNew; pPager->pTmpSpace = pNew;
pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
pPager->pageSize = pageSize; pPager->pageSize = pageSize;
pPager->lckPgno = (Pgno)(PENDING_BYTE/pageSize) + 1;
}else{ }else{
sqlite3PageFree(pNew); sqlite3PageFree(pNew);
} }
@ -3899,8 +3906,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
** current database image, in pages, OR ** current database image, in pages, OR
** **
** b) if the page content were written at this time, it would not ** b) if the page content were written at this time, it would not
** be necessary to write the current content out to the sub-journal ** be necessary to write the current content out to the sub-journal.
** (as determined by function subjRequiresPage()).
** **
** If the condition asserted by this function were not true, and the ** If the condition asserted by this function were not true, and the
** dirty page were to be discarded from the cache via the pagerStress() ** dirty page were to be discarded from the cache via the pagerStress()
@ -3915,8 +3921,16 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
*/ */
#if defined(SQLITE_DEBUG) #if defined(SQLITE_DEBUG)
static void assertTruncateConstraintCb(PgHdr *pPg){ static void assertTruncateConstraintCb(PgHdr *pPg){
Pager *pPager = pPg->pPager;
assert( pPg->flags&PGHDR_DIRTY ); assert( pPg->flags&PGHDR_DIRTY );
assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */
Pgno pgno = pPg->pgno;
int i;
for(i=0; i<pPg->pPager->nSavepoint; i++){
PagerSavepoint *p = &pPager->aSavepoint[i];
assert( p->nOrig<pgno || sqlite3BitvecTestNotNull(p->pInSavepoint,pgno) );
}
}
} }
static void assertTruncateConstraint(Pager *pPager){ static void assertTruncateConstraint(Pager *pPager){
sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);
@ -3937,7 +3951,7 @@ static void assertTruncateConstraint(Pager *pPager){
** then continue writing to the database. ** then continue writing to the database.
*/ */
void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
assert( pPager->dbSize>=nPage ); assert( pPager->dbSize>=nPage || CORRUPT_DB );
assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
pPager->dbSize = nPage; pPager->dbSize = nPage;
@ -4665,7 +4679,7 @@ int sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */ int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */ int memDb = 0; /* True if this is an in-memory file */
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
int memJM = 0; /* Memory journal mode */ int memJM = 0; /* Memory journal mode */
#else #else
# define memJM 0 # define memJM 0
@ -4858,6 +4872,7 @@ int sqlite3PagerOpen(
pPager->zWal = 0; pPager->zWal = 0;
} }
#endif #endif
(void)pPtr; /* Suppress warning about unused pPtr value */
if( nPathname ) sqlite3DbFree(0, zPathname); if( nPathname ) sqlite3DbFree(0, zPathname);
pPager->pVfs = pVfs; pPager->pVfs = pVfs;
@ -4869,8 +4884,8 @@ int sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */ int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout); rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb ); assert( !memDb );
#ifdef SQLITE_ENABLE_DESERIALIZE #ifndef SQLITE_OMIT_DESERIALIZE
memJM = (fout&SQLITE_OPEN_MEMORY)!=0; pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
#endif #endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0; readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
@ -5255,7 +5270,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
** may mean that the pager was in the error-state when this ** may mean that the pager was in the error-state when this
** function was called and the journal file does not exist. ** function was called and the journal file does not exist.
*/ */
if( !isOpen(pPager->jfd) ){ if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
sqlite3_vfs * const pVfs = pPager->pVfs; sqlite3_vfs * const pVfs = pPager->pVfs;
int bExists; /* True if journal file exists */ int bExists; /* True if journal file exists */
rc = sqlite3OsAccess( rc = sqlite3OsAccess(
@ -5500,7 +5515,7 @@ static int getPageNormal(
if( pPg->pPager && !noContent ){ if( pPg->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of /* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */ ** the page. Return without further ado. */
assert( pgno!=PAGER_MJ_PGNO(pPager) ); assert( pgno!=PAGER_SJ_PGNO(pPager) );
pPager->aStat[PAGER_STAT_HIT]++; pPager->aStat[PAGER_STAT_HIT]++;
return SQLITE_OK; return SQLITE_OK;
@ -5511,7 +5526,7 @@ static int getPageNormal(
** (*) obsolete. Was: maximum page number is 2^31 ** (*) obsolete. Was: maximum page number is 2^31
** (2) Never try to fetch the locking page ** (2) Never try to fetch the locking page
*/ */
if( pgno==PAGER_MJ_PGNO(pPager) ){ if( pgno==PAGER_SJ_PGNO(pPager) ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
goto pager_acquire_err; goto pager_acquire_err;
} }
@ -5657,6 +5672,7 @@ int sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */ DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */ int flags /* PAGER_GET_XXX flags */
){ ){
/* printf("PAGE %u\n", pgno); fflush(stdout); */
return pPager->xGet(pPager, pgno, ppPage, flags); return pPager->xGet(pPager, pgno, ppPage, flags);
} }
@ -5770,6 +5786,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->tempFile ){ if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
flags |= SQLITE_OPEN_EXCLUSIVE;
nSpill = sqlite3Config.nStmtSpill; nSpill = sqlite3Config.nStmtSpill;
}else{ }else{
flags |= SQLITE_OPEN_MAIN_JOURNAL; flags |= SQLITE_OPEN_MAIN_JOURNAL;
@ -5805,6 +5822,7 @@ static int pager_open_journal(Pager *pPager){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal); sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0; pPager->pInJournal = 0;
pPager->journalOff = 0;
}else{ }else{
assert( pPager->eState==PAGER_WRITER_LOCKED ); assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD; pPager->eState = PAGER_WRITER_CACHEMOD;
@ -5837,7 +5855,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR ); assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
pPager->subjInMemory = (u8)subjInMemory; pPager->subjInMemory = (u8)subjInMemory;
if( ALWAYS(pPager->eState==PAGER_READER) ){ if( pPager->eState==PAGER_READER ){
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
if( pagerUseWal(pPager) ){ if( pagerUseWal(pPager) ){
@ -5909,7 +5927,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
/* We should never write to the journal file the page that /* We should never write to the journal file the page that
** contains the database locks. The following assert verifies ** contains the database locks. The following assert verifies
** that we do not. */ ** that we do not. */
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff ); assert( pPager->journalHdr<=pPager->journalOff );
pData2 = pPg->pData; pData2 = pPg->pData;
@ -6088,7 +6106,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
Pgno pg = pg1+ii; Pgno pg = pg1+ii;
PgHdr *pPage; PgHdr *pPage;
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
if( pg!=PAGER_MJ_PGNO(pPager) ){ if( pg!=PAGER_SJ_PGNO(pPager) ){
rc = sqlite3PagerGet(pPager, pg, &pPage, 0); rc = sqlite3PagerGet(pPager, pg, &pPage, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = pager_write(pPage); rc = pager_write(pPage);
@ -6566,7 +6584,7 @@ int sqlite3PagerCommitPhaseOne(
** last page is never written out to disk, leaving the database file ** last page is never written out to disk, leaving the database file
** undersized. Fix this now if it is the case. */ ** undersized. Fix this now if it is the case. */
if( pPager->dbSize>pPager->dbFileSize ){ if( pPager->dbSize>pPager->dbFileSize ){
Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_SJ_PGNO(pPager));
assert( pPager->eState==PAGER_WRITER_DBMOD ); assert( pPager->eState==PAGER_WRITER_DBMOD );
rc = pager_truncate(pPager, nNew); rc = pager_truncate(pPager, nNew);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit; if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
@ -6737,8 +6755,8 @@ int sqlite3PagerRefcount(Pager *pPager){
** used by the pager and its associated cache. ** used by the pager and its associated cache.
*/ */
int sqlite3PagerMemUsed(Pager *pPager){ int sqlite3PagerMemUsed(Pager *pPager){
int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr) int perPageSize = pPager->pageSize + pPager->nExtra
+ 5*sizeof(void*); + (int)(sizeof(PgHdr) + 5*sizeof(void*));
return perPageSize*sqlite3PcachePagecount(pPager->pPCache) return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
+ sqlite3MallocSize(pPager) + sqlite3MallocSize(pPager)
+ pPager->pageSize; + pPager->pageSize;
@ -6807,7 +6825,7 @@ void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
** Return true if this is an in-memory or temp-file backed pager. ** Return true if this is an in-memory or temp-file backed pager.
*/ */
int sqlite3PagerIsMemdb(Pager *pPager){ int sqlite3PagerIsMemdb(Pager *pPager){
return pPager->tempFile; return pPager->tempFile || pPager->memVfs;
} }
/* /*
@ -6932,14 +6950,14 @@ int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
} }
pPager->nSavepoint = nNew; pPager->nSavepoint = nNew;
/* If this is a release of the outermost savepoint, truncate /* Truncate the sub-journal so that it only includes the parts
** the sub-journal to zero bytes in size. */ ** that are still in use. */
if( op==SAVEPOINT_RELEASE ){ if( op==SAVEPOINT_RELEASE ){
PagerSavepoint *pRel = &pPager->aSavepoint[nNew]; PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){ if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
/* Only truncate if it is an in-memory sub-journal. */ /* Only truncate if it is an in-memory sub-journal. */
if( sqlite3JournalIsInMemory(pPager->sjfd) ){ if( sqlite3JournalIsInMemory(pPager->sjfd) ){
i64 sz = (pPager->pageSize+4)*pRel->iSubRec; i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec;
rc = sqlite3OsTruncate(pPager->sjfd, sz); rc = sqlite3OsTruncate(pPager->sjfd, sz);
assert( rc==SQLITE_OK ); assert( rc==SQLITE_OK );
} }
@ -7127,7 +7145,7 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
pPgOld = sqlite3PagerLookup(pPager, pgno); pPgOld = sqlite3PagerLookup(pPager, pgno);
assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB );
if( pPgOld ){ if( pPgOld ){
if( pPgOld->nRef>1 ){ if( NEVER(pPgOld->nRef>1) ){
sqlite3PagerUnrefNotNull(pPgOld); sqlite3PagerUnrefNotNull(pPgOld);
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
@ -7262,12 +7280,12 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
u8 eOld = pPager->journalMode; /* Prior journalmode */ u8 eOld = pPager->journalMode; /* Prior journalmode */
/* The eMode parameter is always valid */ /* The eMode parameter is always valid */
assert( eMode==PAGER_JOURNALMODE_DELETE assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */
|| eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */
|| eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_OFF /* 2 */
|| eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */
|| eMode==PAGER_JOURNALMODE_WAL || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */
|| eMode==PAGER_JOURNALMODE_MEMORY ); || eMode==PAGER_JOURNALMODE_WAL /* 5 */ );
/* This routine is only called from the OP_JournalMode opcode, and /* This routine is only called from the OP_JournalMode opcode, and
** the logic there will never allow a temporary file to be changed ** the logic there will never allow a temporary file to be changed
@ -7304,7 +7322,6 @@ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
assert( isOpen(pPager->fd) || pPager->exclusiveMode ); assert( isOpen(pPager->fd) || pPager->exclusiveMode );
if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
/* In this case we would like to delete the journal file. If it is /* In this case we would like to delete the journal file. If it is
** not possible, then that is not a problem. Deleting the journal file ** not possible, then that is not a problem. Deleting the journal file
** here is an optimization only. ** here is an optimization only.
@ -7416,6 +7433,18 @@ int sqlite3PagerCheckpoint(
int *pnCkpt /* OUT: Final number of checkpointed frames */ int *pnCkpt /* OUT: Final number of checkpointed frames */
){ ){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( pPager->pWal==0 && pPager->journalMode==PAGER_JOURNALMODE_WAL ){
/* This only happens when a database file is zero bytes in size opened and
** then "PRAGMA journal_mode=WAL" is run and then sqlite3_wal_checkpoint()
** is invoked without any intervening transactions. We need to start
** a transaction to initialize pWal. The PRAGMA table_list statement is
** used for this since it starts transactions on every database file,
** including all ATTACHed databases. This seems expensive for a single
** sqlite3_wal_checkpoint() call, but it happens very rarely.
** https://sqlite.org/forum/forumpost/fd0f19d229156939
*/
sqlite3_exec(db, "PRAGMA table_list",0,0,0);
}
if( pPager->pWal ){ if( pPager->pWal ){
rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode, rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler), (eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),

View file

@ -13,7 +13,6 @@
** subsystem. The page cache subsystem reads and writes a file a page ** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback. ** at a time and provides a journal for rollback.
*/ */
/* clang-format off */
#ifndef SQLITE_PAGER_H #ifndef SQLITE_PAGER_H
#define SQLITE_PAGER_H #define SQLITE_PAGER_H
@ -44,14 +43,15 @@ typedef struct Pager Pager;
typedef struct PgHdr DbPage; typedef struct PgHdr DbPage;
/* /*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** Page number PAGER_SJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is ** reserved for working around a windows/posix incompatibility). It is
** used in the journal to signify that the remainder of the journal file ** used in the journal to signify that the remainder of the journal file
** is devoted to storing a super-journal name - there are no more pages to ** is devoted to storing a super-journal name - there are no more pages to
** roll back. See comments for function writeSuperJournal() in pager.c ** roll back. See comments for function writeSuperJournal() in pager.c
** for details. ** for details.
*/ */
#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) #define PAGER_SJ_PGNO_COMPUTED(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
#define PAGER_SJ_PGNO(x) ((x)->lckPgno)
/* /*
** Allowed values for the flags parameter to sqlite3PagerOpen(). ** Allowed values for the flags parameter to sqlite3PagerOpen().

File diff suppressed because it is too large Load diff

View file

@ -22,8 +22,8 @@
#define TK_LP 22 #define TK_LP 22
#define TK_RP 23 #define TK_RP 23
#define TK_AS 24 #define TK_AS 24
#define TK_WITHOUT 25 #define TK_COMMA 25
#define TK_COMMA 26 #define TK_WITHOUT 26
#define TK_ABORT 27 #define TK_ABORT 27
#define TK_ACTION 28 #define TK_ACTION 28
#define TK_AFTER 29 #define TK_AFTER 29
@ -109,74 +109,76 @@
#define TK_SLASH 109 #define TK_SLASH 109
#define TK_REM 110 #define TK_REM 110
#define TK_CONCAT 111 #define TK_CONCAT 111
#define TK_COLLATE 112 #define TK_PTR 112
#define TK_BITNOT 113 #define TK_COLLATE 113
#define TK_ON 114 #define TK_BITNOT 114
#define TK_INDEXED 115 #define TK_ON 115
#define TK_STRING 116 #define TK_INDEXED 116
#define TK_JOIN_KW 117 #define TK_STRING 117
#define TK_CONSTRAINT 118 #define TK_JOIN_KW 118
#define TK_DEFAULT 119 #define TK_CONSTRAINT 119
#define TK_NULL 120 #define TK_DEFAULT 120
#define TK_PRIMARY 121 #define TK_NULL 121
#define TK_UNIQUE 122 #define TK_PRIMARY 122
#define TK_CHECK 123 #define TK_UNIQUE 123
#define TK_REFERENCES 124 #define TK_CHECK 124
#define TK_AUTOINCR 125 #define TK_REFERENCES 125
#define TK_INSERT 126 #define TK_AUTOINCR 126
#define TK_DELETE 127 #define TK_INSERT 127
#define TK_UPDATE 128 #define TK_DELETE 128
#define TK_SET 129 #define TK_UPDATE 129
#define TK_DEFERRABLE 130 #define TK_SET 130
#define TK_FOREIGN 131 #define TK_DEFERRABLE 131
#define TK_DROP 132 #define TK_FOREIGN 132
#define TK_UNION 133 #define TK_DROP 133
#define TK_ALL 134 #define TK_UNION 134
#define TK_EXCEPT 135 #define TK_ALL 135
#define TK_INTERSECT 136 #define TK_EXCEPT 136
#define TK_SELECT 137 #define TK_INTERSECT 137
#define TK_VALUES 138 #define TK_SELECT 138
#define TK_DISTINCT 139 #define TK_VALUES 139
#define TK_DOT 140 #define TK_DISTINCT 140
#define TK_FROM 141 #define TK_DOT 141
#define TK_JOIN 142 #define TK_FROM 142
#define TK_USING 143 #define TK_JOIN 143
#define TK_ORDER 144 #define TK_USING 144
#define TK_GROUP 145 #define TK_ORDER 145
#define TK_HAVING 146 #define TK_GROUP 146
#define TK_LIMIT 147 #define TK_HAVING 147
#define TK_WHERE 148 #define TK_LIMIT 148
#define TK_RETURNING 149 #define TK_WHERE 149
#define TK_INTO 150 #define TK_RETURNING 150
#define TK_NOTHING 151 #define TK_INTO 151
#define TK_FLOAT 152 #define TK_NOTHING 152
#define TK_BLOB 153 #define TK_FLOAT 153
#define TK_INTEGER 154 #define TK_BLOB 154
#define TK_VARIABLE 155 #define TK_INTEGER 155
#define TK_CASE 156 #define TK_VARIABLE 156
#define TK_WHEN 157 #define TK_CASE 157
#define TK_THEN 158 #define TK_WHEN 158
#define TK_ELSE 159 #define TK_THEN 159
#define TK_INDEX 160 #define TK_ELSE 160
#define TK_ALTER 161 #define TK_INDEX 161
#define TK_ADD 162 #define TK_ALTER 162
#define TK_WINDOW 163 #define TK_ADD 163
#define TK_OVER 164 #define TK_WINDOW 164
#define TK_FILTER 165 #define TK_OVER 165
#define TK_COLUMN 166 #define TK_FILTER 166
#define TK_AGG_FUNCTION 167 #define TK_COLUMN 167
#define TK_AGG_COLUMN 168 #define TK_AGG_FUNCTION 168
#define TK_TRUEFALSE 169 #define TK_AGG_COLUMN 169
#define TK_ISNOT 170 #define TK_TRUEFALSE 170
#define TK_FUNCTION 171 #define TK_ISNOT 171
#define TK_UMINUS 172 #define TK_FUNCTION 172
#define TK_UPLUS 173 #define TK_UMINUS 173
#define TK_TRUTH 174 #define TK_UPLUS 174
#define TK_REGISTER 175 #define TK_TRUTH 175
#define TK_VECTOR 176 #define TK_REGISTER 176
#define TK_SELECT_COLUMN 177 #define TK_VECTOR 177
#define TK_IF_NULL_ROW 178 #define TK_SELECT_COLUMN 178
#define TK_ASTERISK 179 #define TK_IF_NULL_ROW 179
#define TK_SPAN 180 #define TK_ASTERISK 180
#define TK_SPACE 181 #define TK_SPAN 181
#define TK_ILLEGAL 182 #define TK_ERROR 182
#define TK_SPACE 183
#define TK_ILLEGAL 184

View file

@ -11,8 +11,7 @@
************************************************************************* *************************************************************************
** This file implements that page cache. ** This file implements that page cache.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** A complete page cache is an instance of this structure. Every ** A complete page cache is an instance of this structure. Every
@ -67,12 +66,20 @@ struct PCache {
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
void pcacheDump(PCache *pCache){ static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
int N;
int i, j;
sqlite3_pcache_page *pLower;
PgHdr *pPg; PgHdr *pPg;
unsigned char *a; unsigned char *a;
int j;
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(" ptr %p\n", pPg);
}
static void pcacheDump(PCache *pCache){
int N;
int i;
sqlite3_pcache_page *pLower;
if( sqlite3PcacheTrace<2 ) return; if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return; if( pCache->pCache==0 ) return;
@ -81,21 +88,32 @@ struct PCache {
for(i=1; i<=N; i++){ for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue; if( pLower==0 ) continue;
pPg = (PgHdr*)pLower->pExtra; pcachePageTrace(i, pLower);
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); if( ((PgHdr*)pLower)->pPage==0 ){
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); sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
} }
} }
} }
#else #else
# define pcacheTrace(X) # define pcacheTrace(X)
# define pcachePageTrace(PGNO, X)
# define pcacheDump(X) # define pcacheDump(X)
#endif #endif
/*
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
#ifdef SQLITE_DEBUG
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
if( p==pPg ) return 1;
}
return 0;
}
#endif
/* /*
** Check invariants on a PgHdr entry. Return true if everything is OK. ** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated. ** Return false if any invariant is violated.
@ -114,8 +132,13 @@ int sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */ assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){ if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
assert( pCache->pDirtyTail!=pPg ); }else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
assert( pageOnDirtyList(pCache, pPg) );
} }
/* WRITEABLE pages must also be DIRTY */ /* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){ if( pPg->flags & PGHDR_WRITEABLE ){
@ -244,11 +267,14 @@ static int numberOfCachePages(PCache *p){
** suggested cache size is set to N. */ ** suggested cache size is set to N. */
return p->szCache; return p->szCache;
}else{ }else{
i64 n;
/* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would ** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current ** use approximately abs(N*1024) bytes of memory based on the current
** page size. */ ** page size. */
return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
if( n>1000000000 ) n = 1000000000;
return (int)n;
} }
} }
@ -386,8 +412,9 @@ sqlite3_pcache_page *sqlite3PcacheFetch(
assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = 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, pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes)); createFlag?" create":"",pRes));
pcachePageTrace(pgno, pRes);
return pRes; return pRes;
} }
@ -515,6 +542,7 @@ void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
pcacheUnpin(p); pcacheUnpin(p);
}else{ }else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
} }
} }
} }
@ -558,6 +586,7 @@ void sqlite3PcacheMakeDirty(PgHdr *p){
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
assert( sqlite3PcachePageSanity(p) );
} }
assert( sqlite3PcachePageSanity(p) ); assert( sqlite3PcachePageSanity(p) );
} }
@ -620,14 +649,24 @@ void sqlite3PcacheClearSyncFlags(PCache *pCache){
*/ */
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache; PCache *pCache = p->pCache;
sqlite3_pcache_page *pOther;
assert( p->nRef>0 ); assert( p->nRef>0 );
assert( newPgno>0 ); assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) ); assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
if( pOther ){
PgHdr *pXPage = (PgHdr*)pOther->pExtra;
assert( pXPage->nRef==0 );
pXPage->nRef++;
pCache->nRefSum++;
sqlite3PcacheDrop(pXPage);
}
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno; p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
} }
} }

View file

@ -10,9 +10,8 @@
** **
************************************************************************* *************************************************************************
** This header file defines the interface that the sqlite page cache ** This header file defines the interface that the sqlite page cache
** subsystem. ** subsystem.
*/ */
/* clang-format off */
#ifndef _PCACHE_H_ #ifndef _PCACHE_H_

View file

@ -39,12 +39,13 @@
** size can vary according to architecture, compile-time options, and ** size can vary according to architecture, compile-time options, and
** SQLite library version number. ** SQLite library version number.
** **
** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained ** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER
** using a separate memory allocation from the database page content. This ** was defined, then the page content would be held in a separate memory
** seeks to overcome the "clownshoe" problem (also called "internal ** allocation from the PgHdr1. This was intended to avoid clownshoe memory
** fragmentation" in academic literature) of allocating a few bytes more ** allocations. However, the btree layer needs a small (16-byte) overrun
** than a power of two with the memory allocator rounding up to the next ** area after the page content buffer. The header serves as that overrun
** power of two, and leaving the rounded-up space unused. ** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid
** any possibility of a memory error.
** **
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates ** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
** with this module. Information is passed back and forth as PgHdr1 pointers. ** with this module. Information is passed back and forth as PgHdr1 pointers.
@ -63,7 +64,7 @@
** **
** The third case is a chunk of heap memory (defaulting to 100 pages worth) ** The third case is a chunk of heap memory (defaulting to 100 pages worth)
** that is allocated when the page cache is created. The size of the local ** that is allocated when the page cache is created. The size of the local
** bulk allocation can be adjusted using ** bulk allocation can be adjusted using
** **
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N). ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
** **
@ -82,7 +83,7 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */ /* clang-format off */
typedef struct PCache1 PCache1; typedef struct PCache1 PCache1;
@ -92,30 +93,40 @@ typedef struct PGroup PGroup;
/* /*
** Each cache entry is represented by an instance of the following ** Each cache entry is represented by an instance of the following
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of ** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
** PgHdr1.pCache->szPage bytes is allocated directly before this structure ** directly before this structure and is used to cache the page content.
** in memory.
** **
** Note: Variables isBulkLocal and isAnchor were once type "u8". That works, ** When reading a corrupt database file, it is possible that SQLite might
** read a few bytes (no more than 16 bytes) past the end of the page buffer.
** It will only read past the end of the page buffer, never write. This
** object is positioned immediately after the page buffer to serve as an
** overrun area, so that overreads are harmless.
**
** Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since ** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located ** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is ** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and ** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This ** read part of this structure before the corruption is detected. This
** can cause a valgrind error if the unitialized gap is accessed. Using u16 ** can cause a valgrind error if the unitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of unitialized memory ** ensures there is no such gap, and therefore no bytes of uninitialized
** in the structure. ** memory in the structure.
**
** The pLruNext and pLruPrev pointers form a double-linked circular list
** of all pages that are unpinned. The PGroup.lru element (which should be
** the only element on the list with PgHdr1.isAnchor set to 1) forms the
** beginning and the end of the list.
*/ */
struct PgHdr1 { struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */ sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */ unsigned int iKey; /* Key value (page number) */
u16 isBulkLocal; /* This page from bulk local storage */ u16 isBulkLocal; /* This page from bulk local storage */
u16 isAnchor; /* This is the PGroup.lru element */ u16 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */ PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */ PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
/* NB: pLruPrev is only valid if pLruNext!=0 */ /* NB: pLruPrev is only valid if pLruNext!=0 */
}; };
/* /*
@ -441,25 +452,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
pcache1LeaveMutex(pCache->pGroup); pcache1LeaveMutex(pCache->pGroup);
#endif #endif
if( benignMalloc ){ sqlite3BeginBenignMalloc(); } if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
pPg = pcache1Alloc(pCache->szPage);
p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
if( !pPg || !p ){
pcache1Free(pPg);
sqlite3_free(p);
pPg = 0;
}
#else
pPg = pcache1Alloc(pCache->szAlloc); pPg = pcache1Alloc(pCache->szAlloc);
#endif
if( benignMalloc ){ sqlite3EndBenignMalloc(); } if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup); pcache1EnterMutex(pCache->pGroup);
#endif #endif
if( pPg==0 ) return 0; if( pPg==0 ) return 0;
#ifndef SQLITE_PCACHE_SEPARATE_HEADER
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
p->page.pBuf = pPg; p->page.pBuf = pPg;
p->page.pExtra = &p[1]; p->page.pExtra = &p[1];
p->isBulkLocal = 0; p->isBulkLocal = 0;
@ -483,9 +482,6 @@ static void pcache1FreePage(PgHdr1 *p){
pCache->pFree = p; pCache->pFree = p;
}else{ }else{
pcache1Free(p->page.pBuf); pcache1Free(p->page.pBuf);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
sqlite3_free(p);
#endif
} }
(*pCache->pnPurgeable)--; (*pCache->pnPurgeable)--;
} }
@ -820,12 +816,18 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
*/ */
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
PCache1 *pCache = (PCache1 *)p; PCache1 *pCache = (PCache1 *)p;
u32 n;
assert( nMax>=0 );
if( pCache->bPurgeable ){ if( pCache->bPurgeable ){
PGroup *pGroup = pCache->pGroup; PGroup *pGroup = pCache->pGroup;
pcache1EnterMutex(pGroup); pcache1EnterMutex(pGroup);
pGroup->nMaxPage += (nMax - pCache->nMax); n = (u32)nMax;
if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){
n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax;
}
pGroup->nMaxPage += (n - pCache->nMax);
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
pCache->nMax = nMax; pCache->nMax = n;
pCache->n90pct = pCache->nMax*9/10; pCache->n90pct = pCache->nMax*9/10;
pcache1EnforceMaxPage(pCache); pcache1EnforceMaxPage(pCache);
pcache1LeaveMutex(pGroup); pcache1LeaveMutex(pGroup);
@ -841,7 +843,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
PCache1 *pCache = (PCache1*)p; PCache1 *pCache = (PCache1*)p;
if( pCache->bPurgeable ){ if( pCache->bPurgeable ){
PGroup *pGroup = pCache->pGroup; PGroup *pGroup = pCache->pGroup;
int savedMaxPage; unsigned int savedMaxPage;
pcache1EnterMutex(pGroup); pcache1EnterMutex(pGroup);
savedMaxPage = pGroup->nMaxPage; savedMaxPage = pGroup->nMaxPage;
pGroup->nMaxPage = 0; pGroup->nMaxPage = 0;
@ -1120,23 +1122,26 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p; PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg; PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp; PgHdr1 **pp;
unsigned int h; unsigned int hOld, hNew;
assert( pPage->iKey==iOld ); assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache ); assert( pPage->pCache==pCache );
assert( iOld!=iNew ); /* The page number really is changing */
pcache1EnterMutex(pCache->pGroup); pcache1EnterMutex(pCache->pGroup);
h = iOld%pCache->nHash; assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
pp = &pCache->apHash[h]; hOld = iOld%pCache->nHash;
pp = &pCache->apHash[hOld];
while( (*pp)!=pPage ){ while( (*pp)!=pPage ){
pp = &(*pp)->pNext; pp = &(*pp)->pNext;
} }
*pp = pPage->pNext; *pp = pPage->pNext;
h = iNew%pCache->nHash; assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
hNew = iNew%pCache->nHash;
pPage->iKey = iNew; pPage->iKey = iNew;
pPage->pNext = pCache->apHash[h]; pPage->pNext = pCache->apHash[hNew];
pCache->apHash[h] = pPage; pCache->apHash[hNew] = pPage;
if( iNew>pCache->iMaxKey ){ if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew; pCache->iMaxKey = iNew;
} }
@ -1243,9 +1248,6 @@ int sqlite3PcacheReleaseMemory(int nReq){
&& p->isAnchor==0 && p->isAnchor==0
){ ){
nFree += pcache1MemSize(p->page.pBuf); nFree += pcache1MemSize(p->page.pBuf);
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
assert( PAGE_IS_UNPINNED(p) ); assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p); pcache1PinPage(p);
pcache1RemoveFromHash(p, 1); pcache1RemoveFromHash(p, 1);

View file

@ -11,8 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the PRAGMA command. ** This file contains code used to implement the PRAGMA command.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
#if !defined(SQLITE_ENABLE_LOCKING_STYLE) #if !defined(SQLITE_ENABLE_LOCKING_STYLE)
# if defined(__APPLE__) # if defined(__APPLE__)
@ -308,15 +307,16 @@ static void pragmaFunclistLine(
int isBuiltin, /* True if this is a built-in function */ int isBuiltin, /* True if this is a built-in function */
int showInternFuncs /* True if showing internal functions */ int showInternFuncs /* True if showing internal functions */
){ ){
u32 mask =
SQLITE_DETERMINISTIC |
SQLITE_DIRECTONLY |
SQLITE_SUBTYPE |
SQLITE_INNOCUOUS |
SQLITE_FUNC_INTERNAL
;
if( showInternFuncs ) mask = 0xffffffff;
for(; p; p=p->pNext){ for(; p; p=p->pNext){
const char *zType; const char *zType;
static const u32 mask =
SQLITE_DETERMINISTIC |
SQLITE_DIRECTONLY |
SQLITE_SUBTYPE |
SQLITE_INNOCUOUS |
SQLITE_FUNC_INTERNAL
;
static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" }; static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" };
assert( SQLITE_FUNC_ENCMASK==0x3 ); assert( SQLITE_FUNC_ENCMASK==0x3 );
@ -468,7 +468,11 @@ void sqlite3Pragma(
/* Locate the pragma in the lookup table */ /* Locate the pragma in the lookup table */
pPragma = pragmaLocate(zLeft); pPragma = pragmaLocate(zLeft);
if( pPragma==0 ) goto pragma_out; if( pPragma==0 ){
/* IMP: R-43042-22504 No error messages are generated if an
** unknown pragma is issued. */
goto pragma_out;
}
/* Make sure the database schema is loaded if the pragma requires that */ /* Make sure the database schema is loaded if the pragma requires that */
if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
@ -804,7 +808,7 @@ void sqlite3Pragma(
*/ */
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
case PragTyp_INCREMENTAL_VACUUM: { case PragTyp_INCREMENTAL_VACUUM: {
int iLimit, addr; int iLimit = 0, addr;
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
iLimit = 0x7fffffff; iLimit = 0x7fffffff;
} }
@ -961,6 +965,7 @@ void sqlite3Pragma(
** **
*/ */
case PragTyp_TEMP_STORE_DIRECTORY: { case PragTyp_TEMP_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){ if( !zRight ){
returnSingleText(v, sqlite3_temp_directory); returnSingleText(v, sqlite3_temp_directory);
}else{ }else{
@ -970,6 +975,7 @@ void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){ if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory"); sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out; goto pragma_out;
} }
} }
@ -987,6 +993,7 @@ void sqlite3Pragma(
} }
#endif /* SQLITE_OMIT_WSD */ #endif /* SQLITE_OMIT_WSD */
} }
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break; break;
} }
@ -1005,6 +1012,7 @@ void sqlite3Pragma(
** **
*/ */
case PragTyp_DATA_STORE_DIRECTORY: { case PragTyp_DATA_STORE_DIRECTORY: {
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){ if( !zRight ){
returnSingleText(v, sqlite3_data_directory); returnSingleText(v, sqlite3_data_directory);
}else{ }else{
@ -1014,6 +1022,7 @@ void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){ if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory"); sqlite3ErrorMsg(pParse, "not a writable directory");
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out; goto pragma_out;
} }
} }
@ -1025,6 +1034,7 @@ void sqlite3Pragma(
} }
#endif /* SQLITE_OMIT_WSD */ #endif /* SQLITE_OMIT_WSD */
} }
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break; break;
} }
#endif #endif
@ -1118,6 +1128,14 @@ void sqlite3Pragma(
}else{ }else{
db->flags &= ~mask; db->flags &= ~mask;
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
if( (mask & SQLITE_WriteSchema)!=0
&& sqlite3_stricmp(zRight, "reset")==0
){
/* IMP: R-60817-01178 If the argument is "RESET" then schema
** writing is disabled (as with "PRAGMA writable_schema=OFF") and,
** in addition, the schema is reloaded. */
sqlite3ResetAllSchemasOfConnection(db);
}
} }
/* Many of the flag-pragmas modify the code generated by the SQL /* Many of the flag-pragmas modify the code generated by the SQL
@ -1158,6 +1176,7 @@ void sqlite3Pragma(
sqlite3ViewGetColumnNames(pParse, pTab); sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
int isHidden = 0; int isHidden = 0;
const Expr *pColExpr;
if( pCol->colFlags & COLFLAG_NOINSERT ){ if( pCol->colFlags & COLFLAG_NOINSERT ){
if( pPragma->iArg==0 ){ if( pPragma->iArg==0 ){
nHidden++; nHidden++;
@ -1178,13 +1197,16 @@ void sqlite3Pragma(
}else{ }else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
} }
assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 ); pColExpr = sqlite3ColumnExpr(pTab,pCol);
assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 );
assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue)
|| isHidden>=2 );
sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi",
i-nHidden, i-nHidden,
pCol->zName, pCol->zCnName,
sqlite3ColumnType(pCol,""), sqlite3ColumnType(pCol,""),
pCol->notNull ? 1 : 0, pCol->notNull ? 1 : 0,
pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0, (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken,
k, k,
isHidden); isHidden);
} }
@ -1192,6 +1214,85 @@ void sqlite3Pragma(
} }
break; break;
/*
** PRAGMA table_list
**
** Return a single row for each table, virtual table, or view in the
** entire schema.
**
** schema: Name of attached database hold this table
** name: Name of the table itself
** type: "table", "view", "virtual", "shadow"
** ncol: Number of columns
** wr: True for a WITHOUT ROWID table
** strict: True for a STRICT table
*/
case PragTyp_TABLE_LIST: {
int ii;
pParse->nMem = 6;
sqlite3CodeVerifyNamedSchema(pParse, zDb);
for(ii=0; ii<db->nDb; ii++){
HashElem *k;
Hash *pHash;
int initNCol;
if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue;
/* Ensure that the Table.nCol field is initialized for all views
** and virtual tables. Each time we initialize a Table.nCol value
** for a table, that can potentially disrupt the hash table, so restart
** the initialization scan.
*/
pHash = &db->aDb[ii].pSchema->tblHash;
initNCol = sqliteHashCount(pHash);
while( initNCol-- ){
for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){
Table *pTab;
if( k==0 ){ initNCol = 0; break; }
pTab = sqliteHashData(k);
if( pTab->nCol==0 ){
char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
if( zSql ){
sqlite3_stmt *pDummy = 0;
(void)sqlite3_prepare(db, zSql, -1, &pDummy, 0);
(void)sqlite3_finalize(pDummy);
sqlite3DbFree(db, zSql);
}
if( db->mallocFailed ){
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT;
}
pHash = &db->aDb[ii].pSchema->tblHash;
break;
}
}
}
for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){
Table *pTab = sqliteHashData(k);
const char *zType;
if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue;
if( IsView(pTab) ){
zType = "view";
}else if( IsVirtual(pTab) ){
zType = "virtual";
}else if( pTab->tabFlags & TF_Shadow ){
zType = "shadow";
}else{
zType = "table";
}
sqlite3VdbeMultiLoad(v, 1, "sssiii",
db->aDb[ii].zDbSName,
sqlite3PreferredTableName(pTab->zName),
zType,
pTab->nCol,
(pTab->tabFlags & TF_WithoutRowid)!=0,
(pTab->tabFlags & TF_Strict)!=0
);
}
}
}
break;
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
case PragTyp_STATS: { case PragTyp_STATS: {
Index *pIdx; Index *pIdx;
@ -1201,7 +1302,7 @@ void sqlite3Pragma(
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i); Table *pTab = sqliteHashData(i);
sqlite3VdbeMultiLoad(v, 1, "ssiii", sqlite3VdbeMultiLoad(v, 1, "ssiii",
pTab->zName, sqlite3PreferredTableName(pTab->zName),
0, 0,
pTab->szTabRow, pTab->szTabRow,
pTab->nRowLogEst, pTab->nRowLogEst,
@ -1251,7 +1352,7 @@ void sqlite3Pragma(
for(i=0; i<mx; i++){ for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i]; i16 cnum = pIdx->aiColumn[i];
sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum, sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum,
cnum<0 ? 0 : pTab->aCol[cnum].zName); cnum<0 ? 0 : pTab->aCol[cnum].zCnName);
if( pPragma->iArg ){ if( pPragma->iArg ){
sqlite3VdbeMultiLoad(v, 4, "isiX", sqlite3VdbeMultiLoad(v, 4, "isiX",
pIdx->aSortOrder[i], pIdx->aSortOrder[i],
@ -1320,11 +1421,13 @@ void sqlite3Pragma(
pParse->nMem = 6; pParse->nMem = 6;
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
pragmaFunclistLine(v, p, 1, showInternFunc); pragmaFunclistLine(v, p, 1, showInternFunc);
} }
} }
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
p = (FuncDef*)sqliteHashData(j); p = (FuncDef*)sqliteHashData(j);
assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 );
pragmaFunclistLine(v, p, 0, showInternFunc); pragmaFunclistLine(v, p, 0, showInternFunc);
} }
} }
@ -1358,8 +1461,8 @@ void sqlite3Pragma(
FKey *pFK; FKey *pFK;
Table *pTab; Table *pTab;
pTab = sqlite3FindTable(db, zRight, zDb); pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){ if( pTab && IsOrdinaryTable(pTab) ){
pFK = pTab->pFKey; pFK = pTab->u.tab.pFKey;
if( pFK ){ if( pFK ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int i = 0; int i = 0;
@ -1372,7 +1475,7 @@ void sqlite3Pragma(
i, i,
j, j,
pFK->zTo, pFK->zTo,
pTab->aCol[pFK->aCol[j].iFrom].zName, pTab->aCol[pFK->aCol[j].iFrom].zCnName,
pFK->aCol[j].zCol, pFK->aCol[j].zCol,
actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[1]), /* ON UPDATE */
actionName(pFK->aAction[0]), /* ON DELETE */ actionName(pFK->aAction[0]), /* ON DELETE */
@ -1399,7 +1502,6 @@ void sqlite3Pragma(
HashElem *k; /* Loop counter: Next table in schema */ HashElem *k; /* Loop counter: Next table in schema */
int x; /* result variable */ int x; /* result variable */
int regResult; /* 3 registers to hold a result row */ int regResult; /* 3 registers to hold a result row */
int regKey; /* Register to hold key for checking the FK */
int regRow; /* Registers to hold a row from pTab */ int regRow; /* Registers to hold a row from pTab */
int addrTop; /* Top of a loop checking foreign keys */ int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */ int addrOk; /* Jump here if the key is OK */
@ -1407,7 +1509,6 @@ void sqlite3Pragma(
regResult = pParse->nMem+1; regResult = pParse->nMem+1;
pParse->nMem += 4; pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem; regRow = ++pParse->nMem;
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){ while( k ){
@ -1418,7 +1519,7 @@ void sqlite3Pragma(
pTab = (Table*)sqliteHashData(k); pTab = (Table*)sqliteHashData(k);
k = sqliteHashNext(k); k = sqliteHashNext(k);
} }
if( pTab==0 || pTab->pFKey==0 ) continue; if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema); iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName; zDb = db->aDb[iDb].zDbSName;
sqlite3CodeVerifySchema(pParse, iDb); sqlite3CodeVerifySchema(pParse, iDb);
@ -1426,7 +1527,8 @@ void sqlite3Pragma(
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName); sqlite3VdbeLoadString(v, regResult, pTab->zName);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ assert( IsOrdinaryTable(pTab) );
for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3FindTable(db, pFK->zTo, zDb); pParent = sqlite3FindTable(db, pFK->zTo, zDb);
if( pParent==0 ) continue; if( pParent==0 ) continue;
pIdx = 0; pIdx = 0;
@ -1448,7 +1550,8 @@ void sqlite3Pragma(
if( pFK ) break; if( pFK ) break;
if( pParse->nTab<i ) pParse->nTab = i; if( pParse->nTab<i ) pParse->nTab = i;
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v); addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v);
for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ assert( IsOrdinaryTable(pTab) );
for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){
pParent = sqlite3FindTable(db, pFK->zTo, zDb); pParent = sqlite3FindTable(db, pFK->zTo, zDb);
pIdx = 0; pIdx = 0;
aiCols = 0; aiCols = 0;
@ -1462,6 +1565,7 @@ void sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this ** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in ** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */ ** this case. */
if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
for(j=0; j<pFK->nCol; j++){ for(j=0; j<pFK->nCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@ -1471,9 +1575,9 @@ void sqlite3Pragma(
/* Generate code to query the parent index for a matching parent /* Generate code to query the parent index for a matching parent
** key. If a match is found, jump to addrOk. */ ** key. If a match is found, jump to addrOk. */
if( pIdx ){ if( pIdx ){
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, sqlite3VdbeAddOp4(v, OP_Affinity, regRow, pFK->nCol, 0,
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regRow, pFK->nCol);
VdbeCoverage(v); VdbeCoverage(v);
}else if( pParent ){ }else if( pParent ){
int jmp = sqlite3VdbeCurrentAddr(v)+2; int jmp = sqlite3VdbeCurrentAddr(v)+2;
@ -1644,14 +1748,24 @@ void sqlite3Pragma(
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x); Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk; Index *pIdx, *pPk;
Index *pPrior = 0; Index *pPrior = 0; /* Previous index */
int loopTop; int loopTop;
int iDataCur, iIdxCur; int iDataCur, iIdxCur;
int r1 = -1; int r1 = -1;
int bStrict; /* True for a STRICT table */
int r2; /* Previous key for WITHOUT ROWID tables */
int mxCol; /* Maximum non-virtual column number */
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue; if( pObjTab && pObjTab!=pTab ) continue;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); if( isQuick || HasRowid(pTab) ){
pPk = 0;
r2 = 0;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur); 1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table. /* reg[7] counts the number of entries in the table.
@ -1665,27 +1779,157 @@ void sqlite3Pragma(
assert( sqlite3NoTempsInRange(pParse,1,7+j) ); assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
if( !isQuick ){
/* Sanity check on record header decoding */ /* Fetch the right-most column from the table. This will cause
sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); ** the entire record header to be parsed and sanity checked. It
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); ** will also prepopulate the cursor column cache that is used
** by the OP_IsType code, so it is a required step.
*/
mxCol = pTab->nCol-1;
while( mxCol>=0
&& ((pTab->aCol[mxCol].colFlags & COLFLAG_VIRTUAL)!=0
|| pTab->iPKey==mxCol) ) mxCol--;
if( mxCol>=0 ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, mxCol, 3);
sqlite3VdbeTypeofColumn(v, 3);
} }
/* Verify that all NOT NULL columns really are NOT NULL */
if( !isQuick ){
if( pPk ){
/* Verify WITHOUT ROWID keys are in ascending order */
int a1;
char *zErr;
a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
zErr = sqlite3MPrintf(db,
"row not in PRIMARY KEY order for %s",
pTab->zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, a1);
sqlite3VdbeJumpHere(v, a1+1);
for(j=0; j<pPk->nKeyCol; j++){
sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
}
}
}
/* Verify datatypes for all columns:
**
** (1) NOT NULL columns may not contain a NULL
** (2) Datatype must be exact for non-ANY columns in STRICT tables
** (3) Datatype for TEXT columns in non-STRICT tables must be
** NULL, TEXT, or BLOB.
** (4) Datatype for numeric columns in non-STRICT tables must not
** be a TEXT value that can be losslessly converted to numeric.
*/
bStrict = (pTab->tabFlags & TF_Strict)!=0;
for(j=0; j<pTab->nCol; j++){ for(j=0; j<pTab->nCol; j++){
char *zErr; char *zErr;
int jmp2; Column *pCol = pTab->aCol + j; /* The column to be checked */
int labelError; /* Jump here to report an error */
int labelOk; /* Jump here if all looks ok */
int p1, p3, p4; /* Operands to the OP_IsType opcode */
int doTypeCheck; /* Check datatypes (besides NOT NULL) */
if( j==pTab->iPKey ) continue; if( j==pTab->iPKey ) continue;
if( pTab->aCol[j].notNull==0 ) continue; if( bStrict ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); doTypeCheck = pCol->eCType>COLTYPE_ANY;
if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){ }else{
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
} }
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); if( pCol->notNull==0 && !doTypeCheck ) continue;
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName); /* Compute the operands that will be needed for OP_IsType */
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); p4 = SQLITE_NULL;
if( pCol->colFlags & COLFLAG_VIRTUAL ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
p1 = -1;
p3 = 3;
}else{
if( pCol->iDflt ){
sqlite3_value *pDfltValue = 0;
sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db),
pCol->affinity, &pDfltValue);
if( pDfltValue ){
p4 = sqlite3_value_type(pDfltValue);
sqlite3ValueFree(pDfltValue);
}
}
p1 = iDataCur;
if( !HasRowid(pTab) ){
testcase( j!=sqlite3TableColumnToStorage(pTab, j) );
p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j);
}else{
p3 = sqlite3TableColumnToStorage(pTab,j);
testcase( p3!=j);
}
}
labelError = sqlite3VdbeMakeLabel(pParse);
labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
sqlite3VdbeGoto(v, labelError);
sqlite3VdbeJumpHere(v, jmp2);
}else{
/* VDBE byte code will fall thru */
}
}
if( bStrict && doTypeCheck ){
/* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
static unsigned char aStdTypeMask[] = {
0x1f, /* ANY */
0x18, /* BLOB */
0x11, /* INT */
0x11, /* INTEGER */
0x13, /* REAL */
0x14 /* TEXT */
};
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
sqlite3StdType[pCol->eCType-1],
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
/* (3) Datatype for TEXT columns in non-STRICT tables must be
** NULL, TEXT, or BLOB. */
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s",
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
/* (4) Datatype for numeric columns in non-STRICT tables must not
** be a TEXT value that can be converted to numeric. */
sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
VdbeCoverage(v);
if( p1>=0 ){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
}
sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "TEXT value in %s.%s",
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}
sqlite3VdbeResolveLabel(v, labelError);
integrityCheckResultRow(v); integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeResolveLabel(v, labelOk);
} }
/* Verify CHECK constraints */ /* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
@ -1773,6 +2017,9 @@ void sqlite3Pragma(
integrityCheckResultRow(v); integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
} }
if( pPk ){
sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
}
} }
} }
} }
@ -1923,6 +2170,11 @@ void sqlite3Pragma(
aOp[1].p2 = iCookie; aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight); aOp[1].p3 = sqlite3Atoi(zRight);
aOp[1].p5 = 1; aOp[1].p5 = 1;
if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){
/* Do not allow the use of PRAGMA schema_version=VALUE in defensive
** mode. Change the OP_SetCookie opcode into a no-op. */
aOp[1].opcode = OP_Noop;
}
}else{ }else{
/* Read the specified cookie value */ /* Read the specified cookie value */
static const VdbeOpList readCookie[] = { static const VdbeOpList readCookie[] = {
@ -2219,12 +2471,12 @@ void sqlite3Pragma(
case PragTyp_ANALYSIS_LIMIT: { case PragTyp_ANALYSIS_LIMIT: {
sqlite3_int64 N; sqlite3_int64 N;
if( zRight if( zRight
&& sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */
&& N>=0 && N>=0
){ ){
db->nAnalysisLimit = (int)(N&0x7fffffff); db->nAnalysisLimit = (int)(N&0x7fffffff);
} }
returnSingleInt(v, db->nAnalysisLimit); returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */
break; break;
} }

View file

@ -3,7 +3,6 @@
** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit ** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
** that script and rerun it. ** that script and rerun it.
*/ */
/* clang-format off */
/* The various pragma types */ /* The various pragma types */
#define PragTyp_ACTIVATE_EXTENSIONS 0 #define PragTyp_ACTIVATE_EXTENSIONS 0
@ -44,13 +43,14 @@
#define PragTyp_SOFT_HEAP_LIMIT 35 #define PragTyp_SOFT_HEAP_LIMIT 35
#define PragTyp_SYNCHRONOUS 36 #define PragTyp_SYNCHRONOUS 36
#define PragTyp_TABLE_INFO 37 #define PragTyp_TABLE_INFO 37
#define PragTyp_TEMP_STORE 38 #define PragTyp_TABLE_LIST 38
#define PragTyp_TEMP_STORE_DIRECTORY 39 #define PragTyp_TEMP_STORE 39
#define PragTyp_THREADS 40 #define PragTyp_TEMP_STORE_DIRECTORY 40
#define PragTyp_WAL_AUTOCHECKPOINT 41 #define PragTyp_THREADS 41
#define PragTyp_WAL_CHECKPOINT 42 #define PragTyp_WAL_AUTOCHECKPOINT 42
#define PragTyp_LOCK_STATUS 43 #define PragTyp_WAL_CHECKPOINT 43
#define PragTyp_STATS 44 #define PragTyp_LOCK_STATUS 44
#define PragTyp_STATS 45
/* Property flags associated with various pragma. */ /* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */
@ -83,45 +83,51 @@ static const char *const pragCName[] = {
/* 13 */ "pk", /* 13 */ "pk",
/* 14 */ "hidden", /* 14 */ "hidden",
/* table_info reuses 8 */ /* table_info reuses 8 */
/* 15 */ "seqno", /* Used by: index_xinfo */ /* 15 */ "schema", /* Used by: table_list */
/* 16 */ "cid", /* 16 */ "name",
/* 17 */ "name", /* 17 */ "type",
/* 18 */ "desc", /* 18 */ "ncol",
/* 19 */ "coll", /* 19 */ "wr",
/* 20 */ "key", /* 20 */ "strict",
/* 21 */ "name", /* Used by: function_list */ /* 21 */ "seqno", /* Used by: index_xinfo */
/* 22 */ "builtin", /* 22 */ "cid",
/* 23 */ "type", /* 23 */ "name",
/* 24 */ "enc", /* 24 */ "desc",
/* 25 */ "narg", /* 25 */ "coll",
/* 26 */ "flags", /* 26 */ "key",
/* 27 */ "tbl", /* Used by: stats */ /* 27 */ "name", /* Used by: function_list */
/* 28 */ "idx", /* 28 */ "builtin",
/* 29 */ "wdth", /* 29 */ "type",
/* 30 */ "hght", /* 30 */ "enc",
/* 31 */ "flgs", /* 31 */ "narg",
/* 32 */ "seq", /* Used by: index_list */ /* 32 */ "flags",
/* 33 */ "name", /* 33 */ "tbl", /* Used by: stats */
/* 34 */ "unique", /* 34 */ "idx",
/* 35 */ "origin", /* 35 */ "wdth",
/* 36 */ "partial", /* 36 */ "hght",
/* 37 */ "table", /* Used by: foreign_key_check */ /* 37 */ "flgs",
/* 38 */ "rowid", /* 38 */ "seq", /* Used by: index_list */
/* 39 */ "parent", /* 39 */ "name",
/* 40 */ "fkid", /* 40 */ "unique",
/* index_info reuses 15 */ /* 41 */ "origin",
/* 41 */ "seq", /* Used by: database_list */ /* 42 */ "partial",
/* 42 */ "name", /* 43 */ "table", /* Used by: foreign_key_check */
/* 43 */ "file", /* 44 */ "rowid",
/* 44 */ "busy", /* Used by: wal_checkpoint */ /* 45 */ "parent",
/* 45 */ "log", /* 46 */ "fkid",
/* 46 */ "checkpointed", /* index_info reuses 21 */
/* collation_list reuses 32 */ /* 47 */ "seq", /* Used by: database_list */
/* 47 */ "database", /* Used by: lock_status */ /* 48 */ "name",
/* 48 */ "status", /* 49 */ "file",
/* 49 */ "cache_size", /* Used by: default_cache_size */ /* 50 */ "busy", /* Used by: wal_checkpoint */
/* 51 */ "log",
/* 52 */ "checkpointed",
/* collation_list reuses 38 */
/* 53 */ "database", /* Used by: lock_status */
/* 54 */ "status",
/* 55 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */ /* module_list pragma_list reuses 9 */
/* 50 */ "timeout", /* Used by: busy_timeout */ /* 56 */ "timeout", /* Used by: busy_timeout */
}; };
/* Definitions of all built-in pragmas */ /* Definitions of all built-in pragmas */
@ -172,7 +178,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "busy_timeout", {/* zName: */ "busy_timeout",
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 50, 1, /* ColNames: */ 56, 1,
/* iArg: */ 0 }, /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "cache_size", {/* zName: */ "cache_size",
@ -211,7 +217,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "collation_list", {/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 32, 2, /* ColNames: */ 38, 2,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
@ -245,15 +251,15 @@ static const PragmaName aPragmaName[] = {
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "database_list", {/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 41, 3, /* ColNames: */ 47, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
{/* zName: */ "default_cache_size", {/* zName: */ "default_cache_size",
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
/* ColNames: */ 49, 1, /* ColNames: */ 55, 1,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@ -283,7 +289,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "foreign_key_check", {/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 37, 4, /* ColNames: */ 43, 4,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) #if !defined(SQLITE_OMIT_FOREIGN_KEY)
@ -326,7 +332,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "function_list", {/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 21, 6, /* ColNames: */ 27, 6,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#endif #endif
@ -355,23 +361,23 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "index_info", {/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 15, 3, /* ColNames: */ 21, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "index_list", {/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 32, 5, /* ColNames: */ 38, 5,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "index_xinfo", {/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 15, 6, /* ColNames: */ 21, 6,
/* iArg: */ 1 }, /* iArg: */ 1 },
#endif #endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "integrity_check", {/* zName: */ "integrity_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
@ -405,7 +411,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "lock_status", {/* zName: */ "lock_status",
/* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragTyp: */ PragTyp_LOCK_STATUS,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 47, 2, /* ColNames: */ 53, 2,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@ -479,7 +485,7 @@ static const PragmaName aPragmaName[] = {
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "quick_check", {/* zName: */ "quick_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 0, 0, /* ColNames: */ 0, 0,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
@ -544,7 +550,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "stats", {/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS, /* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
/* ColNames: */ 27, 5, /* ColNames: */ 33, 5,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@ -560,6 +566,11 @@ static const PragmaName aPragmaName[] = {
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 8, 6, /* ColNames: */ 8, 6,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "table_list",
/* ePragTyp: */ PragTyp_TABLE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
/* ColNames: */ 15, 6,
/* iArg: */ 0 },
{/* zName: */ "table_xinfo", {/* zName: */ "table_xinfo",
/* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragTyp: */ PragTyp_TABLE_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
@ -635,7 +646,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "wal_checkpoint", {/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema, /* ePragFlg: */ PragFlg_NeedSchema,
/* ColNames: */ 44, 3, /* ColNames: */ 50, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@ -646,4 +657,4 @@ static const PragmaName aPragmaName[] = {
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif #endif
}; };
/* Number of pragmas: 67 on by default, 77 total. */ /* Number of pragmas: 68 on by default, 78 total. */

View file

@ -13,8 +13,7 @@
** interface, and routines that contribute to loading the database schema ** interface, and routines that contribute to loading the database schema
** from disk. ** from disk.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** Fill the InitData structure with an error message that indicates ** Fill the InitData structure with an error message that indicates
@ -30,10 +29,15 @@ static void corruptSchema(
pData->rc = SQLITE_NOMEM_BKPT; pData->rc = SQLITE_NOMEM_BKPT;
}else if( pData->pzErrMsg[0]!=0 ){ }else if( pData->pzErrMsg[0]!=0 ){
/* A error message has already been generated. Do not overwrite it */ /* A error message has already been generated. Do not overwrite it */
}else if( pData->mInitFlags & (INITFLAG_AlterRename|INITFLAG_AlterDrop) ){ }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){
static const char *azAlterType[] = {
"rename",
"drop column",
"add column"
};
*pData->pzErrMsg = sqlite3MPrintf(db, *pData->pzErrMsg = sqlite3MPrintf(db,
"error in %s %s after %s: %s", azObj[0], azObj[1], "error in %s %s after %s: %s", azObj[0], azObj[1],
(pData->mInitFlags & INITFLAG_AlterRename) ? "rename" : "drop column", azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1],
zExtra zExtra
); );
pData->rc = SQLITE_ERROR; pData->rc = SQLITE_ERROR;
@ -97,6 +101,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
UNUSED_PARAMETER2(NotUsed, argc); UNUSED_PARAMETER2(NotUsed, argc);
assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3_mutex_held(db->mutex) );
db->mDbFlags |= DBFLAG_EncodingFixed; db->mDbFlags |= DBFLAG_EncodingFixed;
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
pData->nInitRow++; pData->nInitRow++;
if( db->mallocFailed ){ if( db->mallocFailed ){
corruptSchema(pData, argv, 0); corruptSchema(pData, argv, 0);
@ -104,7 +109,6 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
} }
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[3]==0 ){ if( argv[3]==0 ){
corruptSchema(pData, argv, 0); corruptSchema(pData, argv, 0);
}else if( argv[4] }else if( argv[4]
@ -135,7 +139,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
} }
} }
db->init.orphanTrigger = 0; db->init.orphanTrigger = 0;
db->init.azInit = argv; db->init.azInit = (const char**)argv;
pStmt = 0; pStmt = 0;
TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0); TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
rc = db->errCode; rc = db->errCode;
@ -154,6 +158,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
} }
} }
} }
db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
corruptSchema(pData, argv, 0); corruptSchema(pData, argv, 0);
@ -378,18 +383,22 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
} }
#endif #endif
} }
assert( pDb == &(db->aDb[iDb]) );
if( db->mallocFailed ){ if( db->mallocFailed ){
rc = SQLITE_NOMEM_BKPT; rc = SQLITE_NOMEM_BKPT;
sqlite3ResetAllSchemasOfConnection(db); sqlite3ResetAllSchemasOfConnection(db);
} pDb = &db->aDb[iDb];
if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ }else
/* Black magic: If the SQLITE_NoSchemaError flag is set, then consider if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){
** the schema loaded, even if errors occurred. In this situation the /* Hack: If the SQLITE_NoSchemaError flag is set, then consider
** current sqlite3_prepare() operation will fail, but the following one ** the schema loaded, even if errors (other than OOM) occurred. In
** will attempt to compile the supplied statement against whatever subset ** this situation the current sqlite3_prepare() operation will fail,
** of the schema was loaded before the error occurred. The primary ** but the following one will attempt to compile the supplied statement
** purpose of this is to allow access to the sqlite_schema table ** against whatever subset of the schema was loaded before the error
** even when its contents have been corrupted. ** occurred.
**
** The primary purpose of this is to allow access to the sqlite_schema
** table even when its contents have been corrupted.
*/ */
DbSetProperty(db, iDb, DB_SchemaLoaded); DbSetProperty(db, iDb, DB_SchemaLoaded);
rc = SQLITE_OK; rc = SQLITE_OK;
@ -499,6 +508,7 @@ static void schemaIsValid(Parse *pParse){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0); rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db); sqlite3OomFault(db);
pParse->rc = SQLITE_NOMEM;
} }
if( rc!=SQLITE_OK ) return; if( rc!=SQLITE_OK ) return;
openedTransaction = 1; openedTransaction = 1;
@ -558,23 +568,30 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
/* /*
** Free all memory allocations in the pParse object ** Free all memory allocations in the pParse object
*/ */
void sqlite3ParserReset(Parse *pParse){ void sqlite3ParseObjectReset(Parse *pParse){
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
assert( db!=0 );
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock);
#endif
while( pParse->pCleanup ){ while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup; ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext; pParse->pCleanup = pCleanup->pNext;
pCleanup->xCleanup(db, pCleanup->pPtr); pCleanup->xCleanup(db, pCleanup->pPtr);
sqlite3DbFreeNN(db, pCleanup); sqlite3DbNNFreeNN(db, pCleanup);
} }
sqlite3DbFree(db, pParse->aLabel); if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel);
if( pParse->pConstExpr ){ if( pParse->pConstExpr ){
sqlite3ExprListDelete(db, pParse->pConstExpr); sqlite3ExprListDelete(db, pParse->pConstExpr);
} }
if( db ){ assert( db->lookaside.bDisable >= pParse->disableLookaside );
assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside;
db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; assert( pParse->db->pParse==pParse );
} db->pParse = pParse->pOuterParse;
pParse->db = 0;
pParse->disableLookaside = 0; pParse->disableLookaside = 0;
} }
@ -587,7 +604,7 @@ void sqlite3ParserReset(Parse *pParse){
** cost for this mechansim (an extra malloc), so it should not be used ** cost for this mechansim (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less ** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in ** common cleanups, we save a single NULL-pointer comparison in
** sqlite3ParserReset(), which reduces the total CPU cycle count. ** sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
** **
** If a memory allocation error occurs, then the cleanup happens immediately. ** If a memory allocation error occurs, then the cleanup happens immediately.
** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the ** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
@ -627,6 +644,33 @@ void *sqlite3ParserAddCleanup(
return pPtr; return pPtr;
} }
/*
** Turn bulk memory into a valid Parse object and link that Parse object
** into database connection db.
**
** Call sqlite3ParseObjectReset() to undo this operation.
**
** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which
** is generated by Lemon.
*/
void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){
memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ);
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
assert( db->pParse!=pParse );
pParse->pOuterParse = db->pParse;
db->pParse = pParse;
pParse->db = db;
if( db->mallocFailed ) sqlite3ErrorMsg(pParse, "out of memory");
}
/*
** Maximum number of times that we will try again to prepare a statement
** that returns SQLITE_ERROR_RETRY.
*/
#ifndef SQLITE_MAX_PREPARE_RETRY
# define SQLITE_MAX_PREPARE_RETRY 25
#endif
/* /*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle. ** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/ */
@ -639,16 +683,19 @@ static int sqlite3Prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */ const char **pzTail /* OUT: End of parsed string */
){ ){
char *zErrMsg = 0; /* Error message */
int rc = SQLITE_OK; /* Result code */ int rc = SQLITE_OK; /* Result code */
int i; /* Loop counter */ int i; /* Loop counter */
Parse sParse; /* Parsing context */ Parse sParse; /* Parsing context */
memset(&sParse, 0, PARSE_HDR_SZ); /* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */
memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ);
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
sParse.pOuterParse = db->pParse;
db->pParse = &sParse;
sParse.db = db;
sParse.pReprepare = pReprepare; sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 ); assert( ppStmt && *ppStmt==0 );
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
assert( sqlite3_mutex_held(db->mutex) ); assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of /* For a long-term use prepared statement avoid the use of
@ -658,7 +705,7 @@ static int sqlite3Prepare(
sParse.disableLookaside++; sParse.disableLookaside++;
DisableLookaside; DisableLookaside;
} }
sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0; sParse.prepFlags = prepFlags & 0xff;
/* Check to verify that it is possible to get a read lock on all /* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that ** database schemas. The inability to get a read lock indicates that
@ -699,9 +746,10 @@ static int sqlite3Prepare(
} }
} }
sqlite3VtabUnlockList(db); #ifndef SQLITE_OMIT_VIRTUALTABLE
if( db->pDisconnect ) sqlite3VtabUnlockList(db);
#endif
sParse.db = db;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy; char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@ -714,14 +762,14 @@ static int sqlite3Prepare(
} }
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){ if( zSqlCopy ){
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); sqlite3RunParser(&sParse, zSqlCopy);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy); sqlite3DbFree(db, zSqlCopy);
}else{ }else{
sParse.zTail = &zSql[nBytes]; sParse.zTail = &zSql[nBytes];
} }
}else{ }else{
sqlite3RunParser(&sParse, zSql, &zErrMsg); sqlite3RunParser(&sParse, zSql);
} }
assert( 0==sParse.nQueryLoop ); assert( 0==sParse.nQueryLoop );
@ -734,9 +782,10 @@ static int sqlite3Prepare(
} }
if( db->mallocFailed ){ if( db->mallocFailed ){
sParse.rc = SQLITE_NOMEM_BKPT; sParse.rc = SQLITE_NOMEM_BKPT;
sParse.checkSchema = 0;
} }
if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){ if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){
if( sParse.checkSchema ){ if( sParse.checkSchema && db->init.busy==0 ){
schemaIsValid(&sParse); schemaIsValid(&sParse);
} }
if( sParse.pVdbe ){ if( sParse.pVdbe ){
@ -744,14 +793,14 @@ static int sqlite3Prepare(
} }
assert( 0==(*ppStmt) ); assert( 0==(*ppStmt) );
rc = sParse.rc; rc = sParse.rc;
if( zErrMsg ){ if( sParse.zErrMsg ){
sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); sqlite3ErrorWithMsg(db, rc, "%s", sParse.zErrMsg);
sqlite3DbFree(db, zErrMsg); sqlite3DbFree(db, sParse.zErrMsg);
}else{ }else{
sqlite3Error(db, rc); sqlite3Error(db, rc);
} }
}else{ }else{
assert( zErrMsg==0 ); assert( sParse.zErrMsg==0 );
*ppStmt = (sqlite3_stmt*)sParse.pVdbe; *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
rc = SQLITE_OK; rc = SQLITE_OK;
sqlite3ErrorClear(db); sqlite3ErrorClear(db);
@ -767,7 +816,7 @@ static int sqlite3Prepare(
end_prepare: end_prepare:
sqlite3ParserReset(&sParse); sqlite3ParseObjectReset(&sParse);
return rc; return rc;
} }
static int sqlite3LockAndPrepare( static int sqlite3LockAndPrepare(
@ -797,7 +846,8 @@ static int sqlite3LockAndPrepare(
** reset is considered a permanent error. */ ** reset is considered a permanent error. */
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
assert( rc==SQLITE_OK || *ppStmt==0 ); assert( rc==SQLITE_OK || *ppStmt==0 );
}while( rc==SQLITE_ERROR_RETRY if( rc==SQLITE_OK || db->mallocFailed ) break;
}while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY)
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) ); || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
sqlite3BtreeLeaveAll(db); sqlite3BtreeLeaveAll(db);
rc = sqlite3ApiExit(db, rc); rc = sqlite3ApiExit(db, rc);

View file

@ -1,6 +1,6 @@
/* /*
** The "printf" code that follows dates from the 1980's. It is in ** The "printf" code that follows dates from the 1980's. It is in
** the public domain. ** the public domain.
** **
************************************************************************** **************************************************************************
** **
@ -9,8 +9,7 @@
** library, though the implementation here has enhancements to support ** library, though the implementation here has enhancements to support
** SQLite. ** SQLite.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*
** Conversion types fall into various categories as defined by the ** Conversion types fall into various categories as defined by the
@ -30,7 +29,7 @@
#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '', #define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */ NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 11 /* a pointer to a Token structure */ #define etTOKEN 11 /* a pointer to a Token structure */
#define etSRCLIST 12 /* a pointer to a SrcList */ #define etSRCITEM 12 /* a pointer to a SrcItem */
#define etPOINTER 13 /* The %p conversion */ #define etPOINTER 13 /* The %p conversion */
#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */ #define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */ #define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
@ -96,10 +95,16 @@ static const et_info fmtinfo[] = {
/* All the rest are undocumented and are for internal use only */ /* All the rest are undocumented and are for internal use only */
{ 'T', 0, 0, etTOKEN, 0, 0 }, { 'T', 0, 0, etTOKEN, 0, 0 },
{ 'S', 0, 0, etSRCLIST, 0, 0 }, { 'S', 0, 0, etSRCITEM, 0, 0 },
{ 'r', 10, 1, etORDINAL, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 },
}; };
/* Notes:
**
** %S Takes a pointer to SrcItem. Shows name or database.name
** %!S Like %S but prefer the zName over the zAlias
*/
/* Floating point constants used for rounding */ /* Floating point constants used for rounding */
static const double arRound[] = { static const double arRound[] = {
5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
@ -140,7 +145,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
/* /*
** Set the StrAccum object to an error mode. ** Set the StrAccum object to an error mode.
*/ */
static void setStrAccumError(StrAccum *p, u8 eError){ void sqlite3StrAccumSetError(StrAccum *p, u8 eError){
assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
p->accError = eError; p->accError = eError;
if( p->mxAlloc ) sqlite3_str_reset(p); if( p->mxAlloc ) sqlite3_str_reset(p);
@ -176,12 +181,12 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
char *z; char *z;
if( pAccum->accError ) return 0; if( pAccum->accError ) return 0;
if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
setStrAccumError(pAccum, SQLITE_TOOBIG); sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
return 0; return 0;
} }
z = sqlite3DbMallocRaw(pAccum->db, n); z = sqlite3DbMallocRaw(pAccum->db, n);
if( z==0 ){ if( z==0 ){
setStrAccumError(pAccum, SQLITE_NOMEM); sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
} }
return z; return z;
} }
@ -798,8 +803,8 @@ void sqlite3_str_vappendf(
case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE: /* %q: Escape ' characters */
case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
case etSQLESCAPE3: { /* %w: Escape " characters */ case etSQLESCAPE3: { /* %w: Escape " characters */
int i, j, k, n, isnull; i64 i, j, k, n;
int needQuote; int needQuote, isnull;
char ch; char ch;
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
char *escarg; char *escarg;
@ -844,31 +849,50 @@ void sqlite3_str_vappendf(
goto adjust_width_for_utf8; goto adjust_width_for_utf8;
} }
case etTOKEN: { case etTOKEN: {
Token *pToken;
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
pToken = va_arg(ap, Token*); if( flag_alternateform ){
assert( bArgList==0 ); /* %#T means an Expr pointer that uses Expr.u.zToken */
if( pToken && pToken->n ){ Expr *pExpr = va_arg(ap,Expr*);
sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); if( ALWAYS(pExpr) && ALWAYS(!ExprHasProperty(pExpr,EP_IntValue)) ){
sqlite3_str_appendall(pAccum, (const char*)pExpr->u.zToken);
sqlite3RecordErrorOffsetOfExpr(pAccum->db, pExpr);
}
}else{
/* %T means a Token pointer */
Token *pToken = va_arg(ap, Token*);
assert( bArgList==0 );
if( pToken && pToken->n ){
sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
sqlite3RecordErrorByteOffset(pAccum->db, pToken->z);
}
} }
length = width = 0; length = width = 0;
break; break;
} }
case etSRCLIST: { case etSRCITEM: {
SrcList *pSrc;
int k;
SrcItem *pItem; SrcItem *pItem;
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
pSrc = va_arg(ap, SrcList*); pItem = va_arg(ap, SrcItem*);
k = va_arg(ap, int);
pItem = &pSrc->a[k];
assert( bArgList==0 ); assert( bArgList==0 );
assert( k>=0 && k<pSrc->nSrc ); if( pItem->zAlias && !flag_altform2 ){
if( pItem->zDatabase ){ sqlite3_str_appendall(pAccum, pItem->zAlias);
sqlite3_str_appendall(pAccum, pItem->zDatabase); }else if( pItem->zName ){
sqlite3_str_append(pAccum, ".", 1); if( pItem->zDatabase ){
sqlite3_str_appendall(pAccum, pItem->zDatabase);
sqlite3_str_append(pAccum, ".", 1);
}
sqlite3_str_appendall(pAccum, pItem->zName);
}else if( pItem->zAlias ){
sqlite3_str_appendall(pAccum, pItem->zAlias);
}else{
Select *pSel = pItem->pSelect;
assert( pSel!=0 );
if( pSel->selFlags & SF_NestedFrom ){
sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
}else{
sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
}
} }
sqlite3_str_appendall(pAccum, pItem->zName);
length = width = 0; length = width = 0;
break; break;
} }
@ -901,6 +925,44 @@ void sqlite3_str_vappendf(
}/* End for loop over the format string */ }/* End for loop over the format string */
} /* End of function */ } /* End of function */
/*
** The z string points to the first character of a token that is
** associated with an error. If db does not already have an error
** byte offset recorded, try to compute the error byte offset for
** z and set the error byte offset in db.
*/
void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){
const Parse *pParse;
const char *zText;
const char *zEnd;
assert( z!=0 );
if( NEVER(db==0) ) return;
if( db->errByteOffset!=(-2) ) return;
pParse = db->pParse;
if( NEVER(pParse==0) ) return;
zText =pParse->zTail;
if( NEVER(zText==0) ) return;
zEnd = &zText[strlen(zText)];
if( SQLITE_WITHIN(z,zText,zEnd) ){
db->errByteOffset = (int)(z-zText);
}
}
/*
** If pExpr has a byte offset for the start of a token, record that as
** as the error offset.
*/
void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
while( pExpr
&& (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
){
pExpr = pExpr->pLeft;
}
if( pExpr==0 ) return;
db->errByteOffset = pExpr->w.iOfst;
}
/* /*
** Enlarge the memory allocation on a StrAccum object so that it is ** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text. ** able to accept at least N more bytes of text.
@ -908,7 +970,7 @@ void sqlite3_str_vappendf(
** Return the number of bytes of text that StrAccum is able to accept ** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero. ** after the attempted enlargement. The value returned might be zero.
*/ */
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew; char *zNew;
assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */ assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){ if( p->accError ){
@ -917,7 +979,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
return 0; return 0;
} }
if( p->mxAlloc==0 ){ if( p->mxAlloc==0 ){
setStrAccumError(p, SQLITE_TOOBIG); sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
return p->nAlloc - p->nChar - 1; return p->nAlloc - p->nChar - 1;
}else{ }else{
char *zOld = isMalloced(p) ? p->zText : 0; char *zOld = isMalloced(p) ? p->zText : 0;
@ -930,7 +992,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
} }
if( szNew > p->mxAlloc ){ if( szNew > p->mxAlloc ){
sqlite3_str_reset(p); sqlite3_str_reset(p);
setStrAccumError(p, SQLITE_TOOBIG); sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
return 0; return 0;
}else{ }else{
p->nAlloc = (int)szNew; p->nAlloc = (int)szNew;
@ -948,7 +1010,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
p->printfFlags |= SQLITE_PRINTF_MALLOCED; p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{ }else{
sqlite3_str_reset(p); sqlite3_str_reset(p);
setStrAccumError(p, SQLITE_NOMEM); sqlite3StrAccumSetError(p, SQLITE_NOMEM);
return 0; return 0;
} }
} }
@ -1021,7 +1083,7 @@ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
memcpy(zText, p->zText, p->nChar+1); memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED; p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{ }else{
setStrAccumError(p, SQLITE_NOMEM); sqlite3StrAccumSetError(p, SQLITE_NOMEM);
} }
p->zText = zText; p->zText = zText;
return zText; return zText;
@ -1036,6 +1098,22 @@ char *sqlite3StrAccumFinish(StrAccum *p){
return p->zText; return p->zText;
} }
/*
** Use the content of the StrAccum passed as the second argument
** as the result of an SQL function.
*/
void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){
if( p->accError ){
sqlite3_result_error_code(pCtx, p->accError);
sqlite3_str_reset(p);
}else if( isMalloced(p) ){
sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC);
}else{
sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
sqlite3_str_reset(p);
}
}
/* /*
** This singleton is an sqlite3_str object that is returned if ** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one. This ** sqlite3_malloc() fails to provide space for a real one. This

View file

@ -15,24 +15,48 @@
** Random numbers are used by some of the database backends in order ** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames. ** to generate random integer keys for tables or random filenames.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* All threads share a single random number generator. /* All threads share a single random number generator.
** This structure is the current state of the generator. ** This structure is the current state of the generator.
*/ */
static SQLITE_WSD struct sqlite3PrngType { static SQLITE_WSD struct sqlite3PrngType {
unsigned char isInit; /* True if initialized */ u32 s[16]; /* 64 bytes of chacha20 state */
unsigned char i, j; /* State variables */ u8 out[64]; /* Output bytes */
unsigned char s[256]; /* State variables */ u8 n; /* Output bytes remaining */
} sqlite3Prng; } sqlite3Prng;
/* The RFC-7539 ChaCha20 block function
*/
#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
#define QR(a, b, c, d) ( \
a += b, d ^= a, d = ROTL(d,16), \
c += d, b ^= c, b = ROTL(b,12), \
a += b, d ^= a, d = ROTL(d, 8), \
c += d, b ^= c, b = ROTL(b, 7))
static void chacha_block(u32 *out, const u32 *in){
int i;
u32 x[16];
memcpy(x, in, 64);
for(i=0; i<10; i++){
QR(x[0], x[4], x[ 8], x[12]);
QR(x[1], x[5], x[ 9], x[13]);
QR(x[2], x[6], x[10], x[14]);
QR(x[3], x[7], x[11], x[15]);
QR(x[0], x[5], x[10], x[15]);
QR(x[1], x[6], x[11], x[12]);
QR(x[2], x[7], x[ 8], x[13]);
QR(x[3], x[4], x[ 9], x[14]);
}
for(i=0; i<16; i++) out[i] = x[i]+in[i];
}
/* /*
** Return N random bytes. ** Return N random bytes.
*/ */
void sqlite3_randomness(int N, void *pBuf){ void sqlite3_randomness(int N, void *pBuf){
unsigned char t;
unsigned char *zBuf = pBuf; unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator /* The "wsdPrng" macro will resolve to the pseudo-random number generator
@ -62,48 +86,46 @@ void sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_enter(mutex); sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){ if( N<=0 || pBuf==0 ){
wsdPrng.isInit = 0; wsdPrng.s[0] = 0;
sqlite3_mutex_leave(mutex); sqlite3_mutex_leave(mutex);
return; return;
} }
/* Initialize the state of the random number generator once, /* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does ** the first time this routine is called.
** not need to contain a lot of randomness since we are not
** trying to do secure encryption or anything like that...
**
** Nothing in this file or anywhere else in SQLite does any kind of
** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/ */
if( !wsdPrng.isInit ){ if( wsdPrng.s[0]==0 ){
int i; sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
char k[256]; static const u32 chacha20_init[] = {
wsdPrng.j = 0; 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
wsdPrng.i = 0; };
sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k); memcpy(&wsdPrng.s[0], chacha20_init, 16);
for(i=0; i<256; i++){ if( NEVER(pVfs==0) ){
wsdPrng.s[i] = (u8)i; memset(&wsdPrng.s[4], 0, 44);
}else{
sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
} }
for(i=0; i<256; i++){ wsdPrng.s[15] = wsdPrng.s[12];
wsdPrng.j += wsdPrng.s[i] + k[i]; wsdPrng.s[12] = 0;
t = wsdPrng.s[wsdPrng.j]; wsdPrng.n = 0;
wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
wsdPrng.s[i] = t;
}
wsdPrng.isInit = 1;
} }
assert( N>0 ); assert( N>0 );
do{ while( 1 /* exit by break */ ){
wsdPrng.i++; if( N<=wsdPrng.n ){
t = wsdPrng.s[wsdPrng.i]; memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
wsdPrng.j += t; wsdPrng.n -= N;
wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; break;
wsdPrng.s[wsdPrng.j] = t; }
t += wsdPrng.s[wsdPrng.i]; if( wsdPrng.n>0 ){
*(zBuf++) = wsdPrng.s[t]; memcpy(zBuf, wsdPrng.out, wsdPrng.n);
}while( --N ); N -= wsdPrng.n;
zBuf += wsdPrng.n;
}
wsdPrng.s[12]++;
chacha_block((u32*)wsdPrng.out, wsdPrng.s);
wsdPrng.n = 64;
}
sqlite3_mutex_leave(mutex); sqlite3_mutex_leave(mutex);
} }

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,7 @@
** extracts the least value from the RowSet. ** extracts the least value from the RowSet.
** **
** The INSERT primitive might allocate additional memory. Memory is ** The INSERT primitive might allocate additional memory. Memory is
** allocated in chunks so most INSERTs do no allocation. There is an ** allocated in chunks so most INSERTs do no allocation. There is an
** upper bound on the size of allocated memory. No memory is freed ** upper bound on the size of allocated memory. No memory is freed
** until DESTROY. ** until DESTROY.
** **
@ -61,8 +61,7 @@
** be possible, but the feature was not used, so it was removed in order ** be possible, but the feature was not used, so it was removed in order
** to simplify the code. ** to simplify the code.
*/ */
#include "third_party/sqlite3/sqliteInt.inc" #include "third_party/sqlite3/sqliteInt.h"
/* clang-format off */
/* /*

View file

@ -12,7 +12,6 @@
** This file contains code for implementations of the r-tree and r*-tree ** This file contains code for implementations of the r-tree and r*-tree
** algorithms packaged as an SQLite virtual table module. ** algorithms packaged as an SQLite virtual table module.
*/ */
/* clang-format off */
/* /*
** Database Format of R-Tree Tables ** Database Format of R-Tree Tables
@ -58,15 +57,19 @@
|| (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE)) || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
#ifndef SQLITE_CORE #ifndef SQLITE_CORE
#include "third_party/sqlite3/sqlite3ext.h" #include "third_party/sqlite3/sqlite3ext.h"
SQLITE_EXTENSION_INIT1 SQLITE_EXTENSION_INIT1
#else #else
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
#endif #endif
int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */ int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
#ifndef SQLITE_AMALGAMATION /*
#include "third_party/sqlite3/sqlite3rtree.inc" ** If building separately, we will need some setup that is normally
** found in sqliteInt.h
*/
#if !defined(SQLITE_AMALGAMATION)
#include "third_party/sqlite3/sqlite3rtree.h"
typedef sqlite3_int64 i64; typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64; typedef sqlite3_uint64 u64;
typedef unsigned char u8; typedef unsigned char u8;
@ -78,10 +81,22 @@ typedef unsigned int u32;
#if defined(NDEBUG) && defined(SQLITE_DEBUG) #if defined(NDEBUG) && defined(SQLITE_DEBUG)
# undef NDEBUG # undef NDEBUG
#endif #endif
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif #endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X) (1)
# define NEVER(X) (0)
#elif !defined(NDEBUG)
# define ALWAYS(X) ((X)?1:(assert(0),0))
# define NEVER(X) ((X)?(assert(0),1):0)
#else
# define ALWAYS(X) (X)
# define NEVER(X) (X)
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -136,7 +151,9 @@ struct Rtree {
u8 nBytesPerCell; /* Bytes consumed per cell */ u8 nBytesPerCell; /* Bytes consumed per cell */
u8 inWrTrans; /* True if inside write transaction */ u8 inWrTrans; /* True if inside write transaction */
u8 nAux; /* # of auxiliary columns in %_rowid */ u8 nAux; /* # of auxiliary columns in %_rowid */
#ifdef SQLITE_ENABLE_GEOPOLY
u8 nAuxNotNull; /* Number of initial not-null aux columns */ u8 nAuxNotNull; /* Number of initial not-null aux columns */
#endif
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
u8 bCorrupt; /* Shadow table corruption detected */ u8 bCorrupt; /* Shadow table corruption detected */
#endif #endif
@ -418,7 +435,12 @@ struct RtreeMatchArg {
** it is not, make it a no-op. ** it is not, make it a no-op.
*/ */
#ifndef SQLITE_AMALGAMATION #ifndef SQLITE_AMALGAMATION
# define testcase(X) # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
unsigned int sqlite3RtreeTestcase = 0;
# define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; }
# else
# define testcase(X)
# endif
#endif #endif
/* /*
@ -667,18 +689,6 @@ static void nodeBlobReset(Rtree *pRtree){
} }
} }
/*
** Check to see if pNode is the same as pParent or any of the parents
** of pParent.
*/
static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
do{
if( pNode==pParent ) return 1;
pParent = pParent->pParent;
}while( pParent );
return 0;
}
/* /*
** Obtain a reference to an r-tree node. ** Obtain a reference to an r-tree node.
*/ */
@ -695,14 +705,7 @@ static int nodeAcquire(
** increase its reference count and return it. ** increase its reference count and return it.
*/ */
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
if( pParent && !pNode->pParent ){ if( pParent && pParent!=pNode->pParent ){
if( nodeInParentChain(pNode, pParent) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
pParent->nRef++;
pNode->pParent = pParent;
}else if( pParent && pNode->pParent && pParent!=pNode->pParent ){
RTREE_IS_CORRUPT(pRtree); RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB; return SQLITE_CORRUPT_VTAB;
} }
@ -760,7 +763,7 @@ static int nodeAcquire(
** are the leaves, and so on. If the depth as specified on the root node ** are the leaves, and so on. If the depth as specified on the root node
** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
*/ */
if( pNode && rc==SQLITE_OK && iNode==1 ){ if( rc==SQLITE_OK && pNode && iNode==1 ){
pRtree->iDepth = readInt16(pNode->zData); pRtree->iDepth = readInt16(pNode->zData);
if( pRtree->iDepth>RTREE_MAX_DEPTH ){ if( pRtree->iDepth>RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB; rc = SQLITE_CORRUPT_VTAB;
@ -1283,20 +1286,29 @@ static void rtreeNonleafConstraint(
switch( p->op ){ switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */ case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */ case RTREE_FALSE: break; /* Never satisfied */
case RTREE_LE:
case RTREE_LT:
case RTREE_EQ: case RTREE_EQ:
RTREE_DECODE_COORD(eInt, pCellData, val);
/* val now holds the lower bound of the coordinate pair */
if( p->u.rValue>=val ){
pCellData += 4;
RTREE_DECODE_COORD(eInt, pCellData, val);
/* val now holds the upper bound of the coordinate pair */
if( p->u.rValue<=val ) return;
}
break;
case RTREE_LE:
case RTREE_LT:
RTREE_DECODE_COORD(eInt, pCellData, val); RTREE_DECODE_COORD(eInt, pCellData, val);
/* val now holds the lower bound of the coordinate pair */ /* val now holds the lower bound of the coordinate pair */
if( p->u.rValue>=val ) return; if( p->u.rValue>=val ) return;
if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ break;
/* Fall through for the RTREE_EQ case */
default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ default:
pCellData += 4; pCellData += 4;
RTREE_DECODE_COORD(eInt, pCellData, val); RTREE_DECODE_COORD(eInt, pCellData, val);
/* val now holds the upper bound of the coordinate pair */ /* val now holds the upper bound of the coordinate pair */
if( p->u.rValue<=val ) return; if( p->u.rValue<=val ) return;
break;
} }
*peWithin = NOT_WITHIN; *peWithin = NOT_WITHIN;
} }
@ -1366,11 +1378,12 @@ static int nodeRowidIndex(
*/ */
static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){ static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
RtreeNode *pParent = pNode->pParent; RtreeNode *pParent = pNode->pParent;
if( pParent ){ if( ALWAYS(pParent) ){
return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
}else{
*piIndex = -1;
return SQLITE_OK;
} }
*piIndex = -1;
return SQLITE_OK;
} }
/* /*
@ -1493,7 +1506,8 @@ static RtreeSearchPoint *rtreeSearchPointNew(
pNew = rtreeEnqueue(pCur, rScore, iLevel); pNew = rtreeEnqueue(pCur, rScore, iLevel);
if( pNew==0 ) return 0; if( pNew==0 ) return 0;
ii = (int)(pNew - pCur->aPoint) + 1; ii = (int)(pNew - pCur->aPoint) + 1;
if( ii<RTREE_CACHE_SZ ){ assert( ii==1 );
if( ALWAYS(ii<RTREE_CACHE_SZ) ){
assert( pCur->aNode[ii]==0 ); assert( pCur->aNode[ii]==0 );
pCur->aNode[ii] = pCur->aNode[0]; pCur->aNode[ii] = pCur->aNode[0];
}else{ }else{
@ -1554,7 +1568,7 @@ static void rtreeSearchPointPop(RtreeCursor *p){
if( p->bPoint ){ if( p->bPoint ){
p->anQueue[p->sPoint.iLevel]--; p->anQueue[p->sPoint.iLevel]--;
p->bPoint = 0; p->bPoint = 0;
}else if( p->nPoint ){ }else if( ALWAYS(p->nPoint) ){
p->anQueue[p->aPoint[0].iLevel]--; p->anQueue[p->aPoint[0].iLevel]--;
n = --p->nPoint; n = --p->nPoint;
p->aPoint[0] = p->aPoint[n]; p->aPoint[0] = p->aPoint[n];
@ -1695,7 +1709,7 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
int rc = SQLITE_OK; int rc = SQLITE_OK;
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc==SQLITE_OK && p ){ if( rc==SQLITE_OK && ALWAYS(p) ){
*pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell); *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
} }
return rc; return rc;
@ -1713,7 +1727,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc ) return rc; if( rc ) return rc;
if( p==0 ) return SQLITE_OK; if( NEVER(p==0) ) return SQLITE_OK;
if( i==0 ){ if( i==0 ){
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else if( i<=pRtree->nDim2 ){ }else if( i<=pRtree->nDim2 ){
@ -1912,8 +1926,11 @@ static int rtreeFilter(
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
RtreeSearchPoint *pNew; RtreeSearchPoint *pNew;
assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */
pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
if( pNew==0 ) return SQLITE_NOMEM; if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */
return SQLITE_NOMEM;
}
pNew->id = 1; pNew->id = 1;
pNew->iCell = 0; pNew->iCell = 0;
pNew->eWithin = PARTLY_WITHIN; pNew->eWithin = PARTLY_WITHIN;
@ -1990,7 +2007,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
if( bMatch==0 && p->usable if( bMatch==0 && p->usable
&& p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
){ ){
/* We have an equality constraint on the rowid. Use strategy 1. */ /* We have an equality constraint on the rowid. Use strategy 1. */
int jj; int jj;
@ -2196,7 +2213,7 @@ static int ChooseLeaf(
int nCell = NCELL(pNode); int nCell = NCELL(pNode);
RtreeCell cell; RtreeCell cell;
RtreeNode *pChild; RtreeNode *pChild = 0;
RtreeCell *aCell = 0; RtreeCell *aCell = 0;
@ -2243,12 +2260,19 @@ static int AdjustTree(
){ ){
RtreeNode *p = pNode; RtreeNode *p = pNode;
int cnt = 0; int cnt = 0;
int rc;
while( p->pParent ){ while( p->pParent ){
RtreeNode *pParent = p->pParent; RtreeNode *pParent = p->pParent;
RtreeCell cell; RtreeCell cell;
int iCell; int iCell;
if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){ cnt++;
if( NEVER(cnt>100) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
rc = nodeParentIndex(pRtree, p, &iCell);
if( NEVER(rc!=SQLITE_OK) ){
RTREE_IS_CORRUPT(pRtree); RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB; return SQLITE_CORRUPT_VTAB;
} }
@ -2537,12 +2561,17 @@ static int updateMapping(
xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
if( iHeight>0 ){ if( iHeight>0 ){
RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);
RtreeNode *p;
for(p=pNode; p; p=p->pParent){
if( p==pChild ) return SQLITE_CORRUPT_VTAB;
}
if( pChild ){ if( pChild ){
nodeRelease(pRtree, pChild->pParent); nodeRelease(pRtree, pChild->pParent);
nodeReference(pNode); nodeReference(pNode);
pChild->pParent = pNode; pChild->pParent = pNode;
} }
} }
if( NEVER(pNode==0) ) return SQLITE_ERROR;
return xSetMapping(pRtree, iRowid, pNode->iNode); return xSetMapping(pRtree, iRowid, pNode->iNode);
} }
@ -2632,11 +2661,12 @@ static int SplitNode(
RtreeNode *pParent = pLeft->pParent; RtreeNode *pParent = pLeft->pParent;
int iCell; int iCell;
rc = nodeParentIndex(pRtree, pLeft, &iCell); rc = nodeParentIndex(pRtree, pLeft, &iCell);
if( rc==SQLITE_OK ){ if( ALWAYS(rc==SQLITE_OK) ){
nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
rc = AdjustTree(pRtree, pParent, &leftbbox); rc = AdjustTree(pRtree, pParent, &leftbbox);
assert( rc==SQLITE_OK );
} }
if( rc!=SQLITE_OK ){ if( NEVER(rc!=SQLITE_OK) ){
goto splitnode_out; goto splitnode_out;
} }
} }
@ -2711,7 +2741,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
*/ */
iNode = sqlite3_column_int64(pRtree->pReadParent, 0); iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent); for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
if( !pTest ){ if( pTest==0 ){
rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
} }
} }
@ -2742,6 +2772,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
pParent = pNode->pParent; pParent = pNode->pParent;
pNode->pParent = 0; pNode->pParent = 0;
rc = deleteCell(pRtree, pParent, iCell, iHeight+1); rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
testcase( rc!=SQLITE_OK );
} }
rc2 = nodeRelease(pRtree, pParent); rc2 = nodeRelease(pRtree, pParent);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -2964,7 +2995,7 @@ static int rtreeInsertCell(
} }
}else{ }else{
rc = AdjustTree(pRtree, pNode, pCell); rc = AdjustTree(pRtree, pNode, pCell);
if( rc==SQLITE_OK ){ if( ALWAYS(rc==SQLITE_OK) ){
if( iHeight==0 ){ if( iHeight==0 ){
rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
}else{ }else{
@ -3070,7 +3101,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc2; int rc2;
RtreeNode *pChild = 0; RtreeNode *pChild = 0;
i64 iChild = nodeGetRowid(pRtree, pRoot, 0); i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = removeNode(pRtree, pChild, pRtree->iDepth-1); rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
} }
@ -3203,7 +3234,7 @@ static int rtreeUpdate(
rtreeReference(pRtree); rtreeReference(pRtree);
assert(nData>=1); assert(nData>=1);
cell.iRowid = 0; /* Used only to suppress a compiler warning */ memset(&cell, 0, sizeof(cell));
/* Constraint handling. A write operation on an r-tree table may return /* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons: ** SQLITE_CONSTRAINT for two reasons:
@ -3405,7 +3436,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
char *zSql; char *zSql;
sqlite3_stmt *p; sqlite3_stmt *p;
int rc; int rc;
i64 nRow = 0; i64 nRow = RTREE_MIN_ROWEST;
rc = sqlite3_table_column_metadata( rc = sqlite3_table_column_metadata(
db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0 db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
@ -3422,20 +3453,10 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0); if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
rc = sqlite3_finalize(p); rc = sqlite3_finalize(p);
}else if( rc!=SQLITE_NOMEM ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
if( nRow==0 ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
}else{
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
}
} }
sqlite3_free(zSql); sqlite3_free(zSql);
} }
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
return rc; return rc;
} }
@ -3585,9 +3606,12 @@ static int rtreeSqlInit(
sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
for(ii=0; ii<pRtree->nAux; ii++){ for(ii=0; ii<pRtree->nAux; ii++){
if( ii ) sqlite3_str_append(p, ",", 1); if( ii ) sqlite3_str_append(p, ",", 1);
#ifdef SQLITE_ENABLE_GEOPOLY
if( ii<pRtree->nAuxNotNull ){ if( ii<pRtree->nAuxNotNull ){
sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
}else{ }else
#endif
{
sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
} }
} }
@ -3852,6 +3876,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
tree.nDim2 = tree.nDim*2; tree.nDim2 = tree.nDim*2;
tree.nBytesPerCell = 8 + 8 * tree.nDim; tree.nBytesPerCell = 8 + 8 * tree.nDim;
node.zData = (u8 *)sqlite3_value_blob(apArg[1]); node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
if( node.zData==0 ) return;
nData = sqlite3_value_bytes(apArg[1]); nData = sqlite3_value_bytes(apArg[1]);
if( nData<4 ) return; if( nData<4 ) return;
if( nData<NCELL(&node)*tree.nBytesPerCell ) return; if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
@ -3891,11 +3916,16 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(nArg);
if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
|| sqlite3_value_bytes(apArg[0])<2 || sqlite3_value_bytes(apArg[0])<2
){ ){
sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1);
}else{ }else{
u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]); u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
sqlite3_result_int(ctx, readInt16(zBlob)); if( zBlob ){
sqlite3_result_int(ctx, readInt16(zBlob));
}else{
sqlite3_result_error_nomem(ctx);
}
} }
} }
@ -4261,8 +4291,10 @@ static int rtreeCheckTable(
if( pStmt ){ if( pStmt ){
nAux = sqlite3_column_count(pStmt) - 2; nAux = sqlite3_column_count(pStmt) - 2;
sqlite3_finalize(pStmt); sqlite3_finalize(pStmt);
}else
if( check.rc!=SQLITE_NOMEM ){
check.rc = SQLITE_OK;
} }
check.rc = SQLITE_OK;
} }
/* Find number of dimensions in the rtree table. */ /* Find number of dimensions in the rtree table. */
@ -4367,7 +4399,7 @@ static void rtreecheck(
/* Conditionally include the geopoly code */ /* Conditionally include the geopoly code */
#ifdef SQLITE_ENABLE_GEOPOLY #ifdef SQLITE_ENABLE_GEOPOLY
#include "third_party/sqlite3/geopoly.inc" # include "geopoly.inc"
#endif #endif
/* /*
@ -4519,7 +4551,10 @@ int sqlite3_rtree_query_callback(
/* Allocate and populate the context object. */ /* Allocate and populate the context object. */
pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback)); pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
if( !pGeomCtx ) return SQLITE_NOMEM; if( !pGeomCtx ){
if( xDestructor ) xDestructor(pContext);
return SQLITE_NOMEM;
}
pGeomCtx->xGeom = 0; pGeomCtx->xGeom = 0;
pGeomCtx->xQueryFunc = xQueryFunc; pGeomCtx->xQueryFunc = xQueryFunc;
pGeomCtx->xDestructor = xDestructor; pGeomCtx->xDestructor = xDestructor;

View file

@ -14,7 +14,6 @@
** RTREE library. All it does is declare the sqlite3RtreeInit() interface. ** RTREE library. All it does is declare the sqlite3RtreeInit() interface.
*/ */
#include "third_party/sqlite3/sqlite3.h" #include "third_party/sqlite3/sqlite3.h"
/* clang-format off */
#ifdef SQLITE_OMIT_VIRTUALTABLE #ifdef SQLITE_OMIT_VIRTUALTABLE
# undef SQLITE_ENABLE_RTREE # undef SQLITE_ENABLE_RTREE

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