mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 06:21:07 +00:00
Merge branch 'sqlite-release' into release-integration
This commit is contained in:
+2
-2
@@ -358,14 +358,14 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
|
||||
/* Reload the table, index and permanent trigger schemas. */
|
||||
zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
|
||||
if( !zWhere ) return;
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Now, if the table is not stored in the temp database, reload any temp
|
||||
** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined.
|
||||
*/
|
||||
if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, 1, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeAddParseSchemaOp(v, 1, zWhere);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+16
-2
@@ -70,8 +70,12 @@ static void attachFunc(
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zName;
|
||||
const char *zFile;
|
||||
char *zPath = 0;
|
||||
char *zErr = 0;
|
||||
unsigned int flags;
|
||||
Db *aNew;
|
||||
char *zErrDyn = 0;
|
||||
sqlite3_vfs *pVfs;
|
||||
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
|
||||
@@ -124,8 +128,18 @@ static void attachFunc(
|
||||
** it to obtain the database schema. At this point the schema may
|
||||
** or may not be initialised.
|
||||
*/
|
||||
rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
|
||||
db->openFlags | SQLITE_OPEN_MAIN_DB);
|
||||
flags = db->openFlags;
|
||||
rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
return;
|
||||
}
|
||||
assert( pVfs );
|
||||
flags |= SQLITE_OPEN_MAIN_DB;
|
||||
rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
|
||||
sqlite3_free( zPath );
|
||||
db->nDb++;
|
||||
if( rc==SQLITE_CONSTRAINT ){
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
+49
-22
@@ -788,6 +788,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
|
||||
*pRC = SQLITE_CORRUPT_BKPT;
|
||||
goto ptrmap_exit;
|
||||
}
|
||||
assert( offset <= (int)pBt->usableSize-5 );
|
||||
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
|
||||
|
||||
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
|
||||
@@ -827,6 +828,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
|
||||
|
||||
offset = PTRMAP_PTROFFSET(iPtrmap, key);
|
||||
if( offset<0 ){
|
||||
sqlite3PagerUnref(pDbPage);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
assert( offset <= (int)pBt->usableSize-5 );
|
||||
assert( pEType!=0 );
|
||||
*pEType = pPtrmap[offset];
|
||||
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
||||
@@ -851,6 +857,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||
*/
|
||||
#define findCell(P,I) \
|
||||
((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
|
||||
#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
|
||||
|
||||
|
||||
/*
|
||||
** This a more complex version of findCell() that works for
|
||||
@@ -1688,13 +1696,13 @@ static int btreeInvokeBusyHandler(void *pArg){
|
||||
** to problems with locking.
|
||||
*/
|
||||
int sqlite3BtreeOpen(
|
||||
sqlite3_vfs *pVfs, /* VFS to use for this b-tree */
|
||||
const char *zFilename, /* Name of the file containing the BTree database */
|
||||
sqlite3 *db, /* Associated database handle */
|
||||
Btree **ppBtree, /* Pointer to new Btree object written here */
|
||||
int flags, /* Options */
|
||||
int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */
|
||||
){
|
||||
sqlite3_vfs *pVfs; /* The VFS to use for this btree */
|
||||
BtShared *pBt = 0; /* Shared part of btree structure */
|
||||
Btree *p; /* Handle to return */
|
||||
sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */
|
||||
@@ -1716,6 +1724,7 @@ int sqlite3BtreeOpen(
|
||||
#endif
|
||||
|
||||
assert( db!=0 );
|
||||
assert( pVfs!=0 );
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
assert( (flags&0xff)==flags ); /* flags fit in 8 bits */
|
||||
|
||||
@@ -1734,7 +1743,6 @@ int sqlite3BtreeOpen(
|
||||
if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
|
||||
vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
|
||||
}
|
||||
pVfs = db->pVfs;
|
||||
p = sqlite3MallocZero(sizeof(Btree));
|
||||
if( !p ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -4445,7 +4453,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
}
|
||||
assert( pCur->apPage[0]->intKey || pIdxKey );
|
||||
for(;;){
|
||||
int lwr, upr;
|
||||
int lwr, upr, idx;
|
||||
Pgno chldPg;
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage];
|
||||
int c;
|
||||
@@ -4461,14 +4469,14 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
if( biasRight ){
|
||||
pCur->aiIdx[pCur->iPage] = (u16)upr;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = upr);
|
||||
}else{
|
||||
pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2);
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = (upr+lwr)/2);
|
||||
}
|
||||
for(;;){
|
||||
int idx = pCur->aiIdx[pCur->iPage]; /* Index of current cell in pPage */
|
||||
u8 *pCell; /* Pointer to current cell in pPage */
|
||||
|
||||
assert( idx==pCur->aiIdx[pCur->iPage] );
|
||||
pCur->info.nSize = 0;
|
||||
pCell = findCell(pPage, idx) + pPage->childPtrSize;
|
||||
if( pPage->intKey ){
|
||||
@@ -4551,7 +4559,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){
|
||||
break;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)((lwr+upr)/2);
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
|
||||
}
|
||||
assert( lwr==upr+1 );
|
||||
assert( pPage->isInit );
|
||||
@@ -5384,10 +5392,10 @@ static int fillInCell(
|
||||
** "sz" must be the number of bytes in the cell.
|
||||
*/
|
||||
static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
int i; /* Loop counter */
|
||||
u32 pc; /* Offset to cell content of cell being deleted */
|
||||
u8 *data; /* pPage->aData */
|
||||
u8 *ptr; /* Used to move bytes around within data[] */
|
||||
u8 *endPtr; /* End of loop */
|
||||
int rc; /* The return code */
|
||||
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
|
||||
|
||||
@@ -5412,9 +5420,11 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
*pRC = rc;
|
||||
return;
|
||||
}
|
||||
for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
|
||||
ptr[0] = ptr[2];
|
||||
ptr[1] = ptr[3];
|
||||
endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2];
|
||||
assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
|
||||
while( ptr<endPtr ){
|
||||
*(u16*)ptr = *(u16*)&ptr[2];
|
||||
ptr += 2;
|
||||
}
|
||||
pPage->nCell--;
|
||||
put2byte(&data[hdr+3], pPage->nCell);
|
||||
@@ -5454,6 +5464,7 @@ static void insertCell(
|
||||
int cellOffset; /* Address of first cell pointer in data[] */
|
||||
u8 *data; /* The content of the whole page */
|
||||
u8 *ptr; /* Used for moving information around in data[] */
|
||||
u8 *endPtr; /* End of the loop */
|
||||
|
||||
int nSkip = (iChild ? 4 : 0);
|
||||
|
||||
@@ -5504,9 +5515,12 @@ static void insertCell(
|
||||
if( iChild ){
|
||||
put4byte(&data[idx], iChild);
|
||||
}
|
||||
for(j=end, ptr=&data[j]; j>ins; j-=2, ptr-=2){
|
||||
ptr[0] = ptr[-2];
|
||||
ptr[1] = ptr[-1];
|
||||
ptr = &data[end];
|
||||
endPtr = &data[ins];
|
||||
assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */
|
||||
while( ptr>endPtr ){
|
||||
*(u16*)ptr = *(u16*)&ptr[-2];
|
||||
ptr -= 2;
|
||||
}
|
||||
put2byte(&data[ins], idx);
|
||||
put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
|
||||
@@ -5551,10 +5565,11 @@ static void assemblePage(
|
||||
pCellptr = &data[pPage->cellOffset + nCell*2];
|
||||
cellbody = nUsable;
|
||||
for(i=nCell-1; i>=0; i--){
|
||||
u16 sz = aSize[i];
|
||||
pCellptr -= 2;
|
||||
cellbody -= aSize[i];
|
||||
cellbody -= sz;
|
||||
put2byte(pCellptr, cellbody);
|
||||
memcpy(&data[cellbody], apCell[i], aSize[i]);
|
||||
memcpy(&data[cellbody], apCell[i], sz);
|
||||
}
|
||||
put2byte(&data[hdr+3], nCell);
|
||||
put2byte(&data[hdr+5], cellbody);
|
||||
@@ -6008,12 +6023,24 @@ static int balance_nonroot(
|
||||
memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize);
|
||||
|
||||
limit = pOld->nCell+pOld->nOverflow;
|
||||
for(j=0; j<limit; j++){
|
||||
assert( nCell<nMaxCells );
|
||||
apCell[nCell] = findOverflowCell(pOld, j);
|
||||
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
|
||||
nCell++;
|
||||
}
|
||||
if( pOld->nOverflow>0 ){
|
||||
for(j=0; j<limit; j++){
|
||||
assert( nCell<nMaxCells );
|
||||
apCell[nCell] = findOverflowCell(pOld, j);
|
||||
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
|
||||
nCell++;
|
||||
}
|
||||
}else{
|
||||
u8 *aData = pOld->aData;
|
||||
u16 maskPage = pOld->maskPage;
|
||||
u16 cellOffset = pOld->cellOffset;
|
||||
for(j=0; j<limit; j++){
|
||||
assert( nCell<nMaxCells );
|
||||
apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j);
|
||||
szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
|
||||
nCell++;
|
||||
}
|
||||
}
|
||||
if( i<nOld-1 && !leafData){
|
||||
u16 sz = (u16)szNew[i];
|
||||
u8 *pTemp;
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef struct BtShared BtShared;
|
||||
|
||||
|
||||
int sqlite3BtreeOpen(
|
||||
sqlite3_vfs *pVfs, /* VFS to use with this b-tree */
|
||||
const char *zFilename, /* Name of database file to open */
|
||||
sqlite3 *db, /* Associated database connection */
|
||||
Btree **ppBtree, /* Return open Btree* here */
|
||||
|
||||
+6
-9
@@ -200,9 +200,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
/* A minimum of one cursor is required if autoincrement is used
|
||||
* See ticket [a696379c1f08866] */
|
||||
if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
|
||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
|
||||
pParse->nTab, pParse->nMaxArg, pParse->explain,
|
||||
pParse->isMultiWrite && pParse->mayAbort);
|
||||
sqlite3VdbeMakeReady(v, pParse);
|
||||
pParse->rc = SQLITE_DONE;
|
||||
pParse->colNamesSet = 0;
|
||||
}else{
|
||||
@@ -1621,8 +1619,8 @@ void sqlite3EndTable(
|
||||
#endif
|
||||
|
||||
/* Reparse everything to update our internal data structures */
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
|
||||
sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P4_DYNAMIC);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "tbl_name='%q'", p->zName));
|
||||
}
|
||||
|
||||
|
||||
@@ -2819,9 +2817,8 @@ Index *sqlite3CreateIndex(
|
||||
if( pTblName ){
|
||||
sqlite3RefillIndex(pParse, pIndex, iMem);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName),
|
||||
P4_DYNAMIC);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
||||
sqlite3VdbeAddOp1(v, OP_Expire, 0);
|
||||
}
|
||||
}
|
||||
@@ -3443,7 +3440,7 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
SQLITE_OPEN_DELETEONCLOSE |
|
||||
SQLITE_OPEN_TEMP_DB;
|
||||
|
||||
rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
|
||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3ErrorMsg(pParse, "unable to open a temporary database "
|
||||
"file for storing temporary tables");
|
||||
|
||||
+97
-67
@@ -50,22 +50,6 @@
|
||||
|
||||
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
||||
|
||||
/*
|
||||
** On recent Windows platforms, the localtime_s() function is available
|
||||
** as part of the "Secure CRT". It is essentially equivalent to
|
||||
** localtime_r() available under most POSIX platforms, except that the
|
||||
** order of the parameters is reversed.
|
||||
**
|
||||
** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
|
||||
**
|
||||
** If the user has not indicated to use localtime_r() or localtime_s()
|
||||
** already, check for an MSVC build environment that provides
|
||||
** localtime_s().
|
||||
*/
|
||||
#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
|
||||
defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
|
||||
#define HAVE_LOCALTIME_S 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A structure for holding a single date and time.
|
||||
@@ -411,15 +395,83 @@ static void clearYMD_HMS_TZ(DateTime *p){
|
||||
p->validTZ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** On recent Windows platforms, the localtime_s() function is available
|
||||
** as part of the "Secure CRT". It is essentially equivalent to
|
||||
** localtime_r() available under most POSIX platforms, except that the
|
||||
** order of the parameters is reversed.
|
||||
**
|
||||
** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
|
||||
**
|
||||
** If the user has not indicated to use localtime_r() or localtime_s()
|
||||
** already, check for an MSVC build environment that provides
|
||||
** localtime_s().
|
||||
*/
|
||||
#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
|
||||
defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
|
||||
#define HAVE_LOCALTIME_S 1
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
/*
|
||||
** Compute the difference (in milliseconds)
|
||||
** between localtime and UTC (a.k.a. GMT)
|
||||
** for the time value p where p is in UTC.
|
||||
** The following routine implements the rough equivalent of localtime_r()
|
||||
** using whatever operating-system specific localtime facility that
|
||||
** is available. This routine returns 0 on success and
|
||||
** non-zero on any kind of error.
|
||||
**
|
||||
** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
|
||||
** routine will always fail.
|
||||
*/
|
||||
static sqlite3_int64 localtimeOffset(DateTime *p){
|
||||
static int osLocaltime(time_t *t, struct tm *pTm){
|
||||
int rc;
|
||||
#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
|
||||
&& (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
|
||||
struct tm *pX;
|
||||
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
sqlite3_mutex_enter(mutex);
|
||||
pX = localtime(t);
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
|
||||
#endif
|
||||
if( pX ) *pTm = *pX;
|
||||
sqlite3_mutex_leave(mutex);
|
||||
rc = pX==0;
|
||||
#else
|
||||
#ifndef SQLITE_OMIT_BUILTIN_TEST
|
||||
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
|
||||
#endif
|
||||
#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
|
||||
rc = localtime_r(t, pTm)==0;
|
||||
#else
|
||||
rc = localtime_s(pTm, t);
|
||||
#endif /* HAVE_LOCALTIME_R */
|
||||
#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LOCALTIME */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_LOCALTIME
|
||||
/*
|
||||
** Compute the difference (in milliseconds) between localtime and UTC
|
||||
** (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(
|
||||
DateTime *p, /* Date at which to calculate offset */
|
||||
sqlite3_context *pCtx, /* Write error here if one occurs */
|
||||
int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
|
||||
){
|
||||
DateTime x, y;
|
||||
time_t t;
|
||||
struct tm sLocal;
|
||||
|
||||
/* Initialize the contents of sLocal to avoid a compiler warning. */
|
||||
memset(&sLocal, 0, sizeof(sLocal));
|
||||
|
||||
x = *p;
|
||||
computeYMD_HMS(&x);
|
||||
if( x.Y<1971 || x.Y>=2038 ){
|
||||
@@ -437,47 +489,23 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
|
||||
x.validJD = 0;
|
||||
computeJD(&x);
|
||||
t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
{
|
||||
struct tm sLocal;
|
||||
localtime_r(&t, &sLocal);
|
||||
y.Y = sLocal.tm_year + 1900;
|
||||
y.M = sLocal.tm_mon + 1;
|
||||
y.D = sLocal.tm_mday;
|
||||
y.h = sLocal.tm_hour;
|
||||
y.m = sLocal.tm_min;
|
||||
y.s = sLocal.tm_sec;
|
||||
if( osLocaltime(&t, &sLocal) ){
|
||||
sqlite3_result_error(pCtx, "local time unavailable", -1);
|
||||
*pRc = SQLITE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
#elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S
|
||||
{
|
||||
struct tm sLocal;
|
||||
localtime_s(&sLocal, &t);
|
||||
y.Y = sLocal.tm_year + 1900;
|
||||
y.M = sLocal.tm_mon + 1;
|
||||
y.D = sLocal.tm_mday;
|
||||
y.h = sLocal.tm_hour;
|
||||
y.m = sLocal.tm_min;
|
||||
y.s = sLocal.tm_sec;
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct tm *pTm;
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
pTm = localtime(&t);
|
||||
y.Y = pTm->tm_year + 1900;
|
||||
y.M = pTm->tm_mon + 1;
|
||||
y.D = pTm->tm_mday;
|
||||
y.h = pTm->tm_hour;
|
||||
y.m = pTm->tm_min;
|
||||
y.s = pTm->tm_sec;
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
}
|
||||
#endif
|
||||
y.Y = sLocal.tm_year + 1900;
|
||||
y.M = sLocal.tm_mon + 1;
|
||||
y.D = sLocal.tm_mday;
|
||||
y.h = sLocal.tm_hour;
|
||||
y.m = sLocal.tm_min;
|
||||
y.s = sLocal.tm_sec;
|
||||
y.validYMD = 1;
|
||||
y.validHMS = 1;
|
||||
y.validJD = 0;
|
||||
y.validTZ = 0;
|
||||
computeJD(&y);
|
||||
*pRc = SQLITE_OK;
|
||||
return y.iJD - x.iJD;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_LOCALTIME */
|
||||
@@ -501,9 +529,12 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
|
||||
** localtime
|
||||
** utc
|
||||
**
|
||||
** Return 0 on success and 1 if there is any kind of error.
|
||||
** Return 0 on success and 1 if there is any kind of error. If the error
|
||||
** is in a system call (i.e. localtime()), then an error message is written
|
||||
** to context pCtx. If the error is an unrecognized modifier, no error is
|
||||
** written to pCtx.
|
||||
*/
|
||||
static int parseModifier(const char *zMod, DateTime *p){
|
||||
static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
|
||||
int rc = 1;
|
||||
int n;
|
||||
double r;
|
||||
@@ -523,9 +554,8 @@ static int parseModifier(const char *zMod, DateTime *p){
|
||||
*/
|
||||
if( strcmp(z, "localtime")==0 ){
|
||||
computeJD(p);
|
||||
p->iJD += localtimeOffset(p);
|
||||
p->iJD += localtimeOffset(p, pCtx, &rc);
|
||||
clearYMD_HMS_TZ(p);
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -546,11 +576,12 @@ static int parseModifier(const char *zMod, DateTime *p){
|
||||
else if( strcmp(z, "utc")==0 ){
|
||||
sqlite3_int64 c1;
|
||||
computeJD(p);
|
||||
c1 = localtimeOffset(p);
|
||||
p->iJD -= c1;
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->iJD += c1 - localtimeOffset(p);
|
||||
rc = 0;
|
||||
c1 = localtimeOffset(p, pCtx, &rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
p->iJD -= c1;
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@@ -731,9 +762,8 @@ static int isDate(
|
||||
}
|
||||
}
|
||||
for(i=1; i<argc; i++){
|
||||
if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
|
||||
return 1;
|
||||
}
|
||||
z = sqlite3_value_text(argv[i]);
|
||||
if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+8
-1
@@ -401,6 +401,7 @@ void sqlite3DeleteFrom(
|
||||
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||
sqlite3VtabMakeWritable(pParse, pTab);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, OE_Abort);
|
||||
sqlite3MayAbort(pParse);
|
||||
}else
|
||||
#endif
|
||||
@@ -635,8 +636,14 @@ int sqlite3GenerateIndexKey(
|
||||
}
|
||||
}
|
||||
if( doMakeRec ){
|
||||
const char *zAff;
|
||||
if( pTab->pSelect || (pParse->db->flags & SQLITE_IdxRealAsInt)!=0 ){
|
||||
zAff = 0;
|
||||
}else{
|
||||
zAff = sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
|
||||
sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
|
||||
return regBase;
|
||||
|
||||
+46
-44
@@ -555,53 +555,53 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
/* Wildcard of the form "?". Assign the next variable number */
|
||||
assert( z[0]=='?' );
|
||||
pExpr->iColumn = (ynVar)(++pParse->nVar);
|
||||
}else if( z[0]=='?' ){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
i64 i;
|
||||
int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
|
||||
pExpr->iColumn = (ynVar)i;
|
||||
testcase( i==0 );
|
||||
testcase( i==1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
|
||||
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
||||
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
|
||||
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
|
||||
}
|
||||
if( i>pParse->nVar ){
|
||||
pParse->nVar = (int)i;
|
||||
}
|
||||
}else{
|
||||
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable
|
||||
** number as the prior appearance of the same name, or if the name
|
||||
** has never appeared before, reuse the same variable number
|
||||
*/
|
||||
int i;
|
||||
u32 n;
|
||||
n = sqlite3Strlen30(z);
|
||||
for(i=0; i<pParse->nVarExpr; i++){
|
||||
Expr *pE = pParse->apVarExpr[i];
|
||||
assert( pE!=0 );
|
||||
if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){
|
||||
pExpr->iColumn = pE->iColumn;
|
||||
break;
|
||||
ynVar x = 0;
|
||||
u32 n = sqlite3Strlen30(z);
|
||||
if( z[0]=='?' ){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
i64 i;
|
||||
int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
|
||||
pExpr->iColumn = x = (ynVar)i;
|
||||
testcase( i==0 );
|
||||
testcase( i==1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
|
||||
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
||||
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
|
||||
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
|
||||
x = 0;
|
||||
}
|
||||
if( i>pParse->nVar ){
|
||||
pParse->nVar = (int)i;
|
||||
}
|
||||
}else{
|
||||
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable
|
||||
** number as the prior appearance of the same name, or if the name
|
||||
** has never appeared before, reuse the same variable number
|
||||
*/
|
||||
ynVar i;
|
||||
for(i=0; i<pParse->nzVar; i++){
|
||||
if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
|
||||
pExpr->iColumn = x = (ynVar)i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
|
||||
}
|
||||
if( i>=pParse->nVarExpr ){
|
||||
pExpr->iColumn = (ynVar)(++pParse->nVar);
|
||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||
pParse->apVarExpr =
|
||||
sqlite3DbReallocOrFree(
|
||||
db,
|
||||
pParse->apVarExpr,
|
||||
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0])
|
||||
);
|
||||
if( x>0 ){
|
||||
if( x>pParse->nzVar ){
|
||||
char **a;
|
||||
a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
|
||||
if( a==0 ) return; /* Error reported through db->mallocFailed */
|
||||
pParse->azVar = a;
|
||||
memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
|
||||
pParse->nzVar = x;
|
||||
}
|
||||
if( !db->mallocFailed ){
|
||||
assert( pParse->apVarExpr!=0 );
|
||||
pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
|
||||
if( z[0]!='?' || pParse->azVar[x-1]==0 ){
|
||||
sqlite3DbFree(db, pParse->azVar[x-1]);
|
||||
pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2345,7 +2345,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
assert( pExpr->u.zToken[0]!=0 );
|
||||
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
|
||||
if( pExpr->u.zToken[1]!=0 ){
|
||||
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, P4_TRANSIENT);
|
||||
assert( pExpr->u.zToken[0]=='?'
|
||||
|| strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 );
|
||||
sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+13
-1
@@ -386,13 +386,25 @@ static void fkLookupParent(
|
||||
/* If the parent table is the same as the child table, and we are about
|
||||
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
||||
** then check if the row being inserted matches itself. If so, do not
|
||||
** increment the constraint-counter. */
|
||||
** increment the constraint-counter.
|
||||
**
|
||||
** If any of the parent-key values are NULL, then the row cannot match
|
||||
** itself. So set JUMPIFNULL to make sure we do the OP_Found if any
|
||||
** of the parent-key values are NULL (at this point it is known that
|
||||
** none of the child key values are).
|
||||
*/
|
||||
if( pTab==pFKey->pFrom && nIncr==1 ){
|
||||
int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1;
|
||||
for(i=0; i<nCol; i++){
|
||||
int iChild = aiCol[i]+1+regData;
|
||||
int iParent = pIdx->aiColumn[i]+1+regData;
|
||||
assert( aiCol[i]!=pTab->iPKey );
|
||||
if( pIdx->aiColumn[i]==pTab->iPKey ){
|
||||
/* The parent key is a composite key that includes the IPK column */
|
||||
iParent = regData;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent);
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
|
||||
}
|
||||
|
||||
+23
-7
@@ -506,10 +506,10 @@ struct compareInfo {
|
||||
** whereas only characters less than 0x80 do in ASCII.
|
||||
*/
|
||||
#if defined(SQLITE_EBCDIC)
|
||||
# define sqlite3Utf8Read(A,C) (*(A++))
|
||||
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
|
||||
# define sqlite3Utf8Read(A,C) (*(A++))
|
||||
# define GlogUpperToLower(A) A = sqlite3UpperToLower[A]
|
||||
#else
|
||||
# define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
|
||||
# define GlogUpperToLower(A) if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }
|
||||
#endif
|
||||
|
||||
static const struct compareInfo globInfo = { '*', '?', '[', 0 };
|
||||
@@ -552,9 +552,9 @@ static int patternCompare(
|
||||
const u8 *zPattern, /* The glob pattern */
|
||||
const u8 *zString, /* The string to compare against the glob */
|
||||
const struct compareInfo *pInfo, /* Information about how to do the compare */
|
||||
const int esc /* The escape character */
|
||||
u32 esc /* The escape character */
|
||||
){
|
||||
int c, c2;
|
||||
u32 c, c2;
|
||||
int invert;
|
||||
int seen;
|
||||
u8 matchOne = pInfo->matchOne;
|
||||
@@ -608,7 +608,7 @@ static int patternCompare(
|
||||
return 0;
|
||||
}
|
||||
}else if( c==matchSet ){
|
||||
int prior_c = 0;
|
||||
u32 prior_c = 0;
|
||||
assert( esc==0 ); /* This only occurs for GLOB, not LIKE */
|
||||
seen = 0;
|
||||
invert = 0;
|
||||
@@ -684,7 +684,7 @@ static void likeFunc(
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const unsigned char *zA, *zB;
|
||||
int escape = 0;
|
||||
u32 escape = 0;
|
||||
int nPat;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
|
||||
@@ -774,6 +774,21 @@ static void sourceidFunc(
|
||||
sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_log() function. This is a wrapper around
|
||||
** sqlite3_log(). The return value is NULL. The function exists purely for
|
||||
** its side-effects.
|
||||
*/
|
||||
static void errlogFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
UNUSED_PARAMETER(argc);
|
||||
UNUSED_PARAMETER(context);
|
||||
sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1]));
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the sqlite_compileoption_used() function.
|
||||
** The result is an integer that identifies if the compiler option
|
||||
@@ -1546,6 +1561,7 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
||||
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
||||
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
|
||||
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
||||
FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
||||
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
|
||||
+5
-1
@@ -129,7 +129,9 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_USE_URI
|
||||
# define SQLITE_USE_URI 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following singleton contains the global configuration for
|
||||
@@ -139,6 +141,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
|
||||
1, /* bCoreMutex */
|
||||
SQLITE_THREADSAFE==1, /* bFullMutex */
|
||||
SQLITE_USE_URI, /* bOpenUri */
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
100, /* szLookaside */
|
||||
500, /* nLookaside */
|
||||
@@ -166,6 +169,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* nRefInitMutex */
|
||||
0, /* xLog */
|
||||
0, /* pLogArg */
|
||||
0, /* bLocaltimeFault */
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -969,6 +969,7 @@ void sqlite3Insert(
|
||||
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||
sqlite3VtabMakeWritable(pParse, pTab);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
|
||||
sqlite3MayAbort(pParse);
|
||||
}else
|
||||
#endif
|
||||
@@ -1734,6 +1735,18 @@ static int xferOptimization(
|
||||
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
||||
}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
/* Disallow the transfer optimization if the destination table constains
|
||||
** any foreign key constraints. This is more restrictive than necessary.
|
||||
** But the main beneficiary of the transfer optimization is the VACUUM
|
||||
** command, and the VACUUM command disables foreign key constraints. So
|
||||
** the extra complication to make this rule less restrictive is probably
|
||||
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
||||
*/
|
||||
if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we get this far, it means either:
|
||||
**
|
||||
|
||||
+288
-15
@@ -426,6 +426,11 @@ int sqlite3_config(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_CONFIG_URI: {
|
||||
sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
@@ -1785,6 +1790,236 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
return oldLimit; /* IMP: R-53341-35419 */
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used to parse both URIs and non-URI filenames passed by the
|
||||
** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
|
||||
** URIs specified as part of ATTACH statements.
|
||||
**
|
||||
** The first argument to this function is the name of the VFS to use (or
|
||||
** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx"
|
||||
** query parameter. The second argument contains the URI (or non-URI filename)
|
||||
** itself. When this function is called the *pFlags variable should contain
|
||||
** the default flags to open the database handle with. The value stored in
|
||||
** *pFlags may be updated before returning if the URI filename contains
|
||||
** "cache=xxx" or "mode=xxx" query parameters.
|
||||
**
|
||||
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
|
||||
** the VFS that should be used to open the database file. *pzFile is set to
|
||||
** point to a buffer containing the name of the file to open. It is the
|
||||
** responsibility of the caller to eventually call sqlite3_free() to release
|
||||
** this buffer.
|
||||
**
|
||||
** If an error occurs, then an SQLite error code is returned and *pzErrMsg
|
||||
** may be set to point to a buffer containing an English language error
|
||||
** message. It is the responsibility of the caller to eventually release
|
||||
** this buffer by calling sqlite3_free().
|
||||
*/
|
||||
int sqlite3ParseUri(
|
||||
const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */
|
||||
const char *zUri, /* Nul-terminated URI to parse */
|
||||
unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */
|
||||
sqlite3_vfs **ppVfs, /* OUT: VFS to use */
|
||||
char **pzFile, /* OUT: Filename component of URI */
|
||||
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
unsigned int flags = *pFlags;
|
||||
const char *zVfs = zDefaultVfs;
|
||||
char *zFile;
|
||||
char c;
|
||||
int nUri = sqlite3Strlen30(zUri);
|
||||
|
||||
assert( *pzErrMsg==0 );
|
||||
|
||||
if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri)
|
||||
&& nUri>=5 && memcmp(zUri, "file:", 5)==0
|
||||
){
|
||||
char *zOpt;
|
||||
int eState; /* Parser state when parsing URI */
|
||||
int iIn; /* Input character index */
|
||||
int iOut = 0; /* Output character index */
|
||||
int nByte = nUri+2; /* Bytes of space to allocate */
|
||||
|
||||
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
|
||||
** method that there may be extra parameters following the file-name. */
|
||||
flags |= SQLITE_OPEN_URI;
|
||||
|
||||
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
|
||||
zFile = sqlite3_malloc(nByte);
|
||||
if( !zFile ) return SQLITE_NOMEM;
|
||||
|
||||
/* Discard the scheme and authority segments of the URI. */
|
||||
if( zUri[5]=='/' && zUri[6]=='/' ){
|
||||
iIn = 7;
|
||||
while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
|
||||
|
||||
if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
|
||||
*pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
|
||||
iIn-7, &zUri[7]);
|
||||
rc = SQLITE_ERROR;
|
||||
goto parse_uri_out;
|
||||
}
|
||||
}else{
|
||||
iIn = 5;
|
||||
}
|
||||
|
||||
/* Copy the filename and any query parameters into the zFile buffer.
|
||||
** Decode %HH escape codes along the way.
|
||||
**
|
||||
** Within this loop, variable eState may be set to 0, 1 or 2, depending
|
||||
** on the parsing context. As follows:
|
||||
**
|
||||
** 0: Parsing file-name.
|
||||
** 1: Parsing name section of a name=value query parameter.
|
||||
** 2: Parsing value section of a name=value query parameter.
|
||||
*/
|
||||
eState = 0;
|
||||
while( (c = zUri[iIn])!=0 && c!='#' ){
|
||||
iIn++;
|
||||
if( c=='%'
|
||||
&& sqlite3Isxdigit(zUri[iIn])
|
||||
&& sqlite3Isxdigit(zUri[iIn+1])
|
||||
){
|
||||
int octet = (sqlite3HexToInt(zUri[iIn++]) << 4);
|
||||
octet += sqlite3HexToInt(zUri[iIn++]);
|
||||
|
||||
assert( octet>=0 && octet<256 );
|
||||
if( octet==0 ){
|
||||
/* This branch is taken when "%00" appears within the URI. In this
|
||||
** case we ignore all text in the remainder of the path, name or
|
||||
** value currently being parsed. So ignore the current character
|
||||
** and skip to the next "?", "=" or "&", as appropriate. */
|
||||
while( (c = zUri[iIn])!=0 && c!='#'
|
||||
&& (eState!=0 || c!='?')
|
||||
&& (eState!=1 || (c!='=' && c!='&'))
|
||||
&& (eState!=2 || c!='&')
|
||||
){
|
||||
iIn++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = octet;
|
||||
}else if( eState==1 && (c=='&' || c=='=') ){
|
||||
if( zFile[iOut-1]==0 ){
|
||||
/* An empty option name. Ignore this option altogether. */
|
||||
while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++;
|
||||
continue;
|
||||
}
|
||||
if( c=='&' ){
|
||||
zFile[iOut++] = '\0';
|
||||
}else{
|
||||
eState = 2;
|
||||
}
|
||||
c = 0;
|
||||
}else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){
|
||||
c = 0;
|
||||
eState = 1;
|
||||
}
|
||||
zFile[iOut++] = c;
|
||||
}
|
||||
if( eState==1 ) zFile[iOut++] = '\0';
|
||||
zFile[iOut++] = '\0';
|
||||
zFile[iOut++] = '\0';
|
||||
|
||||
/* Check if there were any options specified that should be interpreted
|
||||
** here. Options that are interpreted here include "vfs" and those that
|
||||
** correspond to flags that may be passed to the sqlite3_open_v2()
|
||||
** method. */
|
||||
zOpt = &zFile[sqlite3Strlen30(zFile)+1];
|
||||
while( zOpt[0] ){
|
||||
int nOpt = sqlite3Strlen30(zOpt);
|
||||
char *zVal = &zOpt[nOpt+1];
|
||||
int nVal = sqlite3Strlen30(zVal);
|
||||
|
||||
if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
|
||||
zVfs = zVal;
|
||||
}else{
|
||||
struct OpenMode {
|
||||
const char *z;
|
||||
int mode;
|
||||
} *aMode = 0;
|
||||
char *zModeType = 0;
|
||||
int mask = 0;
|
||||
int limit = 0;
|
||||
|
||||
if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){
|
||||
static struct OpenMode aCacheMode[] = {
|
||||
{ "shared", SQLITE_OPEN_SHAREDCACHE },
|
||||
{ "private", SQLITE_OPEN_PRIVATECACHE },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE;
|
||||
aMode = aCacheMode;
|
||||
limit = mask;
|
||||
zModeType = "cache";
|
||||
}
|
||||
if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){
|
||||
static struct OpenMode aOpenMode[] = {
|
||||
{ "ro", SQLITE_OPEN_READONLY },
|
||||
{ "rw", SQLITE_OPEN_READWRITE },
|
||||
{ "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
|
||||
aMode = aOpenMode;
|
||||
limit = mask & flags;
|
||||
zModeType = "access";
|
||||
}
|
||||
|
||||
if( aMode ){
|
||||
int i;
|
||||
int mode = 0;
|
||||
for(i=0; aMode[i].z; i++){
|
||||
const char *z = aMode[i].z;
|
||||
if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){
|
||||
mode = aMode[i].mode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( mode==0 ){
|
||||
*pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal);
|
||||
rc = SQLITE_ERROR;
|
||||
goto parse_uri_out;
|
||||
}
|
||||
if( mode>limit ){
|
||||
*pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s",
|
||||
zModeType, zVal);
|
||||
rc = SQLITE_PERM;
|
||||
goto parse_uri_out;
|
||||
}
|
||||
flags = (flags & ~mask) | mode;
|
||||
}
|
||||
}
|
||||
|
||||
zOpt = &zVal[nVal+1];
|
||||
}
|
||||
|
||||
}else{
|
||||
zFile = sqlite3_malloc(nUri+2);
|
||||
if( !zFile ) return SQLITE_NOMEM;
|
||||
memcpy(zFile, zUri, nUri);
|
||||
zFile[nUri] = '\0';
|
||||
zFile[nUri+1] = '\0';
|
||||
}
|
||||
|
||||
*ppVfs = sqlite3_vfs_find(zVfs);
|
||||
if( *ppVfs==0 ){
|
||||
*pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
parse_uri_out:
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(zFile);
|
||||
zFile = 0;
|
||||
}
|
||||
*pFlags = flags;
|
||||
*pzFile = zFile;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine does the work of opening a database on behalf of
|
||||
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
|
||||
@@ -1793,12 +2028,14 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
static int openDatabase(
|
||||
const char *zFilename, /* Database filename UTF-8 encoded */
|
||||
sqlite3 **ppDb, /* OUT: Returned database handle */
|
||||
unsigned flags, /* Operational flags */
|
||||
unsigned int flags, /* Operational flags */
|
||||
const char *zVfs /* Name of the VFS to use */
|
||||
){
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
int isThreadsafe;
|
||||
sqlite3 *db; /* Store allocated handle here */
|
||||
int rc; /* Return code */
|
||||
int isThreadsafe; /* True for threadsafe connections */
|
||||
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
|
||||
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
|
||||
|
||||
*ppDb = 0;
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
@@ -1822,7 +2059,7 @@ static int openDatabase(
|
||||
testcase( (1<<(flags&7))==0x02 ); /* READONLY */
|
||||
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
|
||||
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
|
||||
if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE;
|
||||
if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT;
|
||||
|
||||
if( sqlite3GlobalConfig.bCoreMutex==0 ){
|
||||
isThreadsafe = 0;
|
||||
@@ -1903,13 +2140,6 @@ static int openDatabase(
|
||||
sqlite3HashInit(&db->aModule);
|
||||
#endif
|
||||
|
||||
db->pVfs = sqlite3_vfs_find(zVfs);
|
||||
if( !db->pVfs ){
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3Error(db, rc, "no such vfs: %s", zVfs);
|
||||
goto opendb_out;
|
||||
}
|
||||
|
||||
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
|
||||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
@@ -1932,9 +2162,18 @@ static int openDatabase(
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0,
|
||||
nocaseCollatingFunc, 0);
|
||||
|
||||
/* Open the backend database driver */
|
||||
/* Parse the filename/URI argument. */
|
||||
db->openFlags = flags;
|
||||
rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0,
|
||||
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
goto opendb_out;
|
||||
}
|
||||
|
||||
/* Open the backend database driver */
|
||||
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
|
||||
flags | SQLITE_OPEN_MAIN_DB);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_IOERR_NOMEM ){
|
||||
@@ -2027,6 +2266,7 @@ static int openDatabase(
|
||||
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
|
||||
|
||||
opendb_out:
|
||||
sqlite3_free(zOpen);
|
||||
if( db ){
|
||||
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@@ -2058,7 +2298,7 @@ int sqlite3_open_v2(
|
||||
int flags, /* Flags */
|
||||
const char *zVfs /* Name of VFS module to use */
|
||||
){
|
||||
return openDatabase(filename, ppDb, flags, zVfs);
|
||||
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
@@ -2663,8 +2903,41 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
|
||||
**
|
||||
** If parameter onoff is non-zero, configure the wrappers so that all
|
||||
** subsequent calls to localtime() and variants fail. If onoff is zero,
|
||||
** undo this setting.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
|
||||
sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a utility routine, useful to VFS implementations, that checks
|
||||
** to see if a database file was a URI that contained a specific query
|
||||
** parameter, and if so obtains the value of the query parameter.
|
||||
**
|
||||
** The zFilename argument is the filename pointer passed into the xOpen()
|
||||
** method of a VFS implementation. The zParam argument is the name of the
|
||||
** query parameter we seek. This routine returns the value of the zParam
|
||||
** parameter if it exists. If the parameter does not exist, this routine
|
||||
** returns a NULL pointer.
|
||||
*/
|
||||
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
while( zFilename[0] ){
|
||||
int x = strcmp(zFilename, zParam);
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
if( x==0 ) return zFilename;
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-5
@@ -266,7 +266,7 @@ static int mallocWithAlarm(int n, void **pp){
|
||||
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
|
||||
if( mem0.alarmCallback!=0 ){
|
||||
int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
if( nUsed+nFull >= mem0.alarmThreshold ){
|
||||
if( nUsed >= mem0.alarmThreshold - nFull ){
|
||||
mem0.nearlyFull = 1;
|
||||
sqlite3MallocAlarm(nFull);
|
||||
}else{
|
||||
@@ -507,7 +507,7 @@ void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
** Change the size of an existing memory allocation
|
||||
*/
|
||||
void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
int nOld, nNew;
|
||||
int nOld, nNew, nDiff;
|
||||
void *pNew;
|
||||
if( pOld==0 ){
|
||||
return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
|
||||
@@ -530,9 +530,10 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
}else if( sqlite3GlobalConfig.bMemstat ){
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);
|
||||
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >=
|
||||
mem0.alarmThreshold ){
|
||||
sqlite3MallocAlarm(nNew-nOld);
|
||||
nDiff = nNew - nOld;
|
||||
if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
|
||||
mem0.alarmThreshold-nDiff ){
|
||||
sqlite3MallocAlarm(nDiff);
|
||||
}
|
||||
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
|
||||
assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
|
||||
|
||||
+54
-19
@@ -138,6 +138,10 @@
|
||||
# include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIME
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Allowed values of unixFile.fsFlags
|
||||
*/
|
||||
@@ -281,6 +285,18 @@ struct unixFile {
|
||||
#define threadid 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Different Unix systems declare open() in different ways. Same use
|
||||
** open(const char*,int,mode_t). Others use open(const char*,int,...).
|
||||
** The difference is important when using a pointer to the function.
|
||||
**
|
||||
** The safest way to deal with the problem is to always use this wrapper
|
||||
** which always has the same well-defined interface.
|
||||
*/
|
||||
static int posixOpen(const char *zFile, int flags, int mode){
|
||||
return open(zFile, flags, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
** Many system calls are accessed through pointer-to-functions so that
|
||||
** they may be overridden at runtime to facilitate fault injection during
|
||||
@@ -292,8 +308,8 @@ static struct unix_syscall {
|
||||
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
|
||||
sqlite3_syscall_ptr pDefault; /* Default value */
|
||||
} aSyscall[] = {
|
||||
{ "open", (sqlite3_syscall_ptr)open, 0 },
|
||||
#define osOpen ((int(*)(const char*,int,...))aSyscall[0].pCurrent)
|
||||
{ "open", (sqlite3_syscall_ptr)posixOpen, 0 },
|
||||
#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
|
||||
|
||||
{ "close", (sqlite3_syscall_ptr)close, 0 },
|
||||
#define osClose ((int(*)(int))aSyscall[1].pCurrent)
|
||||
@@ -330,7 +346,7 @@ static struct unix_syscall {
|
||||
{ "read", (sqlite3_syscall_ptr)read, 0 },
|
||||
#define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
|
||||
|
||||
#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
|
||||
#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
|
||||
{ "pread", (sqlite3_syscall_ptr)pread, 0 },
|
||||
#else
|
||||
{ "pread", (sqlite3_syscall_ptr)0, 0 },
|
||||
@@ -347,7 +363,7 @@ static struct unix_syscall {
|
||||
{ "write", (sqlite3_syscall_ptr)write, 0 },
|
||||
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
|
||||
|
||||
#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
|
||||
#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
|
||||
{ "pwrite", (sqlite3_syscall_ptr)pwrite, 0 },
|
||||
#else
|
||||
{ "pwrite", (sqlite3_syscall_ptr)0, 0 },
|
||||
@@ -933,7 +949,7 @@ struct unixInodeInfo {
|
||||
UnixUnusedFd *pUnused; /* Unused file descriptors to close */
|
||||
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
|
||||
unixInodeInfo *pPrev; /* .... doubly linked */
|
||||
#if defined(SQLITE_ENABLE_LOCKING_STYLE)
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
unsigned long long sharedByte; /* for AFP simulated shared lock */
|
||||
#endif
|
||||
#if OS_VXWORKS
|
||||
@@ -1927,8 +1943,10 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
|
||||
*/
|
||||
if( pFile->eFileLock > NO_LOCK ){
|
||||
pFile->eFileLock = eFileLock;
|
||||
#if !OS_VXWORKS
|
||||
/* Always update the timestamp on the old file */
|
||||
#ifdef HAVE_UTIME
|
||||
utime(zLockFile, NULL);
|
||||
#else
|
||||
utimes(zLockFile, NULL);
|
||||
#endif
|
||||
return SQLITE_OK;
|
||||
@@ -3090,7 +3108,7 @@ static int unixWrite(
|
||||
SimulateDiskfullError(( wrote=0, amt=1 ));
|
||||
|
||||
if( amt>0 ){
|
||||
if( wrote<0 ){
|
||||
if( wrote<0 && pFile->lastErrno!=ENOSPC ){
|
||||
/* lastErrno set by seekAndWrite */
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}else{
|
||||
@@ -3525,7 +3543,8 @@ struct unixShmNode {
|
||||
char *zFilename; /* Name of the mmapped file */
|
||||
int h; /* Open file descriptor */
|
||||
int szRegion; /* Size of shared-memory regions */
|
||||
int nRegion; /* Size of array apRegion */
|
||||
u16 nRegion; /* Size of array apRegion */
|
||||
u8 isReadonly; /* True if read-only */
|
||||
char **apRegion; /* Array of mapped shared-memory regions */
|
||||
int nRef; /* Number of unixShm objects pointing to this */
|
||||
unixShm *pFirst; /* All unixShm objects pointing to this */
|
||||
@@ -3757,6 +3776,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
(u32)sStat.st_ino, (u32)sStat.st_dev);
|
||||
#else
|
||||
sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
|
||||
sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
|
||||
#endif
|
||||
pShmNode->h = -1;
|
||||
pDbFd->pInode->pShmNode = pShmNode;
|
||||
@@ -3771,8 +3791,17 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
|
||||
(sStat.st_mode & 0777));
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
|
||||
goto shm_open_err;
|
||||
const char *zRO;
|
||||
zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
|
||||
if( zRO && sqlite3GetBoolean(zRO) ){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDONLY,
|
||||
(sStat.st_mode & 0777));
|
||||
pShmNode->isReadonly = 1;
|
||||
}
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
|
||||
goto shm_open_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check to see if another process is holding the dead-man switch.
|
||||
@@ -3911,11 +3940,12 @@ static int unixShmMap(
|
||||
while(pShmNode->nRegion<=iRegion){
|
||||
void *pMem;
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
|
||||
pMem = mmap(0, szRegion,
|
||||
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
|
||||
);
|
||||
if( pMem==MAP_FAILED ){
|
||||
rc = SQLITE_IOERR;
|
||||
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
|
||||
goto shmpage_out;
|
||||
}
|
||||
}else{
|
||||
@@ -3937,6 +3967,7 @@ shmpage_out:
|
||||
}else{
|
||||
*pp = 0;
|
||||
}
|
||||
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
|
||||
sqlite3_mutex_leave(pShmNode->mutex);
|
||||
return rc;
|
||||
}
|
||||
@@ -4790,6 +4821,11 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
||||
** corresponding database file and sets *pMode to this value. Whenever
|
||||
** possible, WAL and journal files are created using the same permissions
|
||||
** as the associated database file.
|
||||
**
|
||||
** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
|
||||
** original filename is unavailable. But 8_3_NAMES is only used for
|
||||
** FAT filesystems and permissions do not matter there, so just use
|
||||
** the default permissions.
|
||||
*/
|
||||
static int findCreateFileMode(
|
||||
const char *zPath, /* Path of file (possibly) being created */
|
||||
@@ -4797,6 +4833,7 @@ static int findCreateFileMode(
|
||||
mode_t *pMode /* OUT: Permissions to open file with */
|
||||
){
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
*pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
|
||||
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
|
||||
char zDb[MAX_PATHNAME+1]; /* Database file path */
|
||||
int nDb; /* Number of valid bytes in zDb */
|
||||
@@ -4808,15 +4845,15 @@ static int findCreateFileMode(
|
||||
**
|
||||
** "<path to db>-journal"
|
||||
** "<path to db>-wal"
|
||||
** "<path to db>-journal-NNNN"
|
||||
** "<path to db>-wal-NNNN"
|
||||
** "<path to db>-journalNN"
|
||||
** "<path to db>-walNN"
|
||||
**
|
||||
** where NNNN is a 4 digit decimal number. The NNNN naming schemes are
|
||||
** where NN is a 4 digit decimal number. The NN naming schemes are
|
||||
** used by the test_multiplex.c module.
|
||||
*/
|
||||
nDb = sqlite3Strlen30(zPath) - 1;
|
||||
while( nDb>0 && zPath[nDb]!='l' ) nDb--;
|
||||
nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7);
|
||||
while( nDb>0 && zPath[nDb]!='-' ) nDb--;
|
||||
if( nDb==0 ) return SQLITE_OK;
|
||||
memcpy(zDb, zPath, nDb);
|
||||
zDb[nDb] = '\0';
|
||||
|
||||
@@ -4827,8 +4864,6 @@ static int findCreateFileMode(
|
||||
}
|
||||
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
|
||||
*pMode = 0600;
|
||||
}else{
|
||||
*pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+152
-90
@@ -118,6 +118,7 @@ struct winFile {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Forward prototypes.
|
||||
*/
|
||||
@@ -285,7 +286,7 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
|
||||
** Convert UTF-8 to multibyte character string. Space to hold the
|
||||
** returned string is obtained from malloc().
|
||||
*/
|
||||
static char *utf8ToMbcs(const char *zFilename){
|
||||
char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
|
||||
char *zFilenameMbcs;
|
||||
WCHAR *zTmpWide;
|
||||
|
||||
@@ -298,6 +299,109 @@ static char *utf8ToMbcs(const char *zFilename){
|
||||
return zFilenameMbcs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The return value of getLastErrorMsg
|
||||
** is zero if the error message fits in the buffer, or non-zero
|
||||
** otherwise (if the message was truncated).
|
||||
*/
|
||||
static int getLastErrorMsg(int nBuf, char *zBuf){
|
||||
/* FormatMessage returns 0 on failure. Otherwise it
|
||||
** returns the number of TCHARs written to the output
|
||||
** buffer, excluding the terminating null char.
|
||||
*/
|
||||
DWORD error = GetLastError();
|
||||
DWORD dwLen = 0;
|
||||
char *zOut = 0;
|
||||
|
||||
if( isNT() ){
|
||||
WCHAR *zTempWide = NULL;
|
||||
dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
error,
|
||||
0,
|
||||
(LPWSTR) &zTempWide,
|
||||
0,
|
||||
0);
|
||||
if( dwLen > 0 ){
|
||||
/* allocate a buffer and convert to UTF8 */
|
||||
zOut = unicodeToUtf8(zTempWide);
|
||||
/* free the system buffer allocated by FormatMessage */
|
||||
LocalFree(zTempWide);
|
||||
}
|
||||
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
|
||||
** Since the ASCII version of these Windows API do not exist for WINCE,
|
||||
** it's important to not reference them for WINCE builds.
|
||||
*/
|
||||
#if SQLITE_OS_WINCE==0
|
||||
}else{
|
||||
char *zTemp = NULL;
|
||||
dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
error,
|
||||
0,
|
||||
(LPSTR) &zTemp,
|
||||
0,
|
||||
0);
|
||||
if( dwLen > 0 ){
|
||||
/* allocate a buffer and convert to UTF8 */
|
||||
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
|
||||
/* free the system buffer allocated by FormatMessage */
|
||||
LocalFree(zTemp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( 0 == dwLen ){
|
||||
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
|
||||
}else{
|
||||
/* copy a maximum of nBuf chars to output buffer */
|
||||
sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
|
||||
/* free the UTF8 buffer */
|
||||
free(zOut);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** This function - winLogErrorAtLine() - is only ever called via the macro
|
||||
** winLogError().
|
||||
**
|
||||
** This routine is invoked after an error occurs in an OS function.
|
||||
** It logs a message using sqlite3_log() containing the current value of
|
||||
** error code and, if possible, the human-readable equivalent from
|
||||
** FormatMessage.
|
||||
**
|
||||
** The first argument passed to the macro should be the error code that
|
||||
** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
|
||||
** The two subsequent arguments should be the name of the OS function that
|
||||
** failed and the the associated file-system path, if any.
|
||||
*/
|
||||
#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__)
|
||||
static int winLogErrorAtLine(
|
||||
int errcode, /* SQLite error code */
|
||||
const char *zFunc, /* Name of OS function that failed */
|
||||
const char *zPath, /* File path associated with error */
|
||||
int iLine /* Source line number where error occurred */
|
||||
){
|
||||
char zMsg[500]; /* Human readable error text */
|
||||
int i; /* Loop counter */
|
||||
DWORD iErrno = GetLastError(); /* Error code */
|
||||
|
||||
zMsg[0] = 0;
|
||||
getLastErrorMsg(sizeof(zMsg), zMsg);
|
||||
assert( errcode!=SQLITE_OK );
|
||||
if( zPath==0 ) zPath = "";
|
||||
for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
|
||||
zMsg[i] = 0;
|
||||
sqlite3_log(errcode,
|
||||
"os_win.c:%d: (%d) %s(%s) - %s",
|
||||
iLine, iErrno, zFunc, zPath, zMsg
|
||||
);
|
||||
|
||||
return errcode;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
/*************************************************************************
|
||||
** This section contains code for WinCE only.
|
||||
@@ -375,6 +479,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
|
||||
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
|
||||
if (!pFile->hMutex){
|
||||
pFile->lastErrno = GetLastError();
|
||||
winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
|
||||
free(zName);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -406,6 +511,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
|
||||
/* If mapping failed, close the shared memory handle and erase it */
|
||||
if (!pFile->shared){
|
||||
pFile->lastErrno = GetLastError();
|
||||
winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
|
||||
CloseHandle(pFile->hShared);
|
||||
pFile->hShared = NULL;
|
||||
}
|
||||
@@ -651,6 +757,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
|
||||
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -696,7 +803,8 @@ static int winClose(sqlite3_file *id){
|
||||
#endif
|
||||
OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
|
||||
OpenCounter(-1);
|
||||
return rc ? SQLITE_OK : SQLITE_IOERR;
|
||||
return rc ? SQLITE_OK
|
||||
: winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -722,7 +830,7 @@ static int winRead(
|
||||
}
|
||||
if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
return SQLITE_IOERR_READ;
|
||||
return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
|
||||
}
|
||||
if( nRead<(DWORD)amt ){
|
||||
/* Unread parts of the buffer must be zero-filled */
|
||||
@@ -770,10 +878,11 @@ static int winWrite(
|
||||
}
|
||||
|
||||
if( rc ){
|
||||
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
|
||||
if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
|
||||
|| ( pFile->lastErrno==ERROR_DISK_FULL )){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
return SQLITE_IOERR_WRITE;
|
||||
return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -801,10 +910,10 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
|
||||
|
||||
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
|
||||
if( seekWinFile(pFile, nByte) ){
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
|
||||
}else if( 0==SetEndOfFile(pFile->h) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
|
||||
}
|
||||
|
||||
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
|
||||
@@ -826,6 +935,7 @@ int sqlite3_fullsync_count = 0;
|
||||
static int winSync(sqlite3_file *id, int flags){
|
||||
#if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG)
|
||||
winFile *pFile = (winFile*)id;
|
||||
BOOL rc;
|
||||
#else
|
||||
UNUSED_PARAMETER(id);
|
||||
#endif
|
||||
@@ -838,20 +948,19 @@ static int winSync(sqlite3_file *id, int flags){
|
||||
|
||||
OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
|
||||
|
||||
#ifndef SQLITE_TEST
|
||||
UNUSED_PARAMETER(flags);
|
||||
#else
|
||||
if( flags & SQLITE_SYNC_FULL ){
|
||||
sqlite3_fullsync_count++;
|
||||
}
|
||||
sqlite3_sync_count++;
|
||||
#endif
|
||||
|
||||
/* Unix cannot, but some systems may return SQLITE_FULL from here. This
|
||||
** line is to test that doing so does not cause any problems.
|
||||
*/
|
||||
SimulateDiskfullError( return SQLITE_FULL );
|
||||
SimulateIOError( return SQLITE_IOERR; );
|
||||
|
||||
#ifndef SQLITE_TEST
|
||||
UNUSED_PARAMETER(flags);
|
||||
#else
|
||||
if( (flags&0x0F)==SQLITE_SYNC_FULL ){
|
||||
sqlite3_fullsync_count++;
|
||||
}
|
||||
sqlite3_sync_count++;
|
||||
#endif
|
||||
|
||||
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
|
||||
** no-op
|
||||
@@ -859,11 +968,13 @@ static int winSync(sqlite3_file *id, int flags){
|
||||
#ifdef SQLITE_NO_SYNC
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
if( FlushFileBuffers(pFile->h) ){
|
||||
rc = FlushFileBuffers(pFile->h);
|
||||
SimulateIOError( rc=FALSE );
|
||||
if( rc ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
pFile->lastErrno = GetLastError();
|
||||
return SQLITE_IOERR;
|
||||
return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -884,7 +995,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
|
||||
&& ((error = GetLastError()) != NO_ERROR) )
|
||||
{
|
||||
pFile->lastErrno = error;
|
||||
return SQLITE_IOERR_FSTAT;
|
||||
return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
|
||||
}
|
||||
*pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
|
||||
return SQLITE_OK;
|
||||
@@ -923,6 +1034,7 @@ static int getReadLock(winFile *pFile){
|
||||
}
|
||||
if( res == 0 ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
/* No need to log a failure to lock */
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -941,8 +1053,9 @@ static int unlockReadLock(winFile *pFile){
|
||||
res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
|
||||
#endif
|
||||
}
|
||||
if( res == 0 ){
|
||||
if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1143,7 +1256,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
|
||||
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
|
||||
/* This should never happen. We should always be able to
|
||||
** reacquire the read lock */
|
||||
rc = SQLITE_IOERR_UNLOCK;
|
||||
rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath);
|
||||
}
|
||||
}
|
||||
if( type>=RESERVED_LOCK ){
|
||||
@@ -1458,6 +1571,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->zFilename = (char*)&pNew[1];
|
||||
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
|
||||
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
|
||||
|
||||
/* Look to see if there is an existing winShmNode that can be used.
|
||||
** If no matching winShmNode currently exists, create a new one.
|
||||
@@ -1500,7 +1614,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
|
||||
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = SQLITE_IOERR_SHMOPEN;
|
||||
rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -1759,7 +1873,7 @@ static int winShmMap(
|
||||
*/
|
||||
rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = SQLITE_IOERR_SHMSIZE;
|
||||
rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath);
|
||||
goto shmpage_out;
|
||||
}
|
||||
|
||||
@@ -1773,7 +1887,7 @@ static int winShmMap(
|
||||
if( !isWrite ) goto shmpage_out;
|
||||
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
|
||||
if( rc!=SQLITE_OK ){
|
||||
rc = SQLITE_IOERR_SHMSIZE;
|
||||
rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath);
|
||||
goto shmpage_out;
|
||||
}
|
||||
}
|
||||
@@ -1810,7 +1924,7 @@ static int winShmMap(
|
||||
}
|
||||
if( !pMap ){
|
||||
pShmNode->lastErrno = GetLastError();
|
||||
rc = SQLITE_IOERR;
|
||||
rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
|
||||
if( hMap ) CloseHandle(hMap);
|
||||
goto shmpage_out;
|
||||
}
|
||||
@@ -1892,7 +2006,7 @@ static void *convertUtf8Filename(const char *zFilename){
|
||||
*/
|
||||
#if SQLITE_OS_WINCE==0
|
||||
}else{
|
||||
zConverted = utf8ToMbcs(zFilename);
|
||||
zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
|
||||
#endif
|
||||
}
|
||||
/* caller will handle out of memory */
|
||||
@@ -1972,68 +2086,6 @@ static int getTempname(int nBuf, char *zBuf){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The return value of getLastErrorMsg
|
||||
** is zero if the error message fits in the buffer, or non-zero
|
||||
** otherwise (if the message was truncated).
|
||||
*/
|
||||
static int getLastErrorMsg(int nBuf, char *zBuf){
|
||||
/* FormatMessage returns 0 on failure. Otherwise it
|
||||
** returns the number of TCHARs written to the output
|
||||
** buffer, excluding the terminating null char.
|
||||
*/
|
||||
DWORD error = GetLastError();
|
||||
DWORD dwLen = 0;
|
||||
char *zOut = 0;
|
||||
|
||||
if( isNT() ){
|
||||
WCHAR *zTempWide = NULL;
|
||||
dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
error,
|
||||
0,
|
||||
(LPWSTR) &zTempWide,
|
||||
0,
|
||||
0);
|
||||
if( dwLen > 0 ){
|
||||
/* allocate a buffer and convert to UTF8 */
|
||||
zOut = unicodeToUtf8(zTempWide);
|
||||
/* free the system buffer allocated by FormatMessage */
|
||||
LocalFree(zTempWide);
|
||||
}
|
||||
/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed.
|
||||
** Since the ASCII version of these Windows API do not exist for WINCE,
|
||||
** it's important to not reference them for WINCE builds.
|
||||
*/
|
||||
#if SQLITE_OS_WINCE==0
|
||||
}else{
|
||||
char *zTemp = NULL;
|
||||
dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
error,
|
||||
0,
|
||||
(LPSTR) &zTemp,
|
||||
0,
|
||||
0);
|
||||
if( dwLen > 0 ){
|
||||
/* allocate a buffer and convert to UTF8 */
|
||||
zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
|
||||
/* free the system buffer allocated by FormatMessage */
|
||||
LocalFree(zTemp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if( 0 == dwLen ){
|
||||
sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
|
||||
}else{
|
||||
/* copy a maximum of nBuf chars to output buffer */
|
||||
sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
|
||||
/* free the UTF8 buffer */
|
||||
free(zOut);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a file.
|
||||
*/
|
||||
@@ -2205,6 +2257,7 @@ static int winOpen(
|
||||
|
||||
if( h==INVALID_HANDLE_VALUE ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
|
||||
free(zConverted);
|
||||
if( isReadWrite ){
|
||||
return winOpen(pVfs, zName, id,
|
||||
@@ -2308,7 +2361,8 @@ static int winDelete(
|
||||
"ok" : "failed" ));
|
||||
|
||||
return ( (rc == INVALID_FILE_ATTRIBUTES)
|
||||
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
|
||||
&& (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK :
|
||||
winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2348,6 +2402,7 @@ static int winAccess(
|
||||
}
|
||||
}else{
|
||||
if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
|
||||
winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
|
||||
free(zConverted);
|
||||
return SQLITE_IOERR_ACCESS;
|
||||
}else{
|
||||
@@ -2412,6 +2467,13 @@ static int winFullPathname(
|
||||
void *zConverted;
|
||||
char *zOut;
|
||||
|
||||
/* If this path name begins with "/X:", where "X" is any alphabetic
|
||||
** character, discard the initial "/" from the pathname.
|
||||
*/
|
||||
if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
|
||||
zRelative++;
|
||||
}
|
||||
|
||||
/* It's odd to simulate an io-error here, but really this is just
|
||||
** using the io-error infrastructure to test that SQLite handles this
|
||||
** function failing. This function could fail if, for example, the
|
||||
|
||||
+28
-4
@@ -4299,6 +4299,8 @@ int sqlite3PagerOpen(
|
||||
int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */
|
||||
int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */
|
||||
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
|
||||
const char *zUri = 0; /* URI args to copy */
|
||||
int nUri = 0; /* Number of bytes of URI args at *zUri */
|
||||
|
||||
/* Figure out how much space is required for each journal file-handle
|
||||
** (there are two of them, the main journal and the sub-journal). This
|
||||
@@ -4329,6 +4331,7 @@ int sqlite3PagerOpen(
|
||||
** leave both nPathname and zPathname set to 0.
|
||||
*/
|
||||
if( zFilename && zFilename[0] ){
|
||||
const char *z;
|
||||
nPathname = pVfs->mxPathname+1;
|
||||
zPathname = sqlite3Malloc(nPathname*2);
|
||||
if( zPathname==0 ){
|
||||
@@ -4337,6 +4340,12 @@ int sqlite3PagerOpen(
|
||||
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
|
||||
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
|
||||
nPathname = sqlite3Strlen30(zPathname);
|
||||
z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
|
||||
while( *z ){
|
||||
z += sqlite3Strlen30(z)+1;
|
||||
z += sqlite3Strlen30(z)+1;
|
||||
}
|
||||
nUri = &z[1] - zUri;
|
||||
if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
|
||||
/* This branch is taken when the journal path required by
|
||||
** the database being opened will be more than pVfs->mxPathname
|
||||
@@ -4369,7 +4378,7 @@ int sqlite3PagerOpen(
|
||||
ROUND8(pcacheSize) + /* PCache object */
|
||||
ROUND8(pVfs->szOsFile) + /* The main db file */
|
||||
journalFileSize * 2 + /* The two journal files */
|
||||
nPathname + 1 + /* zFilename */
|
||||
nPathname + 1 + nUri + /* zFilename */
|
||||
nPathname + 8 + 1 /* zJournal */
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
+ nPathname + 4 + 1 /* zWal */
|
||||
@@ -4391,14 +4400,17 @@ int sqlite3PagerOpen(
|
||||
/* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
|
||||
if( zPathname ){
|
||||
assert( nPathname>0 );
|
||||
pPager->zJournal = (char*)(pPtr += nPathname + 1);
|
||||
pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
|
||||
memcpy(pPager->zFilename, zPathname, nPathname);
|
||||
memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
|
||||
memcpy(pPager->zJournal, zPathname, nPathname);
|
||||
memcpy(&pPager->zJournal[nPathname], "-journal", 8);
|
||||
sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
pPager->zWal = &pPager->zJournal[nPathname+8+1];
|
||||
memcpy(pPager->zWal, zPathname, nPathname);
|
||||
memcpy(&pPager->zWal[nPathname], "-wal", 4);
|
||||
sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
|
||||
#endif
|
||||
sqlite3_free(zPathname);
|
||||
}
|
||||
@@ -5735,11 +5747,21 @@ int sqlite3PagerCommitPhaseOne(
|
||||
}else{
|
||||
if( pagerUseWal(pPager) ){
|
||||
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
|
||||
if( pList ){
|
||||
PgHdr *pPageOne = 0;
|
||||
if( pList==0 ){
|
||||
/* Must have at least one page for the WAL commit flag.
|
||||
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
|
||||
rc = sqlite3PagerGet(pPager, 1, &pPageOne);
|
||||
pList = pPageOne;
|
||||
pList->pDirty = 0;
|
||||
}
|
||||
assert( rc==SQLITE_OK );
|
||||
if( ALWAYS(pList) ){
|
||||
rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1,
|
||||
(pPager->fullSync ? pPager->syncFlags : 0)
|
||||
);
|
||||
}
|
||||
sqlite3PagerUnref(pPageOne);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3PcacheCleanAll(pPager->pPCache);
|
||||
}
|
||||
@@ -6597,6 +6619,7 @@ int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
|
||||
i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
|
||||
if( iLimit>=-1 ){
|
||||
pPager->journalSizeLimit = iLimit;
|
||||
sqlite3WalLimit(pPager->pWal, iLimit);
|
||||
}
|
||||
return pPager->journalSizeLimit;
|
||||
}
|
||||
@@ -6688,7 +6711,8 @@ static int pagerOpenWal(Pager *pPager){
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3WalOpen(pPager->pVfs,
|
||||
pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal
|
||||
pPager->fd, pPager->zWal, pPager->exclusiveMode,
|
||||
pPager->journalSizeLimit, &pPager->pWal
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,13 @@ int sqlite3PcacheFetch(
|
||||
}
|
||||
if( pPg ){
|
||||
int rc;
|
||||
#ifdef SQLITE_LOG_CACHE_SPILL
|
||||
sqlite3_log(SQLITE_FULL,
|
||||
"spill page %d making room for %d - cache used: %d/%d",
|
||||
pPg->pgno, pgno,
|
||||
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
|
||||
pCache->nMax);
|
||||
#endif
|
||||
rc = pCache->xStress(pCache->pStress, pPg);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
|
||||
return rc;
|
||||
|
||||
+1
-1
@@ -574,7 +574,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
|
||||
pGroup = (PGroup*)&pCache[1];
|
||||
pGroup->mxPinned = 10;
|
||||
}else{
|
||||
pGroup = &pcache1_g.grp;
|
||||
pGroup = &pcache1.grp;
|
||||
}
|
||||
pCache->pGroup = pGroup;
|
||||
pCache->szPage = szPage;
|
||||
|
||||
+11
-9
@@ -13,10 +13,6 @@
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/* Ignore this whole file if pragmas are disabled
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_PRAGMA)
|
||||
|
||||
/*
|
||||
** Interpret the given string as a safety level. Return 0 for OFF,
|
||||
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
||||
@@ -49,10 +45,16 @@ static u8 getSafetyLevel(const char *z){
|
||||
/*
|
||||
** Interpret the given string as a boolean value.
|
||||
*/
|
||||
static u8 getBoolean(const char *z){
|
||||
u8 sqlite3GetBoolean(const char *z){
|
||||
return getSafetyLevel(z)&1;
|
||||
}
|
||||
|
||||
/* The sqlite3GetBoolean() function is used by other modules but the
|
||||
** remainder of this file is specific to PRAGMA processing. So omit
|
||||
** the rest of the file if PRAGMAs are omitted from the build.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_PRAGMA)
|
||||
|
||||
/*
|
||||
** Interpret the given string as a locking mode value.
|
||||
*/
|
||||
@@ -219,7 +221,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
mask &= ~(SQLITE_ForeignKeys);
|
||||
}
|
||||
|
||||
if( getBoolean(zRight) ){
|
||||
if( sqlite3GetBoolean(zRight) ){
|
||||
db->flags |= mask;
|
||||
}else{
|
||||
db->flags &= ~mask;
|
||||
@@ -433,7 +435,7 @@ void sqlite3Pragma(
|
||||
int b = -1;
|
||||
assert( pBt!=0 );
|
||||
if( zRight ){
|
||||
b = getBoolean(zRight);
|
||||
b = sqlite3GetBoolean(zRight);
|
||||
}
|
||||
if( pId2->n==0 && b>=0 ){
|
||||
int ii;
|
||||
@@ -1033,7 +1035,7 @@ void sqlite3Pragma(
|
||||
#ifndef NDEBUG
|
||||
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
|
||||
if( zRight ){
|
||||
if( getBoolean(zRight) ){
|
||||
if( sqlite3GetBoolean(zRight) ){
|
||||
sqlite3ParserTrace(stderr, "parser: ");
|
||||
}else{
|
||||
sqlite3ParserTrace(0, 0);
|
||||
@@ -1047,7 +1049,7 @@ void sqlite3Pragma(
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
|
||||
if( zRight ){
|
||||
sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
|
||||
sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
|
||||
}
|
||||
}else
|
||||
|
||||
|
||||
+3
-1
@@ -4239,11 +4239,13 @@ int sqlite3Select(
|
||||
** and pKeyInfo to the KeyInfo structure required to navigate the
|
||||
** index.
|
||||
**
|
||||
** (2011-04-15) Do not do a full scan of an unordered index.
|
||||
**
|
||||
** In practice the KeyInfo structure will not be used. It is only
|
||||
** passed to keep OP_OpenRead happy.
|
||||
*/
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( !pBest || pIdx->nColumn<pBest->nColumn ){
|
||||
if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
|
||||
pBest = pIdx;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-3
@@ -2302,6 +2302,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
enableTimer = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
|
||||
printf("SQLite %s %s\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid());
|
||||
}else
|
||||
|
||||
if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
|
||||
int j;
|
||||
assert( nArg<=ArraySize(azArg) );
|
||||
@@ -2649,6 +2654,7 @@ static void main_init(struct callback_data *data) {
|
||||
data->mode = MODE_List;
|
||||
memcpy(data->separator,"|", 2);
|
||||
data->showHeader = 0;
|
||||
sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
|
||||
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
|
||||
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
|
||||
@@ -2663,6 +2669,11 @@ int main(int argc, char **argv){
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
|
||||
fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
|
||||
sqlite3_sourceid(), SQLITE_SOURCE_ID);
|
||||
exit(1);
|
||||
}
|
||||
Argv0 = argv[0];
|
||||
main_init(&data);
|
||||
stdin_is_interactive = isatty(0);
|
||||
@@ -2830,7 +2841,7 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-bail")==0 ){
|
||||
bail_on_error = 1;
|
||||
}else if( strcmp(z,"-version")==0 ){
|
||||
printf("%s\n", sqlite3_libversion());
|
||||
printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
|
||||
return 0;
|
||||
}else if( strcmp(z,"-interactive")==0 ){
|
||||
stdin_is_interactive = 1;
|
||||
@@ -2875,10 +2886,10 @@ int main(int argc, char **argv){
|
||||
char *zHistory = 0;
|
||||
int nHistory;
|
||||
printf(
|
||||
"SQLite version %s\n"
|
||||
"SQLite version %s %.19s\n"
|
||||
"Enter \".help\" for instructions\n"
|
||||
"Enter SQL statements terminated with a \";\"\n",
|
||||
sqlite3_libversion()
|
||||
sqlite3_libversion(), sqlite3_sourceid()
|
||||
);
|
||||
zHome = find_home_dir();
|
||||
if( zHome ){
|
||||
|
||||
+350
-83
@@ -305,7 +305,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** argument. ^If the callback function of the 3rd argument to
|
||||
** sqlite3_exec() is not NULL, then it is invoked for each result row
|
||||
** coming out of the evaluated SQL statements. ^The 4th argument to
|
||||
** to sqlite3_exec() is relayed through to the 1st argument of each
|
||||
** sqlite3_exec() is relayed through to the 1st argument of each
|
||||
** callback invocation. ^If the callback pointer to sqlite3_exec()
|
||||
** is NULL, then no callback is ever invoked and result rows are
|
||||
** ignored.
|
||||
@@ -370,7 +370,8 @@ int sqlite3_exec(
|
||||
**
|
||||
** New error codes may be added in future versions of SQLite.
|
||||
**
|
||||
** See also: [SQLITE_IOERR_READ | extended result codes]
|
||||
** See also: [SQLITE_IOERR_READ | extended result codes],
|
||||
** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
|
||||
*/
|
||||
#define SQLITE_OK 0 /* Successful result */
|
||||
/* beginning-of-error-codes */
|
||||
@@ -447,17 +448,21 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
|
||||
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
|
||||
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
|
||||
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
|
||||
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
**
|
||||
** These bit values are intended for use in the
|
||||
** 3rd parameter to the [sqlite3_open_v2()] interface and
|
||||
** in the 4th parameter to the xOpen method of the
|
||||
** [sqlite3_vfs] object.
|
||||
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
|
||||
*/
|
||||
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||
@@ -465,6 +470,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
|
||||
#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
|
||||
#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
|
||||
#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */
|
||||
#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
|
||||
#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
|
||||
#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
|
||||
@@ -575,17 +581,18 @@ struct sqlite3_file {
|
||||
/*
|
||||
** CAPI3REF: OS Interface File Virtual Methods Object
|
||||
**
|
||||
** Every file opened by the [sqlite3_vfs] xOpen method populates an
|
||||
** Every file opened by the [sqlite3_vfs.xOpen] method populates an
|
||||
** [sqlite3_file] object (or, more commonly, a subclass of the
|
||||
** [sqlite3_file] object) with a pointer to an instance of this object.
|
||||
** This object defines the methods used to perform various operations
|
||||
** against the open file represented by the [sqlite3_file] object.
|
||||
**
|
||||
** If the xOpen method sets the sqlite3_file.pMethods element
|
||||
** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
|
||||
** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
|
||||
** may be invoked even if the xOpen reported that it failed. The
|
||||
** only way to prevent a call to xClose following a failed xOpen
|
||||
** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
|
||||
** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The
|
||||
** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
|
||||
** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element
|
||||
** to NULL.
|
||||
**
|
||||
** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
|
||||
** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
|
||||
@@ -757,7 +764,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
**
|
||||
** An instance of the sqlite3_vfs object defines the interface between
|
||||
** the SQLite core and the underlying operating system. The "vfs"
|
||||
** in the name of the object stands for "virtual file system".
|
||||
** in the name of the object stands for "virtual file system". See
|
||||
** the [VFS | VFS documentation] for further information.
|
||||
**
|
||||
** The value of the iVersion field is initially 1 but may be larger in
|
||||
** future versions of SQLite. Additional fields may be appended to this
|
||||
@@ -786,6 +794,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
** The zName field holds the name of the VFS module. The name must
|
||||
** be unique across all VFS modules.
|
||||
**
|
||||
** [[sqlite3_vfs.xOpen]]
|
||||
** ^SQLite guarantees that the zFilename parameter to xOpen
|
||||
** is either a NULL pointer or string obtained
|
||||
** from xFullPathname() with an optional suffix added.
|
||||
@@ -863,6 +872,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
** element will be valid after xOpen returns regardless of the success
|
||||
** or failure of the xOpen call.
|
||||
**
|
||||
** [[sqlite3_vfs.xAccess]]
|
||||
** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
|
||||
** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
|
||||
** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
|
||||
@@ -887,7 +897,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
** method returns a Julian Day Number for the current date and time as
|
||||
** a floating point value.
|
||||
** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
|
||||
** Day Number multipled by 86400000 (the number of milliseconds in
|
||||
** Day Number multiplied by 86400000 (the number of milliseconds in
|
||||
** a 24-hour day).
|
||||
** ^SQLite will use the xCurrentTimeInt64() method to get the current
|
||||
** date and time if that method is available (if iVersion is 2 or
|
||||
@@ -1109,9 +1119,9 @@ int sqlite3_os_end(void);
|
||||
** implementation of an application-defined [sqlite3_os_init()].
|
||||
**
|
||||
** The first argument to sqlite3_config() is an integer
|
||||
** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines
|
||||
** [configuration option] that determines
|
||||
** what property of SQLite is to be configured. Subsequent arguments
|
||||
** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option]
|
||||
** vary depending on the [configuration option]
|
||||
** in the first argument.
|
||||
**
|
||||
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
|
||||
@@ -1221,6 +1231,7 @@ struct sqlite3_mem_methods {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Configuration Options
|
||||
** KEYWORDS: {configuration option}
|
||||
**
|
||||
** These constants are the available integer configuration options that
|
||||
** can be passed as the first argument to the [sqlite3_config()] interface.
|
||||
@@ -1233,7 +1244,7 @@ struct sqlite3_mem_methods {
|
||||
** is invoked.
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
|
||||
** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
|
||||
** <dd>There are no arguments to this option. ^This option sets the
|
||||
** [threading mode] to Single-thread. In other words, it disables
|
||||
** all mutexing and puts SQLite into a mode where it can only be used
|
||||
@@ -1244,7 +1255,7 @@ struct sqlite3_mem_methods {
|
||||
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
|
||||
** configuration option.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_MULTITHREAD</dt>
|
||||
** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt>
|
||||
** <dd>There are no arguments to this option. ^This option sets the
|
||||
** [threading mode] to Multi-thread. In other words, it disables
|
||||
** mutexing on [database connection] and [prepared statement] objects.
|
||||
@@ -1258,7 +1269,7 @@ struct sqlite3_mem_methods {
|
||||
** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
|
||||
** SQLITE_CONFIG_MULTITHREAD configuration option.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_SERIALIZED</dt>
|
||||
** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt>
|
||||
** <dd>There are no arguments to this option. ^This option sets the
|
||||
** [threading mode] to Serialized. In other words, this option enables
|
||||
** all mutexes including the recursive
|
||||
@@ -1274,7 +1285,7 @@ struct sqlite3_mem_methods {
|
||||
** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
|
||||
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_MALLOC</dt>
|
||||
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** instance of the [sqlite3_mem_methods] structure. The argument specifies
|
||||
** alternative low-level memory allocation routines to be used in place of
|
||||
@@ -1282,7 +1293,7 @@ struct sqlite3_mem_methods {
|
||||
** its own private copy of the content of the [sqlite3_mem_methods] structure
|
||||
** before the [sqlite3_config()] call returns.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_GETMALLOC</dt>
|
||||
** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods]
|
||||
** structure is filled with the currently defined memory allocation routines.)^
|
||||
@@ -1290,7 +1301,7 @@ struct sqlite3_mem_methods {
|
||||
** routines with a wrapper that simulations memory allocation failure or
|
||||
** tracks memory usage, for example. </dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_MEMSTATUS</dt>
|
||||
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
|
||||
** <dd> ^This option takes single argument of type int, interpreted as a
|
||||
** boolean, which enables or disables the collection of memory allocation
|
||||
** statistics. ^(When memory allocation statistics are disabled, the
|
||||
@@ -1306,7 +1317,7 @@ struct sqlite3_mem_methods {
|
||||
** allocation statistics are disabled by default.
|
||||
** </dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_SCRATCH</dt>
|
||||
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
|
||||
** <dd> ^This option specifies a static memory buffer that SQLite can use for
|
||||
** scratch memory. There are three arguments: A pointer an 8-byte
|
||||
** aligned memory buffer from which the scratch allocations will be
|
||||
@@ -1322,9 +1333,9 @@ struct sqlite3_mem_methods {
|
||||
** scratch memory beyond what is provided by this configuration option, then
|
||||
** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_PAGECACHE</dt>
|
||||
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
|
||||
** <dd> ^This option specifies a static memory buffer that SQLite can use for
|
||||
** the database page cache with the default page cache implemenation.
|
||||
** the database page cache with the default page cache implementation.
|
||||
** This configuration should not be used if an application-define page
|
||||
** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
|
||||
** There are three arguments to this option: A pointer to 8-byte aligned
|
||||
@@ -1343,7 +1354,7 @@ struct sqlite3_mem_methods {
|
||||
** be aligned to an 8-byte boundary or subsequent behavior of SQLite
|
||||
** will be undefined.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_HEAP</dt>
|
||||
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
|
||||
** <dd> ^This option specifies a static memory buffer that SQLite will use
|
||||
** for all of its dynamic memory allocation needs beyond those provided
|
||||
** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
|
||||
@@ -1360,7 +1371,7 @@ struct sqlite3_mem_methods {
|
||||
** The minimum allocation size is capped at 2^12. Reasonable values
|
||||
** for the minimum allocation size are 2^5 through 2^8.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_MUTEX</dt>
|
||||
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
|
||||
** alternative low-level mutex routines to be used in place
|
||||
@@ -1372,7 +1383,7 @@ struct sqlite3_mem_methods {
|
||||
** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
|
||||
** return [SQLITE_ERROR].</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_GETMUTEX</dt>
|
||||
** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** instance of the [sqlite3_mutex_methods] structure. The
|
||||
** [sqlite3_mutex_methods]
|
||||
@@ -1385,7 +1396,7 @@ struct sqlite3_mem_methods {
|
||||
** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
|
||||
** return [SQLITE_ERROR].</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_LOOKASIDE</dt>
|
||||
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
|
||||
** <dd> ^(This option takes two arguments that determine the default
|
||||
** memory allocation for the lookaside memory allocator on each
|
||||
** [database connection]. The first argument is the
|
||||
@@ -1395,18 +1406,18 @@ struct sqlite3_mem_methods {
|
||||
** verb to [sqlite3_db_config()] can be used to change the lookaside
|
||||
** configuration on individual connections.)^ </dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_PCACHE</dt>
|
||||
** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to
|
||||
** an [sqlite3_pcache_methods] object. This object specifies the interface
|
||||
** to a custom page cache implementation.)^ ^SQLite makes a copy of the
|
||||
** object and uses it for page cache memory allocations.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_GETPCACHE</dt>
|
||||
** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
** [sqlite3_pcache_methods] object. SQLite copies of the current
|
||||
** page cache implementation into that object.)^ </dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_LOG</dt>
|
||||
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
|
||||
** function with a call signature of void(*)(void*,int,const char*),
|
||||
** and a pointer to void. ^If the function pointer is not NULL, it is
|
||||
@@ -1424,6 +1435,18 @@ struct sqlite3_mem_methods {
|
||||
** In a multi-threaded application, the application-defined logger
|
||||
** function must be threadsafe. </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
|
||||
** <dd> This option takes a single argument of type int. If non-zero, then
|
||||
** URI handling is globally enabled. If the parameter is zero, then URI handling
|
||||
** is globally disabled. If URI handling is globally enabled, all filenames
|
||||
** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
|
||||
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
|
||||
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
|
||||
** connection is opened. If it is globally disabled, filenames are
|
||||
** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
|
||||
** database connection is opened. By default, URI handling is globally
|
||||
** disabled. The default value may be changed by compiling with the
|
||||
** [SQLITE_USE_URI] symbol defined.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
@@ -1442,6 +1465,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */
|
||||
#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */
|
||||
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
|
||||
#define SQLITE_CONFIG_URI 17 /* int */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
@@ -1527,13 +1551,17 @@ int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||
**
|
||||
** ^This routine returns the [rowid] of the most recent
|
||||
** successful [INSERT] into the database from the [database connection]
|
||||
** in the first argument. ^If no successful [INSERT]s
|
||||
** in the first argument. ^As of SQLite version 3.7.7, this routines
|
||||
** records the last insert rowid of both ordinary tables and [virtual tables].
|
||||
** ^If no successful [INSERT]s
|
||||
** have ever occurred on that database connection, zero is returned.
|
||||
**
|
||||
** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted
|
||||
** row is returned by this routine as long as the trigger is running.
|
||||
** But once the trigger terminates, the value returned by this routine
|
||||
** reverts to the last value inserted before the trigger fired.)^
|
||||
** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
|
||||
** method, then this routine will return the [rowid] of the inserted
|
||||
** row as long as the trigger or virtual table method is running.
|
||||
** But once the trigger or virtual table method ends, the value returned
|
||||
** by this routine reverts to what it was before the trigger or virtual
|
||||
** table method began.)^
|
||||
**
|
||||
** ^An [INSERT] that fails due to a constraint violation is not a
|
||||
** successful [INSERT] and does not change the value returned by this
|
||||
@@ -2196,6 +2224,9 @@ int sqlite3_set_authorizer(
|
||||
** to signal SQLite whether or not the action is permitted. See the
|
||||
** [sqlite3_set_authorizer | authorizer documentation] for additional
|
||||
** information.
|
||||
**
|
||||
** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
|
||||
** from the [sqlite3_vtab_on_conflict()] interface.
|
||||
*/
|
||||
#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
|
||||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||
@@ -2318,7 +2349,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
/*
|
||||
** CAPI3REF: Opening A New Database Connection
|
||||
**
|
||||
** ^These routines open an SQLite database file whose name is given by the
|
||||
** ^These routines open an SQLite database file as specified by the
|
||||
** filename argument. ^The filename argument is interpreted as UTF-8 for
|
||||
** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
|
||||
** order for sqlite3_open16(). ^(A [database connection] handle is usually
|
||||
@@ -2345,7 +2376,7 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** sqlite3_open_v2() can take one of
|
||||
** the following three values, optionally combined with the
|
||||
** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
|
||||
** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^
|
||||
** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
|
||||
**
|
||||
** <dl>
|
||||
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
|
||||
@@ -2364,9 +2395,8 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** </dl>
|
||||
**
|
||||
** If the 3rd parameter to sqlite3_open_v2() is not one of the
|
||||
** combinations shown above or one of the combinations shown above combined
|
||||
** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
|
||||
** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
|
||||
** combinations shown above optionally combined with other
|
||||
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
|
||||
** then the behavior is undefined.
|
||||
**
|
||||
** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
|
||||
@@ -2381,6 +2411,11 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
|
||||
** participate in [shared cache mode] even if it is enabled.
|
||||
**
|
||||
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
||||
** [sqlite3_vfs] object that defines the operating system interface that
|
||||
** the new database connection should use. ^If the fourth parameter is
|
||||
** a NULL pointer then the default [sqlite3_vfs] object is used.
|
||||
**
|
||||
** ^If the filename is ":memory:", then a private, temporary in-memory database
|
||||
** is created for the connection. ^This in-memory database will vanish when
|
||||
** the database connection is closed. Future versions of SQLite might
|
||||
@@ -2393,10 +2428,111 @@ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** on-disk database will be created. ^This private database will be
|
||||
** automatically deleted as soon as the database connection is closed.
|
||||
**
|
||||
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
||||
** [sqlite3_vfs] object that defines the operating system interface that
|
||||
** the new database connection should use. ^If the fourth parameter is
|
||||
** a NULL pointer then the default [sqlite3_vfs] object is used.
|
||||
** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3>
|
||||
**
|
||||
** ^If [URI filename] interpretation is enabled, and the filename argument
|
||||
** begins with "file:", then the filename is interpreted as a URI. ^URI
|
||||
** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
|
||||
** set in the fourth argument to sqlite3_open_v2(), or if it has
|
||||
** been enabled globally using the [SQLITE_CONFIG_URI] option with the
|
||||
** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
|
||||
** As of SQLite version 3.7.7, URI filename interpretation is turned off
|
||||
** by default, but future releases of SQLite might enable URI filename
|
||||
** interpretation by default. See "[URI filenames]" for additional
|
||||
** information.
|
||||
**
|
||||
** URI filenames are parsed according to RFC 3986. ^If the URI contains an
|
||||
** authority, then it must be either an empty string or the string
|
||||
** "localhost". ^If the authority is not an empty string or "localhost", an
|
||||
** error is returned to the caller. ^The fragment component of a URI, if
|
||||
** present, is ignored.
|
||||
**
|
||||
** ^SQLite uses the path component of the URI as the name of the disk file
|
||||
** which contains the database. ^If the path begins with a '/' character,
|
||||
** then it is interpreted as an absolute path. ^If the path does not begin
|
||||
** with a '/' (meaning that the authority section is omitted from the URI)
|
||||
** then the path is interpreted as a relative path.
|
||||
** ^On windows, the first component of an absolute path
|
||||
** is a drive specification (e.g. "C:").
|
||||
**
|
||||
** [[core URI query parameters]]
|
||||
** The query component of a URI may contain parameters that are interpreted
|
||||
** either by SQLite itself, or by a [VFS | custom VFS implementation].
|
||||
** SQLite interprets the following three query parameters:
|
||||
**
|
||||
** <ul>
|
||||
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
|
||||
** a VFS object that provides the operating system interface that should
|
||||
** be used to access the database file on disk. ^If this option is set to
|
||||
** an empty string the default VFS object is used. ^Specifying an unknown
|
||||
** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
|
||||
** present, then the VFS specified by the option takes precedence over
|
||||
** the value passed as the fourth parameter to sqlite3_open_v2().
|
||||
**
|
||||
** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or
|
||||
** "rwc". Attempting to set it to any other value is an error)^.
|
||||
** ^If "ro" is specified, then the database is opened for read-only
|
||||
** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
|
||||
** third argument to sqlite3_prepare_v2(). ^If the mode option is set to
|
||||
** "rw", then the database is opened for read-write (but not create)
|
||||
** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
|
||||
** been set. ^Value "rwc" is equivalent to setting both
|
||||
** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is
|
||||
** used, it is an error to specify a value for the mode parameter that is
|
||||
** less restrictive than that specified by the flags passed as the third
|
||||
** parameter.
|
||||
**
|
||||
** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
|
||||
** "private". ^Setting it to "shared" is equivalent to setting the
|
||||
** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
|
||||
** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
|
||||
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
|
||||
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
|
||||
** a URI filename, its value overrides any behaviour requested by setting
|
||||
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
||||
** </ul>
|
||||
**
|
||||
** ^Specifying an unknown parameter in the query component of a URI is not an
|
||||
** error. Future versions of SQLite might understand additional query
|
||||
** parameters. See "[query parameters with special meaning to SQLite]" for
|
||||
** additional information.
|
||||
**
|
||||
** [[URI filename examples]] <h3>URI filename examples</h3>
|
||||
**
|
||||
** <table border="1" align=center cellpadding=5>
|
||||
** <tr><th> URI filenames <th> Results
|
||||
** <tr><td> file:data.db <td>
|
||||
** Open the file "data.db" in the current directory.
|
||||
** <tr><td> file:/home/fred/data.db<br>
|
||||
** file:///home/fred/data.db <br>
|
||||
** file://localhost/home/fred/data.db <br> <td>
|
||||
** Open the database file "/home/fred/data.db".
|
||||
** <tr><td> file://darkstar/home/fred/data.db <td>
|
||||
** An error. "darkstar" is not a recognized authority.
|
||||
** <tr><td style="white-space:nowrap">
|
||||
** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
|
||||
** <td> Windows only: Open the file "data.db" on fred's desktop on drive
|
||||
** C:. Note that the %20 escaping in this example is not strictly
|
||||
** necessary - space characters can be used literally
|
||||
** in URI filenames.
|
||||
** <tr><td> file:data.db?mode=ro&cache=private <td>
|
||||
** Open file "data.db" in the current directory for read-only access.
|
||||
** Regardless of whether or not shared-cache mode is enabled by
|
||||
** default, use a private cache.
|
||||
** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
|
||||
** Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
|
||||
** <tr><td> file:data.db?mode=readonly <td>
|
||||
** An error. "readonly" is not a valid option for the "mode" parameter.
|
||||
** </table>
|
||||
**
|
||||
** ^URI hexadecimal escape sequences (%HH) are supported within the path and
|
||||
** query components of a URI. A hexadecimal escape sequence consists of a
|
||||
** percent sign - "%" - followed by exactly two hexadecimal digits
|
||||
** specifying an octet value. ^Before the path or query components of a
|
||||
** URI filename are interpreted, they are encoded using UTF-8 and all
|
||||
** hexadecimal escape sequences replaced by a single byte containing the
|
||||
** corresponding octet. If this process generates an invalid UTF-8 encoding,
|
||||
** the results are undefined.
|
||||
**
|
||||
** <b>Note to Windows users:</b> The encoding used for the filename argument
|
||||
** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
|
||||
@@ -2419,6 +2555,26 @@ int sqlite3_open_v2(
|
||||
const char *zVfs /* Name of VFS module to use */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Obtain Values For URI Parameters
|
||||
**
|
||||
** This is a utility routine, useful to VFS implementations, that checks
|
||||
** to see if a database file was a URI that contained a specific query
|
||||
** parameter, and if so obtains the value of the query parameter.
|
||||
**
|
||||
** The zFilename argument is the filename pointer passed into the xOpen()
|
||||
** method of a VFS implementation. The zParam argument is the name of the
|
||||
** query parameter we seek. This routine returns the value of the zParam
|
||||
** parameter if it exists. If the parameter does not exist, this routine
|
||||
** returns a NULL pointer.
|
||||
**
|
||||
** If the zFilename argument to this function is not a pointer that SQLite
|
||||
** passed into the xOpen VFS method, then the behavior of this routine
|
||||
** is undefined and probably undesirable.
|
||||
*/
|
||||
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
|
||||
|
||||
|
||||
/*
|
||||
** CAPI3REF: Error Codes And Messages
|
||||
**
|
||||
@@ -2534,43 +2690,45 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** Additional information is available at [limits | Limits in SQLite].
|
||||
**
|
||||
** <dl>
|
||||
** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
|
||||
** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt>
|
||||
** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
|
||||
** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
|
||||
** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_COLUMN</dt>
|
||||
** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt>
|
||||
** <dd>The maximum number of columns in a table definition or in the
|
||||
** result set of a [SELECT] or the maximum number of columns in an index
|
||||
** or in an ORDER BY or GROUP BY clause.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
|
||||
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
|
||||
** <dd>The maximum depth of the parse tree on any expression.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
|
||||
** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
|
||||
** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
|
||||
** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
|
||||
** <dd>The maximum number of instructions in a virtual machine program
|
||||
** used to implement an SQL statement. This limit is not currently
|
||||
** enforced, though that might be added in some future release of
|
||||
** SQLite.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
|
||||
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
|
||||
** <dd>The maximum number of arguments on a function.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
|
||||
** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
|
||||
** <dd>The maximum number of [ATTACH | attached databases].)^</dd>
|
||||
**
|
||||
** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]]
|
||||
** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt>
|
||||
** <dd>The maximum length of the pattern argument to the [LIKE] or
|
||||
** [GLOB] operators.</dd>)^
|
||||
**
|
||||
** [[SQLITE_LIMIT_VARIABLE_NUMBER]]
|
||||
** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
|
||||
** <dd>The maximum index number of any [parameter] in an SQL statement.)^
|
||||
**
|
||||
** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
|
||||
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
|
||||
** <dd>The maximum depth of recursion for triggers.</dd>)^
|
||||
** </dl>
|
||||
*/
|
||||
@@ -3099,7 +3257,7 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
||||
** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
|
||||
** database locks it needs to do its job. ^If the statement is a [COMMIT]
|
||||
** or occurs outside of an explicit transaction, then you can retry the
|
||||
** statement. If the statement is not a [COMMIT] and occurs within a
|
||||
** statement. If the statement is not a [COMMIT] and occurs within an
|
||||
** explicit transaction then you should rollback the transaction before
|
||||
** continuing.
|
||||
**
|
||||
@@ -3378,7 +3536,7 @@ sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
|
||||
** CAPI3REF: Destroy A Prepared Statement Object
|
||||
**
|
||||
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
|
||||
** ^If the most recent evaluation of the statement encountered no errors or
|
||||
** ^If the most recent evaluation of the statement encountered no errors
|
||||
** or if the statement is never been evaluated, then sqlite3_finalize() returns
|
||||
** SQLITE_OK. ^If the most recent evaluation of statement S failed, then
|
||||
** sqlite3_finalize(S) returns the appropriate [error code] or
|
||||
@@ -4605,6 +4763,11 @@ struct sqlite3_module {
|
||||
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void **ppArg);
|
||||
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
|
||||
/* The methods above are in version 1 of the sqlite_module object. Those
|
||||
** below are for version 2 and greater. */
|
||||
int (*xSavepoint)(sqlite3_vtab *pVTab, int);
|
||||
int (*xRelease)(sqlite3_vtab *pVTab, int);
|
||||
int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -5287,7 +5450,7 @@ struct sqlite3_mutex_methods {
|
||||
**
|
||||
** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
|
||||
** the routine should return 1. This seems counter-intuitive since
|
||||
** clearly the mutex cannot be held if it does not exist. But the
|
||||
** clearly the mutex cannot be held if it does not exist. But
|
||||
** the reason the mutex does not exist is because the build is not
|
||||
** using mutexes. And we do not want the assert() containing the
|
||||
** call to sqlite3_mutex_held() to fail, so a non-zero return is
|
||||
@@ -5410,7 +5573,8 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
||||
#define SQLITE_TESTCTRL_PGHDRSZ 17
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 18
|
||||
#define SQLITE_TESTCTRL_LAST 18
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19
|
||||
#define SQLITE_TESTCTRL_LAST 19
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
@@ -5419,7 +5583,7 @@ int sqlite3_test_control(int op, ...);
|
||||
** about the performance of SQLite, and optionally to reset various
|
||||
** highwater marks. ^The first argument is an integer code for
|
||||
** the specific parameter to measure. ^(Recognized integer codes
|
||||
** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
|
||||
** are of the form [status parameters | SQLITE_STATUS_...].)^
|
||||
** ^The current value of the parameter is returned into *pCurrent.
|
||||
** ^The highest recorded value is returned in *pHighwater. ^If the
|
||||
** resetFlag is true, then the highest record value is reset after
|
||||
@@ -5446,12 +5610,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters
|
||||
** KEYWORDS: {status parameters}
|
||||
**
|
||||
** These integer constants designate various run-time status parameters
|
||||
** that can be returned by [sqlite3_status()].
|
||||
**
|
||||
** <dl>
|
||||
** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
|
||||
** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
|
||||
** <dd>This parameter is the current amount of memory checked out
|
||||
** using [sqlite3_malloc()], either directly or indirectly. The
|
||||
** figure includes calls made to [sqlite3_malloc()] by the application
|
||||
@@ -5461,23 +5626,24 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** this parameter. The amount returned is the sum of the allocation
|
||||
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
|
||||
** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
|
||||
** <dd>This parameter records the largest memory allocation request
|
||||
** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
|
||||
** internal equivalents). Only the value returned in the
|
||||
** *pHighwater parameter to [sqlite3_status()] is of interest.
|
||||
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
|
||||
** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
|
||||
** <dd>This parameter records the number of separate memory allocations
|
||||
** currently checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
||||
** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
||||
** <dd>This parameter returns the number of pages used out of the
|
||||
** [pagecache memory allocator] that was configured using
|
||||
** [SQLITE_CONFIG_PAGECACHE]. The
|
||||
** value returned is in pages, not in bytes.</dd>)^
|
||||
**
|
||||
** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
|
||||
** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
|
||||
** <dd>This parameter returns the number of bytes of page cache
|
||||
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
||||
@@ -5487,13 +5653,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
|
||||
** no space was left in the page cache.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
|
||||
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
|
||||
** <dd>This parameter records the largest memory allocation request
|
||||
** handed to [pagecache memory allocator]. Only the value returned in the
|
||||
** *pHighwater parameter to [sqlite3_status()] is of interest.
|
||||
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
|
||||
** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
|
||||
** <dd>This parameter returns the number of allocations used out of the
|
||||
** [scratch memory allocator] configured using
|
||||
** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not
|
||||
@@ -5501,7 +5667,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** outstanding at time, this parameter also reports the number of threads
|
||||
** using scratch memory at the same time.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
|
||||
** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
|
||||
** <dd>This parameter returns the number of bytes of scratch memory
|
||||
** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
|
||||
** buffer and where forced to overflow to [sqlite3_malloc()]. The values
|
||||
@@ -5511,13 +5677,13 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** slots were available.
|
||||
** </dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
|
||||
** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
|
||||
** <dd>This parameter records the largest memory allocation request
|
||||
** handed to [scratch memory allocator]. Only the value returned in the
|
||||
** *pHighwater parameter to [sqlite3_status()] is of interest.
|
||||
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
|
||||
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
|
||||
** <dd>This parameter records the deepest parser stack. It is only
|
||||
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
|
||||
** </dl>
|
||||
@@ -5542,9 +5708,9 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** about a single [database connection]. ^The first argument is the
|
||||
** database connection object to be interrogated. ^The second argument
|
||||
** is an integer constant, taken from the set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
|
||||
** [SQLITE_DBSTATUS options], that
|
||||
** determines the parameter to interrogate. The set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
|
||||
** [SQLITE_DBSTATUS options] is likely
|
||||
** to grow in future releases of SQLite.
|
||||
**
|
||||
** ^The current value of the requested parameter is written into *pCur
|
||||
@@ -5561,6 +5727,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters for database connections
|
||||
** KEYWORDS: {SQLITE_DBSTATUS options}
|
||||
**
|
||||
** These constants are the available integer "verbs" that can be passed as
|
||||
** the second argument to the [sqlite3_db_status()] interface.
|
||||
@@ -5572,15 +5739,16 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** if a discontinued or unsupported verb is invoked.
|
||||
**
|
||||
** <dl>
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
|
||||
** <dd>This parameter returns the number of lookaside memory slots currently
|
||||
** checked out.</dd>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that were
|
||||
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to the amount of
|
||||
@@ -5588,6 +5756,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
|
||||
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
|
||||
** <dd>This parameter returns the number malloc attempts that might have
|
||||
** been satisfied using lookaside memory but failed due to all lookaside
|
||||
@@ -5595,12 +5764,12 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** Only the high-water value is meaningful;
|
||||
** the current value is always zero.)^
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** memory used by all pager caches associated with the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** memory used to store the schema for all databases associated
|
||||
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
||||
@@ -5609,7 +5778,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** [shared cache mode] being enabled.
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** and lookaside memory used by all prepared statements associated with
|
||||
** the database connection.)^
|
||||
@@ -5631,7 +5800,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** CAPI3REF: Prepared Statement Status
|
||||
**
|
||||
** ^(Each prepared statement maintains various
|
||||
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
|
||||
** [SQLITE_STMTSTATUS counters] that measure the number
|
||||
** of times it has performed specific operations.)^ These counters can
|
||||
** be used to monitor the performance characteristics of the prepared
|
||||
** statements. For example, if the number of table steps greatly exceeds
|
||||
@@ -5642,7 +5811,7 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** ^(This interface is used to retrieve and reset counter values from
|
||||
** a [prepared statement]. The first argument is the prepared statement
|
||||
** object to be interrogated. The second argument
|
||||
** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter]
|
||||
** is an integer code for a specific [SQLITE_STMTSTATUS counter]
|
||||
** to be interrogated.)^
|
||||
** ^The current value of the requested counter is returned.
|
||||
** ^If the resetFlg is true, then the counter is reset to zero after this
|
||||
@@ -5654,24 +5823,25 @@ int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters for prepared statements
|
||||
** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters}
|
||||
**
|
||||
** These preprocessor macros define integer codes that name counter
|
||||
** values associated with the [sqlite3_stmt_status()] interface.
|
||||
** The meanings of the various counters are as follows:
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
|
||||
** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
|
||||
** <dd>^This is the number of times that SQLite has stepped forward in
|
||||
** a table as part of a full table scan. Large numbers for this counter
|
||||
** may indicate opportunities for performance improvement through
|
||||
** careful use of indices.</dd>
|
||||
**
|
||||
** <dt>SQLITE_STMTSTATUS_SORT</dt>
|
||||
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
||||
** <dd>^This is the number of sort operations that have occurred.
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
** improvement performance through careful use of indices.</dd>
|
||||
**
|
||||
** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
||||
** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
|
||||
** <dd>^This is the number of rows inserted into transient indices that
|
||||
** were created automatically in order to help joins run faster.
|
||||
** A non-zero value in this counter may indicate an opportunity to
|
||||
@@ -5722,6 +5892,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** the application may discard the parameter after the call to
|
||||
** [sqlite3_config()] returns.)^
|
||||
**
|
||||
** [[the xInit() page cache method]]
|
||||
** ^(The xInit() method is called once for each effective
|
||||
** call to [sqlite3_initialize()])^
|
||||
** (usually only once during the lifetime of the process). ^(The xInit()
|
||||
@@ -5732,6 +5903,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** built-in default page cache is used instead of the application defined
|
||||
** page cache.)^
|
||||
**
|
||||
** [[the xShutdown() page cache method]]
|
||||
** ^The xShutdown() method is called by [sqlite3_shutdown()].
|
||||
** It can be used to clean up
|
||||
** any outstanding resources before process shutdown, if required.
|
||||
@@ -5746,6 +5918,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** ^SQLite will never invoke xInit() more than once without an intervening
|
||||
** call to xShutdown().
|
||||
**
|
||||
** [[the xCreate() page cache methods]]
|
||||
** ^SQLite invokes the xCreate() method to construct a new cache instance.
|
||||
** SQLite will typically create one cache instance for each open database file,
|
||||
** though this is not guaranteed. ^The
|
||||
@@ -5770,6 +5943,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** ^Hence, a cache created with bPurgeable false will
|
||||
** never contain any unpinned pages.
|
||||
**
|
||||
** [[the xCachesize() page cache method]]
|
||||
** ^(The xCachesize() method may be called at any time by SQLite to set the
|
||||
** suggested maximum cache-size (number of pages stored by) the cache
|
||||
** instance passed as the first argument. This is the value configured using
|
||||
@@ -5777,14 +5951,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** parameter, the implementation is not required to do anything with this
|
||||
** value; it is advisory only.
|
||||
**
|
||||
** [[the xPagecount() page cache methods]]
|
||||
** The xPagecount() method must return the number of pages currently
|
||||
** stored in the cache, both pinned and unpinned.
|
||||
**
|
||||
** [[the xFetch() page cache methods]]
|
||||
** The xFetch() method locates a page in the cache and returns a pointer to
|
||||
** the page, or a NULL pointer.
|
||||
** A "page", in this context, means a buffer of szPage bytes aligned at an
|
||||
** 8-byte boundary. The page to be fetched is determined by the key. ^The
|
||||
** mimimum key value is 1. After it has been retrieved using xFetch, the page
|
||||
** minimum key value is 1. After it has been retrieved using xFetch, the page
|
||||
** is considered to be "pinned".
|
||||
**
|
||||
** If the requested page is already in the page cache, then the page cache
|
||||
@@ -5808,6 +5984,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** attempt to unpin one or more cache pages by spilling the content of
|
||||
** pinned pages to disk and synching the operating system disk cache.
|
||||
**
|
||||
** [[the xUnpin() page cache method]]
|
||||
** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
|
||||
** as its second argument. If the third parameter, discard, is non-zero,
|
||||
** then the page must be evicted from the cache.
|
||||
@@ -5820,6 +5997,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** call to xUnpin() unpins the page regardless of the number of prior calls
|
||||
** to xFetch().
|
||||
**
|
||||
** [[the xRekey() page cache methods]]
|
||||
** The xRekey() method is used to change the key value associated with the
|
||||
** page passed as the second argument. If the cache
|
||||
** previously contains an entry associated with newKey, it must be
|
||||
@@ -5832,6 +6010,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
|
||||
** of these pages are pinned, they are implicitly unpinned, meaning that
|
||||
** they can be safely discarded.
|
||||
**
|
||||
** [[the xDestroy() page cache method]]
|
||||
** ^The xDestroy() method is used to delete a cache allocated by xCreate().
|
||||
** All resources associated with the specified cache should be freed. ^After
|
||||
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
|
||||
@@ -5894,7 +6073,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** There should be exactly one call to sqlite3_backup_finish() for each
|
||||
** successful call to sqlite3_backup_init().
|
||||
**
|
||||
** <b>sqlite3_backup_init()</b>
|
||||
** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b>
|
||||
**
|
||||
** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
|
||||
** [database connection] associated with the destination database
|
||||
@@ -5921,7 +6100,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** sqlite3_backup_finish() functions to perform the specified backup
|
||||
** operation.
|
||||
**
|
||||
** <b>sqlite3_backup_step()</b>
|
||||
** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
|
||||
**
|
||||
** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
|
||||
** the source and destination databases specified by [sqlite3_backup] object B.
|
||||
@@ -5978,7 +6157,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** by the backup operation, then the backup database is automatically
|
||||
** updated at the same time.
|
||||
**
|
||||
** <b>sqlite3_backup_finish()</b>
|
||||
** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
|
||||
**
|
||||
** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
|
||||
** application wishes to abandon the backup operation, the application
|
||||
@@ -6001,7 +6180,8 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** is not a permanent error and does not affect the return value of
|
||||
** sqlite3_backup_finish().
|
||||
**
|
||||
** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b>
|
||||
** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
|
||||
** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
|
||||
**
|
||||
** ^Each call to sqlite3_backup_step() sets two values inside
|
||||
** the [sqlite3_backup] object: the number of pages still to be backed
|
||||
@@ -6387,6 +6567,93 @@ int sqlite3_wal_checkpoint_v2(
|
||||
#define SQLITE_CHECKPOINT_FULL 1
|
||||
#define SQLITE_CHECKPOINT_RESTART 2
|
||||
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Interface Configuration
|
||||
**
|
||||
** This function may be called by either the [xConnect] or [xCreate] method
|
||||
** of a [virtual table] implementation to configure
|
||||
** various facets of the virtual table interface.
|
||||
**
|
||||
** If this interface is invoked outside the context of an xConnect or
|
||||
** xCreate virtual table method then the behavior is undefined.
|
||||
**
|
||||
** At present, there is only one option that may be configured using
|
||||
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
|
||||
** may be added in the future.
|
||||
*/
|
||||
int sqlite3_vtab_config(sqlite3*, int op, ...);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Configuration Options
|
||||
**
|
||||
** These macros define the various options to the
|
||||
** [sqlite3_vtab_config()] interface that [virtual table] implementations
|
||||
** can use to customize and optimize their behavior.
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
|
||||
** <dd>Calls of the form
|
||||
** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
|
||||
** where X is an integer. If X is zero, then the [virtual table] whose
|
||||
** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
|
||||
** support constraints. In this configuration (which is the default) if
|
||||
** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
|
||||
** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
|
||||
** specified as part of the users SQL statement, regardless of the actual
|
||||
** ON CONFLICT mode specified.
|
||||
**
|
||||
** If X is non-zero, then the virtual table implementation guarantees
|
||||
** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
|
||||
** any modifications to internal or persistent data structures have been made.
|
||||
** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
|
||||
** is able to roll back a statement or database transaction, and abandon
|
||||
** or continue processing the current SQL statement as appropriate.
|
||||
** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
|
||||
** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
|
||||
** had been ABORT.
|
||||
**
|
||||
** Virtual table implementations that are required to handle OR REPLACE
|
||||
** must do so within the [xUpdate] method. If a call to the
|
||||
** [sqlite3_vtab_on_conflict()] function indicates that the current ON
|
||||
** CONFLICT policy is REPLACE, the virtual table implementation should
|
||||
** silently replace the appropriate rows within the xUpdate callback and
|
||||
** return SQLITE_OK. Or, if this is not possible, it may return
|
||||
** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
|
||||
** constraint handling.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine The Virtual Table Conflict Policy
|
||||
**
|
||||
** This function may only be called from within a call to the [xUpdate] method
|
||||
** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
|
||||
** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
|
||||
** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
|
||||
** of the SQL statement that triggered the call to the [xUpdate] method of the
|
||||
** [virtual table].
|
||||
*/
|
||||
int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Conflict resolution modes
|
||||
**
|
||||
** These constants are returned by [sqlite3_vtab_on_conflict()] to
|
||||
** inform a [virtual table] implementation what the [ON CONFLICT] mode
|
||||
** is for the SQL statement being evaluated.
|
||||
**
|
||||
** Note that the [SQLITE_IGNORE] constant is also used as a potential
|
||||
** return value from the [sqlite3_set_authorizer()] callback and that
|
||||
** [SQLITE_ABORT] is also a [result code].
|
||||
*/
|
||||
#define SQLITE_ROLLBACK 1
|
||||
/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */
|
||||
#define SQLITE_FAIL 3
|
||||
/* #define SQLITE_ABORT 4 // Also an error code */
|
||||
#define SQLITE_REPLACE 5
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
|
||||
+24
-7
@@ -632,6 +632,7 @@ typedef struct TriggerPrg TriggerPrg;
|
||||
typedef struct TriggerStep TriggerStep;
|
||||
typedef struct UnpackedRecord UnpackedRecord;
|
||||
typedef struct VTable VTable;
|
||||
typedef struct VtabCtx VtabCtx;
|
||||
typedef struct Walker Walker;
|
||||
typedef struct WherePlan WherePlan;
|
||||
typedef struct WhereInfo WhereInfo;
|
||||
@@ -681,7 +682,7 @@ struct Db {
|
||||
** A thread must be holding a mutex on the corresponding Btree in order
|
||||
** to access Schema content. This implies that the thread must also be
|
||||
** holding a mutex on the sqlite3 connection pointer that owns the Btree.
|
||||
** For a TEMP Schema, on the connection mutex is required.
|
||||
** For a TEMP Schema, only the connection mutex is required.
|
||||
*/
|
||||
struct Schema {
|
||||
int schema_cookie; /* Database schema version number for this file */
|
||||
@@ -802,7 +803,7 @@ struct sqlite3 {
|
||||
int nDb; /* Number of backends currently in use */
|
||||
Db *aDb; /* All backends */
|
||||
int flags; /* Miscellaneous flags. See below */
|
||||
int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
|
||||
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
|
||||
int errCode; /* Most recent error code (SQLITE_*) */
|
||||
int errMask; /* & result codes with this before returning */
|
||||
u8 autoCommit; /* The auto-commit flag. */
|
||||
@@ -811,6 +812,7 @@ struct sqlite3 {
|
||||
u8 dfltLockMode; /* Default locking-mode for attached dbs */
|
||||
signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */
|
||||
u8 suppressErr; /* Do not issue error messages if true */
|
||||
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
|
||||
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
||||
int nTable; /* Number of tables in the database */
|
||||
CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
|
||||
@@ -869,7 +871,7 @@ struct sqlite3 {
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
Hash aModule; /* populated by sqlite3_create_module() */
|
||||
Table *pVTab; /* vtab with active Connect/Create method */
|
||||
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
|
||||
VTable **aVTrans; /* Virtual tables with open transactions */
|
||||
int nVTrans; /* Allocated size of aVTrans */
|
||||
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
|
||||
@@ -953,6 +955,7 @@ struct sqlite3 {
|
||||
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
|
||||
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */
|
||||
#define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */
|
||||
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
|
||||
|
||||
/*
|
||||
@@ -1232,6 +1235,8 @@ struct VTable {
|
||||
Module *pMod; /* Pointer to module implementation */
|
||||
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
|
||||
int nRef; /* Number of pointers to this structure */
|
||||
u8 bConstraint; /* True if constraints are supported */
|
||||
int iSavepoint; /* Depth of the SAVEPOINT stack */
|
||||
VTable *pNext; /* Next in linked list (see above) */
|
||||
};
|
||||
|
||||
@@ -2226,9 +2231,8 @@ struct Parse {
|
||||
** each recursion */
|
||||
|
||||
int nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
||||
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
||||
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
|
||||
int nzVar; /* Number of available slots in azVar[] */
|
||||
char **azVar; /* Pointers to names of parameters */
|
||||
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
|
||||
int nAlias; /* Number of aliased result set columns */
|
||||
int nAliasAlloc; /* Number of allocated slots for aAlias[] */
|
||||
@@ -2420,6 +2424,7 @@ struct Sqlite3Config {
|
||||
int bMemstat; /* True to enable memory status */
|
||||
int bCoreMutex; /* True to enable core mutexing */
|
||||
int bFullMutex; /* True to enable full mutexing */
|
||||
int bOpenUri; /* True to interpret filenames as URIs */
|
||||
int mxStrlen; /* Maximum string length */
|
||||
int szLookaside; /* Default lookaside buffer size */
|
||||
int nLookaside; /* Default lookaside buffer count */
|
||||
@@ -2448,6 +2453,7 @@ struct Sqlite3Config {
|
||||
int nRefInitMutex; /* Number of users of pInitMutex */
|
||||
void (*xLog)(void*,int,const char*); /* Function for logging */
|
||||
void *pLogArg; /* First argument to xLog() */
|
||||
int bLocaltimeFault; /* True to fail localtime() calls */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -2669,6 +2675,8 @@ void sqlite3AddColumnType(Parse*,Token*);
|
||||
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
|
||||
void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
sqlite3_vfs**,char**,char **);
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
int sqlite3BitvecTest(Bitvec*, u32);
|
||||
@@ -2873,7 +2881,7 @@ int sqlite3GetInt32(const char *, int*);
|
||||
int sqlite3Atoi(const char*);
|
||||
int sqlite3Utf16ByteLen(const void *pData, int nChar);
|
||||
int sqlite3Utf8CharLen(const char *pData, int nByte);
|
||||
int sqlite3Utf8Read(const u8*, const u8**);
|
||||
u32 sqlite3Utf8Read(const u8*, const u8**);
|
||||
|
||||
/*
|
||||
** Routines to read and write variable-length integers. These used to
|
||||
@@ -2919,6 +2927,7 @@ char sqlite3ExprAffinity(Expr *pExpr);
|
||||
int sqlite3Atoi64(const char*, i64*, int, u8);
|
||||
void sqlite3Error(sqlite3*, int, const char*,...);
|
||||
void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
||||
u8 sqlite3HexToInt(int h);
|
||||
int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
|
||||
const char *sqlite3ErrStr(int);
|
||||
int sqlite3ReadSchema(Parse *pParse);
|
||||
@@ -2934,6 +2943,12 @@ int sqlite3AddInt64(i64*,i64);
|
||||
int sqlite3SubInt64(i64*,i64);
|
||||
int sqlite3MulInt64(i64*,i64);
|
||||
int sqlite3AbsInt32(int);
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
void sqlite3FileSuffix3(const char*, char*);
|
||||
#else
|
||||
# define sqlite3FileSuffix3(X,Y)
|
||||
#endif
|
||||
u8 sqlite3GetBoolean(const char *z);
|
||||
|
||||
const void *sqlite3ValueText(sqlite3_value*, u8);
|
||||
int sqlite3ValueBytes(sqlite3_value*, u8);
|
||||
@@ -3043,6 +3058,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3VtabLock(X)
|
||||
# define sqlite3VtabUnlock(X)
|
||||
# define sqlite3VtabUnlockList(X)
|
||||
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
|
||||
#else
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
@@ -3051,6 +3067,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
void sqlite3VtabLock(VTable *);
|
||||
void sqlite3VtabUnlock(VTable *);
|
||||
void sqlite3VtabUnlockList(sqlite3*);
|
||||
int sqlite3VtabSavepoint(sqlite3 *, int, int);
|
||||
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
|
||||
#endif
|
||||
void sqlite3VtabMakeWritable(Parse*,Table*);
|
||||
|
||||
+11
-3
@@ -761,7 +761,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite_int64 v = sqlite3_value_int64(pIn);
|
||||
if( v>=-2147483647 && v<=2147483647 ){
|
||||
pVal = Tcl_NewIntObj(v);
|
||||
pVal = Tcl_NewIntObj((int)v);
|
||||
}else{
|
||||
pVal = Tcl_NewWideIntObj(v);
|
||||
}
|
||||
@@ -1441,7 +1441,7 @@ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite_int64 v = sqlite3_column_int64(pStmt, iCol);
|
||||
if( v>=-2147483647 && v<=2147483647 ){
|
||||
return Tcl_NewIntObj(v);
|
||||
return Tcl_NewIntObj((int)v);
|
||||
}else{
|
||||
return Tcl_NewWideIntObj(v);
|
||||
}
|
||||
@@ -2367,7 +2367,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
if( zNull && len>0 ){
|
||||
pDb->zNull = Tcl_Alloc( len + 1 );
|
||||
strncpy(pDb->zNull, zNull, len);
|
||||
memcpy(pDb->zNull, zNull, len);
|
||||
pDb->zNull[len] = '\0';
|
||||
}else{
|
||||
pDb->zNull = 0;
|
||||
@@ -3585,6 +3585,10 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestwholenumber_Init(Tcl_Interp*);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
Zipvfs_Init(interp);
|
||||
@@ -3625,6 +3629,10 @@ static void init_all(Tcl_Interp *interp){
|
||||
Sqlitetestfuzzer_Init(interp);
|
||||
Sqlitetestwholenumber_Init(interp);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
Sqlitetestfts3_Init(interp);
|
||||
#endif
|
||||
|
||||
Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
|
||||
+157
@@ -14,6 +14,7 @@
|
||||
** testing of the SQLite library.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -162,6 +163,9 @@ const char *sqlite3TestErrorName(int rc){
|
||||
case SQLITE_IOERR_CHECKRESERVEDLOCK:
|
||||
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
|
||||
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
|
||||
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
|
||||
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
|
||||
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
|
||||
default: zName = "SQLITE_Unknown"; break;
|
||||
}
|
||||
return zName;
|
||||
@@ -2326,6 +2330,32 @@ static int test_stmt_readonly(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: uses_stmt_journal STMT
|
||||
**
|
||||
** Return true if STMT uses a statement journal.
|
||||
*/
|
||||
static int uses_stmt_journal(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
rc = sqlite3_stmt_readonly(pStmt);
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_reset STMT
|
||||
@@ -3818,6 +3848,76 @@ static int test_open(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_open_v2 FILENAME FLAGS VFS
|
||||
*/
|
||||
static int test_open_v2(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zFilename;
|
||||
const char *zVfs;
|
||||
int flags = 0;
|
||||
sqlite3 *db;
|
||||
int rc;
|
||||
char zBuf[100];
|
||||
|
||||
int nFlag;
|
||||
Tcl_Obj **apFlag;
|
||||
int i;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zFilename = Tcl_GetString(objv[1]);
|
||||
zVfs = Tcl_GetString(objv[3]);
|
||||
if( zVfs[0]==0x00 ) zVfs = 0;
|
||||
|
||||
rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
for(i=0; i<nFlag; i++){
|
||||
int iFlag;
|
||||
struct OpenFlag {
|
||||
const char *zFlag;
|
||||
int flag;
|
||||
} aFlag[] = {
|
||||
{ "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY },
|
||||
{ "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE },
|
||||
{ "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE },
|
||||
{ "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE },
|
||||
{ "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE },
|
||||
{ "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY },
|
||||
{ "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB },
|
||||
{ "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB },
|
||||
{ "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB },
|
||||
{ "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
|
||||
{ "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
|
||||
{ "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
|
||||
{ "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL },
|
||||
{ "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
|
||||
{ "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
|
||||
{ "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
|
||||
{ "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE },
|
||||
{ "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL },
|
||||
{ "SQLITE_OPEN_URI", SQLITE_OPEN_URI },
|
||||
{ 0, 0 }
|
||||
};
|
||||
rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]),
|
||||
"flag", 0, &iFlag
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
flags |= aFlag[iFlag].flag;
|
||||
}
|
||||
|
||||
rc = sqlite3_open_v2(zFilename, &db, flags, zVfs);
|
||||
if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
|
||||
Tcl_AppendResult(interp, zBuf, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_open16 filename options
|
||||
*/
|
||||
@@ -5417,11 +5517,64 @@ static int test_print_eqp(
|
||||
}
|
||||
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
|
||||
rc = printExplainQueryPlan(pStmt);
|
||||
/* This is needed on Windows so that a test case using this
|
||||
** function can open a read pipe and get the output of
|
||||
** printExplainQueryPlan() immediately.
|
||||
*/
|
||||
fflush(stdout);
|
||||
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
|
||||
/*
|
||||
** sqlite3_test_control VERB ARGS...
|
||||
*/
|
||||
static int test_test_control(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
struct Verb {
|
||||
const char *zName;
|
||||
int i;
|
||||
} aVerb[] = {
|
||||
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
|
||||
};
|
||||
int iVerb;
|
||||
int iFlag;
|
||||
int rc;
|
||||
|
||||
if( objc<2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = Tcl_GetIndexFromObjStruct(
|
||||
interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
|
||||
iFlag = aVerb[iVerb].i;
|
||||
switch( iFlag ){
|
||||
case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
|
||||
int val;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "ONOFF");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** optimization_control DB OPT BOOLEAN
|
||||
**
|
||||
@@ -5452,6 +5605,7 @@ static int optimization_control(
|
||||
{ "index-cover", SQLITE_IndexCover },
|
||||
{ "groupby-order", SQLITE_GroupByOrder },
|
||||
{ "factor-constants", SQLITE_FactorOutConst },
|
||||
{ "real-as-int", SQLITE_IdxRealAsInt },
|
||||
};
|
||||
|
||||
if( objc!=4 ){
|
||||
@@ -5566,6 +5720,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
|
||||
{ "sqlite3_open", test_open ,0 },
|
||||
{ "sqlite3_open16", test_open16 ,0 },
|
||||
{ "sqlite3_open_v2", test_open_v2 ,0 },
|
||||
{ "sqlite3_complete16", test_complete16 ,0 },
|
||||
|
||||
{ "sqlite3_prepare", test_prepare ,0 },
|
||||
@@ -5583,6 +5738,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_sql", test_sql ,0 },
|
||||
{ "sqlite3_next_stmt", test_next_stmt ,0 },
|
||||
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
|
||||
{ "uses_stmt_journal", uses_stmt_journal ,0 },
|
||||
|
||||
{ "sqlite3_release_memory", test_release_memory, 0},
|
||||
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0},
|
||||
@@ -5683,6 +5839,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
{ "print_explain_query_plan", test_print_eqp, 0 },
|
||||
#endif
|
||||
{ "sqlite3_test_control", test_test_control },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ static int btree_open(
|
||||
sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
|
||||
sqlite3_mutex_enter(sDb.mutex);
|
||||
}
|
||||
rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, 0,
|
||||
rc = sqlite3BtreeOpen(sDb.pVfs, argv[1], &sDb, &pBt, 0,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
|
||||
+6
-4
@@ -73,6 +73,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "memdebug", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
Tcl_SetVar2(interp, "sqlite_options", "8_3_names", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "8_3_names", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMSYS3
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
@@ -219,11 +225,7 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "compound", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "conflict", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_UNIX
|
||||
Tcl_SetVar2(interp, "sqlite_options", "crashtest", "1", TCL_GLOBAL_ONLY);
|
||||
|
||||
+6
-7
@@ -10,14 +10,12 @@
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** An example of a simple VFS implementation that omits complex features
|
||||
** often not required or not possible on embedded platforms. Also includes
|
||||
** code to buffer writes to the journal file, which can be a significant
|
||||
** performance improvement on some embedded platforms.
|
||||
** This file implements an example of a simple VFS implementation that
|
||||
** omits complex features often not required or not possible on embedded
|
||||
** platforms. Code is included to buffer writes to the journal file,
|
||||
** which can be a significant performance improvement on some embedded
|
||||
** platforms.
|
||||
**
|
||||
*/
|
||||
|
||||
/*
|
||||
** OVERVIEW
|
||||
**
|
||||
** The code in this file implements a minimal SQLite VFS that can be
|
||||
@@ -128,6 +126,7 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
** Size of the write buffer used by journal files in bytes.
|
||||
|
||||
+5
-7
@@ -14,13 +14,7 @@
|
||||
** an existing VFS. The code in this file attempts to verify that SQLite
|
||||
** correctly populates and syncs a journal file before writing to a
|
||||
** corresponding database file.
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for testing only */
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
**
|
||||
** INTERFACE
|
||||
**
|
||||
** The public interface to this wrapper VFS is two functions:
|
||||
@@ -99,6 +93,10 @@
|
||||
**
|
||||
** c) The journal file is deleted using xDelete.
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for testing only */
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Maximum pathname length supported by the jt backend.
|
||||
|
||||
@@ -1174,6 +1174,35 @@ static int test_config_error(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_config_uri BOOLEAN
|
||||
**
|
||||
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
|
||||
** opcodes and verify that they return errors.
|
||||
*/
|
||||
static int test_config_uri(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc;
|
||||
int bOpenUri;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &bOpenUri) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
|
||||
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage:
|
||||
**
|
||||
@@ -1422,6 +1451,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
|
||||
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
|
||||
{ "sqlite3_config_error", test_config_error ,0 },
|
||||
{ "sqlite3_config_uri", test_config_uri ,0 },
|
||||
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
|
||||
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
|
||||
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
|
||||
|
||||
+126
-23
@@ -11,13 +11,36 @@
|
||||
*************************************************************************
|
||||
**
|
||||
** This file contains a VFS "shim" - a layer that sits in between the
|
||||
** pager and the real VFS.
|
||||
** pager and the real VFS - that breaks up a very large database file
|
||||
** into two or more smaller files on disk. This is useful, for example,
|
||||
** in order to support large, multi-gigabyte databases on older filesystems
|
||||
** that limit the maximum file size to 2 GiB.
|
||||
**
|
||||
** This particular shim enforces a multiplex system on DB files.
|
||||
** This shim shards/partitions a single DB file into smaller
|
||||
** "chunks" such that the total DB file size may exceed the maximum
|
||||
** file size of the underlying file system.
|
||||
** USAGE:
|
||||
**
|
||||
** Compile this source file and link it with your application. Then
|
||||
** at start-time, invoke the following procedure:
|
||||
**
|
||||
** int sqlite3_multiplex_initialize(
|
||||
** const char *zOrigVfsName, // The underlying real VFS
|
||||
** int makeDefault // True to make multiplex the default VFS
|
||||
** );
|
||||
**
|
||||
** The procedure call above will create and register a new VFS shim named
|
||||
** "multiplex". The multiplex VFS will use the VFS named by zOrigVfsName to
|
||||
** do the actual disk I/O. (The zOrigVfsName parameter may be NULL, in
|
||||
** which case the default VFS at the moment sqlite3_multiplex_initialize()
|
||||
** is called will be used as the underlying real VFS.)
|
||||
**
|
||||
** If the makeDefault parameter is TRUE then multiplex becomes the new
|
||||
** default VFS. Otherwise, you can use the multiplex VFS by specifying
|
||||
** "multiplex" as the 4th parameter to sqlite3_open_v2() or by employing
|
||||
** URI filenames and adding "vfs=multiplex" as a parameter to the filename
|
||||
** URI.
|
||||
**
|
||||
** The multiplex VFS allows databases up to 32 GiB in size. But it splits
|
||||
** the files up into 1 GiB pieces, so that they will work even on filesystems
|
||||
** that do not support large files.
|
||||
*/
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
@@ -185,13 +208,77 @@ static void multiplexLeave(void){ sqlite3_mutex_leave(gMultiplex.pMutex); }
|
||||
** than the actual length of the string. For very long strings (greater
|
||||
** than 1GiB) the value returned might be less than the true string length.
|
||||
*/
|
||||
int multiplexStrlen30(const char *z){
|
||||
static int multiplexStrlen30(const char *z){
|
||||
const char *z2 = z;
|
||||
if( z==0 ) return 0;
|
||||
while( *z2 ){ z2++; }
|
||||
return 0x3fffffff & (int)(z2 - z);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at pOrigVfs->mxPathname characters. This function departs
|
||||
** from the traditional temporary name generation in the os_win
|
||||
** and os_unix VFS in several ways, but is necessary so that
|
||||
** the file name is known for temporary files (like those used
|
||||
** during vacuum.)
|
||||
**
|
||||
** N.B. This routine assumes your underlying VFS is ok with using
|
||||
** "/" as a directory seperator. This is the default for UNIXs
|
||||
** and is allowed (even mixed) for most versions of Windows.
|
||||
*/
|
||||
static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){
|
||||
static char zChars[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789";
|
||||
int i,j;
|
||||
int attempts = 0;
|
||||
int exists = 0;
|
||||
int rc = SQLITE_ERROR;
|
||||
|
||||
/* Check that the output buffer is large enough for
|
||||
** pVfs->mxPathname characters.
|
||||
*/
|
||||
if( pOrigVfs->mxPathname <= nBuf ){
|
||||
char *zTmp = sqlite3_malloc(pOrigVfs->mxPathname);
|
||||
if( zTmp==0 ) return SQLITE_NOMEM;
|
||||
|
||||
/* sqlite3_temp_directory should always be less than
|
||||
** pVfs->mxPathname characters.
|
||||
*/
|
||||
sqlite3_snprintf(pOrigVfs->mxPathname,
|
||||
zTmp,
|
||||
"%s/",
|
||||
sqlite3_temp_directory ? sqlite3_temp_directory : ".");
|
||||
rc = pOrigVfs->xFullPathname(pOrigVfs, zTmp, nBuf, zBuf);
|
||||
sqlite3_free(zTmp);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check that the output buffer is large enough for the temporary file
|
||||
** name.
|
||||
*/
|
||||
j = multiplexStrlen30(zBuf);
|
||||
if( (j + 8 + 1 + 3 + 1) <= nBuf ){
|
||||
/* Make 3 attempts to generate a unique name. */
|
||||
do {
|
||||
attempts++;
|
||||
sqlite3_randomness(8, &zBuf[j]);
|
||||
for(i=0; i<8; i++){
|
||||
zBuf[j+i] = (char)zChars[ ((unsigned char)zBuf[j+i])%(sizeof(zChars)-1) ];
|
||||
}
|
||||
memcpy(&zBuf[j+i], ".tmp", 5);
|
||||
rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists);
|
||||
} while ( (rc==SQLITE_OK) && exists && (attempts<3) );
|
||||
if( rc==SQLITE_OK && exists ){
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Translate an sqlite3_file* that is really a multiplexGroup* into
|
||||
** the sqlite3_file* for the underlying original VFS.
|
||||
*/
|
||||
@@ -295,12 +382,12 @@ static int multiplexOpen(
|
||||
int flags, /* Flags to control the opening */
|
||||
int *pOutFlags /* Flags showing results of opening */
|
||||
){
|
||||
int rc; /* Result code */
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
multiplexConn *pMultiplexOpen; /* The new multiplex file descriptor */
|
||||
multiplexGroup *pGroup; /* Corresponding multiplexGroup object */
|
||||
sqlite3_file *pSubOpen; /* Real file descriptor */
|
||||
sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */
|
||||
int nName = multiplexStrlen30(zName);
|
||||
int nName;
|
||||
int i;
|
||||
int sz;
|
||||
|
||||
@@ -311,23 +398,39 @@ static int multiplexOpen(
|
||||
*/
|
||||
multiplexEnter();
|
||||
pMultiplexOpen = (multiplexConn*)pConn;
|
||||
/* allocate space for group */
|
||||
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
||||
+ (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */
|
||||
+ (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */
|
||||
+ SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */
|
||||
+ nName + 1; /* zName */
|
||||
|
||||
/* If the second argument to this function is NULL, generate a
|
||||
** temporary file name to use. This will be handled by the
|
||||
** original xOpen method. We just need to allocate space for
|
||||
** it.
|
||||
*/
|
||||
if( !zName ){
|
||||
rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, gMultiplex.zName);
|
||||
zName = gMultiplex.zName;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* allocate space for group */
|
||||
nName = multiplexStrlen30(zName);
|
||||
sz = sizeof(multiplexGroup) /* multiplexGroup */
|
||||
+ (sizeof(sqlite3_file *)*SQLITE_MULTIPLEX_MAX_CHUNKS) /* pReal[] */
|
||||
+ (pOrigVfs->szOsFile*SQLITE_MULTIPLEX_MAX_CHUNKS) /* *pReal */
|
||||
+ SQLITE_MULTIPLEX_MAX_CHUNKS /* bOpen[] */
|
||||
+ nName + 1; /* zName */
|
||||
#ifndef SQLITE_MULTIPLEX_EXT_OVWR
|
||||
sz += SQLITE_MULTIPLEX_EXT_SZ;
|
||||
assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
|
||||
sz += SQLITE_MULTIPLEX_EXT_SZ;
|
||||
assert(nName+SQLITE_MULTIPLEX_EXT_SZ < pOrigVfs->mxPathname);
|
||||
#else
|
||||
assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
|
||||
assert(nName < pOrigVfs->mxPathname);
|
||||
assert(nName >= SQLITE_MULTIPLEX_EXT_SZ);
|
||||
assert(nName < pOrigVfs->mxPathname);
|
||||
#endif
|
||||
pGroup = sqlite3_malloc( sz );
|
||||
if( pGroup==0 ){
|
||||
rc=SQLITE_NOMEM;
|
||||
}else{
|
||||
pGroup = sqlite3_malloc( sz );
|
||||
if( pGroup==0 ){
|
||||
rc=SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* assign pointers to extra space allocated */
|
||||
char *p = (char *)&pGroup[1];
|
||||
pMultiplexOpen->pGroup = pGroup;
|
||||
@@ -411,7 +514,7 @@ static int multiplexDelete(
|
||||
}
|
||||
rc2 = pOrigVfs->xAccess(pOrigVfs, gMultiplex.zName,
|
||||
SQLITE_ACCESS_EXISTS, &exists);
|
||||
if( rc2==SQLITE_OK && exists){
|
||||
if( rc2==SQLITE_OK && exists ){
|
||||
/* if it exists, delete it */
|
||||
rc2 = pOrigVfs->xDelete(pOrigVfs, gMultiplex.zName, syncDir);
|
||||
if( rc2!=SQLITE_OK ) rc = rc2;
|
||||
|
||||
+2
-2
@@ -323,7 +323,7 @@ static int quotaOpen(
|
||||
pFile=pFile->pNext){}
|
||||
if( pFile==0 ){
|
||||
int nName = strlen(zName);
|
||||
pFile = sqlite3_malloc( sizeof(*pFile) + nName + 1 );
|
||||
pFile = (quotaFile *)sqlite3_malloc( sizeof(*pFile) + nName + 1 );
|
||||
if( pFile==0 ){
|
||||
quotaLeave();
|
||||
pSubOpen->pMethods->xClose(pSubOpen);
|
||||
@@ -683,7 +683,7 @@ int sqlite3_quota_set(
|
||||
quotaLeave();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pGroup = sqlite3_malloc( sizeof(*pGroup) + nPattern + 1 );
|
||||
pGroup = (quotaGroup *)sqlite3_malloc( sizeof(*pGroup) + nPattern + 1 );
|
||||
if( pGroup==0 ){
|
||||
quotaLeave();
|
||||
return SQLITE_NOMEM;
|
||||
|
||||
+3
-3
@@ -404,9 +404,9 @@ static int clock_seconds_proc(
|
||||
*/
|
||||
typedef struct UnlockNotification UnlockNotification;
|
||||
struct UnlockNotification {
|
||||
int fired; /* True after unlock event has occured */
|
||||
pthread_cond_t cond; /* Condition variable to wait on */
|
||||
pthread_mutex_t mutex; /* Mutex to protect structure */
|
||||
int fired; /* True after unlock event has occurred */
|
||||
pthread_cond_t cond; /* Condition variable to wait on */
|
||||
pthread_mutex_t mutex; /* Mutex to protect structure */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+62
-71
@@ -10,10 +10,6 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for testing only */
|
||||
|
||||
/*
|
||||
** This file contains the implementation of the Tcl [testvfs] command,
|
||||
** used to create SQLite VFS implementations with various properties and
|
||||
** instrumentation to support testing SQLite.
|
||||
@@ -28,6 +24,7 @@
|
||||
** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname)
|
||||
** -iversion INTEGER (Value for sqlite3_vfs.iVersion)
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for testing only */
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqliteInt.h"
|
||||
@@ -82,8 +79,6 @@ struct Testvfs {
|
||||
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
|
||||
Tcl_Interp *interp; /* Interpreter to run script in */
|
||||
Tcl_Obj *pScript; /* Script to execute */
|
||||
int nScript; /* Number of elements in array apScript */
|
||||
Tcl_Obj **apScript; /* Array version of pScript */
|
||||
TestvfsBuffer *pBuffer; /* List of shared buffers */
|
||||
int isNoshm;
|
||||
|
||||
@@ -114,20 +109,21 @@ struct Testvfs {
|
||||
** + Simulating IO errors, and
|
||||
** + Invoking the Tcl callback script.
|
||||
*/
|
||||
#define TESTVFS_SHMOPEN_MASK 0x00000001
|
||||
#define TESTVFS_SHMLOCK_MASK 0x00000010
|
||||
#define TESTVFS_SHMMAP_MASK 0x00000020
|
||||
#define TESTVFS_SHMBARRIER_MASK 0x00000040
|
||||
#define TESTVFS_SHMCLOSE_MASK 0x00000080
|
||||
#define TESTVFS_SHMOPEN_MASK 0x00000001
|
||||
#define TESTVFS_SHMLOCK_MASK 0x00000010
|
||||
#define TESTVFS_SHMMAP_MASK 0x00000020
|
||||
#define TESTVFS_SHMBARRIER_MASK 0x00000040
|
||||
#define TESTVFS_SHMCLOSE_MASK 0x00000080
|
||||
|
||||
#define TESTVFS_OPEN_MASK 0x00000100
|
||||
#define TESTVFS_SYNC_MASK 0x00000200
|
||||
#define TESTVFS_DELETE_MASK 0x00000400
|
||||
#define TESTVFS_CLOSE_MASK 0x00000800
|
||||
#define TESTVFS_WRITE_MASK 0x00001000
|
||||
#define TESTVFS_TRUNCATE_MASK 0x00002000
|
||||
#define TESTVFS_ACCESS_MASK 0x00004000
|
||||
#define TESTVFS_ALL_MASK 0x00007FFF
|
||||
#define TESTVFS_OPEN_MASK 0x00000100
|
||||
#define TESTVFS_SYNC_MASK 0x00000200
|
||||
#define TESTVFS_DELETE_MASK 0x00000400
|
||||
#define TESTVFS_CLOSE_MASK 0x00000800
|
||||
#define TESTVFS_WRITE_MASK 0x00001000
|
||||
#define TESTVFS_TRUNCATE_MASK 0x00002000
|
||||
#define TESTVFS_ACCESS_MASK 0x00004000
|
||||
#define TESTVFS_FULLPATHNAME_MASK 0x00008000
|
||||
#define TESTVFS_ALL_MASK 0x0001FFFF
|
||||
|
||||
|
||||
#define TESTVFS_MAX_PAGES 1024
|
||||
@@ -269,48 +265,26 @@ static void tvfsExecTcl(
|
||||
Tcl_Obj *arg3
|
||||
){
|
||||
int rc; /* Return code from Tcl_EvalObj() */
|
||||
int nArg; /* Elements in eval'd list */
|
||||
int nScript;
|
||||
Tcl_Obj ** ap;
|
||||
|
||||
Tcl_Obj *pEval;
|
||||
assert( p->pScript );
|
||||
|
||||
if( !p->apScript ){
|
||||
int nByte;
|
||||
int i;
|
||||
if( TCL_OK!=Tcl_ListObjGetElements(p->interp, p->pScript, &nScript, &ap) ){
|
||||
Tcl_BackgroundError(p->interp);
|
||||
Tcl_ResetResult(p->interp);
|
||||
return;
|
||||
}
|
||||
p->nScript = nScript;
|
||||
nByte = (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *);
|
||||
p->apScript = (Tcl_Obj **)ckalloc(nByte);
|
||||
memset(p->apScript, 0, nByte);
|
||||
for(i=0; i<nScript; i++){
|
||||
p->apScript[i] = ap[i];
|
||||
}
|
||||
}
|
||||
assert( zMethod );
|
||||
assert( p );
|
||||
assert( arg2==0 || arg1!=0 );
|
||||
assert( arg3==0 || arg2!=0 );
|
||||
|
||||
p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
|
||||
p->apScript[p->nScript+1] = arg1;
|
||||
p->apScript[p->nScript+2] = arg2;
|
||||
p->apScript[p->nScript+3] = arg3;
|
||||
pEval = Tcl_DuplicateObj(p->pScript);
|
||||
Tcl_IncrRefCount(p->pScript);
|
||||
Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zMethod, -1));
|
||||
if( arg1 ) Tcl_ListObjAppendElement(p->interp, pEval, arg1);
|
||||
if( arg2 ) Tcl_ListObjAppendElement(p->interp, pEval, arg2);
|
||||
if( arg3 ) Tcl_ListObjAppendElement(p->interp, pEval, arg3);
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_IncrRefCount(p->apScript[nArg]);
|
||||
}
|
||||
|
||||
rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL);
|
||||
rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
Tcl_BackgroundError(p->interp);
|
||||
Tcl_ResetResult(p->interp);
|
||||
}
|
||||
|
||||
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
|
||||
Tcl_DecrRefCount(p->apScript[nArg]);
|
||||
p->apScript[nArg] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -545,7 +519,7 @@ static int tvfsOpen(
|
||||
|
||||
/* Evaluate the Tcl script:
|
||||
**
|
||||
** SCRIPT xOpen FILENAME
|
||||
** SCRIPT xOpen FILENAME KEY-VALUE-ARGS
|
||||
**
|
||||
** If the script returns an SQLite error code other than SQLITE_OK, an
|
||||
** error is returned to the caller. If it returns SQLITE_OK, the new
|
||||
@@ -554,7 +528,19 @@ static int tvfsOpen(
|
||||
*/
|
||||
Tcl_ResetResult(p->interp);
|
||||
if( p->pScript && p->mask&TESTVFS_OPEN_MASK ){
|
||||
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
|
||||
Tcl_Obj *pArg = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pArg);
|
||||
if( flags&SQLITE_OPEN_MAIN_DB ){
|
||||
const char *z = &zName[strlen(zName)+1];
|
||||
while( *z ){
|
||||
Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
|
||||
z += strlen(z) + 1;
|
||||
Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1));
|
||||
z += strlen(z) + 1;
|
||||
}
|
||||
}
|
||||
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}else{
|
||||
@@ -663,6 +649,14 @@ static int tvfsFullPathname(
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
Testvfs *p = (Testvfs *)pVfs->pAppData;
|
||||
if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){
|
||||
int rc;
|
||||
tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
}
|
||||
return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
|
||||
}
|
||||
|
||||
@@ -1028,18 +1022,19 @@ static int testvfs_obj_cmd(
|
||||
char *zName;
|
||||
int mask;
|
||||
} vfsmethod [] = {
|
||||
{ "xShmOpen", TESTVFS_SHMOPEN_MASK },
|
||||
{ "xShmLock", TESTVFS_SHMLOCK_MASK },
|
||||
{ "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
|
||||
{ "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
|
||||
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
||||
{ "xSync", TESTVFS_SYNC_MASK },
|
||||
{ "xDelete", TESTVFS_DELETE_MASK },
|
||||
{ "xWrite", TESTVFS_WRITE_MASK },
|
||||
{ "xTruncate", TESTVFS_TRUNCATE_MASK },
|
||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||
{ "xClose", TESTVFS_CLOSE_MASK },
|
||||
{ "xAccess", TESTVFS_ACCESS_MASK },
|
||||
{ "xShmOpen", TESTVFS_SHMOPEN_MASK },
|
||||
{ "xShmLock", TESTVFS_SHMLOCK_MASK },
|
||||
{ "xShmBarrier", TESTVFS_SHMBARRIER_MASK },
|
||||
{ "xShmUnmap", TESTVFS_SHMCLOSE_MASK },
|
||||
{ "xShmMap", TESTVFS_SHMMAP_MASK },
|
||||
{ "xSync", TESTVFS_SYNC_MASK },
|
||||
{ "xDelete", TESTVFS_DELETE_MASK },
|
||||
{ "xWrite", TESTVFS_WRITE_MASK },
|
||||
{ "xTruncate", TESTVFS_TRUNCATE_MASK },
|
||||
{ "xOpen", TESTVFS_OPEN_MASK },
|
||||
{ "xClose", TESTVFS_CLOSE_MASK },
|
||||
{ "xAccess", TESTVFS_ACCESS_MASK },
|
||||
{ "xFullPathname", TESTVFS_FULLPATHNAME_MASK },
|
||||
};
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem = 0;
|
||||
@@ -1076,9 +1071,6 @@ static int testvfs_obj_cmd(
|
||||
int nByte;
|
||||
if( p->pScript ){
|
||||
Tcl_DecrRefCount(p->pScript);
|
||||
ckfree((char *)p->apScript);
|
||||
p->apScript = 0;
|
||||
p->nScript = 0;
|
||||
p->pScript = 0;
|
||||
}
|
||||
Tcl_GetStringFromObj(objv[2], &nByte);
|
||||
@@ -1232,7 +1224,6 @@ static void testvfs_obj_del(ClientData cd){
|
||||
Testvfs *p = (Testvfs *)cd;
|
||||
if( p->pScript ) Tcl_DecrRefCount(p->pScript);
|
||||
sqlite3_vfs_unregister(p->pVfs);
|
||||
ckfree((char *)p->apScript);
|
||||
ckfree((char *)p->pVfs);
|
||||
ckfree((char *)p);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,100 @@
|
||||
**
|
||||
** This file contains code implements a VFS shim that writes diagnostic
|
||||
** output for each VFS call, similar to "strace".
|
||||
**
|
||||
** USAGE:
|
||||
**
|
||||
** This source file exports a single symbol which is the name of a
|
||||
** function:
|
||||
**
|
||||
** int vfstrace_register(
|
||||
** const char *zTraceName, // Name of the newly constructed VFS
|
||||
** const char *zOldVfsName, // Name of the underlying VFS
|
||||
** int (*xOut)(const char*,void*), // Output routine. ex: fputs
|
||||
** void *pOutArg, // 2nd argument to xOut. ex: stderr
|
||||
** int makeDefault // Make the new VFS the default
|
||||
** );
|
||||
**
|
||||
** Applications that want to trace their VFS usage must provide a callback
|
||||
** function with this prototype:
|
||||
**
|
||||
** int traceOutput(const char *zMessage, void *pAppData);
|
||||
**
|
||||
** This function will "output" the trace messages, where "output" can
|
||||
** mean different things to different applications. The traceOutput function
|
||||
** for the command-line shell (see shell.c) is "fputs" from the standard
|
||||
** library, which means that all trace output is written on the stream
|
||||
** specified by the second argument. In the case of the command-line shell
|
||||
** the second argument is stderr. Other applications might choose to output
|
||||
** trace information to a file, over a socket, or write it into a buffer.
|
||||
**
|
||||
** The vfstrace_register() function creates a new "shim" VFS named by
|
||||
** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
|
||||
** not really perform the duties of a true backend, but simply filters or
|
||||
** interprets VFS calls before passing them off to another VFS which does
|
||||
** the actual work. In this case the other VFS - the one that does the
|
||||
** real work - is identified by the second parameter, zOldVfsName. If
|
||||
** the the 2nd parameter is NULL then the default VFS is used. The common
|
||||
** case is for the 2nd parameter to be NULL.
|
||||
**
|
||||
** The third and fourth parameters are the pointer to the output function
|
||||
** and the second argument to the output function. For the SQLite
|
||||
** command-line shell, when the -vfstrace option is used, these parameters
|
||||
** are fputs and stderr, respectively.
|
||||
**
|
||||
** The fifth argument is true (non-zero) to cause the newly created VFS
|
||||
** to become the default VFS. The common case is for the fifth parameter
|
||||
** to be true.
|
||||
**
|
||||
** The call to vfstrace_register() simply creates the shim VFS that does
|
||||
** tracing. The application must also arrange to use the new VFS for
|
||||
** all database connections that are created and for which tracing is
|
||||
** desired. This can be done by specifying the trace VFS using URI filename
|
||||
** notation, or by specifying the trace VFS as the 4th parameter to
|
||||
** sqlite3_open_v2() or by making the trace VFS be the default (by setting
|
||||
** the 5th parameter of vfstrace_register() to 1).
|
||||
**
|
||||
**
|
||||
** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
|
||||
**
|
||||
** The SQLite command line shell implemented by the shell.c source file
|
||||
** can be used with this module. To compile in -vfstrace support, first
|
||||
** gather this file (test_vfstrace.c), the shell source file (shell.c),
|
||||
** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
|
||||
** the working directory. Then compile using a command like the following:
|
||||
**
|
||||
** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
|
||||
** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
|
||||
** -DHAVE_READLINE -DHAVE_USLEEP=1 \
|
||||
** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
|
||||
**
|
||||
** The gcc command above works on Linux and provides (in addition to the
|
||||
** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
|
||||
** editing using the readline library. The command-line shell does not
|
||||
** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
|
||||
** run a little faster. For compiling on a Mac, you'll probably need
|
||||
** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
|
||||
** The compilation could be simplified to just this:
|
||||
**
|
||||
** gcc -DSQLITE_ENABLE_VFSTRACE \
|
||||
** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
|
||||
**
|
||||
** In this second example, all unnecessary options have been removed
|
||||
** Note that since the code is now threadsafe, we had to add the -lpthread
|
||||
** option to pull in the pthreads library.
|
||||
**
|
||||
** To cross-compile for windows using MinGW, a command like this might
|
||||
** work:
|
||||
**
|
||||
** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
|
||||
** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
|
||||
** shell.c test_vfstrace.c sqlite3.c
|
||||
**
|
||||
** Similar compiler commands will work on different systems. The key
|
||||
** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
|
||||
** the shell.c source file will know to include the -vfstrace command-line
|
||||
** option and (2) you must compile and link the three source files
|
||||
** shell,c, test_vfstrace.c, and sqlite3.c.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
+9
-10
@@ -353,13 +353,12 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
testcase( z[0]=='x' ); testcase( z[0]=='X' );
|
||||
if( z[1]=='\'' ){
|
||||
*tokenType = TK_BLOB;
|
||||
for(i=2; (c=z[i])!=0 && c!='\''; i++){
|
||||
if( !sqlite3Isxdigit(c) ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
}
|
||||
for(i=2; sqlite3Isxdigit(z[i]); i++){}
|
||||
if( z[i]!='\'' || i%2 ){
|
||||
*tokenType = TK_ILLEGAL;
|
||||
while( z[i] && z[i]!='\'' ){ i++; }
|
||||
}
|
||||
if( i%2 || !c ) *tokenType = TK_ILLEGAL;
|
||||
if( c ) i++;
|
||||
if( z[i] ) i++;
|
||||
return i;
|
||||
}
|
||||
/* Otherwise fall through to the next case */
|
||||
@@ -412,9 +411,8 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( pParse->pNewTrigger==0 );
|
||||
assert( pParse->nVar==0 );
|
||||
assert( pParse->nVarExpr==0 );
|
||||
assert( pParse->nVarExprAlloc==0 );
|
||||
assert( pParse->apVarExpr==0 );
|
||||
assert( pParse->nzVar==0 );
|
||||
assert( pParse->azVar==0 );
|
||||
enableLookaside = db->lookaside.bEnabled;
|
||||
if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
|
||||
while( !db->mallocFailed && zSql[i]!=0 ){
|
||||
@@ -508,7 +506,8 @@ abort_parse:
|
||||
}
|
||||
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
sqlite3DbFree(db, pParse->apVarExpr);
|
||||
for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
|
||||
sqlite3DbFree(db, pParse->azVar);
|
||||
sqlite3DbFree(db, pParse->aAlias);
|
||||
while( pParse->pAinc ){
|
||||
AutoincInfo *p = pParse->pAinc;
|
||||
|
||||
+2
-3
@@ -301,9 +301,8 @@ void sqlite3FinishTrigger(
|
||||
pTrig->table, z);
|
||||
sqlite3DbFree(db, z);
|
||||
sqlite3ChangeCookie(pParse, iDb);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
|
||||
db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC
|
||||
);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
||||
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
|
||||
}
|
||||
|
||||
if( db->init.busy ){
|
||||
|
||||
+7
-4
@@ -23,7 +23,8 @@ static void updateVirtualTable(
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowidExpr, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
Expr *pWhere, /* WHERE clause of the UPDATE statement */
|
||||
int onError /* ON CONFLICT strategy */
|
||||
);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -243,7 +244,7 @@ void sqlite3Update(
|
||||
}
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int reg;
|
||||
if( chngRowid ){
|
||||
if( hasFK || chngRowid ){
|
||||
reg = ++pParse->nMem;
|
||||
}else{
|
||||
reg = 0;
|
||||
@@ -267,7 +268,7 @@ void sqlite3Update(
|
||||
/* Virtual tables must be handled separately */
|
||||
if( IsVirtual(pTab) ){
|
||||
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
|
||||
pWhere);
|
||||
pWhere, onError);
|
||||
pWhere = 0;
|
||||
pTabList = 0;
|
||||
goto update_cleanup;
|
||||
@@ -597,7 +598,8 @@ static void updateVirtualTable(
|
||||
ExprList *pChanges, /* The columns to change in the UPDATE statement */
|
||||
Expr *pRowid, /* Expression used to recompute the rowid */
|
||||
int *aXRef, /* Mapping from columns of pTab to entries in pChanges */
|
||||
Expr *pWhere /* WHERE clause of the UPDATE statement */
|
||||
Expr *pWhere, /* WHERE clause of the UPDATE statement */
|
||||
int onError /* ON CONFLICT strategy */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */
|
||||
ExprList *pEList = 0; /* The result set of the SELECT statement */
|
||||
@@ -654,6 +656,7 @@ static void updateVirtualTable(
|
||||
}
|
||||
sqlite3VtabMakeWritable(pParse, pTab);
|
||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
|
||||
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
|
||||
sqlite3MayAbort(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
@@ -163,7 +163,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|
||||
|| (c&0xFFFFF800)==0xD800 \
|
||||
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
|
||||
}
|
||||
int sqlite3Utf8Read(
|
||||
u32 sqlite3Utf8Read(
|
||||
const unsigned char *zIn, /* First byte of UTF-8 character */
|
||||
const unsigned char **pzNext /* Write first byte past UTF-8 char here */
|
||||
){
|
||||
|
||||
+28
-4
@@ -983,13 +983,12 @@ void sqlite3Put4byte(unsigned char *p, u32 v){
|
||||
|
||||
|
||||
|
||||
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
** This routine only works if h really is a valid hexadecimal
|
||||
** character: 0..9a..fA..F
|
||||
*/
|
||||
static u8 hexToInt(int h){
|
||||
u8 sqlite3HexToInt(int h){
|
||||
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
|
||||
#ifdef SQLITE_ASCII
|
||||
h += 9*(1&(h>>6));
|
||||
@@ -999,7 +998,6 @@ static u8 hexToInt(int h){
|
||||
#endif
|
||||
return (u8)(h & 0xf);
|
||||
}
|
||||
#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
|
||||
|
||||
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
|
||||
/*
|
||||
@@ -1016,7 +1014,7 @@ void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
|
||||
n--;
|
||||
if( zBlob ){
|
||||
for(i=0; i<n; i+=2){
|
||||
zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
|
||||
zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
|
||||
}
|
||||
zBlob[i/2] = 0;
|
||||
}
|
||||
@@ -1148,3 +1146,29 @@ int sqlite3AbsInt32(int x){
|
||||
if( x==(int)0x80000000 ) return 0x7fffffff;
|
||||
return -x;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_8_3_NAMES
|
||||
/*
|
||||
** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database
|
||||
** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
|
||||
** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
|
||||
** three characters, then shorten the suffix on z[] to be the last three
|
||||
** characters of the original suffix.
|
||||
**
|
||||
** Examples:
|
||||
**
|
||||
** test.db-journal => test.nal
|
||||
** test.db-wal => test.wal
|
||||
** test.db-shm => test.shm
|
||||
*/
|
||||
void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
|
||||
const char *zOk;
|
||||
zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
|
||||
if( zOk && sqlite3GetBoolean(zOk) ){
|
||||
int i, sz;
|
||||
sz = sqlite3Strlen30(z);
|
||||
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
|
||||
if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+79
-38
@@ -564,6 +564,7 @@ int sqlite3VdbeExec(
|
||||
Mem *pOut = 0; /* Output operand */
|
||||
int iCompare = 0; /* Result of last OP_Compare operation */
|
||||
int *aPermute = 0; /* Permutation of columns for OP_Compare */
|
||||
i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */
|
||||
#ifdef VDBE_PROFILE
|
||||
u64 start; /* CPU clock count at start of opcode */
|
||||
int origPc; /* Program counter at start of opcode */
|
||||
@@ -796,7 +797,7 @@ case OP_Yield: { /* in1 */
|
||||
|
||||
/* Opcode: HaltIfNull P1 P2 P3 P4 *
|
||||
**
|
||||
** Check the value in register P3. If is is NULL then Halt using
|
||||
** Check the value in register P3. If it is NULL then Halt using
|
||||
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
|
||||
** value in register P3 is not NULL, then this routine is a no-op.
|
||||
*/
|
||||
@@ -833,6 +834,7 @@ case OP_Halt: {
|
||||
p->nFrame--;
|
||||
sqlite3VdbeSetChanges(db, p->nChange);
|
||||
pc = sqlite3VdbeFrameRestore(pFrame);
|
||||
lastRowid = db->lastRowid;
|
||||
if( pOp->p2==OE_Ignore ){
|
||||
/* Instruction pc is the OP_Program that invoked the sub-program
|
||||
** currently being halted. If the p2 instruction of this OP_Halt
|
||||
@@ -986,6 +988,7 @@ case OP_Variable: { /* out2-prerelease */
|
||||
Mem *pVar; /* Value being transferred */
|
||||
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
||||
assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
|
||||
pVar = &p->aVar[pOp->p1 - 1];
|
||||
if( sqlite3VdbeMemTooBig(pVar) ){
|
||||
goto too_big;
|
||||
@@ -1393,16 +1396,9 @@ case OP_Function: {
|
||||
assert( pOp[-1].opcode==OP_CollSeq );
|
||||
ctx.pColl = pOp[-1].p4.pColl;
|
||||
}
|
||||
db->lastRowid = lastRowid;
|
||||
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
|
||||
if( db->mallocFailed ){
|
||||
/* Even though a malloc() has failed, the implementation of the
|
||||
** user function may have called an sqlite3_result_XXX() function
|
||||
** to return a value. The following call releases any resources
|
||||
** associated with such a value.
|
||||
*/
|
||||
sqlite3VdbeMemRelease(&ctx.s);
|
||||
goto no_mem;
|
||||
}
|
||||
lastRowid = db->lastRowid;
|
||||
|
||||
/* If any auxiliary data functions have been called by this user function,
|
||||
** immediately call the destructor for any non-static values.
|
||||
@@ -1413,6 +1409,16 @@ case OP_Function: {
|
||||
pOp->p4type = P4_VDBEFUNC;
|
||||
}
|
||||
|
||||
if( db->mallocFailed ){
|
||||
/* Even though a malloc() has failed, the implementation of the
|
||||
** user function may have called an sqlite3_result_XXX() function
|
||||
** to return a value. The following call releases any resources
|
||||
** associated with such a value.
|
||||
*/
|
||||
sqlite3VdbeMemRelease(&ctx.s);
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
/* If the function returned an error, throw an exception */
|
||||
if( ctx.isError ){
|
||||
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
|
||||
@@ -1714,7 +1720,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
||||
** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
|
||||
** true or false and is never NULL. If both operands are NULL then the result
|
||||
** of comparison is false. If either operand is NULL then the result is true.
|
||||
** If neither operand is NULL the the result is the same as it would be if
|
||||
** If neither operand is NULL the result is the same as it would be if
|
||||
** the SQLITE_NULLEQ flag were omitted from P5.
|
||||
*/
|
||||
/* Opcode: Eq P1 P2 P3 P4 P5
|
||||
@@ -1726,7 +1732,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
|
||||
** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
|
||||
** true or false and is never NULL. If both operands are NULL then the result
|
||||
** of comparison is true. If either operand is NULL then the result is false.
|
||||
** If neither operand is NULL the the result is the same as it would be if
|
||||
** If neither operand is NULL the result is the same as it would be if
|
||||
** the SQLITE_NULLEQ flag were omitted from P5.
|
||||
*/
|
||||
/* Opcode: Le P1 P2 P3 P4 P5
|
||||
@@ -1762,7 +1768,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
flags1 = pIn1->flags;
|
||||
flags3 = pIn3->flags;
|
||||
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
|
||||
if( (flags1 | flags3)&MEM_Null ){
|
||||
/* One or both operands are NULL */
|
||||
if( pOp->p5 & SQLITE_NULLEQ ){
|
||||
/* If SQLITE_NULLEQ is set (which will only happen if the operator is
|
||||
@@ -1770,7 +1776,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** or not both operands are null.
|
||||
*/
|
||||
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
|
||||
res = (pIn1->flags & pIn3->flags & MEM_Null)==0;
|
||||
res = (flags1 & flags3 & MEM_Null)==0;
|
||||
}else{
|
||||
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
|
||||
** then the result is always NULL.
|
||||
@@ -2005,13 +2011,13 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
|
||||
/* Opcode: If P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is true. The value is
|
||||
** Jump to P2 if the value in register P1 is true. The value
|
||||
** is considered true if it is numeric and non-zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
*/
|
||||
/* Opcode: IfNot P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is False. The value is
|
||||
** Jump to P2 if the value in register P1 is False. The value
|
||||
** is considered true if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
*/
|
||||
@@ -2580,6 +2586,17 @@ case OP_Savepoint: {
|
||||
}else{
|
||||
nName = sqlite3Strlen30(zName);
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* This call is Ok even if this savepoint is actually a transaction
|
||||
** savepoint (and therefore should not prompt xSavepoint()) callbacks.
|
||||
** If this is a transaction savepoint being opened, it is guaranteed
|
||||
** that the db->aVTrans[] array is empty. */
|
||||
assert( db->autoCommit==0 || db->nVTrans==0 );
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN,
|
||||
db->nStatement+db->nSavepoint);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
#endif
|
||||
|
||||
/* Create a new savepoint structure. */
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1);
|
||||
if( pNew ){
|
||||
@@ -2686,6 +2703,11 @@ case OP_Savepoint: {
|
||||
}else{
|
||||
db->nDeferredCons = pSavepoint->nDeferredCons;
|
||||
}
|
||||
|
||||
if( !isTransaction ){
|
||||
rc = sqlite3VtabSavepoint(db, p1, iSavepoint);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2821,7 +2843,11 @@ case OP_Transaction: {
|
||||
db->nStatement++;
|
||||
p->iStatement = db->nSavepoint + db->nStatement;
|
||||
}
|
||||
rc = sqlite3BtreeBeginStmt(pBt, p->iStatement);
|
||||
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeBeginStmt(pBt, p->iStatement);
|
||||
}
|
||||
|
||||
/* Store the current value of the database handles deferred constraint
|
||||
** counter. If the statement transaction needs to be rolled back,
|
||||
@@ -3132,7 +3158,7 @@ case OP_OpenEphemeral: {
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
rc = sqlite3BtreeOpen(0, db, &pCx->pBt,
|
||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
|
||||
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
|
||||
@@ -3609,7 +3635,7 @@ case OP_IsUnique: { /* jump, in3 */
|
||||
|
||||
/* Opcode: NotExists P1 P2 P3 * *
|
||||
**
|
||||
** Use the content of register P3 as a integer key. If a record
|
||||
** Use the content of register P3 as an integer key. If a record
|
||||
** with that key does not exist in table of P1, then jump to P2.
|
||||
** If the record does exist, then fall through. The cursor is left
|
||||
** pointing to the record if it exists.
|
||||
@@ -3685,7 +3711,7 @@ case OP_Sequence: { /* out2-prerelease */
|
||||
** If P3>0 then P3 is a register in the root frame of this VDBE that holds
|
||||
** the largest previously generated record number. No new record numbers are
|
||||
** allowed to be less than this value. When this value reaches its maximum,
|
||||
** a SQLITE_FULL error is generated. The P3 register is updated with the '
|
||||
** an SQLITE_FULL error is generated. The P3 register is updated with the '
|
||||
** generated record number. This P3 mechanism is used to help implement the
|
||||
** AUTOINCREMENT feature.
|
||||
*/
|
||||
@@ -3792,7 +3818,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is
|
||||
** an AUTOINCREMENT table. */
|
||||
/* on the first attempt, simply do one more than previous */
|
||||
v = db->lastRowid;
|
||||
v = lastRowid;
|
||||
v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
|
||||
v++; /* ensure non-zero */
|
||||
cnt = 0;
|
||||
@@ -3902,7 +3928,7 @@ case OP_InsertInt: {
|
||||
}
|
||||
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey;
|
||||
if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey;
|
||||
if( pData->flags & MEM_Null ){
|
||||
pData->z = 0;
|
||||
pData->n = 0;
|
||||
@@ -4309,7 +4335,7 @@ case OP_Next: { /* jump */
|
||||
|
||||
/* Opcode: IdxInsert P1 P2 P3 * P5
|
||||
**
|
||||
** Register P2 holds a SQL index key made using the
|
||||
** Register P2 holds an SQL index key made using the
|
||||
** MakeRecord instructions. This opcode writes that key
|
||||
** into the index P1. Data for the entry is nil.
|
||||
**
|
||||
@@ -4990,7 +5016,7 @@ case OP_Program: { /* jump */
|
||||
|
||||
p->nFrame++;
|
||||
pFrame->pParent = p->pFrame;
|
||||
pFrame->lastRowid = db->lastRowid;
|
||||
pFrame->lastRowid = lastRowid;
|
||||
pFrame->nChange = p->nChange;
|
||||
p->nChange = 0;
|
||||
p->pFrame = pFrame;
|
||||
@@ -5773,11 +5799,15 @@ case OP_VUpdate: {
|
||||
Mem **apArg;
|
||||
Mem *pX;
|
||||
|
||||
assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|
||||
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
|
||||
);
|
||||
pVtab = pOp->p4.pVtab->pVtab;
|
||||
pModule = (sqlite3_module *)pVtab->pModule;
|
||||
nArg = pOp->p2;
|
||||
assert( pOp->p4type==P4_VTAB );
|
||||
if( ALWAYS(pModule->xUpdate) ){
|
||||
u8 vtabOnConflict = db->vtabOnConflict;
|
||||
apArg = p->apArg;
|
||||
pX = &aMem[pOp->p3];
|
||||
for(i=0; i<nArg; i++){
|
||||
@@ -5787,13 +5817,23 @@ case OP_VUpdate: {
|
||||
apArg[i] = pX;
|
||||
pX++;
|
||||
}
|
||||
db->vtabOnConflict = pOp->p5;
|
||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||
db->vtabOnConflict = vtabOnConflict;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( rc==SQLITE_OK && pOp->p1 ){
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = rowid;
|
||||
db->lastRowid = lastRowid = rowid;
|
||||
}
|
||||
if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
|
||||
if( pOp->p5==OE_Ignore ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
|
||||
}
|
||||
}else{
|
||||
p->nChange++;
|
||||
}
|
||||
p->nChange++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5844,20 +5884,20 @@ case OP_MaxPgcnt: { /* out2-prerelease */
|
||||
*/
|
||||
case OP_Trace: {
|
||||
char *zTrace;
|
||||
char *z;
|
||||
|
||||
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
|
||||
if( zTrace ){
|
||||
if( db->xTrace ){
|
||||
char *z = sqlite3VdbeExpandSql(p, zTrace);
|
||||
db->xTrace(db->pTraceArg, z);
|
||||
sqlite3DbFree(db, z);
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (db->flags & SQLITE_SqlTrace)!=0 ){
|
||||
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
if( db->xTrace && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
|
||||
z = sqlite3VdbeExpandSql(p, zTrace);
|
||||
db->xTrace(db->pTraceArg, z);
|
||||
sqlite3DbFree(db, z);
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (db->flags & SQLITE_SqlTrace)!=0
|
||||
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
||||
){
|
||||
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -5941,6 +5981,7 @@ vdbe_error_halt:
|
||||
** release the mutexes on btrees that were acquired at the
|
||||
** top. */
|
||||
vdbe_return:
|
||||
db->lastRowid = lastRowid;
|
||||
sqlite3VdbeLeave(p);
|
||||
return rc;
|
||||
|
||||
|
||||
+3
-1
@@ -172,6 +172,7 @@ int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
|
||||
int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
|
||||
int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
|
||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
|
||||
@@ -185,7 +186,7 @@ int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
@@ -194,6 +195,7 @@ int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||
void sqlite3VdbeTrace(Vdbe*,FILE*);
|
||||
#endif
|
||||
void sqlite3VdbeResetStepResult(Vdbe*);
|
||||
void sqlite3VdbeRewind(Vdbe*);
|
||||
int sqlite3VdbeReset(Vdbe*);
|
||||
void sqlite3VdbeSetNumCols(Vdbe*,int);
|
||||
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
|
||||
|
||||
+1
-1
@@ -287,11 +287,11 @@ struct Vdbe {
|
||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||
char **azVar; /* Name of variables */
|
||||
ynVar nVar; /* Number of entries in aVar[] */
|
||||
ynVar nzVar; /* Number of entries in azVar[] */
|
||||
u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
||||
int pc; /* The program counter */
|
||||
int rc; /* Value to return */
|
||||
u8 errorAction; /* Recovery action to do in case of an error */
|
||||
u8 okVar; /* True if azVar[] has been initialized */
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 expired; /* True if the VM needs to be recompiled */
|
||||
|
||||
+12
-32
@@ -102,7 +102,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
sqlite3_mutex_enter(v->db->mutex);
|
||||
rc = sqlite3VdbeReset(v);
|
||||
sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0);
|
||||
sqlite3VdbeRewind(v);
|
||||
assert( (rc & (v->db->errMask))==rc );
|
||||
rc = sqlite3ApiExit(v->db, rc);
|
||||
sqlite3_mutex_leave(v->db->mutex);
|
||||
@@ -459,6 +459,14 @@ end_of_step:
|
||||
return (rc&db->errMask);
|
||||
}
|
||||
|
||||
/*
|
||||
** The maximum number of times that a statement will try to reparse
|
||||
** itself before giving up and returning SQLITE_SCHEMA.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_SCHEMA_RETRY
|
||||
# define SQLITE_MAX_SCHEMA_RETRY 5
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This is the top-level implementation of sqlite3_step(). Call
|
||||
** sqlite3Step() to do most of the work. If a schema error occurs,
|
||||
@@ -477,7 +485,7 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||
db = v->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
||||
&& cnt++ < 5
|
||||
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY
|
||||
&& (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
|
||||
sqlite3_reset(pStmt);
|
||||
v->expired = 0;
|
||||
@@ -1167,32 +1175,6 @@ int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
|
||||
return p ? p->nVar : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a mapping from variable numbers to variable names
|
||||
** in the Vdbe.azVar[] array, if such a mapping does not already
|
||||
** exist.
|
||||
*/
|
||||
static void createVarMap(Vdbe *p){
|
||||
if( !p->okVar ){
|
||||
int j;
|
||||
Op *pOp;
|
||||
sqlite3_mutex_enter(p->db->mutex);
|
||||
/* The race condition here is harmless. If two threads call this
|
||||
** routine on the same Vdbe at the same time, they both might end
|
||||
** up initializing the Vdbe.azVar[] array. That is a little extra
|
||||
** work but it results in the same answer.
|
||||
*/
|
||||
for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
|
||||
if( pOp->opcode==OP_Variable ){
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nVar );
|
||||
p->azVar[pOp->p1-1] = pOp->p4.z;
|
||||
}
|
||||
}
|
||||
p->okVar = 1;
|
||||
sqlite3_mutex_leave(p->db->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of a wildcard parameter. Return NULL if the index
|
||||
** is out of range or if the wildcard is unnamed.
|
||||
@@ -1201,10 +1183,9 @@ static void createVarMap(Vdbe *p){
|
||||
*/
|
||||
const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
if( p==0 || i<1 || i>p->nVar ){
|
||||
if( p==0 || i<1 || i>p->nzVar ){
|
||||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
return p->azVar[i-1];
|
||||
}
|
||||
|
||||
@@ -1218,9 +1199,8 @@ int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
|
||||
if( p==0 ){
|
||||
return 0;
|
||||
}
|
||||
createVarMap(p);
|
||||
if( zName ){
|
||||
for(i=0; i<p->nVar; i++){
|
||||
for(i=0; i<p->nzVar; i++){
|
||||
const char *z = p->azVar[i];
|
||||
if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
|
||||
return i+1;
|
||||
|
||||
+156
-119
@@ -156,13 +156,6 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
||||
pOp->p3 = p3;
|
||||
pOp->p4.p = 0;
|
||||
pOp->p4type = P4_NOTUSED;
|
||||
p->expired = 0;
|
||||
if( op==OP_ParseSchema ){
|
||||
/* Any program that uses the OP_ParseSchema opcode needs to lock
|
||||
** all btrees. */
|
||||
int j;
|
||||
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
pOp->zComment = 0;
|
||||
if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
||||
@@ -201,6 +194,20 @@ int sqlite3VdbeAddOp4(
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an OP_ParseSchema opcode. This routine is broken out from
|
||||
** sqlite3VdbeAddOp4() since it needs to also local all btrees.
|
||||
**
|
||||
** The zWhere string must have been obtained from sqlite3_malloc().
|
||||
** This routine will take ownership of the allocated memory.
|
||||
*/
|
||||
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
|
||||
int j;
|
||||
int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
|
||||
sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
|
||||
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add an opcode that includes the p4 value as an integer.
|
||||
*/
|
||||
@@ -1391,34 +1398,13 @@ static void *allocSpace(
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare a virtual machine for execution. This involves things such
|
||||
** as allocating stack space and initializing the program counter.
|
||||
** After the VDBE has be prepped, it can be executed by one or more
|
||||
** calls to sqlite3VdbeExec().
|
||||
**
|
||||
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
|
||||
** VDBE_MAGIC_RUN.
|
||||
**
|
||||
** This function may be called more than once on a single virtual machine.
|
||||
** The first call is made while compiling the SQL statement. Subsequent
|
||||
** calls are made as part of the process of resetting a statement to be
|
||||
** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor
|
||||
** and isExplain parameters are only passed correct values the first time
|
||||
** the function is called. On subsequent calls, from sqlite3_reset(), nVar
|
||||
** is passed -1 and nMem, nCursor and isExplain are all passed zero.
|
||||
** Rewind the VDBE back to the beginning in preparation for
|
||||
** running it.
|
||||
*/
|
||||
void sqlite3VdbeMakeReady(
|
||||
Vdbe *p, /* The VDBE */
|
||||
int nVar, /* Number of '?' see in the SQL statement */
|
||||
int nMem, /* Number of memory cells to allocate */
|
||||
int nCursor, /* Number of cursors to allocate */
|
||||
int nArg, /* Maximum number of args in SubPrograms */
|
||||
int isExplain, /* True if the EXPLAIN keywords is present */
|
||||
int usesStmtJournal /* True to set Vdbe.usesStmtJournal */
|
||||
){
|
||||
int n;
|
||||
sqlite3 *db = p->db;
|
||||
|
||||
void sqlite3VdbeRewind(Vdbe *p){
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
int i;
|
||||
#endif
|
||||
assert( p!=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
|
||||
@@ -1429,6 +1415,71 @@ void sqlite3VdbeMakeReady(
|
||||
/* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(i=1; i<p->nMem; i++){
|
||||
assert( p->aMem[i].db==p->db );
|
||||
}
|
||||
#endif
|
||||
p->pc = -1;
|
||||
p->rc = SQLITE_OK;
|
||||
p->errorAction = OE_Abort;
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
p->nChange = 0;
|
||||
p->cacheCtr = 1;
|
||||
p->minWriteFileFormat = 255;
|
||||
p->iStatement = 0;
|
||||
p->nFkConstraint = 0;
|
||||
#ifdef VDBE_PROFILE
|
||||
for(i=0; i<p->nOp; i++){
|
||||
p->aOp[i].cnt = 0;
|
||||
p->aOp[i].cycles = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare a virtual machine for execution for the first time after
|
||||
** creating the virtual machine. This involves things such
|
||||
** as allocating stack space and initializing the program counter.
|
||||
** After the VDBE has be prepped, it can be executed by one or more
|
||||
** calls to sqlite3VdbeExec().
|
||||
**
|
||||
** This function may be called exact once on a each virtual machine.
|
||||
** After this routine is called the VM has been "packaged" and is ready
|
||||
** to run. After this routine is called, futher calls to
|
||||
** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
|
||||
** the Vdbe from the Parse object that helped generate it so that the
|
||||
** the Vdbe becomes an independent entity and the Parse object can be
|
||||
** destroyed.
|
||||
**
|
||||
** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back
|
||||
** to its initial state after it has been run.
|
||||
*/
|
||||
void sqlite3VdbeMakeReady(
|
||||
Vdbe *p, /* The VDBE */
|
||||
Parse *pParse /* Parsing context */
|
||||
){
|
||||
sqlite3 *db; /* The database connection */
|
||||
int nVar; /* Number of parameters */
|
||||
int nMem; /* Number of VM memory registers */
|
||||
int nCursor; /* Number of cursors required */
|
||||
int nArg; /* Number of arguments in subprograms */
|
||||
int n; /* Loop counter */
|
||||
u8 *zCsr; /* Memory available for allocation */
|
||||
u8 *zEnd; /* First byte past allocated memory */
|
||||
int nByte; /* How much extra memory is needed */
|
||||
|
||||
assert( p!=0 );
|
||||
assert( p->nOp>0 );
|
||||
assert( pParse!=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
db = p->db;
|
||||
assert( db->mallocFailed==0 );
|
||||
nVar = pParse->nVar;
|
||||
nMem = pParse->nMem;
|
||||
nCursor = pParse->nTab;
|
||||
nArg = pParse->nMaxArg;
|
||||
|
||||
/* For each cursor required, also allocate a memory cell. Memory
|
||||
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
|
||||
** the vdbe program. Instead they are used to allocate space for
|
||||
@@ -1441,91 +1492,69 @@ void sqlite3VdbeMakeReady(
|
||||
nMem += nCursor;
|
||||
|
||||
/* Allocate space for memory registers, SQL variables, VDBE cursors and
|
||||
** an array to marshal SQL function arguments in. This is only done the
|
||||
** first time this function is called for a given VDBE, not when it is
|
||||
** being called from sqlite3_reset() to reset the virtual machine.
|
||||
** an array to marshal SQL function arguments in.
|
||||
*/
|
||||
if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
|
||||
u8 *zCsr = (u8 *)&p->aOp[p->nOp]; /* Memory avaliable for alloation */
|
||||
u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; /* First byte past available mem */
|
||||
int nByte; /* How much extra memory needed */
|
||||
zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */
|
||||
zEnd = (u8*)&p->aOp[p->nOpAlloc]; /* First byte past end of zCsr[] */
|
||||
|
||||
resolveP2Values(p, &nArg);
|
||||
p->usesStmtJournal = (u8)usesStmtJournal;
|
||||
if( isExplain && nMem<10 ){
|
||||
nMem = 10;
|
||||
resolveP2Values(p, &nArg);
|
||||
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
|
||||
if( pParse->explain && nMem<10 ){
|
||||
nMem = 10;
|
||||
}
|
||||
memset(zCsr, 0, zEnd-zCsr);
|
||||
zCsr += (zCsr - (u8*)0)&7;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
||||
p->expired = 0;
|
||||
|
||||
/* Memory for registers, parameters, cursor, etc, is allocated in two
|
||||
** passes. On the first pass, we try to reuse unused space at the
|
||||
** end of the opcode array. If we are unable to satisfy all memory
|
||||
** requirements by reusing the opcode array tail, then the second
|
||||
** pass will fill in the rest using a fresh allocation.
|
||||
**
|
||||
** This two-pass approach that reuses as much memory as possible from
|
||||
** the leftover space at the end of the opcode array can significantly
|
||||
** reduce the amount of memory held by a prepared statement.
|
||||
*/
|
||||
do {
|
||||
nByte = 0;
|
||||
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
||||
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
||||
&zCsr, zEnd, &nByte);
|
||||
if( nByte ){
|
||||
p->pFree = sqlite3DbMallocZero(db, nByte);
|
||||
}
|
||||
memset(zCsr, 0, zEnd-zCsr);
|
||||
zCsr += (zCsr - (u8*)0)&7;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
|
||||
zCsr = p->pFree;
|
||||
zEnd = &zCsr[nByte];
|
||||
}while( nByte && !db->mallocFailed );
|
||||
|
||||
/* Memory for registers, parameters, cursor, etc, is allocated in two
|
||||
** passes. On the first pass, we try to reuse unused space at the
|
||||
** end of the opcode array. If we are unable to satisfy all memory
|
||||
** requirements by reusing the opcode array tail, then the second
|
||||
** pass will fill in the rest using a fresh allocation.
|
||||
**
|
||||
** This two-pass approach that reuses as much memory as possible from
|
||||
** the leftover space at the end of the opcode array can significantly
|
||||
** reduce the amount of memory held by a prepared statement.
|
||||
*/
|
||||
do {
|
||||
nByte = 0;
|
||||
p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
|
||||
p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
|
||||
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
||||
&zCsr, zEnd, &nByte);
|
||||
if( nByte ){
|
||||
p->pFree = sqlite3DbMallocZero(db, nByte);
|
||||
}
|
||||
zCsr = p->pFree;
|
||||
zEnd = &zCsr[nByte];
|
||||
}while( nByte && !db->mallocFailed );
|
||||
|
||||
p->nCursor = (u16)nCursor;
|
||||
if( p->aVar ){
|
||||
p->nVar = (ynVar)nVar;
|
||||
for(n=0; n<nVar; n++){
|
||||
p->aVar[n].flags = MEM_Null;
|
||||
p->aVar[n].db = db;
|
||||
}
|
||||
}
|
||||
if( p->aMem ){
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
p->nCursor = (u16)nCursor;
|
||||
if( p->aVar ){
|
||||
p->nVar = (ynVar)nVar;
|
||||
for(n=0; n<nVar; n++){
|
||||
p->aVar[n].flags = MEM_Null;
|
||||
p->aVar[n].db = db;
|
||||
}
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(n=1; n<p->nMem; n++){
|
||||
assert( p->aMem[n].db==db );
|
||||
if( p->azVar ){
|
||||
p->nzVar = pParse->nzVar;
|
||||
memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
|
||||
memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
|
||||
}
|
||||
#endif
|
||||
|
||||
p->pc = -1;
|
||||
p->rc = SQLITE_OK;
|
||||
p->errorAction = OE_Abort;
|
||||
p->explain |= isExplain;
|
||||
p->magic = VDBE_MAGIC_RUN;
|
||||
p->nChange = 0;
|
||||
p->cacheCtr = 1;
|
||||
p->minWriteFileFormat = 255;
|
||||
p->iStatement = 0;
|
||||
p->nFkConstraint = 0;
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<p->nOp; i++){
|
||||
p->aOp[i].cnt = 0;
|
||||
p->aOp[i].cycles = 0;
|
||||
if( p->aMem ){
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p->explain = pParse->explain;
|
||||
sqlite3VdbeRewind(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1799,6 +1828,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
if( !zMaster ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3FileSuffix3(zMainFile, zMaster);
|
||||
rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
|
||||
}while( rc==SQLITE_OK && res );
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2013,6 +2043,15 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
||||
db->nStatement--;
|
||||
p->iStatement = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( eOp==SAVEPOINT_ROLLBACK ){
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the statement transaction is being rolled back, also restore the
|
||||
** database handles deferred constraint counter to the value it had when
|
||||
** the statement transaction was opened. */
|
||||
@@ -2192,17 +2231,11 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
** do so. If this operation returns an error, and the current statement
|
||||
** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
|
||||
** current statement error code.
|
||||
**
|
||||
** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
|
||||
** is SAVEPOINT_ROLLBACK. But if p->rc==SQLITE_OK then eStatementOp
|
||||
** must be SAVEPOINT_RELEASE. Hence the NEVER(p->rc==SQLITE_OK) in
|
||||
** the following code.
|
||||
*/
|
||||
if( eStatementOp ){
|
||||
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
|
||||
if( rc ){
|
||||
assert( eStatementOp==SAVEPOINT_ROLLBACK );
|
||||
if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
|
||||
if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
|
||||
p->rc = rc;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
@@ -2395,6 +2428,7 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
|
||||
*/
|
||||
void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
|
||||
SubProgram *pSub, *pNext;
|
||||
int i;
|
||||
assert( p->db==0 || p->db==db );
|
||||
releaseMemArray(p->aVar, p->nVar);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
@@ -2403,6 +2437,7 @@ void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
|
||||
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
|
||||
sqlite3DbFree(db, pSub);
|
||||
}
|
||||
for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
|
||||
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
||||
sqlite3DbFree(db, p->aLabel);
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
@@ -2848,7 +2883,7 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
|
||||
idx += getVarint32(&aKey[idx], serial_type);
|
||||
pMem->enc = pKeyInfo->enc;
|
||||
pMem->db = pKeyInfo->db;
|
||||
pMem->flags = 0;
|
||||
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
|
||||
pMem->zMalloc = 0;
|
||||
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
||||
pMem++;
|
||||
@@ -2863,6 +2898,7 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(
|
||||
** This routine destroys a UnpackedRecord object.
|
||||
*/
|
||||
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
|
||||
#ifdef SQLITE_DEBUG
|
||||
int i;
|
||||
Mem *pMem;
|
||||
|
||||
@@ -2876,6 +2912,7 @@ void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
|
||||
*/
|
||||
if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
#endif
|
||||
if( p->flags & UNPACKED_NEED_FREE ){
|
||||
sqlite3DbFree(p->pKeyInfo->db, p);
|
||||
}
|
||||
@@ -2929,7 +2966,7 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
/* Compilers may complain that mem1.u.i is potentially uninitialized.
|
||||
** We could initialize it, as shown here, to silence those complaints.
|
||||
** But in fact, mem1.u.i will never actually be used initialized, and doing
|
||||
** But in fact, mem1.u.i will never actually be used uninitialized, and doing
|
||||
** the unnecessary initialization has a measurable negative performance
|
||||
** impact, since this routine is a very high runner. And so, we choose
|
||||
** to ignore the compiler warnings and leave this variable uninitialized.
|
||||
|
||||
+4
-1
@@ -297,7 +297,10 @@ int sqlite3_blob_open(
|
||||
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
|
||||
if( !db->mallocFailed ){
|
||||
sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0);
|
||||
pParse->nVar = 1;
|
||||
pParse->nMem = 1;
|
||||
pParse->nTab = 1;
|
||||
sqlite3VdbeMakeReady(v, pParse);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+146
-20
@@ -14,6 +14,18 @@
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/*
|
||||
** Before a virtual table xCreate() or xConnect() method is invoked, the
|
||||
** sqlite3.pVtabCtx member variable is set to point to an instance of
|
||||
** this struct allocated on the stack. It is used by the implementation of
|
||||
** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
|
||||
** are invoked only from within xCreate and xConnect methods.
|
||||
*/
|
||||
struct VtabCtx {
|
||||
Table *pTab;
|
||||
VTable *pVTable;
|
||||
};
|
||||
|
||||
/*
|
||||
** The actual function that does the work of creating a new module.
|
||||
** This function implements the sqlite3_create_module() and
|
||||
@@ -42,13 +54,13 @@ static int createModule(
|
||||
pMod->xDestroy = xDestroy;
|
||||
pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
|
||||
if( pDel && pDel->xDestroy ){
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
pDel->xDestroy(pDel->pAux);
|
||||
}
|
||||
sqlite3DbFree(db, pDel);
|
||||
if( pDel==pMod ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, -1);
|
||||
}else if( xDestroy ){
|
||||
xDestroy(pAux);
|
||||
}
|
||||
@@ -371,7 +383,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
|
||||
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
||||
sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
|
||||
pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
|
||||
}
|
||||
@@ -434,6 +446,7 @@ static int vtabCallConstructor(
|
||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||
char **pzErr
|
||||
){
|
||||
VtabCtx sCtx;
|
||||
VTable *pVTable;
|
||||
int rc;
|
||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||
@@ -453,12 +466,14 @@ static int vtabCallConstructor(
|
||||
pVTable->db = db;
|
||||
pVTable->pMod = pMod;
|
||||
|
||||
assert( !db->pVTab );
|
||||
assert( xConstruct );
|
||||
db->pVTab = pTab;
|
||||
|
||||
/* Invoke the virtual table constructor */
|
||||
assert( &db->pVtabCtx );
|
||||
assert( xConstruct );
|
||||
sCtx.pTab = pTab;
|
||||
sCtx.pVTable = pVTable;
|
||||
db->pVtabCtx = &sCtx;
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
db->pVtabCtx = 0;
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
@@ -474,7 +489,7 @@ static int vtabCallConstructor(
|
||||
** the sqlite3_vtab object if successful. */
|
||||
pVTable->pVtab->pModule = pMod->pModule;
|
||||
pVTable->nRef = 1;
|
||||
if( db->pVTab ){
|
||||
if( sCtx.pTab ){
|
||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||
sqlite3VtabUnlock(pVTable);
|
||||
@@ -522,7 +537,6 @@ static int vtabCallConstructor(
|
||||
}
|
||||
|
||||
sqlite3DbFree(db, zModuleName);
|
||||
db->pVTab = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -563,11 +577,11 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the virtual table pVTab to the array sqlite3.aVTrans[].
|
||||
** Grow the db->aVTrans[] array so that there is room for at least one
|
||||
** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise.
|
||||
*/
|
||||
static int addToVTrans(sqlite3 *db, VTable *pVTab){
|
||||
static int growVTrans(sqlite3 *db){
|
||||
const int ARRAY_INCR = 5;
|
||||
|
||||
/* Grow the sqlite3.aVTrans array if required */
|
||||
@@ -582,10 +596,17 @@ static int addToVTrans(sqlite3 *db, VTable *pVTab){
|
||||
db->aVTrans = aVTrans;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should
|
||||
** have already been reserved using growVTrans().
|
||||
*/
|
||||
static void addToVTrans(sqlite3 *db, VTable *pVTab){
|
||||
/* Add pVtab to the end of sqlite3.aVTrans */
|
||||
db->aVTrans[db->nVTrans++] = pVTab;
|
||||
sqlite3VtabLock(pVTab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -623,7 +644,10 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
||||
/* Justification of ALWAYS(): The xConstructor method is required to
|
||||
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
|
||||
if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){
|
||||
rc = addToVTrans(db, sqlite3GetVTable(db, pTab));
|
||||
rc = growVTrans(db);
|
||||
if( rc==SQLITE_OK ){
|
||||
addToVTrans(db, sqlite3GetVTable(db, pTab));
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -642,8 +666,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
char *zErr = 0;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
pTab = db->pVTab;
|
||||
if( !pTab ){
|
||||
if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
|
||||
sqlite3Error(db, SQLITE_MISUSE, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
@@ -670,7 +693,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
pParse->pNewTable->nCol = 0;
|
||||
pParse->pNewTable->aCol = 0;
|
||||
}
|
||||
db->pVTab = 0;
|
||||
db->pVtabCtx->pTab = 0;
|
||||
}else{
|
||||
sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
@@ -740,6 +763,7 @@ static void callFinaliser(sqlite3 *db, int offset){
|
||||
x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset);
|
||||
if( x ) x(p);
|
||||
}
|
||||
pVTab->iSavepoint = 0;
|
||||
sqlite3VtabUnlock(pVTab);
|
||||
}
|
||||
sqlite3DbFree(db, db->aVTrans);
|
||||
@@ -822,7 +846,6 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
||||
if( pModule->xBegin ){
|
||||
int i;
|
||||
|
||||
|
||||
/* If pVtab is already in the aVTrans array, return early */
|
||||
for(i=0; i<db->nVTrans; i++){
|
||||
if( db->aVTrans[i]==pVTab ){
|
||||
@@ -830,10 +853,62 @@ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the xBegin method */
|
||||
rc = pModule->xBegin(pVTab->pVtab);
|
||||
/* Invoke the xBegin method. If successful, add the vtab to the
|
||||
** sqlite3.aVTrans[] array. */
|
||||
rc = growVTrans(db);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = addToVTrans(db, pVTab);
|
||||
rc = pModule->xBegin(pVTab->pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
addToVTrans(db, pVTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Invoke either the xSavepoint, xRollbackTo or xRelease method of all
|
||||
** virtual tables that currently have an open transaction. Pass iSavepoint
|
||||
** as the second argument to the virtual table method invoked.
|
||||
**
|
||||
** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is
|
||||
** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is
|
||||
** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with
|
||||
** an open transaction is invoked.
|
||||
**
|
||||
** If any virtual table method returns an error code other than SQLITE_OK,
|
||||
** processing is abandoned and the error returned to the caller of this
|
||||
** function immediately. If all calls to virtual table methods are successful,
|
||||
** SQLITE_OK is returned.
|
||||
*/
|
||||
int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
|
||||
assert( iSavepoint>=0 );
|
||||
if( db->aVTrans ){
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
||||
VTable *pVTab = db->aVTrans[i];
|
||||
const sqlite3_module *pMod = pVTab->pMod->pModule;
|
||||
if( pMod->iVersion>=2 ){
|
||||
int (*xMethod)(sqlite3_vtab *, int);
|
||||
switch( op ){
|
||||
case SAVEPOINT_BEGIN:
|
||||
xMethod = pMod->xSavepoint;
|
||||
pVTab->iSavepoint = iSavepoint+1;
|
||||
break;
|
||||
case SAVEPOINT_ROLLBACK:
|
||||
xMethod = pMod->xRollbackTo;
|
||||
break;
|
||||
default:
|
||||
xMethod = pMod->xRelease;
|
||||
break;
|
||||
}
|
||||
if( xMethod && pVTab->iSavepoint>iSavepoint ){
|
||||
rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -937,4 +1012,55 @@ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the ON CONFLICT resolution mode in effect for the virtual
|
||||
** table update operation currently in progress.
|
||||
**
|
||||
** The results of this routine are undefined unless it is called from
|
||||
** within an xUpdate method.
|
||||
*/
|
||||
int sqlite3_vtab_on_conflict(sqlite3 *db){
|
||||
static const unsigned char aMap[] = {
|
||||
SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
|
||||
};
|
||||
assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
|
||||
assert( OE_Ignore==4 && OE_Replace==5 );
|
||||
assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
|
||||
return (int)aMap[db->vtabOnConflict-1];
|
||||
}
|
||||
|
||||
/*
|
||||
** Call from within the xCreate() or xConnect() methods to provide
|
||||
** the SQLite core with additional information about the behavior
|
||||
** of the virtual table being implemented.
|
||||
*/
|
||||
int sqlite3_vtab_config(sqlite3 *db, int op, ...){
|
||||
va_list ap;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
|
||||
va_start(ap, op);
|
||||
switch( op ){
|
||||
case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
|
||||
VtabCtx *p = db->pVtabCtx;
|
||||
if( !p ){
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
}else{
|
||||
assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 );
|
||||
p->pVTable->bConstraint = (u8)va_arg(ap, int);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
break;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
@@ -412,6 +412,7 @@ struct Wal {
|
||||
sqlite3_file *pDbFd; /* File handle for the database file */
|
||||
sqlite3_file *pWalFd; /* File handle for WAL file */
|
||||
u32 iCallback; /* Value to pass to log callback (or 0) */
|
||||
i64 mxWalSize; /* Truncate WAL to this size upon reset */
|
||||
int nWiData; /* Size of array apWiData */
|
||||
volatile u32 **apWiData; /* Pointer to wal-index content in memory */
|
||||
u32 szPage; /* Database page size */
|
||||
@@ -419,7 +420,7 @@ struct Wal {
|
||||
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
|
||||
u8 writeLock; /* True if in a write transaction */
|
||||
u8 ckptLock; /* True if holding a checkpoint lock */
|
||||
u8 readOnly; /* True if the WAL file is open read-only */
|
||||
u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
|
||||
WalIndexHdr hdr; /* Wal-index header for current transaction */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
@@ -435,6 +436,13 @@ struct Wal {
|
||||
#define WAL_EXCLUSIVE_MODE 1
|
||||
#define WAL_HEAPMEMORY_MODE 2
|
||||
|
||||
/*
|
||||
** Possible values for WAL.readOnly
|
||||
*/
|
||||
#define WAL_RDWR 0 /* Normal read/write connection */
|
||||
#define WAL_RDONLY 1 /* The WAL file is readonly */
|
||||
#define WAL_SHM_RDONLY 2 /* The SHM file is readonly */
|
||||
|
||||
/*
|
||||
** Each page of the wal-index mapping contains a hash-table made up of
|
||||
** an array of HASHTABLE_NSLOT elements of the following type.
|
||||
@@ -528,6 +536,10 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
|
||||
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
||||
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
||||
);
|
||||
if( rc==SQLITE_READONLY ){
|
||||
pWal->readOnly |= WAL_SHM_RDONLY;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,6 +1246,7 @@ int sqlite3WalOpen(
|
||||
sqlite3_file *pDbFd, /* The open database file */
|
||||
const char *zWalName, /* Name of the WAL file */
|
||||
int bNoShm, /* True to run in heap-memory mode */
|
||||
i64 mxWalSize, /* Truncate WAL to this size on reset */
|
||||
Wal **ppWal /* OUT: Allocated Wal handle */
|
||||
){
|
||||
int rc; /* Return Code */
|
||||
@@ -1266,6 +1279,7 @@ int sqlite3WalOpen(
|
||||
pRet->pWalFd = (sqlite3_file *)&pRet[1];
|
||||
pRet->pDbFd = pDbFd;
|
||||
pRet->readLock = -1;
|
||||
pRet->mxWalSize = mxWalSize;
|
||||
pRet->zWalName = zWalName;
|
||||
pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
|
||||
|
||||
@@ -1273,7 +1287,7 @@ int sqlite3WalOpen(
|
||||
flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
|
||||
rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
|
||||
if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
|
||||
pRet->readOnly = 1;
|
||||
pRet->readOnly = WAL_RDONLY;
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -1287,6 +1301,13 @@ int sqlite3WalOpen(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the size to which the WAL file is trucated on each reset.
|
||||
*/
|
||||
void sqlite3WalLimit(Wal *pWal, i64 iLimit){
|
||||
if( pWal ) pWal->mxWalSize = iLimit;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the smallest page number out of all pages held in the WAL that
|
||||
** has not been returned by any prior invocation of this method on the
|
||||
@@ -1907,21 +1928,28 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
** with a writer. So get a WRITE lock and try again.
|
||||
*/
|
||||
assert( badHdr==0 || pWal->writeLock==0 );
|
||||
if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
if( badHdr ){
|
||||
if( pWal->readOnly & WAL_SHM_RDONLY ){
|
||||
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
||||
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
||||
rc = SQLITE_READONLY_RECOVERY;
|
||||
}
|
||||
}else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
}
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
|
||||
/* If the header is read successfully, check the version number to make
|
||||
@@ -2108,7 +2136,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
/* There was once an "if" here. The extra "{" is to preserve indentation. */
|
||||
{
|
||||
if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){
|
||||
if( (pWal->readOnly & WAL_SHM_RDONLY)==0
|
||||
&& (mxReadMark<pWal->hdr.mxFrame || mxI==0)
|
||||
){
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -2122,8 +2152,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
}
|
||||
if( mxI==0 ){
|
||||
assert( rc==SQLITE_BUSY );
|
||||
return WAL_RETRY;
|
||||
assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
|
||||
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
|
||||
}
|
||||
|
||||
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
|
||||
@@ -2522,6 +2552,24 @@ static int walRestartLog(Wal *pWal){
|
||||
*/
|
||||
int i; /* Loop counter */
|
||||
u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
|
||||
|
||||
/* Limit the size of WAL file if the journal_size_limit PRAGMA is
|
||||
** set to a non-negative value. Log errors encountered
|
||||
** during the truncation attempt. */
|
||||
if( pWal->mxWalSize>=0 ){
|
||||
i64 sz;
|
||||
int rx;
|
||||
sqlite3BeginBenignMalloc();
|
||||
rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
|
||||
if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){
|
||||
rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize);
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
if( rx ){
|
||||
sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
|
||||
}
|
||||
}
|
||||
|
||||
pWal->nCkpt++;
|
||||
pWal->hdr.mxFrame = 0;
|
||||
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
|
||||
@@ -2747,6 +2795,7 @@ int sqlite3WalCheckpoint(
|
||||
assert( pWal->ckptLock==0 );
|
||||
assert( pWal->writeLock==0 );
|
||||
|
||||
if( pWal->readOnly ) return SQLITE_READONLY;
|
||||
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
if( rc ){
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
# define sqlite3WalOpen(x,y,z) 0
|
||||
# define sqlite3WalLimit(x,y)
|
||||
# define sqlite3WalClose(w,x,y,z) 0
|
||||
# define sqlite3WalBeginReadTransaction(y,z) 0
|
||||
# define sqlite3WalEndReadTransaction(z)
|
||||
@@ -46,9 +47,12 @@
|
||||
typedef struct Wal Wal;
|
||||
|
||||
/* Open and close a connection to a write-ahead log. */
|
||||
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**);
|
||||
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
|
||||
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
|
||||
|
||||
/* Set the limiting size of a WAL file. */
|
||||
void sqlite3WalLimit(Wal*, i64);
|
||||
|
||||
/* Used by readers to open (lock) and close (unlock) a snapshot. A
|
||||
** snapshot is like a read-transaction. It is the state of the database
|
||||
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
|
||||
|
||||
Reference in New Issue
Block a user