Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 837b661f2c | |||
| 7b1a49c993 | |||
| 359c5ac1fb | |||
| f84aeac274 | |||
| 053a29c291 | |||
| a5eab9579a | |||
| ab4af9c368 | |||
| acb4050cfc | |||
| 690ebc6908 | |||
| 68c0da6f66 | |||
| 48824f23cb | |||
| 5c45a9fbaf | |||
| ae6f6ef3b0 | |||
| 0e429cf934 | |||
| e45317a50a | |||
| a8e9a7763d | |||
| 7dcc3dfc04 | |||
| 9726db69e6 | |||
| 5f347a426d | |||
| cdb8a698c1 | |||
| 67f678138d | |||
| 112500028e | |||
| 3fc123b7bc | |||
| d36106c954 | |||
| 41334cf960 | |||
| 95dc3e08bd | |||
| deabd6969b | |||
| a73f51447b | |||
| 2142b7c0a6 | |||
| 731a1aaeb2 | |||
| 8efa288f99 | |||
| 017bdf7838 | |||
| 4e87950b48 | |||
| 3f4a319934 | |||
| be0023faba | |||
| 6b507423a0 | |||
| 7877dca93f | |||
| 02877e9558 | |||
| ad5a7da489 | |||
| 015020cd1a | |||
| 67f3765876 | |||
| 82aacda7eb | |||
| e4d8e7e5df | |||
| 69881887b8 | |||
| ed36917835 | |||
| 8346f8dacc | |||
| d27c18818c | |||
| d4fe3c77e6 | |||
| 1a2f490fbc | |||
| df3944ecb8 | |||
| 9e0181fcf7 | |||
| a9b20c0937 | |||
| 2da07d9025 | |||
| 65aae44b87 | |||
| 3da5e2a9f3 | |||
| 81e31c9c2b | |||
| 706c33d9ba | |||
| 34ceb7e622 | |||
| 6d47af64e4 | |||
| b39f037ca5 | |||
| 1e24f9f1f3 | |||
| 50dc8d9720 | |||
| 82412051db | |||
| ebec9c475e | |||
| 5482afd6cf | |||
| c6349ce205 | |||
| 1ba1806637 | |||
| 072a02ce2c | |||
| 9d10ba8b1f | |||
| 8907cb2f88 | |||
| c6c4bae80a | |||
| cd0f540761 | |||
| c6a54f418c | |||
| 20537f0dc7 | |||
| 0d3651bd85 | |||
| 39b07f1afc | |||
| f61bf3dbe8 | |||
| 555970bf83 | |||
| 0669d6ebbf | |||
| 5517538a9c | |||
| d8c34e3311 | |||
| 6455a7066e | |||
| c406ecc662 | |||
| 26cc3a1387 | |||
| af33654533 | |||
| 756c6cf281 | |||
| 8d1005a593 | |||
| 4d5a5a48c5 | |||
| 54b81e36ff | |||
| e5ea81ae85 | |||
| 2e89f1cdeb | |||
| 1839b7990d | |||
| 567b069e42 | |||
| 09db37c022 | |||
| 53ed383075 | |||
| 8fe84a40c7 | |||
| e1afa2bd24 | |||
| 7b56e97866 | |||
| 0dc43fd4c8 | |||
| a9fd5f224c | |||
| df542e0500 | |||
| e1be2b7ad9 | |||
| 3cbf38c783 | |||
| fc6c3936aa | |||
| 3594b2b303 | |||
| aa9192e6aa | |||
| 418f947b98 | |||
| b900f9e6e8 | |||
| 7bb842642c |
@@ -7,7 +7,7 @@ and most of the documentation are managed separately.
|
||||
|
||||
## Version Control
|
||||
|
||||
SQLite sources are managed using the
|
||||
SQLite sources are managed using
|
||||
[Fossil](https://www.fossil-scm.org/), a distributed version control system
|
||||
that was specifically designed and written to support SQLite development.
|
||||
The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext.
|
||||
|
||||
+8
-2
@@ -199,6 +199,7 @@ struct Fts5Config {
|
||||
int ePattern; /* FTS_PATTERN_XXX constant */
|
||||
|
||||
/* Values loaded from the %_config table */
|
||||
int iVersion; /* fts5 file format 'version' */
|
||||
int iCookie; /* Incremented when %_config is modified */
|
||||
int pgsz; /* Approximate page size used in %_data */
|
||||
int nAutomerge; /* 'automerge' setting */
|
||||
@@ -207,6 +208,7 @@ struct Fts5Config {
|
||||
int nHashSize; /* Bytes of memory for in-memory hash */
|
||||
char *zRank; /* Name of rank function */
|
||||
char *zRankArgs; /* Arguments to rank function */
|
||||
int bSecureDelete; /* 'secure-delete' */
|
||||
|
||||
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
|
||||
char **pzErrmsg;
|
||||
@@ -216,8 +218,11 @@ struct Fts5Config {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Current expected value of %_config table 'version' field */
|
||||
#define FTS5_CURRENT_VERSION 4
|
||||
/* Current expected value of %_config table 'version' field. And
|
||||
** the expected version if the 'secure-delete' option has ever been
|
||||
** set on the table. */
|
||||
#define FTS5_CURRENT_VERSION 4
|
||||
#define FTS5_CURRENT_VERSION_SECUREDELETE 5
|
||||
|
||||
#define FTS5_CONTENT_NORMAL 0
|
||||
#define FTS5_CONTENT_NONE 1
|
||||
@@ -383,6 +388,7 @@ struct Fts5IndexIter {
|
||||
** above. */
|
||||
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
|
||||
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
|
||||
#define FTS5INDEX_QUERY_SKIPHASH 0x0040
|
||||
|
||||
/*
|
||||
** Create/destroy an Fts5Index object.
|
||||
|
||||
+21
-4
@@ -903,6 +903,18 @@ int sqlite3Fts5ConfigSetValue(
|
||||
rc = SQLITE_OK;
|
||||
*pbBadkey = 1;
|
||||
}
|
||||
}
|
||||
|
||||
else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){
|
||||
int bVal = -1;
|
||||
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
|
||||
bVal = sqlite3_value_int(pVal);
|
||||
}
|
||||
if( bVal<0 ){
|
||||
*pbBadkey = 1;
|
||||
}else{
|
||||
pConfig->bSecureDelete = (bVal ? 1 : 0);
|
||||
}
|
||||
}else{
|
||||
*pbBadkey = 1;
|
||||
}
|
||||
@@ -947,15 +959,20 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
|
||||
rc = sqlite3_finalize(p);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
|
||||
if( rc==SQLITE_OK
|
||||
&& iVersion!=FTS5_CURRENT_VERSION
|
||||
&& iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
|
||||
){
|
||||
rc = SQLITE_ERROR;
|
||||
if( pConfig->pzErrmsg ){
|
||||
assert( 0==*pConfig->pzErrmsg );
|
||||
*pConfig->pzErrmsg = sqlite3_mprintf(
|
||||
"invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
|
||||
iVersion, FTS5_CURRENT_VERSION
|
||||
*pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
|
||||
"(found %d, expected %d or %d) - run 'rebuild'",
|
||||
iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
|
||||
);
|
||||
}
|
||||
}else{
|
||||
pConfig->iVersion = iVersion;
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+539
-89
@@ -302,6 +302,8 @@ struct Fts5Index {
|
||||
sqlite3_stmt *pIdxSelect;
|
||||
int nRead; /* Total number of blocks read */
|
||||
|
||||
sqlite3_stmt *pDeleteFromIdx;
|
||||
|
||||
sqlite3_stmt *pDataVersion;
|
||||
i64 iStructVersion; /* data_version when pStruct read */
|
||||
Fts5Structure *pStruct; /* Current db structure (or NULL) */
|
||||
@@ -394,9 +396,6 @@ struct Fts5CResult {
|
||||
** iLeafOffset:
|
||||
** Byte offset within the current leaf that is the first byte of the
|
||||
** position list data (one byte passed the position-list size field).
|
||||
** rowid field of the current entry. Usually this is the size field of the
|
||||
** position list data. The exception is if the rowid for the current entry
|
||||
** is the last thing on the leaf page.
|
||||
**
|
||||
** pLeaf:
|
||||
** Buffer containing current leaf page data. Set to NULL at EOF.
|
||||
@@ -1443,42 +1442,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
|
||||
pLvl->bEof = 1;
|
||||
}else{
|
||||
u8 *a = pLvl->pData->p;
|
||||
i64 iVal;
|
||||
int iLimit;
|
||||
int ii;
|
||||
int nZero = 0;
|
||||
|
||||
/* Currently iOff points to the first byte of a varint. This block
|
||||
** decrements iOff until it points to the first byte of the previous
|
||||
** varint. Taking care not to read any memory locations that occur
|
||||
** before the buffer in memory. */
|
||||
iLimit = (iOff>9 ? iOff-9 : 0);
|
||||
for(iOff--; iOff>iLimit; iOff--){
|
||||
if( (a[iOff-1] & 0x80)==0 ) break;
|
||||
}
|
||||
pLvl->iOff = 0;
|
||||
fts5DlidxLvlNext(pLvl);
|
||||
while( 1 ){
|
||||
int nZero = 0;
|
||||
int ii = pLvl->iOff;
|
||||
u64 delta = 0;
|
||||
|
||||
fts5GetVarint(&a[iOff], (u64*)&iVal);
|
||||
pLvl->iRowid -= iVal;
|
||||
pLvl->iLeafPgno--;
|
||||
|
||||
/* Skip backwards past any 0x00 varints. */
|
||||
for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
|
||||
nZero++;
|
||||
}
|
||||
if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
|
||||
/* The byte immediately before the last 0x00 byte has the 0x80 bit
|
||||
** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
|
||||
** bytes before a[ii]. */
|
||||
int bZero = 0; /* True if last 0x00 counts */
|
||||
if( (ii-8)>=pLvl->iFirstOff ){
|
||||
int j;
|
||||
for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
|
||||
bZero = (j>8);
|
||||
while( a[ii]==0 ){
|
||||
nZero++;
|
||||
ii++;
|
||||
}
|
||||
if( bZero==0 ) nZero--;
|
||||
ii += sqlite3Fts5GetVarint(&a[ii], &delta);
|
||||
|
||||
if( ii>=iOff ) break;
|
||||
pLvl->iLeafPgno += nZero+1;
|
||||
pLvl->iRowid += delta;
|
||||
pLvl->iOff = ii;
|
||||
}
|
||||
pLvl->iLeafPgno -= nZero;
|
||||
pLvl->iOff = iOff - nZero;
|
||||
}
|
||||
|
||||
return pLvl->bEof;
|
||||
@@ -1674,7 +1656,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
|
||||
i64 iOff = pIter->iLeafOffset;
|
||||
|
||||
ASSERT_SZLEAF_OK(pIter->pLeaf);
|
||||
if( iOff>=pIter->pLeaf->szLeaf ){
|
||||
while( iOff>=pIter->pLeaf->szLeaf ){
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
if( pIter->pLeaf==0 ){
|
||||
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
|
||||
@@ -1773,10 +1755,12 @@ static void fts5SegIterInit(
|
||||
fts5SegIterSetNext(p, pIter);
|
||||
pIter->pSeg = pSeg;
|
||||
pIter->iLeafPgno = pSeg->pgnoFirst-1;
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
do {
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
}while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( p->rc==SQLITE_OK && pIter->pLeaf ){
|
||||
pIter->iLeafOffset = 4;
|
||||
assert( pIter->pLeaf!=0 );
|
||||
assert_nc( pIter->pLeaf->nn>4 );
|
||||
@@ -1970,7 +1954,7 @@ static void fts5SegIterNext_None(
|
||||
iOff = pIter->iLeafOffset;
|
||||
|
||||
/* Next entry is on the next page */
|
||||
if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
|
||||
while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
if( p->rc || pIter->pLeaf==0 ) return;
|
||||
pIter->iRowid = 0;
|
||||
@@ -2163,7 +2147,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
||||
Fts5Data *pLast = 0;
|
||||
int pgnoLast = 0;
|
||||
|
||||
if( pDlidx ){
|
||||
if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
|
||||
int iSegid = pIter->pSeg->iSegid;
|
||||
pgnoLast = fts5DlidxIterPgno(pDlidx);
|
||||
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
|
||||
@@ -2724,7 +2708,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
|
||||
|
||||
/*
|
||||
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
|
||||
** It is an error if leaf iLeafPgno does not exist or contains no rowids.
|
||||
** It is an error if leaf iLeafPgno does not exist. Unless the db is
|
||||
** a 'secure-delete' db, if it contains no rowids then this is also an error.
|
||||
*/
|
||||
static void fts5SegIterGotoPage(
|
||||
Fts5Index *p, /* FTS5 backend object */
|
||||
@@ -2739,21 +2724,23 @@ static void fts5SegIterGotoPage(
|
||||
fts5DataRelease(pIter->pNextLeaf);
|
||||
pIter->pNextLeaf = 0;
|
||||
pIter->iLeafPgno = iLeafPgno-1;
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
|
||||
|
||||
if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
|
||||
while( p->rc==SQLITE_OK ){
|
||||
int iOff;
|
||||
u8 *a = pIter->pLeaf->p;
|
||||
int n = pIter->pLeaf->szLeaf;
|
||||
|
||||
fts5SegIterNextPage(p, pIter);
|
||||
if( pIter->pLeaf==0 ) break;
|
||||
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
|
||||
if( iOff<4 || iOff>=n ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
|
||||
pIter->iLeafOffset = iOff;
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
if( iOff>0 ){
|
||||
u8 *a = pIter->pLeaf->p;
|
||||
int n = pIter->pLeaf->szLeaf;
|
||||
if( iOff<4 || iOff>=n ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
|
||||
pIter->iLeafOffset = iOff;
|
||||
fts5SegIterLoadNPos(p, pIter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3468,7 +3455,7 @@ static void fts5MultiIterNew(
|
||||
if( iLevel<0 ){
|
||||
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
|
||||
nSeg = pStruct->nSegment;
|
||||
nSeg += (p->pHash ? 1 : 0);
|
||||
nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
|
||||
}else{
|
||||
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
|
||||
}
|
||||
@@ -3489,7 +3476,7 @@ static void fts5MultiIterNew(
|
||||
if( p->rc==SQLITE_OK ){
|
||||
if( iLevel<0 ){
|
||||
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
|
||||
if( p->pHash ){
|
||||
if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
|
||||
/* Add a segment iterator for the current contents of the hash table. */
|
||||
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
|
||||
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
|
||||
@@ -4244,7 +4231,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
||||
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
|
||||
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
|
||||
fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
|
||||
fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
/* Set the szLeaf field */
|
||||
fts5PutU16(&buf.p[2], (u16)buf.n);
|
||||
@@ -4522,16 +4509,16 @@ static void fts5IndexCrisismerge(
|
||||
){
|
||||
const int nCrisis = p->pConfig->nCrisisMerge;
|
||||
Fts5Structure *pStruct = *ppStruct;
|
||||
int iLvl = 0;
|
||||
|
||||
assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
|
||||
while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
|
||||
fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
|
||||
assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
|
||||
fts5StructurePromote(p, iLvl+1, pStruct);
|
||||
iLvl++;
|
||||
if( pStruct && pStruct->nLevel>0 ){
|
||||
int iLvl = 0;
|
||||
while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
|
||||
fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
|
||||
assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
|
||||
fts5StructurePromote(p, iLvl+1, pStruct);
|
||||
iLvl++;
|
||||
}
|
||||
*ppStruct = pStruct;
|
||||
}
|
||||
*ppStruct = pStruct;
|
||||
}
|
||||
|
||||
static int fts5IndexReturn(Fts5Index *p){
|
||||
@@ -4565,6 +4552,411 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute the SQL statement:
|
||||
**
|
||||
** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
|
||||
**
|
||||
** This is used when a secure-delete operation removes the last term
|
||||
** from a segment leaf page. In that case the %_idx entry is removed
|
||||
** too. This is done to ensure that if all instances of a token are
|
||||
** removed from an fts5 database in secure-delete mode, no trace of
|
||||
** the token itself remains in the database.
|
||||
*/
|
||||
static void fts5SecureDeleteIdxEntry(
|
||||
Fts5Index *p, /* FTS5 backend object */
|
||||
int iSegid, /* Id of segment to delete entry for */
|
||||
int iPgno /* Page number within segment */
|
||||
){
|
||||
if( iPgno!=1 ){
|
||||
assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
|
||||
if( p->pDeleteFromIdx==0 ){
|
||||
fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlite3_mprintf(
|
||||
"DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
|
||||
p->pConfig->zDb, p->pConfig->zName
|
||||
));
|
||||
}
|
||||
if( p->rc==SQLITE_OK ){
|
||||
sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
|
||||
sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
|
||||
sqlite3_step(p->pDeleteFromIdx);
|
||||
p->rc = sqlite3_reset(p->pDeleteFromIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called when a secure-delete operation removes a position-list
|
||||
** that overflows onto segment page iPgno of segment pSeg. This function
|
||||
** rewrites node iPgno, and possibly one or more of its right-hand peers,
|
||||
** to remove this portion of the position list.
|
||||
**
|
||||
** Output variable (*pbLastInDoclist) is set to true if the position-list
|
||||
** removed is followed by a new term or the end-of-segment, or false if
|
||||
** it is followed by another rowid/position list.
|
||||
*/
|
||||
static void fts5SecureDeleteOverflow(
|
||||
Fts5Index *p,
|
||||
Fts5StructureSegment *pSeg,
|
||||
int iPgno,
|
||||
int *pbLastInDoclist
|
||||
){
|
||||
const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
|
||||
int pgno;
|
||||
Fts5Data *pLeaf = 0;
|
||||
assert( iPgno!=1 );
|
||||
|
||||
*pbLastInDoclist = 1;
|
||||
for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
|
||||
i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
|
||||
int iNext = 0;
|
||||
u8 *aPg = 0;
|
||||
|
||||
pLeaf = fts5DataRead(p, iRowid);
|
||||
if( pLeaf==0 ) break;
|
||||
aPg = pLeaf->p;
|
||||
|
||||
iNext = fts5GetU16(&aPg[0]);
|
||||
if( iNext!=0 ){
|
||||
*pbLastInDoclist = 0;
|
||||
}
|
||||
if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
|
||||
fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
|
||||
}
|
||||
|
||||
if( iNext==0 ){
|
||||
/* The page contains no terms or rowids. Replace it with an empty
|
||||
** page and move on to the right-hand peer. */
|
||||
const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
|
||||
assert_nc( bDetailNone==0 || pLeaf->nn==4 );
|
||||
if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
|
||||
fts5DataRelease(pLeaf);
|
||||
pLeaf = 0;
|
||||
}else if( bDetailNone ){
|
||||
break;
|
||||
}else{
|
||||
int nShift = iNext - 4;
|
||||
int nPg;
|
||||
|
||||
int nIdx = 0;
|
||||
u8 *aIdx = 0;
|
||||
|
||||
/* Unless the current page footer is 0 bytes in size (in which case
|
||||
** the new page footer will be as well), allocate and populate a
|
||||
** buffer containing the new page footer. Set stack variables aIdx
|
||||
** and nIdx accordingly. */
|
||||
if( pLeaf->nn>pLeaf->szLeaf ){
|
||||
int iFirst = 0;
|
||||
int i1 = pLeaf->szLeaf;
|
||||
int i2 = 0;
|
||||
|
||||
aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
|
||||
if( aIdx==0 ) break;
|
||||
i1 += fts5GetVarint32(&aPg[i1], iFirst);
|
||||
i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
|
||||
if( i1<pLeaf->nn ){
|
||||
memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
|
||||
i2 += (pLeaf->nn-i1);
|
||||
}
|
||||
nIdx = i2;
|
||||
}
|
||||
|
||||
/* Modify the contents of buffer aPg[]. Set nPg to the new size
|
||||
** in bytes. The new page is always smaller than the old. */
|
||||
nPg = pLeaf->szLeaf - nShift;
|
||||
memmove(&aPg[4], &aPg[4+nShift], nPg-4);
|
||||
fts5PutU16(&aPg[2], nPg);
|
||||
if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
|
||||
if( nIdx>0 ){
|
||||
memcpy(&aPg[nPg], aIdx, nIdx);
|
||||
nPg += nIdx;
|
||||
}
|
||||
sqlite3_free(aIdx);
|
||||
|
||||
/* Write the new page to disk and exit the loop */
|
||||
assert( nPg>4 || fts5GetU16(aPg)==0 );
|
||||
fts5DataWrite(p, iRowid, aPg, nPg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fts5DataRelease(pLeaf);
|
||||
}
|
||||
|
||||
/*
|
||||
** Completely remove the entry that pSeg currently points to from
|
||||
** the database.
|
||||
*/
|
||||
static void fts5DoSecureDelete(
|
||||
Fts5Index *p,
|
||||
Fts5Structure *pStruct,
|
||||
Fts5SegIter *pSeg
|
||||
){
|
||||
const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
|
||||
int iSegid = pSeg->pSeg->iSegid;
|
||||
u8 *aPg = pSeg->pLeaf->p;
|
||||
int nPg = pSeg->pLeaf->nn;
|
||||
int iPgIdx = pSeg->pLeaf->szLeaf;
|
||||
|
||||
u64 iDelta = 0;
|
||||
u64 iNextDelta = 0;
|
||||
int iNextOff = 0;
|
||||
int iOff = 0;
|
||||
int nIdx = 0;
|
||||
u8 *aIdx = 0;
|
||||
int bLastInDoclist = 0;
|
||||
int iIdx = 0;
|
||||
int iStart = 0;
|
||||
int iKeyOff = 0;
|
||||
int iPrevKeyOff = 0;
|
||||
int iDelKeyOff = 0; /* Offset of deleted key, if any */
|
||||
|
||||
nIdx = nPg-iPgIdx;
|
||||
aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
|
||||
if( p->rc ) return;
|
||||
memcpy(aIdx, &aPg[iPgIdx], nIdx);
|
||||
|
||||
/* At this point segment iterator pSeg points to the entry
|
||||
** this function should remove from the b-tree segment.
|
||||
**
|
||||
** In detail=full or detail=column mode, pSeg->iLeafOffset is the
|
||||
** offset of the first byte in the position-list for the entry to
|
||||
** remove. Immediately before this comes two varints that will also
|
||||
** need to be removed:
|
||||
**
|
||||
** + the rowid or delta rowid value for the entry, and
|
||||
** + the size of the position list in bytes.
|
||||
**
|
||||
** Or, in detail=none mode, there is a single varint prior to
|
||||
** pSeg->iLeafOffset - the rowid or delta rowid value.
|
||||
**
|
||||
** This block sets the following variables:
|
||||
**
|
||||
** iStart:
|
||||
** iDelta:
|
||||
*/
|
||||
{
|
||||
int iSOP;
|
||||
if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
|
||||
iStart = pSeg->iTermLeafOffset;
|
||||
}else{
|
||||
iStart = fts5GetU16(&aPg[0]);
|
||||
}
|
||||
|
||||
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||
assert_nc( iSOP<=pSeg->iLeafOffset );
|
||||
|
||||
if( bDetailNone ){
|
||||
while( iSOP<pSeg->iLeafOffset ){
|
||||
if( aPg[iSOP]==0x00 ) iSOP++;
|
||||
if( aPg[iSOP]==0x00 ) iSOP++;
|
||||
iStart = iSOP;
|
||||
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||
}
|
||||
|
||||
iNextOff = iSOP;
|
||||
if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
|
||||
if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
|
||||
|
||||
}else{
|
||||
int nPos = 0;
|
||||
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
||||
while( iSOP<pSeg->iLeafOffset ){
|
||||
iStart = iSOP + (nPos/2);
|
||||
iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
|
||||
iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
|
||||
}
|
||||
assert_nc( iSOP==pSeg->iLeafOffset );
|
||||
iNextOff = pSeg->iLeafOffset + pSeg->nPos;
|
||||
}
|
||||
}
|
||||
|
||||
iOff = iStart;
|
||||
if( iNextOff>=iPgIdx ){
|
||||
int pgno = pSeg->iLeafPgno+1;
|
||||
fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
|
||||
iNextOff = iPgIdx;
|
||||
}else{
|
||||
/* Set bLastInDoclist to true if the entry being removed is the last
|
||||
** in its doclist. */
|
||||
for(iIdx=0, iKeyOff=0; iIdx<nIdx; /* no-op */){
|
||||
u32 iVal = 0;
|
||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||
iKeyOff += iVal;
|
||||
if( iKeyOff==iNextOff ){
|
||||
bLastInDoclist = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist||iNextOff==iPgIdx) ){
|
||||
fts5PutU16(&aPg[0], 0);
|
||||
}
|
||||
|
||||
if( bLastInDoclist==0 ){
|
||||
if( iNextOff!=iPgIdx ){
|
||||
iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
|
||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
|
||||
}
|
||||
}else if(
|
||||
iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
||||
){
|
||||
/* The entry being removed was the only position list in its
|
||||
** doclist. Therefore the term needs to be removed as well. */
|
||||
int iKey = 0;
|
||||
for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
|
||||
u32 iVal = 0;
|
||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||
if( (iKeyOff+iVal)>iStart ) break;
|
||||
iKeyOff += iVal;
|
||||
}
|
||||
|
||||
iDelKeyOff = iOff = iKeyOff;
|
||||
if( iNextOff!=iPgIdx ){
|
||||
int nPrefix = 0;
|
||||
int nSuffix = 0;
|
||||
int nPrefix2 = 0;
|
||||
int nSuffix2 = 0;
|
||||
|
||||
iDelKeyOff = iNextOff;
|
||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
|
||||
iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
|
||||
|
||||
if( iKey!=1 ){
|
||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
|
||||
}
|
||||
iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
|
||||
|
||||
nPrefix = MIN(nPrefix, nPrefix2);
|
||||
nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
|
||||
|
||||
if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
if( iKey!=1 ){
|
||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
|
||||
}
|
||||
iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
|
||||
if( nPrefix2>nPrefix ){
|
||||
memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
|
||||
iOff += (nPrefix2-nPrefix);
|
||||
}
|
||||
memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
|
||||
iOff += nSuffix2;
|
||||
iNextOff += nSuffix2;
|
||||
}
|
||||
}
|
||||
}else if( iStart==4 ){
|
||||
assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
|
||||
/* The entry being removed may be the only position list in
|
||||
** its doclist. */
|
||||
int iPgno = pSeg->iLeafPgno-1;
|
||||
|
||||
for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
|
||||
Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
|
||||
int bEmpty = (pPg && pPg->nn==4);
|
||||
fts5DataRelease(pPg);
|
||||
if( bEmpty==0 ) break;
|
||||
}
|
||||
|
||||
if( iPgno==pSeg->iTermLeafPgno ){
|
||||
i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
|
||||
Fts5Data *pTerm = fts5DataRead(p, iId);
|
||||
if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
|
||||
u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
|
||||
int nTermIdx = pTerm->nn - pTerm->szLeaf;
|
||||
int iTermIdx = 0;
|
||||
int iTermOff = 0;
|
||||
|
||||
while( 1 ){
|
||||
u32 iVal = 0;
|
||||
int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
|
||||
iTermOff += iVal;
|
||||
if( (iTermIdx+nByte)>=nTermIdx ) break;
|
||||
iTermIdx += nByte;
|
||||
}
|
||||
nTermIdx = iTermIdx;
|
||||
|
||||
memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
|
||||
fts5PutU16(&pTerm->p[2], iTermOff);
|
||||
|
||||
fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
|
||||
if( nTermIdx==0 ){
|
||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
|
||||
}
|
||||
}
|
||||
fts5DataRelease(pTerm);
|
||||
}
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK ){
|
||||
const int nMove = nPg - iNextOff;
|
||||
int nShift = 0;
|
||||
|
||||
memmove(&aPg[iOff], &aPg[iNextOff], nMove);
|
||||
iPgIdx -= (iNextOff - iOff);
|
||||
nPg = iPgIdx;
|
||||
fts5PutU16(&aPg[2], iPgIdx);
|
||||
|
||||
nShift = iNextOff - iOff;
|
||||
for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdx<nIdx; /* no-op */){
|
||||
u32 iVal = 0;
|
||||
iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
|
||||
iKeyOff += iVal;
|
||||
if( iKeyOff!=iDelKeyOff ){
|
||||
if( iKeyOff>iOff ){
|
||||
iKeyOff -= nShift;
|
||||
nShift = 0;
|
||||
}
|
||||
nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff);
|
||||
iPrevKeyOff = iKeyOff;
|
||||
}
|
||||
}
|
||||
|
||||
if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
|
||||
fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
|
||||
}
|
||||
|
||||
assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
|
||||
fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg);
|
||||
}
|
||||
sqlite3_free(aIdx);
|
||||
}
|
||||
|
||||
/*
|
||||
** This is called as part of flushing a delete to disk in 'secure-delete'
|
||||
** mode. It edits the segments within the database described by argument
|
||||
** pStruct to remove the entries for term zTerm, rowid iRowid.
|
||||
*/
|
||||
static void fts5FlushSecureDelete(
|
||||
Fts5Index *p,
|
||||
Fts5Structure *pStruct,
|
||||
const char *zTerm,
|
||||
i64 iRowid
|
||||
){
|
||||
const int f = FTS5INDEX_QUERY_SKIPHASH;
|
||||
int nTerm = strlen(zTerm);
|
||||
Fts5Iter *pIter = 0; /* Used to find term instance */
|
||||
|
||||
fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
|
||||
if( fts5MultiIterEof(p, pIter)==0 ){
|
||||
i64 iThis = fts5MultiIterRowid(pIter);
|
||||
if( iThis<iRowid ){
|
||||
fts5MultiIterNextFrom(p, pIter, iRowid);
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK
|
||||
&& fts5MultiIterEof(p, pIter)==0
|
||||
&& iRowid==fts5MultiIterRowid(pIter)
|
||||
){
|
||||
Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
|
||||
fts5DoSecureDelete(p, pStruct, pSeg);
|
||||
}
|
||||
}
|
||||
|
||||
fts5MultiIterFree(pIter);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Flush the contents of in-memory hash table iHash to a new level-0
|
||||
** segment on disk. Also update the corresponding structure record.
|
||||
@@ -4587,6 +4979,7 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
if( iSegid ){
|
||||
const int pgsz = p->pConfig->pgsz;
|
||||
int eDetail = p->pConfig->eDetail;
|
||||
int bSecureDelete = p->pConfig->bSecureDelete;
|
||||
Fts5StructureSegment *pSeg; /* New segment within pStruct */
|
||||
Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
|
||||
Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
|
||||
@@ -4609,40 +5002,77 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
}
|
||||
while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
|
||||
const char *zTerm; /* Buffer containing term */
|
||||
int nTerm; /* Size of zTerm in bytes */
|
||||
const u8 *pDoclist; /* Pointer to doclist for this term */
|
||||
int nDoclist; /* Size of doclist in bytes */
|
||||
|
||||
/* Write the term for this entry to disk. */
|
||||
/* Get the term and doclist for this entry. */
|
||||
sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
|
||||
fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
nTerm = (int)strlen(zTerm);
|
||||
if( bSecureDelete==0 ){
|
||||
fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
assert( writer.bFirstRowidInPage==0 );
|
||||
}
|
||||
|
||||
assert( writer.bFirstRowidInPage==0 );
|
||||
if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
|
||||
if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
|
||||
/* The entire doclist will fit on the current leaf. */
|
||||
fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
|
||||
}else{
|
||||
int bTermWritten = !bSecureDelete;
|
||||
i64 iRowid = 0;
|
||||
u64 iDelta = 0;
|
||||
i64 iPrev = 0;
|
||||
int iOff = 0;
|
||||
|
||||
/* The entire doclist will not fit on this leaf. The following
|
||||
** loop iterates through the poslists that make up the current
|
||||
** doclist. */
|
||||
while( p->rc==SQLITE_OK && iOff<nDoclist ){
|
||||
u64 iDelta = 0;
|
||||
iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
|
||||
iRowid += iDelta;
|
||||
|
||||
/* If in secure delete mode, and if this entry in the poslist is
|
||||
** in fact a delete, then edit the existing segments directly
|
||||
** using fts5FlushSecureDelete(). */
|
||||
if( bSecureDelete ){
|
||||
if( eDetail==FTS5_DETAIL_NONE ){
|
||||
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
|
||||
fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
|
||||
iOff++;
|
||||
if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
|
||||
iOff++;
|
||||
nDoclist = 0;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}else if( (pDoclist[iOff] & 0x01) ){
|
||||
fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
|
||||
if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
|
||||
iOff++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( p->rc==SQLITE_OK && bTermWritten==0 ){
|
||||
fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
|
||||
bTermWritten = 1;
|
||||
assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
|
||||
}
|
||||
|
||||
if( writer.bFirstRowidInPage ){
|
||||
fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
|
||||
writer.bFirstRowidInPage = 0;
|
||||
fts5WriteDlidxAppend(p, &writer, iRowid);
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
}else{
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
|
||||
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid-iPrev);
|
||||
}
|
||||
if( p->rc!=SQLITE_OK ) break;
|
||||
assert( pBuf->n<=pBuf->nSpace );
|
||||
iPrev = iRowid;
|
||||
|
||||
if( eDetail==FTS5_DETAIL_NONE ){
|
||||
if( iOff<nDoclist && pDoclist[iOff]==0 ){
|
||||
@@ -4701,20 +5131,23 @@ static void fts5FlushOneHash(Fts5Index *p){
|
||||
sqlite3Fts5HashClear(pHash);
|
||||
fts5WriteFinish(p, &writer, &pgnoLast);
|
||||
|
||||
/* Update the Fts5Structure. It is written back to the database by the
|
||||
** fts5StructureRelease() call below. */
|
||||
if( pStruct->nLevel==0 ){
|
||||
fts5StructureAddLevel(&p->rc, &pStruct);
|
||||
assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
|
||||
if( pgnoLast>0 ){
|
||||
/* Update the Fts5Structure. It is written back to the database by the
|
||||
** fts5StructureRelease() call below. */
|
||||
if( pStruct->nLevel==0 ){
|
||||
fts5StructureAddLevel(&p->rc, &pStruct);
|
||||
}
|
||||
fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
|
||||
pSeg->iSegid = iSegid;
|
||||
pSeg->pgnoFirst = 1;
|
||||
pSeg->pgnoLast = pgnoLast;
|
||||
pStruct->nSegment++;
|
||||
}
|
||||
fts5StructurePromote(p, 0, pStruct);
|
||||
}
|
||||
fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
|
||||
if( p->rc==SQLITE_OK ){
|
||||
pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
|
||||
pSeg->iSegid = iSegid;
|
||||
pSeg->pgnoFirst = 1;
|
||||
pSeg->pgnoLast = pgnoLast;
|
||||
pStruct->nSegment++;
|
||||
}
|
||||
fts5StructurePromote(p, 0, pStruct);
|
||||
}
|
||||
|
||||
fts5IndexAutomerge(p, &pStruct, pgnoLast);
|
||||
@@ -5455,6 +5888,7 @@ int sqlite3Fts5IndexClose(Fts5Index *p){
|
||||
sqlite3_finalize(p->pIdxDeleter);
|
||||
sqlite3_finalize(p->pIdxSelect);
|
||||
sqlite3_finalize(p->pDataVersion);
|
||||
sqlite3_finalize(p->pDeleteFromIdx);
|
||||
sqlite3Fts5HashFree(p->pHash);
|
||||
sqlite3_free(p->zDataTbl);
|
||||
sqlite3_free(p);
|
||||
@@ -6085,6 +6519,7 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
Fts5StructureSegment *pSeg /* Segment to check internal consistency */
|
||||
){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE);
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
int rc2;
|
||||
int iIdxPrevLeaf = pSeg->pgnoFirst-1;
|
||||
@@ -6120,7 +6555,19 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
** is also a rowid pointer within the leaf page header, it points to a
|
||||
** location before the term. */
|
||||
if( pLeaf->nn<=pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
|
||||
if( nIdxTerm==0
|
||||
&& pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE
|
||||
&& pLeaf->nn==pLeaf->szLeaf
|
||||
&& pLeaf->nn==4
|
||||
){
|
||||
/* special case - the very first page in a segment keeps its %_idx
|
||||
** entry even if all the terms are removed from it by secure-delete
|
||||
** operations. */
|
||||
}else{
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}
|
||||
|
||||
}else{
|
||||
int iOff; /* Offset of first term on leaf */
|
||||
int iRowidOff; /* Offset of first rowid on leaf */
|
||||
@@ -6184,9 +6631,12 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
ASSERT_SZLEAF_OK(pLeaf);
|
||||
if( iRowidOff>=pLeaf->szLeaf ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}else{
|
||||
}else if( bSecureDelete==0 || iRowidOff>0 ){
|
||||
i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
|
||||
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
|
||||
if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
|
||||
if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
}
|
||||
}
|
||||
fts5DataRelease(pLeaf);
|
||||
}
|
||||
|
||||
@@ -1623,6 +1623,8 @@ static int fts5UpdateMethod(
|
||||
Fts5Config *pConfig = pTab->p.pConfig;
|
||||
int eType0; /* value_type() of apVal[0] */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int bUpdateOrDelete = 0;
|
||||
|
||||
|
||||
/* A transaction must be open when this is called. */
|
||||
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
|
||||
@@ -1633,6 +1635,11 @@ static int fts5UpdateMethod(
|
||||
|| sqlite3_value_type(apVal[0])==SQLITE_NULL
|
||||
);
|
||||
assert( pTab->p.pConfig->pzErrmsg==0 );
|
||||
if( pConfig->pgsz==0 ){
|
||||
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
|
||||
/* Put any active cursors into REQUIRE_SEEK state. */
|
||||
@@ -1685,6 +1692,7 @@ static int fts5UpdateMethod(
|
||||
else if( nArg==1 ){
|
||||
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
|
||||
bUpdateOrDelete = 1;
|
||||
}
|
||||
|
||||
/* INSERT or UPDATE */
|
||||
@@ -1700,6 +1708,7 @@ static int fts5UpdateMethod(
|
||||
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
bUpdateOrDelete = 1;
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
@@ -1728,10 +1737,24 @@ static int fts5UpdateMethod(
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
bUpdateOrDelete = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK
|
||||
&& bUpdateOrDelete
|
||||
&& pConfig->bSecureDelete
|
||||
&& pConfig->iVersion==FTS5_CURRENT_VERSION
|
||||
){
|
||||
rc = sqlite3Fts5StorageConfigValue(
|
||||
pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
|
||||
}
|
||||
}
|
||||
|
||||
pTab->p.pConfig->pzErrmsg = 0;
|
||||
return rc;
|
||||
}
|
||||
@@ -2591,6 +2614,7 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
||||
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
|
||||
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
|
||||
fts5TripCursors(pTab);
|
||||
pTab->p.pConfig->pgsz = 0;
|
||||
return sqlite3Fts5StorageRollback(pTab->pStorage);
|
||||
}
|
||||
|
||||
|
||||
@@ -594,6 +594,10 @@ proc nearset_rc {aCol args} {
|
||||
list
|
||||
}
|
||||
|
||||
proc dump {tname} {
|
||||
execsql_pp "SELECT * FROM ${tname}_idx"
|
||||
execsql_pp "SELECT id, quote(block), fts5_decode(id,block) FROM ${tname}_data"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Code for a simple Tcl tokenizer that supports synonyms at query time.
|
||||
|
||||
@@ -154,4 +154,30 @@ do_execsql_test 3.2 {
|
||||
|
||||
}
|
||||
|
||||
# 2023-04-06 https://sqlite.org/forum/forumpost/cae4367d9b
|
||||
#
|
||||
# This is not a test of FTS5, but rather a test of the of what happens to
|
||||
# prepared statements that encounter SQLITE_SCHEMA while other prepared
|
||||
# statements are running. The original problem POC used FTS5, and so
|
||||
# is seems reasonable to put the test here.
|
||||
#
|
||||
# The vdbeaux24.test module in TH3 also tests this same behavior but
|
||||
# without requiring FTS5 or an other extension.
|
||||
#
|
||||
reset_db
|
||||
db null NULL
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t5(a PRIMARY KEY);
|
||||
INSERT INTO t5 VALUES(0);
|
||||
CREATE VIRTUAL TABLE t6 USING fts5(0);
|
||||
DELETE FROM t6;
|
||||
CREATE TABLE t7(x);
|
||||
WITH cte(a) AS (
|
||||
SELECT a FROM t5
|
||||
WHERE ((0,0) IN (SELECT 0, LAG(0) OVER (PARTITION BY 0) FROM t6), 0)
|
||||
< (a,0)
|
||||
)
|
||||
SELECT max(a) FROM cte;
|
||||
} NULL
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
# 2023 Feb 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
ifcapable !fts5 { finish_test ; return }
|
||||
set ::testprefix fts5secure
|
||||
|
||||
proc dump {tname} {
|
||||
execsql_pp "SELECT * FROM ${tname}_idx"
|
||||
execsql_pp "SELECT id, quote(block), fts5_decode(id,block) FROM ${tname}_data"
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 0.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
CREATE VIRTUAL TABLE v1 USING fts5vocab('t1', 'instance');
|
||||
INSERT INTO t1(rowid, ab) VALUES
|
||||
(0,'abc'), (1,'abc'), (2,'abc'), (3,'abc'), (4,'def');
|
||||
}
|
||||
|
||||
do_execsql_test 0.1 {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 0.2 {
|
||||
DELETE FROM t1 WHERE rowid=2;
|
||||
}
|
||||
|
||||
do_execsql_test 0.3 {
|
||||
SELECT count(*) FROM t1_data
|
||||
} 3
|
||||
|
||||
do_execsql_test 0.4 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 0.5 {
|
||||
DELETE FROM t1 WHERE rowid=3;
|
||||
}
|
||||
|
||||
do_execsql_test 0.6 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 0.7 {
|
||||
DELETE FROM t1 WHERE rowid=0;
|
||||
}
|
||||
|
||||
do_execsql_test 0.8 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#----------------------------------
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(ab);
|
||||
INSERT INTO t2(rowid, ab) VALUES (5, 'key'), (6, 'value');
|
||||
INSERT INTO t2(t2, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
#execsql_pp { SELECT id, quote(block) FROM t1_data }
|
||||
#execsql_pp { SELECT segid, quote(term), pgno FROM t1_idx }
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
DELETE FROM t2 WHERE rowid = 5;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t2(t2) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DELETE FROM t2 WHERE rowid = 6;
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
INSERT INTO t2(t2) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT * FROM t2('value');
|
||||
SELECT * FROM t2('v*');
|
||||
}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
SELECT * FROM t2('value') ORDER BY rowid DESC;
|
||||
SELECT * FROM t2('v*') ORDER BY rowid DESC;
|
||||
}
|
||||
execsql_pp {
|
||||
SELECT id, quote(block) FROM t2_data;
|
||||
}
|
||||
|
||||
#----------------------------------
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(ab);
|
||||
CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', 'instance');
|
||||
INSERT INTO ft(rowid, ab) VALUES
|
||||
(1, 'one'),
|
||||
(2, 'two'),
|
||||
(3, 'three'),
|
||||
(4, 'four'),
|
||||
(5, 'one one'),
|
||||
(6, 'one two'),
|
||||
(7, 'one three'),
|
||||
(8, 'one four'),
|
||||
(9, 'two one'),
|
||||
(10, 'two two'),
|
||||
(11, 'two three'),
|
||||
(12, 'two four'),
|
||||
(13, 'three one'),
|
||||
(14, 'three two'),
|
||||
(15, 'three three'),
|
||||
(16, 'three four');
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {3}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
DELETE FROM ft WHERE rowid=9;
|
||||
}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
DELETE FROM ft WHERE ab LIKE '%two%'
|
||||
}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
SELECT count(*) FROM ft_data;
|
||||
} {3}
|
||||
|
||||
#----------------------------------
|
||||
reset_db
|
||||
|
||||
set ::vocab {
|
||||
one two three four five six seven eight nine ten
|
||||
eleven twelve thirteen fourteen fifteen sixteen
|
||||
seventeen eighteen nineteen twenty
|
||||
}
|
||||
proc rnddoc {} {
|
||||
set nVocab [llength $::vocab]
|
||||
set ret [list]
|
||||
for {set ii 0} {$ii < 8} {incr ii} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * $nVocab)]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
|
||||
proc contains {list val} {
|
||||
expr {[lsearch $list $val]>=0}
|
||||
}
|
||||
|
||||
foreach {tn pgsz} {
|
||||
2 64
|
||||
1 1000
|
||||
} {
|
||||
reset_db
|
||||
db function rnddoc rnddoc
|
||||
db function contains contains
|
||||
|
||||
expr srand(1)
|
||||
|
||||
do_execsql_test 3.$tn.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', $pgsz);
|
||||
WITH s(i) AS (
|
||||
VALUES(1) UNION SELECT i+1 FROM s WHERE i<20
|
||||
)
|
||||
INSERT INTO t1 SELECT rnddoc() FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 3.$tn.1 {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
foreach {rowid} {
|
||||
6 16 3 4 9 14 13 7 20 15 19 10 11 2 5 18 17 1 12 8
|
||||
} {
|
||||
|
||||
do_execsql_test 3.$tn.2.$rowid {
|
||||
DELETE FROM t1 WHERE rowid=$rowid;
|
||||
}
|
||||
do_execsql_test 3.$tn.2.$rowid.ic {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
foreach v $::vocab {
|
||||
do_execsql_test 3.$tn.2.$rowid.q.$v {
|
||||
SELECT rowid FROM t1($v)
|
||||
} [db eval {SELECT rowid FROM t1 WHERE contains(x, $v)}]
|
||||
|
||||
do_execsql_test 3.$tn.2.$rowid.q.$v.DESC {
|
||||
SELECT rowid FROM t1($v) ORDER BY 1 DESC
|
||||
} [db eval {SELECT rowid FROM t1 WHERE contains(x, $v) ORDER BY 1 DESC}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO t1(x) VALUES('optimize');
|
||||
INSERT INTO t1(t1) VALUES('optimize');
|
||||
SELECT count(*) FROM t1_data;
|
||||
} {3}
|
||||
|
||||
#----------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
set L1 [string repeat abcdefghij 10]
|
||||
set L2 [string repeat 1234567890 10]
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
INSERT INTO t1 VALUES('aa' || $L1 || ' ' || $L2);
|
||||
}
|
||||
do_execsql_test 4.2 {
|
||||
DELETE FROM t1 WHERE rowid=1
|
||||
}
|
||||
do_execsql_test 4.3 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#----------------------------------
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
set doc "aa [string repeat {abc } 60]"
|
||||
|
||||
do_execsql_test 5.1 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES($doc);
|
||||
INSERT INTO t1 VALUES('aa abc');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
DELETE FROM t1 WHERE rowid = 1;
|
||||
}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 5.4 { SELECT rowid FROM t1('abc'); } 2
|
||||
do_execsql_test 5.5 { SELECT rowid FROM t1('aa'); } 2
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# 2023 Feb 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
ifcapable !fts5 { finish_test ; return }
|
||||
set ::testprefix fts5secure2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(col);
|
||||
INSERT INTO ft VALUES('data for the table');
|
||||
INSERT INTO ft VALUES('more of the same');
|
||||
INSERT INTO ft VALUES('and extra data');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT * FROM ft_config
|
||||
} {version 4}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
|
||||
SELECT * FROM ft_config;
|
||||
} {secure-delete 1 version 4}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
|
||||
SELECT * FROM ft_config;
|
||||
} {secure-delete 1 version 4}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
DELETE FROM ft WHERE rowid=2;
|
||||
SELECT * FROM ft_config;
|
||||
} {secure-delete 1 version 5}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT rowid, col FROM ft('data');
|
||||
} {1 {data for the table} 3 {and extra data}}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
SELECT rowid, col FROM ft('data');
|
||||
} {1 {data for the table} 3 {and extra data}}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(col);
|
||||
INSERT INTO ft VALUES('one zero one one zero');
|
||||
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
SELECT count(*) FROM ft_data WHERE block=X'00000004';
|
||||
} {0}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
UPDATE ft SET col = 'zero one zero zero one' WHERE rowid=1;
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT count(*) FROM ft_data WHERE block=X'00000004';
|
||||
} {1}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO ft VALUES('one zero zero one');
|
||||
DELETE FROM ft WHERE rowid=1;
|
||||
}
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
SELECT count(*) FROM ft_data WHERE block=X'00000004';
|
||||
} {2}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
# 2023 Feb 17
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# TESTRUNNER: slow
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
ifcapable !fts5 { finish_test ; return }
|
||||
set ::testprefix fts5secure3
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(col);
|
||||
INSERT INTO ft VALUES('data for the table');
|
||||
INSERT INTO ft VALUES('more of the same');
|
||||
INSERT INTO ft VALUES('and extra data');
|
||||
|
||||
INSERT INTO ft(ft, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft(rowid, col) VALUES(0, 'the next data');
|
||||
DELETE FROM ft WHERE rowid=1;
|
||||
DELETE FROM ft WHERE rowid=2;
|
||||
INSERT INTO ft(rowid, col) VALUES(6, 'with some more of the same data');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO ft(ft) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('the start');
|
||||
}
|
||||
do_test 2.1 {
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql { INSERT INTO t1 VALUES('the ' || hex(randomblob(3))) }
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES('the end');
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
DELETE FROM t1 WHERE rowid BETWEEN 2 AND 1000;
|
||||
}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.6 {
|
||||
INSERT INTO t1(rowid, x) VALUES(500, 'middle');
|
||||
INSERT INTO t1(rowid, x) VALUES(501, 'value');
|
||||
SELECT * FROM t1('the middle');
|
||||
}
|
||||
|
||||
do_execsql_test 2.7 {
|
||||
INSERT INTO t1(t1) VALUES('optimize');
|
||||
}
|
||||
|
||||
do_execsql_test 2.8 {
|
||||
SELECT count(*) FROM t1_data
|
||||
} 4
|
||||
|
||||
#execsql_pp { SELECT id, quote(block), fts5_decode(id, block) FROM t1_data; }
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests with large/small rowid values.
|
||||
#
|
||||
|
||||
reset_db
|
||||
|
||||
expr srand(0)
|
||||
|
||||
set vocab {
|
||||
Popper Poppins Popsicle Porfirio Porrima Porsche
|
||||
Porter Portia Portland Portsmouth Portugal Portuguese
|
||||
Poseidon Post PostgreSQL Potemkin Potomac Potsdam
|
||||
Pottawatomie Potter Potts Pound Poussin Powell
|
||||
PowerPC PowerPoint Powers Powhatan Poznan Prada
|
||||
Prado Praetorian Prague Praia Prakrit Pratchett
|
||||
Pratt Pravda Praxiteles Preakness Precambrian Preminger
|
||||
Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
|
||||
}
|
||||
proc newdoc {} {
|
||||
for {set i 0} {$i<8} {incr i} {
|
||||
lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
db func newdoc newdoc
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE fff USING fts5(y);
|
||||
INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
|
||||
INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
|
||||
|
||||
INSERT INTO fff(fff, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
proc lshuffle {in} {
|
||||
set out [list]
|
||||
while {[llength $in]>0} {
|
||||
set idx [expr int(abs(rand()) * [llength $in])]
|
||||
lappend out [lindex $in $idx]
|
||||
set in [lreplace $in $idx $idx]
|
||||
}
|
||||
set out
|
||||
}
|
||||
|
||||
#dump fff
|
||||
|
||||
set iTest 1
|
||||
foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
|
||||
#if {$iTest==1} { dump fff }
|
||||
#if {$iTest==1} { breakpoint }
|
||||
do_execsql_test 3.1.$iTest.$ii {
|
||||
DELETE FROM fff WHERE rowid=$ii;
|
||||
}
|
||||
#if {$iTest==1} { dump fff }
|
||||
if {($iTest % 20)==0} {
|
||||
do_execsql_test 3.1.$iTest.$ii.ic {
|
||||
INSERT INTO fff(fff) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
#if {$iTest==1} { break }
|
||||
incr iTest
|
||||
}
|
||||
|
||||
#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }
|
||||
#breakpoint
|
||||
#execsql_pp {
|
||||
# SELECT rowid FROM fff('post') ORDER BY rowid DESC
|
||||
#}
|
||||
#
|
||||
#dump fff
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
# 2023 April 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
return_if_no_fts5
|
||||
set ::testprefix fts5secure4
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test using the 'delete' command to attempt to delete a token that
|
||||
# is not present in the index in secure-delete mode.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, b, content=x1);
|
||||
|
||||
CREATE TABLE x1(rowid INTEGER PRIMARY KEY, a, b);
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 'hello world', 'today xyz'),
|
||||
(2, 'not the day', 'crunch crumble and chomp'),
|
||||
(3, 'one', 'two');
|
||||
INSERT INTO t1(t1) VALUES('rebuild');
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 4, 'nosuchtoken', '');
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 1, 'crunch', '');
|
||||
}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 3, 'crunch', '');
|
||||
}
|
||||
|
||||
do_execsql_test 1.6 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.7 {
|
||||
CREATE VIRTUAL TABLE y1 USING fts5(xx, prefix='1,2');
|
||||
INSERT INTO y1(y1, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO y1(y1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
do_execsql_test 1.8 {
|
||||
BEGIN;
|
||||
INSERT INTO y1(rowid, xx) VALUES(1, 'abc def');
|
||||
INSERT INTO y1(rowid, xx) VALUES(2, 'reallyreallylongtoken');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 1.9 {
|
||||
DELETE FROM y1 WHERE rowid=1;
|
||||
INSERT INTO y1(y1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 1.10 {
|
||||
CREATE VIRTUAL TABLE w1 USING fts5(ww, content="");
|
||||
INSERT INTO w1(rowid, ww) VALUES(123, '');
|
||||
}
|
||||
do_catchsql_test 1.11 {
|
||||
INSERT INTO w1(w1, rowid, ww) VALUES('delete', 123, 'xyz');
|
||||
} {1 {database disk image is malformed}}
|
||||
do_catchsql_test 1.12 {
|
||||
DROP TABLE w1;
|
||||
CREATE VIRTUAL TABLE w1 USING fts5(ww, content="");
|
||||
INSERT INTO w1(rowid, ww) VALUES(123, '');
|
||||
DELETE FROM w1_data WHERE id>10;
|
||||
INSERT INTO w1(w1, rowid, ww) VALUES('delete', 123, 'xyz');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test using secure-delete with detail=none or detail=col.
|
||||
#
|
||||
foreach {tn d} {1 full 2 none 3 column} {
|
||||
reset_db
|
||||
do_execsql_test 2.$tn.1 "
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(xx, yy, zz, detail=$d, prefix='10,20');
|
||||
INSERT INTO x1(x1, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO x1(x1, rank) VALUES('secure-delete', 1);
|
||||
"
|
||||
|
||||
do_execsql_test 2.$tn.2 {
|
||||
BEGIN;
|
||||
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||
INSERT INTO x1(xx, yy, zz) VALUES('a b c', 'd e f', 'a b c');
|
||||
COMMIT;
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.3 {
|
||||
DELETE FROM x1 WHERE rowid IN (2, 4, 6);
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.4 {
|
||||
DELETE FROM x1 WHERE rowid IN (1, 3, 5);
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.5 {
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO x1
|
||||
SELECT 'seems to be', 'used brew to', 'everything is working' FROM s
|
||||
UNION ALL
|
||||
SELECT 'used brew to', 'everything is working', 'seems to be' FROM s
|
||||
UNION ALL
|
||||
SELECT 'everything is working', 'seems to be', 'used brew to' FROM s
|
||||
UNION ALL
|
||||
SELECT 'abc', 'zzz', 'a b c d'
|
||||
UNION ALL
|
||||
SELECT 'z', 'z', 'z' FROM s
|
||||
}
|
||||
|
||||
do_test 2.$tn.6 {
|
||||
for {set i 300} {$i > 200} {incr i -1} {
|
||||
execsql {
|
||||
DELETE FROM x1 WHERE rowid=$i;
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 2.$tn.7 {
|
||||
for {set i 1} {$i < 100} {incr i} {
|
||||
execsql {
|
||||
DELETE FROM x1 WHERE rowid=$i;
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 2.$tn.8 {
|
||||
foreach i [db eval {SELECT rowid FROM x1}] {
|
||||
execsql {
|
||||
DELETE FROM x1 WHERE rowid=$i;
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.$tn.9 {
|
||||
SELECT * FROM x1
|
||||
} {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# 2023 April 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
return_if_no_fts5
|
||||
set ::testprefix fts5secure5
|
||||
return_if_no_fts5
|
||||
|
||||
proc dump {} {
|
||||
execsql_pp {
|
||||
SELECT id, quote(block), fts5_decode_none(id, block) FROM ft1_data
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft1(rowid, a) VALUES(1, 'abcd');
|
||||
INSERT INTO ft1(rowid, a) VALUES(2, 'abcd');
|
||||
INSERT INTO ft1(rowid, a) VALUES(3, 'abcd');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 1.2 {
|
||||
DELETE FROM ft1 WHERE rowid=1;
|
||||
}
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 1.4 {
|
||||
DELETE FROM ft1 WHERE rowid=3;
|
||||
}
|
||||
do_execsql_test 1.5 {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 1.6 {
|
||||
DELETE FROM ft1 WHERE rowid=3;
|
||||
}
|
||||
do_execsql_test 1.7 {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft1(rowid, a) VALUES(1, 'abcd one');
|
||||
INSERT INTO ft1(rowid, a) VALUES(2, 'abcd two');
|
||||
INSERT INTO ft1(rowid, a) VALUES(3, 'abcd two');
|
||||
INSERT INTO ft1(rowid, a) VALUES(4, 'abcd two');
|
||||
INSERT INTO ft1(rowid, a) VALUES(5, 'abcd three');
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
do_execsql_test 2.2a {
|
||||
DELETE FROM ft1 WHERE rowid=3;
|
||||
}
|
||||
do_execsql_test 2.2b {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.3a {
|
||||
DELETE FROM ft1 WHERE rowid=2;
|
||||
}
|
||||
do_execsql_test 2.3b {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 2.4a {
|
||||
DELETE FROM ft1 WHERE rowid=4;
|
||||
}
|
||||
do_execsql_test 2.4b {
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none, prefix=1);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64);
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
BEGIN;
|
||||
INSERT INTO ft1(a) VALUES('c');
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
DELETE FROM ft1 WHERE rowid IN (1);
|
||||
INSERT INTO ft1(ft1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(a, detail=none);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('secure-delete', 1);
|
||||
INSERT INTO ft1(ft1, rank) VALUES('pgsz', 64);
|
||||
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
|
||||
)
|
||||
INSERT INTO ft1 SELECT 'abcdefg' FROM s;
|
||||
}
|
||||
|
||||
do_test 4.1 {
|
||||
for {set i 500} {$i > 0} {incr i -1} {
|
||||
execsql { DELETE FROM ft1 WHERE rowid=$i }
|
||||
execsql { INSERT INTO ft1(ft1) VALUES('integrity-check') }
|
||||
}
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
# 2023 April 14
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script is testing the FTS5 module.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix fts5securefault
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
return_if_no_fts5
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(rowid, ab) VALUES
|
||||
(0, 'abc'), (1, 'abc'), (2, 'abc'), (3, 'abc'), (4, 'def');
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid=2 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
do_faultsim_test 1.2 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid IN(0, 1, 2, 3, 4) }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
set big [string repeat abcdefghij 5]
|
||||
set big2 [string repeat klmnopqrst 5]
|
||||
set doc "$big $big2"
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<4
|
||||
)
|
||||
INSERT INTO t1(rowid, ab) SELECT i, $doc FROM s;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid = 3 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 4 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
set big [string repeat abcdefghij 5]
|
||||
set big2 [string repeat klmnopqrst 5]
|
||||
set doc "$big $big2"
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<25
|
||||
)
|
||||
INSERT INTO t1(rowid, ab) SELECT i, $doc FROM s;
|
||||
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
DELETE FROM t1 WHERE rowid BETWEEN 3 AND 23;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 3.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid = 24 }
|
||||
execsql { DELETE FROM t1 WHERE rowid = 25 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
set doc [string repeat "tok " 400]
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
INSERT INTO t1(rowid, ab) VALUES(1, $doc), (2, $doc), (3, $doc);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 4.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid = 2 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
|
||||
set doc1 [string repeat "abc " 10]
|
||||
set doc2 [string repeat "def " 10]
|
||||
|
||||
do_test 5.0 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
BEGIN;
|
||||
}
|
||||
for {set i 0} {$i < 50} {incr i} {
|
||||
execsql {
|
||||
INSERT INTO t1(rowid, ab) VALUES($i, 'abcdefg');
|
||||
}
|
||||
}
|
||||
execsql {
|
||||
INSERT INTO t1(rowid, ab) VALUES(105, 'def');
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 5.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql { DELETE FROM t1 WHERE rowid = 105 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 6.0 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
|
||||
BEGIN;
|
||||
INSERT INTO t1(rowid, ab) VALUES(1, 'abcdefg');
|
||||
INSERT INTO t1(rowid, ab) VALUES(2, 'abcdefg');
|
||||
INSERT INTO t1(rowid, ab) VALUES(3, 'abcdefg');
|
||||
COMMIT;
|
||||
}
|
||||
} {}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 6.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} -body {
|
||||
execsql {
|
||||
UPDATE t1 SET ab='abcdefg' WHERE rowid=2;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 7.0 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(ab);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO t1(t1, rank) VALUES('secure-delete', 1);
|
||||
}
|
||||
} {}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 7.1 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
set big1 "[string repeat x 50] [string repeat y 50] [string repeat z 50]"
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES($big1);
|
||||
}
|
||||
} -body {
|
||||
execsql { COMMIT }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -38,20 +38,20 @@ do_execsql_test 1.3 {
|
||||
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
do_execsql_test 1.4 {
|
||||
UPDATE t1_config set v=5 WHERE k='version';
|
||||
UPDATE t1_config set v=6 WHERE k='version';
|
||||
}
|
||||
|
||||
do_test 1.5 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
|
||||
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}
|
||||
} {1 {invalid fts5 file format (found 6, expected 4 or 5) - run 'rebuild'}}
|
||||
|
||||
do_test 1.6 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { INSERT INTO t1 VALUES('x y z') }
|
||||
} {1 {invalid fts5 file format (found 5, expected 4) - run 'rebuild'}}
|
||||
} {1 {invalid fts5 file format (found 6, expected 4 or 5) - run 'rebuild'}}
|
||||
|
||||
do_test 1.7 {
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
@@ -59,7 +59,75 @@ do_test 1.7 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
|
||||
} {1 {invalid fts5 file format (found 0, expected 4) - run 'rebuild'}}
|
||||
} {1 {invalid fts5 file format (found 0, expected 4 or 5) - run 'rebuild'}}
|
||||
|
||||
do_test 1.8 {
|
||||
sqlite3_db_config db DEFENSIVE 0
|
||||
execsql { INSERT INTO t1_config VALUES('version', 4) }
|
||||
execsql { INSERT INTO t1(t1, rank) VALUES('secure-delete', 1) }
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.10 {
|
||||
SELECT * FROM t1_config
|
||||
} {secure-delete 1 version 4}
|
||||
|
||||
do_execsql_test 1.11 {
|
||||
INSERT INTO t1(rowid, one) VALUES(123, 'one two three');
|
||||
DELETE FROM t1 WHERE rowid=123;
|
||||
SELECT * FROM t1_config
|
||||
} {secure-delete 1 version 5}
|
||||
|
||||
do_execsql_test 1.11 {
|
||||
INSERT INTO t1(t1) VALUES('rebuild');
|
||||
SELECT * FROM t1_config
|
||||
} {secure-delete 1 version 4}
|
||||
|
||||
do_execsql_test 1.12 {
|
||||
SELECT * FROM t1_config
|
||||
} {secure-delete 1 version 4}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE xyz USING fts5(x);
|
||||
INSERT INTO xyz(rowid, x) VALUES
|
||||
(1, 'one document'),
|
||||
(2, 'two document'),
|
||||
(3, 'three document'),
|
||||
(4, 'four document'),
|
||||
(5, 'five document'),
|
||||
(6, 'six document');
|
||||
|
||||
INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 1);
|
||||
SELECT v FROM xyz_config WHERE k='version';
|
||||
} {4}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
BEGIN;
|
||||
INSERT INTO xyz(rowid, x) VALUES(7, 'seven document');
|
||||
SAVEPOINT one;
|
||||
DELETE FROM xyz WHERE rowid = 4;
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT v FROM xyz_config WHERE k='version';
|
||||
} {5}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
ROLLBACK TO one;
|
||||
SELECT v FROM xyz_config WHERE k='version';
|
||||
} {4}
|
||||
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
DELETE FROM xyz WHERE rowid = 3;
|
||||
COMMIT;
|
||||
SELECT v FROM xyz_config WHERE k='version';
|
||||
} {5}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
Executable → Regular
+1
@@ -76,6 +76,7 @@ typedef unsigned char u8;
|
||||
#define U8_TYPEDEF
|
||||
#endif
|
||||
|
||||
/* Decoding table, ASCII (7-bit) value to base 64 digit value or other */
|
||||
static const u8 b64DigitValues[128] = {
|
||||
/* HT LF VT FF CR */
|
||||
ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND,
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This SQLite extension implements functions that compute SHA3 hashes.
|
||||
** This SQLite extension implements functions that compute SHA3 hashes
|
||||
** in the way described by the (U.S.) NIST FIPS 202 SHA-3 Standard.
|
||||
** Two SQL functions are implemented:
|
||||
**
|
||||
** sha3(X,SIZE)
|
||||
|
||||
+4
-1
@@ -1097,7 +1097,10 @@ static int zipfileColumn(
|
||||
** it to be a directory either if the mode suggests so, or if
|
||||
** the final character in the name is '/'. */
|
||||
u32 mode = pCDS->iExternalAttr >> 16;
|
||||
if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
|
||||
if( !(mode & S_IFDIR)
|
||||
&& pCDS->nFile>=1
|
||||
&& pCDS->zFile[pCDS->nFile-1]!='/'
|
||||
){
|
||||
sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,5 +207,86 @@ do_test 3.4.0 {
|
||||
} SQLITE_OK
|
||||
rbu close
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
forcedelete rbu1.db
|
||||
forcedelete rbu2.db
|
||||
|
||||
sqlite3 rbu rbu1.db
|
||||
do_execsql_test -db rbu 4.1 {
|
||||
CREATE TABLE data_t1(a, b, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(1, 'one', 0);
|
||||
}
|
||||
rbu close
|
||||
sqlite3 rbu rbu2.db
|
||||
do_execsql_test -db rbu 4.2 {
|
||||
CREATE TABLE data_t1(a, b, rbu_control);
|
||||
INSERT INTO data_t1 VALUES(2, 'two', 0);
|
||||
}
|
||||
rbu close
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b);
|
||||
}
|
||||
db close
|
||||
|
||||
do_test 4.4 {
|
||||
sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu1.db
|
||||
rbu step
|
||||
rbu state
|
||||
} {oal}
|
||||
|
||||
sqlite3 cons test.db
|
||||
do_execsql_test -db cons 4.5 {
|
||||
SELECT * FROM t1
|
||||
} {}
|
||||
|
||||
do_test 4.6 { rbu step ; rbu state } {oal}
|
||||
do_test 4.7 { rbu step ; rbu state } {move}
|
||||
do_execsql_test -db cons 4.8 {
|
||||
SELECT * FROM t1
|
||||
} {}
|
||||
do_test 4.9 { rbu step ; rbu state } {checkpoint}
|
||||
do_test 4.10 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {1 {database is locked}}
|
||||
do_test 4.11 { rbu step ; rbu state } {checkpoint}
|
||||
do_test 4.11 { rbu step ; rbu state } {done}
|
||||
rbu close
|
||||
|
||||
do_test 4.12 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {0 {1 one}}
|
||||
|
||||
do_test 4.13 {
|
||||
sqlite3rbu rbu file:test.db?rbu_exclusive_checkpoint=1 rbu2.db
|
||||
rbu step
|
||||
rbu state
|
||||
} {oal}
|
||||
|
||||
do_test 4.14 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {0 {1 one}}
|
||||
|
||||
do_test 4.15 { rbu step ; rbu state } {oal}
|
||||
do_test 4.16 { rbu step ; rbu state } {move}
|
||||
|
||||
do_test 4.17 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {0 {1 one}}
|
||||
|
||||
do_test 4.18 { rbu step ; rbu state } {checkpoint}
|
||||
do_test 4.19 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {1 {database is locked}}
|
||||
do_test 4.20 { rbu step ; rbu state } {checkpoint}
|
||||
do_test 4.21 { rbu step ; rbu state } {done}
|
||||
rbu close
|
||||
|
||||
do_test 4.22 {
|
||||
catchsql { SELECT * FROM t1 } cons
|
||||
} {0 {1 one 2 two}}
|
||||
|
||||
cons close
|
||||
|
||||
finish_test
|
||||
|
||||
+10
-1
@@ -3141,6 +3141,11 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
|
||||
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
|
||||
}
|
||||
|
||||
/*
|
||||
** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
|
||||
** in zipvfs.h.
|
||||
*/
|
||||
#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
|
||||
|
||||
/*
|
||||
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
|
||||
@@ -3149,7 +3154,11 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
|
||||
static int rbuLockDatabase(sqlite3 *db){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_file *fd = 0;
|
||||
sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
|
||||
|
||||
sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
|
||||
if( fd==0 ){
|
||||
sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
|
||||
}
|
||||
|
||||
if( fd->pMethods ){
|
||||
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
|
||||
|
||||
@@ -167,6 +167,7 @@ static int dbdataConnect(
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
(void)pzErr;
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
|
||||
if( pTab==0 ){
|
||||
|
||||
@@ -28,7 +28,7 @@ do_execsql_test 1.0 {
|
||||
forcedelete test.db2
|
||||
do_test 1.1 {
|
||||
set R [sqlite3_recover_init db main test.db2]
|
||||
} {sqlite_recover1}
|
||||
} {/sqlite_recover.*/}
|
||||
|
||||
do_test 1.2 {
|
||||
$R run
|
||||
|
||||
@@ -117,7 +117,7 @@ const installOpfsVfs = function callee(options){
|
||||
if('function' === typeof options.proxyUri){
|
||||
options.proxyUri = options.proxyUri();
|
||||
}
|
||||
const thePromise = new Promise(function(promiseResolve, promiseReject_){
|
||||
const thePromise = new Promise(function(promiseResolve_, promiseReject_){
|
||||
const loggers = {
|
||||
0:sqlite3.config.error,
|
||||
1:sqlite3.config.warn,
|
||||
@@ -193,10 +193,16 @@ const installOpfsVfs = function callee(options){
|
||||
}/*metrics*/;
|
||||
const opfsVfs = new sqlite3_vfs();
|
||||
const opfsIoMethods = new sqlite3_io_methods();
|
||||
const promiseReject = function(err){
|
||||
let promiseWasRejected = undefined;
|
||||
const promiseReject = (err)=>{
|
||||
promiseWasRejected = true;
|
||||
opfsVfs.dispose();
|
||||
return promiseReject_(err);
|
||||
};
|
||||
const promiseResolve = (value)=>{
|
||||
promiseWasRejected = false;
|
||||
return promiseResolve_(value);
|
||||
};
|
||||
const W =
|
||||
//#if target=es6-bundler-friendly
|
||||
new Worker(new URL("sqlite3-opfs-async-proxy.js", import.meta.url));
|
||||
@@ -205,6 +211,18 @@ const installOpfsVfs = function callee(options){
|
||||
//#else
|
||||
new Worker(options.proxyUri);
|
||||
//#endif
|
||||
setTimeout(()=>{
|
||||
/* At attempt to work around a browser-specific quirk in which
|
||||
the Worker load is failing in such a way that we neither
|
||||
resolve nor reject it. This workaround gives that resolve/reject
|
||||
a time limit and rejects if that timer expires. Discussion:
|
||||
https://sqlite.org/forum/forumpost/a708c98dcb3ef */
|
||||
if(undefined===promiseWasRejected){
|
||||
promiseReject(
|
||||
new Error("Timeout while waiting for OPFS async proxy worker.")
|
||||
);
|
||||
}
|
||||
}, 4000);
|
||||
W._originalOnError = W.onerror /* will be restored later */;
|
||||
W.onerror = function(err){
|
||||
// The error object doesn't contain any useful info when the
|
||||
@@ -1269,6 +1287,9 @@ const installOpfsVfs = function callee(options){
|
||||
/*Indicates that the async partner has received the 'init'
|
||||
and has finished initializing, so the real work can
|
||||
begin...*/
|
||||
if(true===promiseWasRejected){
|
||||
break /* promise was already rejected via timer */;
|
||||
}
|
||||
try {
|
||||
sqlite3.vfs.installVfs({
|
||||
io: {struct: opfsIoMethods, methods: ioSyncWrappers},
|
||||
|
||||
@@ -928,6 +928,7 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
DefInt(SQLITE_VTAB_CONSTRAINT_SUPPORT);
|
||||
DefInt(SQLITE_VTAB_INNOCUOUS);
|
||||
DefInt(SQLITE_VTAB_DIRECTONLY);
|
||||
DefInt(SQLITE_VTAB_USES_ALL_SCHEMAS);
|
||||
DefInt(SQLITE_ROLLBACK);
|
||||
//DefInt(SQLITE_IGNORE); // Also used by sqlite3_authorizer() callback
|
||||
DefInt(SQLITE_FAIL);
|
||||
|
||||
@@ -1189,17 +1189,6 @@ self.sqlite3InitModule = sqlite3InitModule;
|
||||
const stack = wasm.pstack.pointer;
|
||||
try {
|
||||
const [pCur, pHi] = wasm.pstack.allocChunks(2,'i64');
|
||||
rc = capi.sqlite3_db_status(this.db, capi.SQLITE_DBSTATUS_LOOKASIDE_USED,
|
||||
pCur, pHi, 0);
|
||||
T.assert(0===rc);
|
||||
if(!wasm.peek32(pCur)){
|
||||
rc = capi.sqlite3_db_config(this.db, capi.SQLITE_DBCONFIG_LOOKASIDE,
|
||||
0, 4096, 12);
|
||||
T.assert(0 === rc);
|
||||
}else{
|
||||
console.debug("Cannot test db_config(SQLITE_DBCONFIG_LOOKASIDE)",
|
||||
"while lookaside memory is in use.");
|
||||
}
|
||||
wasm.poke32([pCur, pHi], 0);
|
||||
let [vCur, vHi] = wasm.peek32(pCur, pHi);
|
||||
T.assert(0===vCur).assert(0===vHi);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Add\susage\sdetection\sto\sthe\sNULL\svalue\sgenerator\sfor\sthe\sleft\stable\sof\sa\nRIGHT\sJOIN\sinside\sof\san\saggregate.
|
||||
D 2023-03-25T23:40:21.196
|
||||
C Add\scomment\son\sCLI\s^C\sfix\s(because\sit\sis\sa\sbit\ssubtle.)
|
||||
D 2023-04-18T22:53:30.926
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 764f2e3e8fb4ae1c8dfe03e65b2b3b01bd1fc57edf78ec2cab3a1301e90e1905
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc ada3466f8f0112a8baead4d6cc2a99bf544d228958baae12ca35a3ee5755c806
|
||||
F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e
|
||||
F README.md e05bd8fcb45da04ab045c37f79a98654e8aa3b3b8f302cfbba80a0d510df75f7
|
||||
F VERSION 17f95ae2fdf21f0e9575eb0b0511ea63f15d71dfff431b21c2b4adbfa70cfbbf
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -86,14 +86,14 @@ F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6d
|
||||
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h c132a9323f22a972c4c93a8d5a3d901113a6e612faf30ca8e695788438c5ca2a
|
||||
F ext/fts5/fts5Int.h c0d46e399e345e35985b72a1c1af025973bfaa5b1e3563b0ce3bb0ce144a7ca3
|
||||
F ext/fts5/fts5Int.h f473de2bdae0977af0d6c8cce96e3666821b85efba5f6006c7732662c3aabcb3
|
||||
F ext/fts5/fts5_aux.c 572d5ec92ba7301df2fea3258576332f2f4d2dfd66d8263afd157d9deceac480
|
||||
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
|
||||
F ext/fts5/fts5_config.c 501e7d3566bc92766b0e11c0109a7c5a6146bc41144195459af5422f6c2078aa
|
||||
F ext/fts5/fts5_config.c 46af0b3c3c3f00bfc5bdd307434d7c5f0fa0678a034dd48345cd83b20068efbd
|
||||
F ext/fts5/fts5_expr.c 48e8e45261c6030cf5c77f606217a22722b1a4d0b34e2ba6cbfc386581627989
|
||||
F ext/fts5/fts5_hash.c d4fb70940359f2120ccd1de7ffe64cc3efe65de9e8995b822cd536ff64c96982
|
||||
F ext/fts5/fts5_index.c df5b29576a409f673e54b470723d817df9d5167cff208c48ab9a3773cba6fa89
|
||||
F ext/fts5/fts5_main.c fe67b6fb2ef134d9dbfa3941c63f777d755b075449be1863cb913a7f8754cb69
|
||||
F ext/fts5/fts5_index.c 17dca8e874df04182bc45063dc0b761acc242b91f1264d2257b7e37bd4e4c2ad
|
||||
F ext/fts5/fts5_main.c b4dba04a36aaf9b8e8cef0100b6dbb422cc74753eacc11d6401cac7a87c0f38d
|
||||
F ext/fts5/fts5_storage.c 76c6085239eb44424004c022e9da17a5ecd5aaec859fba90ad47d3b08f4c8082
|
||||
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
@@ -104,7 +104,7 @@ F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d0988
|
||||
F ext/fts5/fts5_vocab.c 12138e84616b56218532e3e8feb1d3e0e7ae845e33408dbe911df520424dc9d6
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5_common.tcl a9de9c2209cc4e7ae3c753e783504e67206c6c1467d08f209cd0c5923d3e8d8b
|
||||
F ext/fts5/test/fts5aa.test 5bd43427b7d08ce2e19c488a26534be450538b9232d4d5305049e8de236e9aa9
|
||||
F ext/fts5/test/fts5ab.test 9205c839332c908aaad2b01ab8670ece8b161e8f2ec8a9fabf18ca9385880bb7
|
||||
F ext/fts5/test/fts5ac.test a7aa7e1fefc6e1918aa4d3111d5c44a09177168e962c5fd2cca9620de8a7ed6d
|
||||
@@ -115,7 +115,7 @@ F ext/fts5/test/fts5ag.test 7816f25a0707578f08145ab539fc0ca025f8951e788b28a6a18a
|
||||
F ext/fts5/test/fts5ah.test 2f047dfe89dc8611fa53e3d8bfc453b79cff037aa423c8d171e91e645745aa2c
|
||||
F ext/fts5/test/fts5ai.test bc97e4758cc93e06bf851d61c98fdf4e8b8f8315ee28a84fb15f916360856414
|
||||
F ext/fts5/test/fts5aj.test 745020852d85f5dd49d11cb7ad11d3cc6dafc4fe6d6d24bc0875ac8f43ee4149
|
||||
F ext/fts5/test/fts5ak.test fc3595f8e6873bb86d70c9bd4b67d0413ce577bd4793c39a2b60a7b8825b60a6
|
||||
F ext/fts5/test/fts5ak.test f459a64c9d38698af72a7c657ab6349bca96150241dd69fcce752634b2742d41
|
||||
F ext/fts5/test/fts5al.test 00c4c1c6a1366b73aa48ce2068c634520867c3cf7f5d1676ebbb775ee1f35734
|
||||
F ext/fts5/test/fts5alter.test 5565f7e4605512b69171ac18ca84398603f9f6456dbe377beeca97e83cc242cd
|
||||
F ext/fts5/test/fts5auto.test 78989e6527ce69c9eddbef7392fea5c10b0010cd2b2ae68eec7bc869c471e691
|
||||
@@ -187,6 +187,12 @@ F ext/fts5/test/fts5rebuild.test 55d6f17715cddbf825680dd6551efbc72ed916d8cf1cde4
|
||||
F ext/fts5/test/fts5restart.test 835ecc8f449e3919f72509ab58056d0cedca40d1fe04108ccf8ac4c2ba41f415
|
||||
F ext/fts5/test/fts5rowid.test b8790ec170a8dc1942a15aef3db926a5f3061b1ff171013003d8297203a20ad6
|
||||
F ext/fts5/test/fts5savepoint.test fc02929f238d02a22df4172625704e029f7c1e0e92e332d654375690f8e6e43f
|
||||
F ext/fts5/test/fts5secure.test 214a561519d1b1817f146efd1057e2a97cc896e75c2accc77157d874154bda64
|
||||
F ext/fts5/test/fts5secure2.test 2e961d7eef939f294c56b5d895cac7f1c3a60b934ee2cfd5e5e620bdf1ba6bbc
|
||||
F ext/fts5/test/fts5secure3.test c7e1080a6912f2a3ac68f2e05b88b72a99de38543509b2bbf427cac5c9c1c610
|
||||
F ext/fts5/test/fts5secure4.test 0d10a80590c07891478700af7793b232962042677432b9846cf7fc8337b67c97
|
||||
F ext/fts5/test/fts5secure5.test c07a68ced5951567ac116c22f2d2aafae497e47fe9fcb6a335c22f9c7a4f2c3a
|
||||
F ext/fts5/test/fts5securefault.test dbca2b6a1c16700017f5051138991b705410889933f2a37c57ae8a23b296b10b
|
||||
F ext/fts5/test/fts5simple.test a298670508c1458b88ce6030440f26a30673931884eb5f4094ac1773b3ba217b
|
||||
F ext/fts5/test/fts5simple2.test 258a1b0c590409bfa5271e872c79572b319d2a56554d0585f68f146a0da603f0
|
||||
F ext/fts5/test/fts5simple3.test d5c74a9d3ca71bd5dd5cacb7c55b86ea12cdddfc8b1910e3de2995206898380f
|
||||
@@ -204,7 +210,7 @@ F ext/fts5/test/fts5unicode3.test 590c72e18195bda2446133f9d82d04a4e89d094bba58c7
|
||||
F ext/fts5/test/fts5unicode4.test 6463301d669f963c83988017aa354108be0b947d325aef58d3abddf27147b687
|
||||
F ext/fts5/test/fts5unindexed.test 9021af86a0fb9fc616f7a69a996db0116e7936d0db63892db6bafabbec21af4d
|
||||
F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d9f005b5a80ccf0bc
|
||||
F ext/fts5/test/fts5version.test c8f2cc105f0abf0224965f93e584633dee3e06c91478bc67e468f7cfdf97fd6a
|
||||
F ext/fts5/test/fts5version.test d6e5a5897550afeccc2f8531d87404dc1c289ee89385dd4318dbdd75e71d7a67
|
||||
F ext/fts5/test/fts5vocab.test 7ed80d9af1ddaaa1637da05e406327b5aac250848bc604c1c1cc667908b87760
|
||||
F ext/fts5/test/fts5vocab2.test 681980e92e031c9f3fe8d9c149189e876c108da2fb0fb3a25bd8a9b94bff8f68
|
||||
F ext/fts5/tool/fts5speed.tcl b0056f91a55b2d1a3684ec05729de92b042e2f85
|
||||
@@ -264,7 +270,7 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23
|
||||
F ext/misc/amatch.c e3ad5532799cee9a97647f483f67f43b38796b84b5a8c60594fe782a4338f358
|
||||
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
|
||||
F ext/misc/appendvfs.c 9642c7a194a2a25dca7ad3e36af24a0a46d7702168c4ad7e59c9f9b0e16a3824
|
||||
F ext/misc/base64.c d43d2b209c8ab70ca3f860104bb353b0f52a1c5462a2466140025c954e4f3ea7 x
|
||||
F ext/misc/base64.c e83a915fcb94c9332e9a92aa4c3beafe2552bd3da2813fc5fff31918cca0b834
|
||||
F ext/misc/base85.c 77dfd5813d23ea561d0348f922583888e78f8eaeb2b9a4a28226d092389890b8
|
||||
F ext/misc/basexx.c 5e859e1820620aa8080fb9145eb47089de426ae808f6abb01a8e12921c3a8e67
|
||||
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
|
||||
@@ -300,7 +306,7 @@ F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d385
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c 8d79354f2c3d46b95ee21272a07cf0bcabb58d1f2b06d9e7b8a31dca1dacb3e5
|
||||
F ext/misc/sha1.c 4011aef176616872b2a0d5bccf0ecfb1f7ce3fe5c3d107f3a8e949d8e1e3f08d
|
||||
F ext/misc/shathree.c 9b7af7b7d55b27c5bbd16548b67fe6aa47a819e71bc6a80a456144f86f4e834d
|
||||
F ext/misc/shathree.c 543af7ce71d391cd3a9ab6924a6a1124efc63211fd0f2e240dc4b56077ba88ac
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
|
||||
F ext/misc/sqlar.c 53e7d48f68d699a24f1a92e68e71eca8b3a9ff991fe9588c2a05bde103c6e7b7
|
||||
@@ -316,7 +322,7 @@ F ext/misc/vfsstat.c 474d08efc697b8eba300082cb1eb74a5f0f3df31ed257db1cb07e72ab0e
|
||||
F ext/misc/vtablog.c 5538acd0c8ddaae372331bee11608d76973436b77d6a91e8635cfc9432fba5ae
|
||||
F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c a838d1bea913c514ff316c69695efbb49ea3b8cb37d22afc57f73b6b010b4546
|
||||
F ext/misc/zipfile.c f98239261488397618ce4754c500626d1de20cd2d44bf2f2d571d7ddaab668a7
|
||||
F ext/misc/zipfile.c b9d615e1d9af7577833861cfaa79b253aec0f26c89239c75af8c790d287d1d39
|
||||
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
@@ -341,7 +347,7 @@ F ext/rbu/rbucrash.test d2b5d619d9281c89cad74401b73b46172daa89906940b1d739c813dd
|
||||
F ext/rbu/rbucrash2.test 0a1a72223d880215ce2893a3260320c31a9358d23cb124c610e4f0d984a93285
|
||||
F ext/rbu/rbudiff.test 8b8b8b569c68fc880134e0fac4bf6b4b7a907aea4cc6eacf7e1d45e1d47b6aac
|
||||
F ext/rbu/rbudor.test 293a192e668bb8e9c7c9704b080c1086ee17496f768e0f1823049e7d02651d1b
|
||||
F ext/rbu/rbuexlock.test e3ece733cc8e0a6cb08533a41ed6f562438539ed309028c63375a5adee4a263b
|
||||
F ext/rbu/rbuexlock.test e07a0875d0b72f7c007e5d5dcf424e9d48a4752a1a9bcee8ee36947e6add6d5b
|
||||
F ext/rbu/rbuexpr.test 2c91617509c88b6e9030f7bf6ff720df26032fcd801adc25533feae726a57382
|
||||
F ext/rbu/rbufault.test c51de14067cfe867849530d3d1718ffeb28522f28d52937f95dd7bc2116eb42e
|
||||
F ext/rbu/rbufault2.test 8cc8f6298d2d7d20080b2c77e65b607af8b89839f9d87c0972b27e6442edc258
|
||||
@@ -362,13 +368,13 @@ F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f3237
|
||||
F ext/rbu/rbuvacuum2.test ae097d04feb041446a74fac94b24bffeb3fdd60e32b848c5611e507ab702b81b
|
||||
F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de
|
||||
F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205
|
||||
F ext/rbu/sqlite3rbu.c 348bb6251e6ec459de102f8b2dd50789a98643ef7a28e56e4c787ac9659c15ea
|
||||
F ext/rbu/sqlite3rbu.c 71a7f0dea3a846ff7c2499dc34a2528f5ddcbe23e2c54dc3cd1fa4d933377c6d
|
||||
F ext/rbu/sqlite3rbu.h 9d923eb135c5d04aa6afd7c39ca47b0d1d0707c100e02f19fdde6a494e414304
|
||||
F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
|
||||
F ext/recover/dbdata.c 501227169803bfafb34cd8ec7fffda6e64c1a282ac33315d3a096076c5928feb
|
||||
F ext/recover/dbdata.c 31d580785cf14eb3c20ed6fbb421a10a66569858f837928e6b326088c38d4c72
|
||||
F ext/recover/recover1.test 2072993624d5e32fef20ae03b17fc06c02bcb344421fe17bb329b24d2a51e647
|
||||
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
|
||||
F ext/recover/recoverbuild.test a6f05273ff5fe517afd166444597c70cb97033e7f58496433a4428a1ecb5d79f
|
||||
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
|
||||
F ext/recover/recoverclobber.test 3ba6c0c373c5c63d17e82eced64c05c57ccaf26c1abe1ca7141334022a79f32e
|
||||
F ext/recover/recovercorrupt.test 64c081ad1200ae77b447da99eb724785d6bf71715f394543dc7689642e92bf49
|
||||
F ext/recover/recovercorrupt2.test 74bef7dd2d7dd4856f3da21be6e213d27da44827e0f5f0946ca0325b46d163ed
|
||||
@@ -489,9 +495,9 @@ F ext/wasm/api/sqlite3-api-worker1.js 40a5b1813fcbe789f23ae196c833432c8c83e7054d
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 70914ae97784d3028150bbf252e07a423056c42cc345903c81b5fae661ce512f
|
||||
F ext/wasm/api/sqlite3-v-helper.js e5c202a9ecde9ef818536d3f5faf26c03a1a9f5192b1ddea8bdabf30d75ef487
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 26f6240170d415726d9cfe2fa7a0163e153775e1a74fa91c9ba5446502c71097
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 5cb63f847737ded723d0bdf9b3313e8f7deb0bbfd0082dedde540991edde155b
|
||||
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
|
||||
F ext/wasm/api/sqlite3-wasm.c e04e863be7c3a58aa144a463770c1b68ce69f7cfc9e1a5d6397a67877acaf006
|
||||
F ext/wasm/api/sqlite3-wasm.c c42413ca9f3e64c424b2bbfc5decf639670ca38bc8f7afb7760d5379398c9307
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 2710a06a59620c6bf7ce298ab1fb6c9ce825b9f9379728b74c486db6613beecc
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
|
||||
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
|
||||
@@ -535,7 +541,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
||||
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
||||
F ext/wasm/tester1-worker.html 258d08f1ba9cc2d455958751e26be833893cf9ff7853e9436e593e1f778a386b
|
||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
||||
F ext/wasm/tester1.c-pp.js 942e31e5acacdea8f7e5c134c9c23433d56ca95e9f033708556aead1e11a6e6c
|
||||
F ext/wasm/tester1.c-pp.js 587a18db0f794c594eb0fade37c92af3e2370501576bb08dafd8ed7d009b6516
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
|
||||
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||
@@ -557,35 +563,35 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
|
||||
F src/alter.c 3ca2f449c890f8b86ec9e06f0c4fccf0648941c3308a16904cb2852227db83f7
|
||||
F src/analyze.c d0a84c1de4640485c0752123dc89788b8333438cde8e4e8ec1e046a374d27cec
|
||||
F src/alter.c 482c534877fbb543f8295992cde925df55443febac5db5438d5aaba6f78c4940
|
||||
F src/analyze.c 01bfd40026632eaae1d93212b684f539c6674cb573535dc90199674cbf7e0cdc
|
||||
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
|
||||
F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf
|
||||
F src/backup.c a2891172438e385fdbe97c11c9745676bec54f518d4447090af97189fd8e52d7
|
||||
F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d
|
||||
F src/btmutex.c 6ffb0a22c19e2f9110be0964d0731d2ef1c67b5f7fabfbaeb7b9dabc4b7740ca
|
||||
F src/btree.c 47def1b43b10fcffd927ef6e17c9382a39c898af9eb98318460253ddb5e4a07f
|
||||
F src/btree.c af379d801906f21dc18b534fc250a479f56045a450d8d5859ba2f57fd9eefcef
|
||||
F src/btree.h aa354b9bad4120af71e214666b35132712b8f2ec11869cb2315c52c81fad45cc
|
||||
F src/btreeInt.h 06bb2c1a07172d5a1cd27a2a5d617b93b1e976c5873709c31964786f86365a6e
|
||||
F src/btreeInt.h a3268a60cbc91f578001f44ba40aae9c1b8aecbb0d2c095dd7fc54b0872ea4b8
|
||||
F src/build.c 8357d6ca9a8c9afc297c431df28bc2af407b47f3ef2311875276c944b30c4d54
|
||||
F src/callback.c 4cd7225b26a97f7de5fee5ae10464bed5a78f2adefe19534cc2095b3a8ca484a
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 20507cc0b0a6c19cd882fcd0eaeda32ae6a4229fb4b024cfdf3183043d9b703d
|
||||
F src/date.c f21815ca7172ce073db3163ac54c8d9f2841077165c1a6123b4d1c376a0c7ec7
|
||||
F src/dbpage.c d47549716549311f79dc39fe5c8fb19390a6eb2c960f8e37c89a9c4de0c1052e
|
||||
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
|
||||
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
|
||||
F src/delete.c 201fe0763c52783d205c8c13cdd9d55c1bd5cb21c1f036753f99103b43284b90
|
||||
F src/expr.c c938990570effc02e065b176702d627a0237ec796263c142868f8007b0b703c0
|
||||
F src/delete.c a9c6d3f51c0a31e9b831e0a0580a98d702904b42d216fee530940e40dec34873
|
||||
F src/expr.c 6353f4d92d9f67ec3466d8e6978cd31a45e34cb755c4d11e689077f03f7c0a15
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 722f20779f5342a787922deded3628d8c74b5249cab04098cf17ee2f2aaff002
|
||||
F src/fkey.c 03c134cc8bffe54835f742ddea0b72ebfc8f6b32773d175c71b8afeea6cb5c83
|
||||
F src/func.c d187be57a886ddf4e6b7ef584a494361899be3df5eee6d4a747b68ff4aff4122
|
||||
F src/global.c 428d2580a1cdf5dbe1f356d1feab83710ae0cc862ece0fb57bc8259e43838c74
|
||||
F src/hash.c c6af5f96a7a76d000f07c5402c48c318c2566beecdee9e78b9d9f60ce7119565
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h b638809e083b601b618df877b2e89cb87c2a47a01f4def10be4c4ebb54664ac7
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 7940fce7d4aa855606432d82d20694e17c18a03956f5f5776f2404e2df7c18a8
|
||||
F src/json.c 9e3a6acf9e4fa8bb6c84a38538ed9c2f9ad09f106910ef0e9cc68e19c8dc4fc8
|
||||
F src/insert.c a8de1db43335fc4946370a7a7e47d89975ad678ddb15078a150e993ba2fb37d4
|
||||
F src/json.c edae65fe1f66ce8b1e7fa6eb036a3d8cf525dacd91d58f12068e80a81ac34f61
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c be5af440f3192c58681b5d43167dbca3ccbfce394d89faa22378a14264781136
|
||||
F src/main.c 09bc5191f75dc48fc4dfddda143cb864c0c3dbc3297eb9a9c8e01fea58ff847d
|
||||
@@ -609,7 +615,7 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
|
||||
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
|
||||
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
|
||||
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
|
||||
F src/os_unix.c 90c4fa0a88c8b0817c7ce4dbea0ac3aebfd7deb0797945ac34dfd25006ba393a
|
||||
F src/os_unix.c 1b3ddb7814c4bf37f494c04d2ab30c1ced5b2c927267e1930ce7cd388787a96d
|
||||
F src/os_win.c 295fe45f18bd86f2477f4cd79f3377c6f883ceb941b1f46808665c73747f2345
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 39af8ff7c73a991f61f4d1e3a6f8f98b1c8e29144723507822774cac5e6ee0b5
|
||||
@@ -618,24 +624,24 @@ F src/parse.y 424e49ed8fc6c907920db9be5a13a75ed43811e1ea8dd21b0fa9ef97f083dc6b
|
||||
F src/pcache.c 842410539b544e12d5fccfcf29890782f46a58f227a77bc0bd76243799662c0c
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc
|
||||
F src/pragma.c c0c6e0735436e0e9e8d490f82959ddc9475d438e9f808a51953a4d43e30cea51
|
||||
F src/pragma.c 26ed2cfdc5c12aa1c707178635709684960288cacc9cff9d491a38ff10e395f1
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c ce87a08cfddd45a147150db34190b1986f2d4a0e0828858cb6bd908c78fb02e3
|
||||
F src/prepare.c 06ecbb25db151a009be99471757c73272cd61306903dc3eeb7250bdcf54896dd
|
||||
F src/printf.c 7eac1a9896a80697e03e08963e210830532ae2ff610e16c193e95af007ca5623
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c 83812448cf5a645f37d79c43fa92d38d7a9f7790d95f7ac09ac02b4064810bd2
|
||||
F src/shell.c.in d80b53a9ec0a43ac0157fc54d667cb49fb6dd2229558135530feab2fc04b909d
|
||||
F src/sqlite.h.in f01033703156615566bb329144d736a37fc35a278049db91127782a9c799b938
|
||||
F src/select.c 4054886848b2aaf3d92d28bda9fabff3b5c5c1ffe8511b0dbafcea008d58a66b
|
||||
F src/shell.c.in 9d5da77007123401da702e8587558edddd520c925f8f561aa7b8d9387e71e096
|
||||
F src/sqlite.h.in 4fff9c6cc5d4cbba9532a668112efb6dc469c425e1a2196664d7c07d508363ef
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
|
||||
F src/sqliteInt.h ee87a8982f59897ea0594df986bb3ebbe971b16fa0248c9c4940ae18beda7deb
|
||||
F src/sqliteInt.h bf15f7db635d2e64a227bbf86845bc19755dbd932021a6461d6dd15b0da2cfd3
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c 8522a04fb9c84faa1d80354430ae0ee9349727a3a4b32e3cfe39b9be8324cabd
|
||||
F src/test1.c 74d87bbc29954c239fdcd7c0c3dd472c0eb9761c7289b85389f322233932780a
|
||||
F src/test1.c 8eab61fb2813aa212d97ab188e85fc9ca7b89d9ff5ff05d59d9aa0c491a6c721
|
||||
F src/test2.c 827446e259a3b7ab949da1542953edda7b5117982576d3e6f1c24a0dd20a5cef
|
||||
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
|
||||
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
|
||||
@@ -689,36 +695,37 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 1305797eab3542a0896b552c6e7669c972c1468e11e92b370533c1f37a37082b
|
||||
F src/treeview.c fccf3b8c517c1f55cb380c1522febe6921fcb2bd800c16c78cab571d0eb0ccbd
|
||||
F src/trigger.c f34367fad4df451b5dfe63fcc1d384fd16e40077e42092b1c3682dedeef5a7e3
|
||||
F src/update.c 76664e1beae86e8e961983ebe19a4ee9ebd7e26683ead2b288ba08f81fc7ba4e
|
||||
F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
|
||||
F src/update.c 3f4fb5ad7c9b48d7911974d6579192bb3a6c27f46140b6cbb9139cc8a77b8691
|
||||
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 3ff7bc2b48dd425b1448304bb86273b05da1621f136d51dbb9789f8803559a1f
|
||||
F src/util.c 2106b5176a847d5b91a9345b38a098c202b7691a19070e0fa194cbd3ff139d24
|
||||
F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd
|
||||
F src/vdbe.c 2bb4694bff3c1c4f52fd47e66be30278b5251d62d23b768af7c3b3a0dd7ba901
|
||||
F src/vdbe.h 73b904a6b3bb27f308c6cc287a5751ebc7f1f89456be0ed068a12b92844c6e8c
|
||||
F src/vdbe.c a6c52ba65e8ceb574fe0eda62af84e6c50c176ffc5f310c613425f7ab2b1484b
|
||||
F src/vdbe.h 637ae853b7d42ae3951034cc63ab7c8af837861f79504cdb5399552fcd89a884
|
||||
F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb
|
||||
F src/vdbeapi.c 40c47b1528d308a322203de21d2e0d711753257ed9771771b6129214b1d65932
|
||||
F src/vdbeaux.c 0f5201346a83a35a08e833c3a03abe626119c07b7361c28bc6a259b98540f1d6
|
||||
F src/vdbeapi.c 1a95162e26d5eda3b7b46fbe4fcbc33eb7f801529d66fc2e14c52094a5523339
|
||||
F src/vdbeaux.c 128de68cade63c914e97d31c2fa71fd6186927ebfbedabc68019ce99256c3ddf
|
||||
F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd
|
||||
F src/vdbemem.c 656a51f3e99d7123ef852413c0249101718f3f3138e66be37ba2f16dcf7ce43e
|
||||
F src/vdbemem.c 1d9a0f37b0097fbb53f0d7ba081f7181b83cee2c6f46364706ea0c3896bd8ec0
|
||||
F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35
|
||||
F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823
|
||||
F src/vdbevtab.c aae4bd769410eb7e1d02c42613eec961d514459b1c3c1c63cfc84e92a137daac
|
||||
F src/vtab.c 4516e9fecff8d4f353132be0468bc6424b102937c50c52e01fd9a0a9e9e34ca5
|
||||
F src/vtab.c 4a1b231b5938de0282fbb605eb068ca673a1b6a383130f54d1bcbbac951988ad
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
|
||||
F src/wal.c 3f4ac276a60bda76f9f1f6f1c2c38599bacd4987e5efcd3f7fed2647bf97280a
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
|
||||
F src/where.c 2bf0f0e28a7093b8f3fa661c5474993413bfac5cc55939288856952e73d9d140
|
||||
F src/where.c ef9e644d1d76e86f68c941eb05d30a98fc0811eeef2a110906d81fedde81b6bf
|
||||
F src/whereInt.h e25203e5bfee149f5f1225ae0166cfb4f1e65490c998a024249e98bb0647377c
|
||||
F src/wherecode.c 9919e5a22f4b24dd96c49b8981484cbe6bbfcf466ff73ac40a06e1356aa8bf87
|
||||
F src/wherecode.c 85790d7e5365ac41085713331ce52e4343586ad3d37d218ffe00572357baa62b
|
||||
F src/whereexpr.c 1dfda1695e4480c24248157df55bb4d66c732dc8d14ac16b4f076bb15de93d63
|
||||
F src/window.c 76a27cff9ea2ded0c2c3527187029259440fabcc4cc4c07b11d942c78494a614
|
||||
F src/window.c e075ea85bea322e30e361fa6e69eddba74f461e99e2a564dc09973f8a1fb27d9
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
|
||||
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
|
||||
F test/aggnested.test 7269d07ac879fce161cb26c8fabe65cba5715742fac8a1fccac570dcdaf28f00
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
|
||||
@@ -738,7 +745,7 @@ F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74
|
||||
F test/altermalloc2.test 17fb3724c4b004c469c27dc4ef181608aa644555fbd3f3236767584f73747c81
|
||||
F test/altermalloc3.test 8531b3086f0a7889f43971a579a8c81832d5123f4703d8c86b89ba1136c63b9a
|
||||
F test/alterqf.test ff6c6f881485c29ed699b8ef4774864ca1b0c01a6c08f5cdd624a008e4b40fca
|
||||
F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912
|
||||
F test/altertab.test 8a2712f9076da5012a002d0b5cc0a421398a5bf61c25bab41b77c427586a7a27
|
||||
F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0
|
||||
F test/altertab3.test 6c432fbb9963e0bd6549bf1422f6861d744ee5a80cb3298564e81e556481df16
|
||||
F test/altertrig.test fb5951d21a2c954be3b8a8cf8e10b5c0fa20687c53fd67d63cea88d08dd058d5
|
||||
@@ -753,7 +760,7 @@ F test/analyze8.test 29ef237d8a59b39cc31c3310134fefe96a690b195e3deed5ecb65283908
|
||||
F test/analyze9.test 30e1cb99336045a384a11d97900720184333c88174b3b89bc07444ea39e7df19
|
||||
F test/analyzeC.test 1111830ad355d29a294a5dda654dd5f6a8622c6a223a4f7b7b3d091df7a7a42b
|
||||
F test/analyzeD.test 485f621cfd2ef0a8f8ac79672586651bfa495bd899db50461bb4b558400ab3c1
|
||||
F test/analyzeE.test 8770de3834bb9aea1c892f4d155a5bd9578c23c0c3f199dc6f1b5d597b5bf65c
|
||||
F test/analyzeE.test d2ec7921c162cdc33ac8e7eb01f9ebf78100610af7c94c8552bbf551de1fb397
|
||||
F test/analyzeF.test 40b5cc3ad7b10e81020d7ca86f1417647ecfae7477cfd88acc5aa7ae1068f949
|
||||
F test/analyzeG.test 623be33038c49648872746c8dd8b23b5792c08fef173c55e82f1b12fca259852
|
||||
F test/analyzer1.test 459fa02c445ddbf0101a3bad47b34290a35f2e49
|
||||
@@ -871,23 +878,23 @@ F test/conflict2.test 5557909ce683b1073982f5d1b61dfb1d41e369533bfdaf003180c5bc87
|
||||
F test/conflict3.test 81865d9599609aca394fb3b9cd5f561d4729ea5b176bece3644f6ecb540f88ac
|
||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||
F test/corrupt.test d7cb0300e4a297147b6a05e92a1684bc8973635c3bcaa3d66e983c9cbdbf47a3
|
||||
F test/corrupt2.test bb50042cf9a1f1023d73af325d47eb02a6bb11e3c52f8812644b220c5d4bca35
|
||||
F test/corrupt3.test 2520432b1fbf99994841e69804a3c59fb828183f4d09b85a1631bc7adca17e31
|
||||
F test/corrupt2.test 6e0c1e1c2ff4bedde4bc73f16250d74ae5b3d9ece086640ce88b9a94620ba993
|
||||
F test/corrupt3.test 6a982535d52c8165654cbc79a043cfd0bf02495a5efbf4754295e056fc548539
|
||||
F test/corrupt4.test b5ae41607e8d17d9c1f3e94fdb572ce061ed3beeebdb46fb3a348181b8c8a097
|
||||
F test/corrupt5.test 387be3250795e2a86e6234745558b80efb248a357d0cd8e53bce75c7463f545d
|
||||
F test/corrupt6.test fc6a891716139665dae0073b6945e3670bf92568
|
||||
F test/corrupt7.test b036f94bda4b0b23a2919bf717046ce9ecca4543
|
||||
F test/corrupt7.test ffa86896fe63a3d00b0a131e1e64f402e4da9f7e5d89609d6501c851e511d73a
|
||||
F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
|
||||
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
|
||||
F test/corruptA.test 112f4b2ae0b95ebf3ea63718642fb969a93acea557ace3a307234d19c245989b
|
||||
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
|
||||
F test/corruptC.test 74d4498fd25759618b393f1e9cde111de828b88c1848ab320f6c179fd52b5a60
|
||||
F test/corruptD.test 33a37ce3ed56a20093ceee778cd2d7109c7085a59f3213d2baede11d952e8e50
|
||||
F test/corruptC.test 9cf32275dae3ca33f645afe5d1d3f5ba5ac2af2b0833dfb5282f9dccb6fb81bb
|
||||
F test/corruptD.test a828c788535946a372a56a750b242cd96287cd823657abe5a73c5e51b91bdd28
|
||||
F test/corruptE.test 4143791f2dfb443aec5b7fabfa5821e6063eccc3b49b06f212c2f014715fd476
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b
|
||||
F test/corruptI.test 9d8cbf6214e492abe9e822e759b9751ae336cec0a6fe3ff3b37bfbd8ff9c22ca
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
|
||||
F test/corruptL.test b42978028afc5eefc8b51d8d7cd6a9344ba7362d7ed4511ee2070f56e06d5a1c
|
||||
@@ -895,7 +902,7 @@ F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c
|
||||
F test/corruptN.test 7c099d153a554001b4fb829c799b01f2ea6276cbc32479131e0db0da4efd9cc4
|
||||
F test/cost.test b11cdbf9f11ffe8ef99c9881bf390e61fe92baf2182bad1dbe6de59a7295c576
|
||||
F test/count.test cd4bd531066e8d77ef8fe1e3fc8253d042072e117ccab214b290cf83f1602249
|
||||
F test/countofview.test f9025dba8a9bb673a1f3ce25405900f630f81592c226546242df1ef1e62d0192
|
||||
F test/countofview.test 4088e461a10ee33e69803c177a69aa1d7bba81a9ffc2df66d76465a22ca7fdfc
|
||||
F test/coveridxscan.test f35c7208dedc4f98e471c569df64c0f95a49f6e072d8dc7c8f99bdee2697de1b
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||
@@ -911,7 +918,7 @@ F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f5414069
|
||||
F test/cse.test 00b3aea44b16828833c94fbe92475fd6977583fcb064ae0bc590986812b38d0c
|
||||
F test/csv01.test 2ab5514005fd308995c8910bc313e47f0368b94213b9d6c27f9a2da78796a091
|
||||
F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c4773
|
||||
F test/cursorhint.test 12e7d03262be8705798fe7b5719956bcda14989f10296a5e8fdc13466b7b75fc
|
||||
F test/cursorhint.test a44811a341281ebb73b939cb11bdcc2f374dc70e7e0f6cd7bfcb02e6fee67831
|
||||
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
|
||||
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
|
||||
F test/date.test 118e04db8c8b4efeb885542b4918c7b869a34c460a6bebbfe927dfd75706b80d
|
||||
@@ -990,7 +997,7 @@ F test/filter1.test 590f8ba9a0cd0823b80d89ac75c5ce72276189cef9225d2436adaf1ee87f
|
||||
F test/filter2.tcl 44e525497ce07382915f01bd29ffd0fa49dab3adb87253b5e5103ba8f93393e8
|
||||
F test/filter2.test 485cf95d1f6d6ceee5632201ca52a71868599836f430cdee42e5f7f14666e30a
|
||||
F test/filterfault.test c08fb491d698e8df6c122c98f7db1c65ffcfcad2c1ab0e07fa8a5be1b34eaa8b
|
||||
F test/fkey1.test 55663090ab6735319a52647057b9f19f8ec8c6c7d7da25170b71a75e3e5bdeb7
|
||||
F test/fkey1.test e563bcb4cb108ce3f40363cda4f84009dc89a39e2973076e5057ba99fca35378
|
||||
F test/fkey2.test 1063d65e5923c054cfb8f0555a92a3ae0fa8c067275a33ee1715bd856cdb304c
|
||||
F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
@@ -1167,7 +1174,7 @@ F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
|
||||
F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1
|
||||
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
F test/in.test 7399a6562fb09de7f786901f0b24b7bbe7c0b541f29ead9eb13f091edea37da4
|
||||
F test/in.test d1cad4ededd425568b2e39fb0c31fa9a3772311dd595801ff13ba3912b69bba6
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a
|
||||
@@ -1194,8 +1201,8 @@ F test/index7.test b238344318e0b4e42126717f6554f0e7dfd0b39cecad4b736039b43e1e3b6
|
||||
F test/index8.test caa097735c91dbc23d8a402f5e63a2a03c83840ba3928733ed7f9a03f8a912a3
|
||||
F test/index9.test 2ac891806a4136ef3e91280477e23114e67575207dc331e6797fa0ed9379f997
|
||||
F test/indexedby.test f21eca4f7a6ffe14c8500a7ad6cd53166666c99e5ccd311842a28bc94a195fe0
|
||||
F test/indexexpr1.test b2a15637dcbae7fd8d7e2fc51f74ac4feaf5510130ee2089a5ec5bd1ef7270e1
|
||||
F test/indexexpr2.test 8a4cf83e12b041334c5ef36b9a3932451808378352c24d65049b31f3737a82b9
|
||||
F test/indexexpr1.test 62558b1cfd7ccbe7bc015849cc6d1a13ef124e80cbd5b3a98dc66c3c9cce0cf4
|
||||
F test/indexexpr2.test 1c382e81ef996d8ae8b834a74f2a9013dddf59214c32201d7c8a656d739f999a
|
||||
F test/indexfault.test 98d78a8ff1f5335628b62f886a1cb7c7dac1ef6d48fa39c51ec871c87dce9811
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 4e3f0de67aac3c5be1f4aaedbcea11638f1b5cdc9a3115be14d19aa9db7623c6
|
||||
@@ -1379,7 +1386,7 @@ F test/pendingrace.test cbdf0f74bc939fb43cebad64dda7a0b5a3941a10b7e9cc2b596ff3e4
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 8bd6b6db541e2a7f9bb894be99ef5c00526b23762c4a00c574e1cba697495125
|
||||
F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f
|
||||
F test/pragma.test aeefa47ba5ebbf4ffc6addc223568d2a95dc7ec3ba3e3c4a26b199e805f94514
|
||||
F test/pragma.test 57a36226218c03cfb381019fe43234b2cefbd8a1f12825514f906a17ccf7991e
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 92a46bbea12322dd94a404f49edcfbfc913a2c98115f0d030a7459bb4712ef31
|
||||
F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8b1f8
|
||||
@@ -1409,7 +1416,7 @@ F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2
|
||||
F test/releasetest_data.tcl b550dd1b122a9c969df794d05ea272df535f10ff1a245062e7ba080822378016
|
||||
F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/returning1.test c78efa2829d5f44165fcc7959961b298ae005d7775f09e5542bb2815bbaee692
|
||||
F test/returning1.test db532cde29d6aebbc48c6ddc3149b30476f8e69ca7a2c4b53986c7635e6fd8ec
|
||||
F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb0767937d5de5692a4
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
|
||||
@@ -1440,7 +1447,7 @@ F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
|
||||
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
|
||||
F test/scanstatus.test b249328caf4d317e71058006872b8012598a5fa045b30bf24a81eeff650ab49e
|
||||
F test/scanstatus2.test b77de449be6ffd7a913a06dd84276dc6eb3517d479126e00ac51cd409c0a0af5
|
||||
F test/scanstatus2.test 9a00becb1d60d168944f8e2f3585d44d46123aa95c5c7c25563309e1f15f924d
|
||||
F test/schema.test 5dd11c96ba64744de955315d2e4f8992e447533690153b93377dffb2a5ef5431
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 8ed4ae66e082cdd8b1b1f22d8549e1e7a0db4527a8e6ee8b6193053ee1e5c9ce
|
||||
@@ -1450,7 +1457,7 @@ F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce
|
||||
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
|
||||
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
|
||||
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
|
||||
F test/seekscan1.test d79c97de5bb1dd1fd466687f3014add514fddf8248c57baf51d749c7dfd573d8
|
||||
F test/seekscan1.test 31af16e3bb3203d153aea320939c5da97ec44705c2710d153c06a01397d45b09
|
||||
F test/select1.test 692e84cfa29c405854c69e8a4027183d64c22952866a123fabbce741a379e889
|
||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||
F test/select3.test 8d04b66df7475275a65f7e4a786d6a724c30bd9929f8ae5bd59c8d3d6e75e6cd
|
||||
@@ -1524,7 +1531,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
|
||||
F test/speedtest1.c 4a883fe277c289161f84f8c805a38f78bfbd9515eb417071f9bce817c2ca8756
|
||||
F test/speedtest1.c 9703465daf778dd90bad7adadc1d2ee205ec90a79437cababab0a4111190f0c8
|
||||
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
|
||||
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
|
||||
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
|
||||
@@ -1618,7 +1625,7 @@ F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
|
||||
F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed
|
||||
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
|
||||
F test/tkt-94c04eaadb.test f738c57c7f68ab8be1c054415af7774617cb6223
|
||||
F test/tkt-99378177930f87bd.test 28530bf9903dcd7743185ce78b1c02b1f9ba09fe4fa77a70ecbd0af83fe3353c
|
||||
F test/tkt-99378177930f87bd.test 9d6cff39b50d062c813ae1cb0ebbd1b7acf81ecc23ae5d5215e5bb05667dc137
|
||||
F test/tkt-9a8b09f8e6.test b2ef151d0984b2ebf237760dbeaa50724e5a0667
|
||||
F test/tkt-9d68c883.test 16f7cb96781ba579bc2e19bb14b4ad609d9774b6
|
||||
F test/tkt-9f2eb3abac.test cb6123ac695a08b4454c3792fbe85108f67fabf8
|
||||
@@ -1806,7 +1813,7 @@ F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test d4c4281e1679245829db35597817282f60dc513fc39cc5439078f009bd118487
|
||||
F test/view2.test db32c8138b5b556f610b35dfddd38c5a58a292f07fda5281eedb0851b2672679
|
||||
F test/view3.test ad8a8290ee2b55ff6ce66c9ef1ce3f1e47926273a3814e1c425293e128a95456
|
||||
F test/vt02.c 86253b57d6bc2170dfca33f45fd099b66d0bf874e95ecd7786dcbb134f179469
|
||||
F test/vt02.c f4a357c8180d71120ca2b466a8df48d9c40fc50873694840327d9647450485f3
|
||||
F test/vtab1.test 09a72330d0f31eda2ffaa828b06a6b917fb86250ee72de0301570af725774c07
|
||||
F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
@@ -1901,7 +1908,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
|
||||
F test/win32lock.test e0924eb8daac02bf80e9da88930747bd44dd9b230b7759fed927b1655b467c9c
|
||||
F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976
|
||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||
F test/window1.test 5ad2f3e2aec3f2dc5cf4a66998d42a455b8ebd57ec173c0329f6b8788bcae0aa
|
||||
F test/window1.test 5ba48e9d33231e6ef16f21426bade9ccc52abf65a10587bff90a6c14fe174594
|
||||
F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
|
||||
F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
|
||||
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
|
||||
@@ -1977,7 +1984,7 @@ F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a19
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl 38e3db33210a200aae791635125052a643a27aa0619a0debf19aa9c55e1b2dde x
|
||||
F tool/mkkeywordhash.c 35bfc41adacc4aa6ef6fca7fd0c63e0ec0534b78daf4d0cfdebe398216bbffc3
|
||||
F tool/mkkeywordhash.c 9822bd1f58a70e5f84179df3045bba4791df69180e991bec88662703f2e93761
|
||||
F tool/mkmsvcmin.tcl 6ecab9fe22c2c8de4d82d4c46797bda3d2deac8e763885f5a38d0c44a895ab33
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
F tool/mkopcodeh.tcl 769d9e6a8b462323150dc13a8539d6064664b72974f7894befe2491cc73e05cd
|
||||
@@ -2051,8 +2058,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 3572b40a7dfc4acc35e72e08e79f64688f8737e57ac89e4d10e6b32bd5178c63
|
||||
R c45a71619ca942293d80f31a1a49eea4
|
||||
U drh
|
||||
Z aa39fec11cd82de6900c756e7906d67c
|
||||
P 7b1f635268bd5b093b22f832c3ac9e5d642d1aac5ebc620619be5a24930feb83
|
||||
R 94128278c59c8b6776a5748252e83b85
|
||||
U larrybr
|
||||
Z e64ea4c126276298324ed24c1a272560
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
4d05a009dfb63bcb4173da4d09ccc00c308ce4dd2534a32aeb23c5d8d6a1fd4b
|
||||
19c062f1cd814a33bf9c10928217464cddaea7c3291ff44e605901a86b82a06d
|
||||
+23
@@ -1279,6 +1279,19 @@ static int renameEditSql(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set all pEList->a[].fg.eEName fields in the expression-list to val.
|
||||
*/
|
||||
static void renameSetENames(ExprList *pEList, int val){
|
||||
if( pEList ){
|
||||
int i;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
|
||||
pEList->a[i].fg.eEName = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
|
||||
** it was read from the schema of database zDb. Return SQLITE_OK if
|
||||
@@ -1326,7 +1339,17 @@ static int renameResolveTrigger(Parse *pParse){
|
||||
pSrc = 0;
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
/* pStep->pExprList contains an expression-list used for an UPDATE
|
||||
** statement. So the a[].zEName values are the RHS of the
|
||||
** "<col> = <expr>" clauses of the UPDATE statement. So, before
|
||||
** running SelectPrep(), change all the eEName values in
|
||||
** pStep->pExprList to ENAME_SPAN (from their current value of
|
||||
** ENAME_NAME). This is to prevent any ids in ON() clauses that are
|
||||
** part of pSrc from being incorrectly resolved against the
|
||||
** a[].zEName values as if they were column aliases. */
|
||||
renameSetENames(pStep->pExprList, ENAME_SPAN);
|
||||
sqlite3SelectPrep(pParse, pSel, 0);
|
||||
renameSetENames(pStep->pExprList, ENAME_NAME);
|
||||
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
|
||||
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
|
||||
assert( pSrc==pSel->pSrc );
|
||||
|
||||
+15
-14
@@ -1001,7 +1001,8 @@ static void analyzeOneTable(
|
||||
Table *pStat1 = 0;
|
||||
#endif
|
||||
|
||||
pParse->nMem = MAX(pParse->nMem, iMem);
|
||||
sqlite3TouchRegister(pParse, iMem);
|
||||
assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 || NEVER(pTab==0) ){
|
||||
return;
|
||||
@@ -1107,7 +1108,7 @@ static void analyzeOneTable(
|
||||
** the regPrev array and a trailing rowid (the rowid slot is required
|
||||
** when building a record to insert into the sample column of
|
||||
** the sqlite_stat4 table. */
|
||||
pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
|
||||
sqlite3TouchRegister(pParse, regPrev+nColTest);
|
||||
|
||||
/* Open a read-only cursor on the index being analyzed. */
|
||||
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
|
||||
@@ -1295,24 +1296,19 @@ static void analyzeOneTable(
|
||||
}
|
||||
|
||||
/* Allocate space to compute results for the largest index */
|
||||
pParse->nMem = MAX(pParse->nMem, regCol+mxCol);
|
||||
sqlite3TouchRegister(pParse, regCol+mxCol);
|
||||
doOnce = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* Verify that setting pParse->nTempReg to zero below really
|
||||
** is needed in some cases, in order to excise all temporary
|
||||
** registers from the middle of the STAT4 buffer.
|
||||
/* Verify that the call to sqlite3ClearTempRegCache() below
|
||||
** really is needed.
|
||||
** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
|
||||
*/
|
||||
if( pParse->nTempReg>0 ){
|
||||
int kk;
|
||||
for(kk=0; kk<pParse->nTempReg; kk++){
|
||||
int regT = pParse->aTempReg[kk];
|
||||
testcase( regT>=regCol && regT<regCol+mxCol );
|
||||
}
|
||||
}
|
||||
testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
|
||||
#endif
|
||||
pParse->nTempReg = 0; /* tag-20230325-1 */
|
||||
sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
|
||||
assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
|
||||
}
|
||||
assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
|
||||
|
||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
||||
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
|
||||
@@ -1393,6 +1389,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
Table *pTab = (Table*)sqliteHashData(k);
|
||||
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
iMem = sqlite3FirstAvailableRegister(pParse, iMem);
|
||||
#else
|
||||
assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) );
|
||||
#endif
|
||||
}
|
||||
loadAnalysis(pParse, iDb);
|
||||
}
|
||||
|
||||
+201
-84
@@ -136,8 +136,8 @@ sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
|
||||
int corruptPageError(int lineno, MemPage *p){
|
||||
char *zMsg;
|
||||
sqlite3BeginBenignMalloc();
|
||||
zMsg = sqlite3_mprintf("database corruption page %d of %s",
|
||||
(int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
|
||||
zMsg = sqlite3_mprintf("database corruption page %u of %s",
|
||||
p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
|
||||
);
|
||||
sqlite3EndBenignMalloc();
|
||||
if( zMsg ){
|
||||
@@ -946,8 +946,25 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){
|
||||
*/
|
||||
void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
|
||||
/* Used only by system that substitute their own storage engine */
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
|
||||
va_list ap;
|
||||
Expr *pExpr;
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = sqlite3CursorRangeHintExprCheck;
|
||||
va_start(ap, eHintType);
|
||||
pExpr = va_arg(ap, Expr*);
|
||||
w.u.aMem = va_arg(ap, Mem*);
|
||||
va_end(ap);
|
||||
assert( pExpr!=0 );
|
||||
assert( w.u.aMem!=0 );
|
||||
sqlite3WalkExpr(&w, pExpr);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
|
||||
|
||||
|
||||
/*
|
||||
** Provide flag hints to the cursor.
|
||||
@@ -1032,7 +1049,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
|
||||
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
|
||||
|
||||
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
|
||||
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
|
||||
TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
|
||||
*pRC= rc = sqlite3PagerWrite(pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
pPtrmap[offset] = eType;
|
||||
@@ -1746,7 +1763,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
** allocation is being made in order to insert a new cell, so we will
|
||||
** also end up needing a new cell pointer.
|
||||
*/
|
||||
static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
|
||||
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
|
||||
int top; /* First byte of cell content area */
|
||||
@@ -1772,13 +1789,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
** integer, so a value of 0 is used in its place. */
|
||||
pTmp = &data[hdr+5];
|
||||
top = get2byte(pTmp);
|
||||
assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
|
||||
if( gap>top ){
|
||||
if( top==0 && pPage->pBt->usableSize==65536 ){
|
||||
top = 65536;
|
||||
}else{
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}else if( top>(int)pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
|
||||
/* If there is enough space between gap and top for one more cell pointer,
|
||||
@@ -1861,7 +1879,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( iSize>=4 ); /* Minimum cell size is 4 */
|
||||
assert( iStart<=pPage->pBt->usableSize-4 );
|
||||
assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
|
||||
|
||||
/* The list of freeblocks must be in ascending order. Find the
|
||||
** spot on the list where iStart should be inserted.
|
||||
@@ -1918,6 +1936,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
}
|
||||
pTmp = &data[hdr+5];
|
||||
x = get2byte(pTmp);
|
||||
if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
|
||||
/* Overwrite deleted information with zeros when the secure_delete
|
||||
** option is enabled */
|
||||
memset(&data[iStart], 0, iSize);
|
||||
}
|
||||
if( iStart<=x ){
|
||||
/* The new freeblock is at the beginning of the cell content area,
|
||||
** so just extend the cell content area rather than create another
|
||||
@@ -1929,14 +1952,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
}else{
|
||||
/* Insert the new freeblock into the freelist */
|
||||
put2byte(&data[iPtr], iStart);
|
||||
put2byte(&data[iStart], iFreeBlk);
|
||||
put2byte(&data[iStart+2], iSize);
|
||||
}
|
||||
if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
|
||||
/* Overwrite deleted information with zeros when the secure_delete
|
||||
** option is enabled */
|
||||
memset(&data[iStart], 0, iSize);
|
||||
}
|
||||
put2byte(&data[iStart], iFreeBlk);
|
||||
put2byte(&data[iStart+2], iSize);
|
||||
pPage->nFree += iOrigSize;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -3846,7 +3864,7 @@ static int relocatePage(
|
||||
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
|
||||
|
||||
/* Move page iDbPage from its current location to page number iFreePage */
|
||||
TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
|
||||
TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
|
||||
iDbPage, iFreePage, iPtrPage, eType));
|
||||
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -6396,7 +6414,7 @@ static int allocateBtreePage(
|
||||
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
|
||||
*ppPage = pTrunk;
|
||||
pTrunk = 0;
|
||||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||
TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
|
||||
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
|
||||
/* Value of k is out of range. Database corruption */
|
||||
rc = SQLITE_CORRUPT_PGNO(iTrunk);
|
||||
@@ -6462,7 +6480,7 @@ static int allocateBtreePage(
|
||||
}
|
||||
}
|
||||
pTrunk = 0;
|
||||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||
TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
|
||||
#endif
|
||||
}else if( k>0 ){
|
||||
/* Extract a leaf from the trunk */
|
||||
@@ -6507,8 +6525,8 @@ static int allocateBtreePage(
|
||||
){
|
||||
int noContent;
|
||||
*pPgno = iPage;
|
||||
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
||||
": %d more free pages\n",
|
||||
TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
|
||||
": %u more free pages\n",
|
||||
*pPgno, closest+1, k, pTrunk->pgno, n-1));
|
||||
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
||||
if( rc ) goto end_allocate_page;
|
||||
@@ -6564,7 +6582,7 @@ static int allocateBtreePage(
|
||||
** becomes a new pointer-map page, the second is used by the caller.
|
||||
*/
|
||||
MemPage *pPg = 0;
|
||||
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
|
||||
TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
|
||||
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -6587,7 +6605,7 @@ static int allocateBtreePage(
|
||||
releasePage(*ppPage);
|
||||
*ppPage = 0;
|
||||
}
|
||||
TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
|
||||
TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
|
||||
}
|
||||
|
||||
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
@@ -6715,7 +6733,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
}
|
||||
rc = btreeSetHasContent(pBt, iPage);
|
||||
}
|
||||
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
|
||||
TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
|
||||
goto freepage_out;
|
||||
}
|
||||
}
|
||||
@@ -6736,7 +6754,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
put4byte(pPage->aData, iTrunk);
|
||||
put4byte(&pPage->aData[4], 0);
|
||||
put4byte(&pPage1->aData[32], iPage);
|
||||
TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
|
||||
TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
|
||||
|
||||
freepage_out:
|
||||
if( pPage ){
|
||||
@@ -7095,6 +7113,14 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
** in pTemp or the original pCell) and also record its index.
|
||||
** Allocating a new entry in pPage->aCell[] implies that
|
||||
** pPage->nOverflow is incremented.
|
||||
**
|
||||
** The insertCellFast() routine below works exactly the same as
|
||||
** insertCell() except that it lacks the pTemp and iChild parameters
|
||||
** which are assumed zero. Other than that, the two routines are the
|
||||
** same.
|
||||
**
|
||||
** Fixes or enhancements to this routine should be reflected in
|
||||
** insertCellFast()!
|
||||
*/
|
||||
static int insertCell(
|
||||
MemPage *pPage, /* Page into which we are copying */
|
||||
@@ -7117,14 +7143,103 @@ static int insertCell(
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
|
||||
assert( pPage->nFree>=0 );
|
||||
assert( iChild>0 );
|
||||
if( pPage->nOverflow || sz+2>pPage->nFree ){
|
||||
if( pTemp ){
|
||||
memcpy(pTemp, pCell, sz);
|
||||
pCell = pTemp;
|
||||
}
|
||||
if( iChild ){
|
||||
put4byte(pCell, iChild);
|
||||
put4byte(pCell, iChild);
|
||||
j = pPage->nOverflow++;
|
||||
/* Comparison against ArraySize-1 since we hold back one extra slot
|
||||
** as a contingency. In other words, never need more than 3 overflow
|
||||
** slots but 4 are allocated, just to be safe. */
|
||||
assert( j < ArraySize(pPage->apOvfl)-1 );
|
||||
pPage->apOvfl[j] = pCell;
|
||||
pPage->aiOvfl[j] = (u16)i;
|
||||
|
||||
/* When multiple overflows occur, they are always sequential and in
|
||||
** sorted order. This invariants arise because multiple overflows can
|
||||
** only occur when inserting divider cells into the parent page during
|
||||
** balancing, and the dividers are adjacent and sorted.
|
||||
*/
|
||||
assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
|
||||
assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
|
||||
}else{
|
||||
int rc = sqlite3PagerWrite(pPage->pDbPage);
|
||||
if( NEVER(rc!=SQLITE_OK) ){
|
||||
return rc;
|
||||
}
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
data = pPage->aData;
|
||||
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
|
||||
rc = allocateSpace(pPage, sz, &idx);
|
||||
if( rc ){ return rc; }
|
||||
/* The allocateSpace() routine guarantees the following properties
|
||||
** if it returns successfully */
|
||||
assert( idx >= 0 );
|
||||
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
|
||||
assert( idx+sz <= (int)pPage->pBt->usableSize );
|
||||
pPage->nFree -= (u16)(2 + sz);
|
||||
/* In a corrupt database where an entry in the cell index section of
|
||||
** a btree page has a value of 3 or less, the pCell value might point
|
||||
** as many as 4 bytes in front of the start of the aData buffer for
|
||||
** the source page. Make sure this does not cause problems by not
|
||||
** reading the first 4 bytes */
|
||||
memcpy(&data[idx+4], pCell+4, sz-4);
|
||||
put4byte(&data[idx], iChild);
|
||||
pIns = pPage->aCellIdx + i*2;
|
||||
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
|
||||
put2byte(pIns, idx);
|
||||
pPage->nCell++;
|
||||
/* increment the cell count */
|
||||
if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
|
||||
assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pPage->pBt->autoVacuum ){
|
||||
int rc2 = SQLITE_OK;
|
||||
/* The cell may contain a pointer to an overflow page. If so, write
|
||||
** the entry for the overflow page into the pointer map.
|
||||
*/
|
||||
ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
|
||||
if( rc2 ) return rc2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This variant of insertCell() assumes that the pTemp and iChild
|
||||
** parameters are both zero. Use this variant in sqlite3BtreeInsert()
|
||||
** for performance improvement, and also so that this variant is only
|
||||
** called from that one place, and is thus inlined, and thus runs must
|
||||
** faster.
|
||||
**
|
||||
** Fixes or enhancements to this routine should be reflected into
|
||||
** the insertCell() routine.
|
||||
*/
|
||||
static int insertCellFast(
|
||||
MemPage *pPage, /* Page into which we are copying */
|
||||
int i, /* New cell becomes the i-th cell of the page */
|
||||
u8 *pCell, /* Content of the new cell */
|
||||
int sz /* Bytes of content in pCell */
|
||||
){
|
||||
int idx = 0; /* Where to write new cell content in data[] */
|
||||
int j; /* Loop counter */
|
||||
u8 *data; /* The content of the whole page */
|
||||
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
|
||||
|
||||
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
|
||||
assert( MX_CELL(pPage->pBt)<=10921 );
|
||||
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
|
||||
assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
|
||||
assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
|
||||
assert( pPage->nFree>=0 );
|
||||
assert( pPage->nOverflow==0 );
|
||||
if( sz+2>pPage->nFree ){
|
||||
j = pPage->nOverflow++;
|
||||
/* Comparison against ArraySize-1 since we hold back one extra slot
|
||||
** as a contingency. In other words, never need more than 3 overflow
|
||||
@@ -7156,17 +7271,7 @@ static int insertCell(
|
||||
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
|
||||
assert( idx+sz <= (int)pPage->pBt->usableSize );
|
||||
pPage->nFree -= (u16)(2 + sz);
|
||||
if( iChild ){
|
||||
/* In a corrupt database where an entry in the cell index section of
|
||||
** a btree page has a value of 3 or less, the pCell value might point
|
||||
** as many as 4 bytes in front of the start of the aData buffer for
|
||||
** the source page. Make sure this does not cause problems by not
|
||||
** reading the first 4 bytes */
|
||||
memcpy(&data[idx+4], pCell+4, sz-4);
|
||||
put4byte(&data[idx], iChild);
|
||||
}else{
|
||||
memcpy(&data[idx], pCell, sz);
|
||||
}
|
||||
memcpy(&data[idx], pCell, sz);
|
||||
pIns = pPage->aCellIdx + i*2;
|
||||
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
|
||||
put2byte(pIns, idx);
|
||||
@@ -7351,7 +7456,7 @@ static int rebuildPage(
|
||||
|
||||
assert( i<iEnd );
|
||||
j = get2byte(&aData[hdr+5]);
|
||||
if( j>(u32)usableSize ){ j = 0; }
|
||||
if( NEVER(j>(u32)usableSize) ){ j = 0; }
|
||||
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
||||
|
||||
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
@@ -7495,42 +7600,50 @@ static int pageFreeArray(
|
||||
u8 * const pEnd = &aData[pPg->pBt->usableSize];
|
||||
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
|
||||
int nRet = 0;
|
||||
int i;
|
||||
int i, j;
|
||||
int iEnd = iFirst + nCell;
|
||||
u8 *pFree = 0; /* \__ Parameters for pending call to */
|
||||
int szFree = 0; /* / freeSpace() */
|
||||
int nFree = 0;
|
||||
int aOfst[10];
|
||||
int aAfter[10];
|
||||
|
||||
for(i=iFirst; i<iEnd; i++){
|
||||
u8 *pCell = pCArray->apCell[i];
|
||||
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
|
||||
int sz;
|
||||
int iAfter;
|
||||
int iOfst;
|
||||
/* No need to use cachedCellSize() here. The sizes of all cells that
|
||||
** are to be freed have already been computing while deciding which
|
||||
** cells need freeing */
|
||||
sz = pCArray->szCell[i]; assert( sz>0 );
|
||||
if( pFree!=(pCell + sz) ){
|
||||
if( pFree ){
|
||||
assert( pFree>aData && (pFree - aData)<65536 );
|
||||
freeSpace(pPg, (u16)(pFree - aData), szFree);
|
||||
iOfst = (u16)(pCell - aData);
|
||||
iAfter = iOfst+sz;
|
||||
for(j=0; j<nFree; j++){
|
||||
if( aOfst[j]==iAfter ){
|
||||
aOfst[j] = iOfst;
|
||||
break;
|
||||
}else if( aAfter[j]==iOfst ){
|
||||
aAfter[j] = iAfter;
|
||||
break;
|
||||
}
|
||||
pFree = pCell;
|
||||
szFree = sz;
|
||||
if( pFree+sz>pEnd ){
|
||||
return 0;
|
||||
}
|
||||
if( j>=nFree ){
|
||||
if( nFree>=sizeof(aOfst)/sizeof(aOfst[0]) ){
|
||||
for(j=0; j<nFree; j++){
|
||||
freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
|
||||
}
|
||||
nFree = 0;
|
||||
}
|
||||
}else{
|
||||
/* The current cell is adjacent to and before the pFree cell.
|
||||
** Combine the two regions into one to reduce the number of calls
|
||||
** to freeSpace(). */
|
||||
pFree = pCell;
|
||||
szFree += sz;
|
||||
aOfst[nFree] = iOfst;
|
||||
aAfter[nFree] = iAfter;
|
||||
if( &aData[iAfter]>pEnd ) return 0;
|
||||
nFree++;
|
||||
}
|
||||
nRet++;
|
||||
}
|
||||
}
|
||||
if( pFree ){
|
||||
assert( pFree>aData && (pFree - aData)<65536 );
|
||||
freeSpace(pPg, (u16)(pFree - aData), szFree);
|
||||
for(j=0; j<nFree; j++){
|
||||
freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
@@ -7585,7 +7698,7 @@ static int editPage(
|
||||
|
||||
pData = &aData[get2byteNotZero(&aData[hdr+5])];
|
||||
if( pData<pBegin ) goto editpage_fail;
|
||||
if( pData>pPg->aDataEnd ) goto editpage_fail;
|
||||
if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
|
||||
|
||||
/* Add cells to the start of the page */
|
||||
if( iNew<iOld ){
|
||||
@@ -8322,7 +8435,7 @@ static int balance_nonroot(
|
||||
** that page.
|
||||
*/
|
||||
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
|
||||
TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
|
||||
TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
|
||||
apOld[0]->pgno, apOld[0]->nCell,
|
||||
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
|
||||
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
|
||||
@@ -8406,8 +8519,8 @@ static int balance_nonroot(
|
||||
}
|
||||
}
|
||||
|
||||
TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
|
||||
"%d(%d nc=%d) %d(%d nc=%d)\n",
|
||||
TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
|
||||
"%u(%u nc=%u) %u(%u nc=%u)\n",
|
||||
apNew[0]->pgno, szNew[0], cntNew[0],
|
||||
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
|
||||
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
|
||||
@@ -8652,7 +8765,7 @@ static int balance_nonroot(
|
||||
}
|
||||
|
||||
assert( pParent->isInit );
|
||||
TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
|
||||
TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
|
||||
nOld, nNew, b.nCell));
|
||||
|
||||
/* Free any old pages that were not reused as new pages.
|
||||
@@ -8737,7 +8850,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
||||
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
|
||||
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
|
||||
|
||||
TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
|
||||
TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
|
||||
|
||||
/* Copy the overflow cells from pRoot to pChild */
|
||||
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
|
||||
@@ -9235,7 +9348,7 @@ int sqlite3BtreeInsert(
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
||||
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
|
||||
TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
|
||||
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
|
||||
loc==0 ? "overwrite" : "new entry"));
|
||||
assert( pPage->isInit || CORRUPT_DB );
|
||||
@@ -9311,7 +9424,7 @@ int sqlite3BtreeInsert(
|
||||
}else{
|
||||
assert( pPage->leaf );
|
||||
}
|
||||
rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
|
||||
rc = insertCellFast(pPage, idx, newCell, szNew);
|
||||
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
|
||||
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
|
||||
|
||||
@@ -9535,6 +9648,9 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
||||
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
if( pCell<&pPage->aCellIdx[pPage->nCell] ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
|
||||
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
|
||||
** be preserved following this delete operation. If the current delete
|
||||
@@ -10283,7 +10399,8 @@ static void checkAppendMsg(
|
||||
sqlite3_str_append(&pCheck->errMsg, "\n", 1);
|
||||
}
|
||||
if( pCheck->zPfx ){
|
||||
sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
|
||||
sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
|
||||
pCheck->v0, pCheck->v1, pCheck->v2);
|
||||
}
|
||||
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
|
||||
va_end(ap);
|
||||
@@ -10323,11 +10440,11 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
|
||||
*/
|
||||
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
|
||||
if( iPage>pCheck->nPage || iPage==0 ){
|
||||
checkAppendMsg(pCheck, "invalid page number %d", iPage);
|
||||
checkAppendMsg(pCheck, "invalid page number %u", iPage);
|
||||
return 1;
|
||||
}
|
||||
if( getPageReferenced(pCheck, iPage) ){
|
||||
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
|
||||
checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
|
||||
return 1;
|
||||
}
|
||||
setPageReferenced(pCheck, iPage);
|
||||
@@ -10353,13 +10470,13 @@ static void checkPtrmap(
|
||||
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
|
||||
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
|
||||
checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
|
||||
return;
|
||||
}
|
||||
|
||||
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
|
||||
"Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
|
||||
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
|
||||
}
|
||||
}
|
||||
@@ -10384,7 +10501,7 @@ static void checkList(
|
||||
if( checkRef(pCheck, iPage) ) break;
|
||||
N--;
|
||||
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
|
||||
checkAppendMsg(pCheck, "failed to get page %d", iPage);
|
||||
checkAppendMsg(pCheck, "failed to get page %u", iPage);
|
||||
break;
|
||||
}
|
||||
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
|
||||
@@ -10397,7 +10514,7 @@ static void checkList(
|
||||
#endif
|
||||
if( n>pCheck->pBt->usableSize/4-2 ){
|
||||
checkAppendMsg(pCheck,
|
||||
"freelist leaf count too big on page %d", iPage);
|
||||
"freelist leaf count too big on page %u", iPage);
|
||||
N--;
|
||||
}else{
|
||||
for(i=0; i<(int)n; i++){
|
||||
@@ -10429,7 +10546,7 @@ static void checkList(
|
||||
}
|
||||
if( N && nErrAtStart==pCheck->nErr ){
|
||||
checkAppendMsg(pCheck,
|
||||
"%s is %d but should be %d",
|
||||
"%s is %u but should be %u",
|
||||
isFreeList ? "size" : "overflow list length",
|
||||
expected-N, expected);
|
||||
}
|
||||
@@ -10544,8 +10661,8 @@ static int checkTreePage(
|
||||
usableSize = pBt->usableSize;
|
||||
if( iPage==0 ) return 0;
|
||||
if( checkRef(pCheck, iPage) ) return 0;
|
||||
pCheck->zPfx = "Page %u: ";
|
||||
pCheck->v1 = iPage;
|
||||
pCheck->zPfx = "Tree %u page %u: ";
|
||||
pCheck->v0 = pCheck->v1 = iPage;
|
||||
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
|
||||
checkAppendMsg(pCheck,
|
||||
"unable to get the page. error code=%d", rc);
|
||||
@@ -10571,7 +10688,7 @@ static int checkTreePage(
|
||||
hdr = pPage->hdrOffset;
|
||||
|
||||
/* Set up for cell analysis */
|
||||
pCheck->zPfx = "On tree page %u cell %d: ";
|
||||
pCheck->zPfx = "Tree %u page %u cell %u: ";
|
||||
contentOffset = get2byteNotZero(&data[hdr+5]);
|
||||
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
|
||||
@@ -10591,7 +10708,7 @@ static int checkTreePage(
|
||||
pgno = get4byte(&data[hdr+8]);
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
if( pBt->autoVacuum ){
|
||||
pCheck->zPfx = "On page %u at right child: ";
|
||||
pCheck->zPfx = "Tree %u page %u right child: ";
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
|
||||
}
|
||||
#endif
|
||||
@@ -10615,7 +10732,7 @@ static int checkTreePage(
|
||||
pc = get2byteAligned(pCellIdx);
|
||||
pCellIdx -= 2;
|
||||
if( pc<contentOffset || pc>usableSize-4 ){
|
||||
checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
|
||||
checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
|
||||
pc, contentOffset, usableSize-4);
|
||||
doCoverageCheck = 0;
|
||||
continue;
|
||||
@@ -10747,7 +10864,7 @@ static int checkTreePage(
|
||||
*/
|
||||
if( heap[0]==0 && nFrag!=data[hdr+7] ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Fragmentation of %d bytes reported as %d on page %u",
|
||||
"Fragmentation of %u bytes reported as %u on page %u",
|
||||
nFrag, data[hdr+7], iPage);
|
||||
}
|
||||
}
|
||||
@@ -10844,7 +10961,7 @@ int sqlite3BtreeIntegrityCheck(
|
||||
/* Check the integrity of the freelist
|
||||
*/
|
||||
if( bCkFreelist ){
|
||||
sCheck.zPfx = "Main freelist: ";
|
||||
sCheck.zPfx = "Freelist: ";
|
||||
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
|
||||
get4byte(&pBt->pPage1->aData[36]));
|
||||
sCheck.zPfx = 0;
|
||||
@@ -10861,7 +10978,7 @@ int sqlite3BtreeIntegrityCheck(
|
||||
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
||||
if( mx!=mxInHdr ){
|
||||
checkAppendMsg(&sCheck,
|
||||
"max rootpage (%d) disagrees with header (%d)",
|
||||
"max rootpage (%u) disagrees with header (%u)",
|
||||
mx, mxInHdr
|
||||
);
|
||||
}
|
||||
@@ -10892,7 +11009,7 @@ int sqlite3BtreeIntegrityCheck(
|
||||
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||
if( getPageReferenced(&sCheck, i)==0 ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
checkAppendMsg(&sCheck, "Page %u: never used", i);
|
||||
}
|
||||
#else
|
||||
/* If the database supports auto-vacuum, make sure no tables contain
|
||||
@@ -10900,11 +11017,11 @@ int sqlite3BtreeIntegrityCheck(
|
||||
*/
|
||||
if( getPageReferenced(&sCheck, i)==0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Page %d is never used", i);
|
||||
checkAppendMsg(&sCheck, "Page %u: never used", i);
|
||||
}
|
||||
if( getPageReferenced(&sCheck, i)!=0 &&
|
||||
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
||||
checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
|
||||
checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
+3
-2
@@ -701,8 +701,9 @@ struct IntegrityCk {
|
||||
int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
|
||||
u32 nStep; /* Number of steps into the integrity_check process */
|
||||
const char *zPfx; /* Error message prefix */
|
||||
Pgno v1; /* Value for first %u substitution in zPfx */
|
||||
int v2; /* Value for second %d substitution in zPfx */
|
||||
Pgno v0; /* Value for first %u substitution in zPfx (root page) */
|
||||
Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
|
||||
int v2; /* Value for third %d substitution in zPfx */
|
||||
StrAccum errMsg; /* Accumulate the error message text here */
|
||||
u32 *heap; /* Min-heap used for analyzing cell coverage */
|
||||
sqlite3 *db; /* Database connection running the check */
|
||||
|
||||
+1
-1
@@ -78,6 +78,7 @@ static int dbpageConnect(
|
||||
(void)pzErr;
|
||||
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -161,7 +162,6 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
){
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
sqlite3VtabUsesAllSchemas(pIdxInfo);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -114,13 +114,15 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
|
||||
** If pTab is writable but other errors have occurred -> return 1.
|
||||
** If pTab is writable and no prior errors -> return 0;
|
||||
*/
|
||||
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
|
||||
if( tabIsReadOnly(pParse, pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( !viewOk && IsView(pTab) ){
|
||||
if( IsView(pTab)
|
||||
&& (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
||||
return 1;
|
||||
}
|
||||
@@ -374,7 +376,7 @@ void sqlite3DeleteFrom(
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
|
||||
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
||||
if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
|
||||
goto delete_from_cleanup;
|
||||
}
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
+62
-12
@@ -278,11 +278,10 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
|
||||
}else{
|
||||
Expr *pNext = p->pRight;
|
||||
/* The Expr.x union is never used at the same time as Expr.pRight */
|
||||
assert( ExprUseXList(p) );
|
||||
assert( p->x.pList==0 || p->pRight==0 );
|
||||
if( p->x.pList!=0 && !db->mallocFailed ){
|
||||
assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
|
||||
if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
|
||||
int i;
|
||||
for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
|
||||
for(i=0; i<p->x.pList->nExpr; i++){
|
||||
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
|
||||
pNext = p->x.pList->a[i].pExpr;
|
||||
break;
|
||||
@@ -2936,7 +2935,6 @@ int sqlite3FindInIndex(
|
||||
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
||||
int j;
|
||||
|
||||
assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
|
||||
for(j=0; j<nExpr; j++){
|
||||
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
|
||||
assert( pIdx->azColl[j] );
|
||||
@@ -5101,7 +5099,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
||||
if( inReg!=target ){
|
||||
u8 op;
|
||||
if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
|
||||
if( ALWAYS(pExpr)
|
||||
&& (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER)
|
||||
){
|
||||
op = OP_Copy;
|
||||
}else{
|
||||
op = OP_SCopy;
|
||||
@@ -6286,9 +6286,11 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
int iAgg = pExpr->iAgg;
|
||||
Parse *pParse = pWalker->pParse;
|
||||
sqlite3 *db = pParse->db;
|
||||
assert( iAgg>=0 );
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ){
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
|
||||
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
|
||||
if( iAgg<pAggInfo->nColumn
|
||||
&& pAggInfo->aCol[iAgg].pCExpr==pExpr
|
||||
){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aCol[iAgg].pCExpr = pExpr;
|
||||
@@ -6297,8 +6299,9 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
}else{
|
||||
assert( pExpr->op==TK_AGG_FUNCTION );
|
||||
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
|
||||
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
|
||||
if( ALWAYS(iAgg<pAggInfo->nFunc)
|
||||
&& pAggInfo->aFunc[iAgg].pFExpr==pExpr
|
||||
){
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
if( pExpr ){
|
||||
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
|
||||
@@ -6448,7 +6451,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( pIEpr==0 ) break;
|
||||
if( NEVER(!ExprUseYTab(pExpr)) ) break;
|
||||
if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
|
||||
for(i=0; i<pSrcList->nSrc; i++){
|
||||
if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
|
||||
}
|
||||
if( i>=pSrcList->nSrc ) break;
|
||||
if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
|
||||
if( pParse->nErr ){ return WRC_Abort; }
|
||||
|
||||
/* If we reach this point, it means that expression pExpr can be
|
||||
** translated into a reference to an index column as described by
|
||||
@@ -6459,6 +6467,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
tmp.iTable = pIEpr->iIdxCur;
|
||||
tmp.iColumn = pIEpr->iIdxCol;
|
||||
findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
|
||||
if( pParse->nErr ){ return WRC_Abort; }
|
||||
assert( pAggInfo->aCol!=0 );
|
||||
assert( tmp.iAgg<pAggInfo->nColumn );
|
||||
pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
|
||||
pExpr->pAggInfo = pAggInfo;
|
||||
pExpr->iAgg = tmp.iAgg;
|
||||
@@ -6482,7 +6493,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
} /* endif pExpr->iTable==pItem->iCursor */
|
||||
} /* end loop over pSrcList */
|
||||
}
|
||||
return WRC_Prune;
|
||||
return WRC_Continue;
|
||||
}
|
||||
case TK_AGG_FUNCTION: {
|
||||
if( (pNC->ncFlags & NC_InAggFunc)==0
|
||||
@@ -6635,6 +6646,37 @@ void sqlite3ClearTempRegCache(Parse *pParse){
|
||||
pParse->nRangeReg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make sure sufficient registers have been allocated so that
|
||||
** iReg is a valid register number.
|
||||
*/
|
||||
void sqlite3TouchRegister(Parse *pParse, int iReg){
|
||||
if( pParse->nMem<iReg ) pParse->nMem = iReg;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** Return the latest reusable register in the set of all registers.
|
||||
** The value returned is no less than iMin. If any register iMin or
|
||||
** greater is in permanent use, then return one more than that last
|
||||
** permanent register.
|
||||
*/
|
||||
int sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
|
||||
const ExprList *pList = pParse->pConstExpr;
|
||||
if( pList ){
|
||||
int i;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].u.iConstExprReg>=iMin ){
|
||||
iMin = pList->a[i].u.iConstExprReg + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pParse->nTempReg = 0;
|
||||
pParse->nRangeReg = 0;
|
||||
return iMin;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Validate that no temporary register falls within the range of
|
||||
** iFirst..iLast, inclusive. This routine is only call from within assert()
|
||||
@@ -6654,6 +6696,14 @@ int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if( pParse->pConstExpr ){
|
||||
ExprList *pList = pParse->pConstExpr;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
int iReg = pList->a[i].u.iConstExprReg;
|
||||
if( iReg==0 ) continue;
|
||||
if( iReg>=iFirst && iReg<=iLast ) return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
+8
-8
@@ -1317,22 +1317,22 @@ static Trigger *fkActionTrigger(
|
||||
|
||||
if( action==OE_Restrict ){
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
Token tFrom;
|
||||
Token tDb;
|
||||
SrcList *pSrc;
|
||||
Expr *pRaise;
|
||||
|
||||
tFrom.z = zFrom;
|
||||
tFrom.n = nFrom;
|
||||
tDb.z = db->aDb[iDb].zDbSName;
|
||||
tDb.n = sqlite3Strlen30(tDb.z);
|
||||
|
||||
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
||||
if( pRaise ){
|
||||
pRaise->affExpr = OE_Abort;
|
||||
}
|
||||
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
||||
if( pSrc ){
|
||||
assert( pSrc->nSrc==1 );
|
||||
pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
|
||||
pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
||||
}
|
||||
pSelect = sqlite3SelectNew(pParse,
|
||||
sqlite3ExprListAppend(pParse, 0, pRaise),
|
||||
sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
|
||||
pSrc,
|
||||
pWhere,
|
||||
0, 0, 0, 0, 0
|
||||
);
|
||||
|
||||
+2
-2
@@ -796,7 +796,7 @@ void sqlite3Insert(
|
||||
|
||||
/* Cannot insert into a read-only table.
|
||||
*/
|
||||
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
|
||||
if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
@@ -1243,7 +1243,7 @@ void sqlite3Insert(
|
||||
}
|
||||
|
||||
/* Copy the new data already generated. */
|
||||
assert( pTab->nNVCol>0 );
|
||||
assert( pTab->nNVCol>0 || pParse->nErr>0 );
|
||||
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
|
||||
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
|
||||
+53
@@ -757,6 +757,27 @@ static int jsonIs4Hex(const char *z){
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_JSON_NAN_INF
|
||||
/*
|
||||
** Extra floating-point literals to allow in JSON.
|
||||
*/
|
||||
static const struct NanInfName {
|
||||
char c1;
|
||||
char c2;
|
||||
char n;
|
||||
char eType;
|
||||
char nRepl;
|
||||
char *zMatch;
|
||||
char *zRepl;
|
||||
} aNanInfName[] = {
|
||||
{ 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" },
|
||||
{ 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" },
|
||||
{ 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" },
|
||||
{ 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" },
|
||||
{ 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" },
|
||||
};
|
||||
#endif /* SQLITE_ENABLE_JSON_NAN_INF */
|
||||
|
||||
/*
|
||||
** Parse a single JSON value which begins at pParse->zJson[i]. Return the
|
||||
** index of the first character past the end of the value parsed.
|
||||
@@ -902,6 +923,24 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
if( c<'0' || c>'9' ) return -1;
|
||||
continue;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_JSON_NAN_INF
|
||||
/* Non-standard JSON: Allow "-Inf" (in any case)
|
||||
** to be understood as floating point literals. */
|
||||
if( (c=='i' || c=='I')
|
||||
&& j==i+1
|
||||
&& z[i]=='-'
|
||||
&& sqlite3StrNICmp(&z[j], "inf",3)==0
|
||||
){
|
||||
if( !sqlite3Isalnum(z[j+3]) ){
|
||||
jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
|
||||
return i+4;
|
||||
}else if( (sqlite3StrNICmp(&z[j],"infinity",8)==0 &&
|
||||
!sqlite3Isalnum(z[j+8])) ){
|
||||
jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
|
||||
return i+9;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if( z[j-1]<'0' ) return -1;
|
||||
@@ -915,6 +954,20 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
||||
}else if( c==0 ){
|
||||
return 0; /* End of file */
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_JSON_NAN_INF
|
||||
int k, nn;
|
||||
for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
|
||||
if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
|
||||
nn = aNanInfName[k].n;
|
||||
if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
|
||||
continue;
|
||||
}
|
||||
if( sqlite3Isalnum(z[i+nn]) ) continue;
|
||||
jsonParseAddNode(pParse, aNanInfName[k].eType,
|
||||
aNanInfName[k].nRepl, aNanInfName[k].zRepl);
|
||||
return i + nn;
|
||||
}
|
||||
#endif
|
||||
return -1; /* Syntax error */
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -72,7 +72,7 @@
|
||||
#endif
|
||||
|
||||
/* Use pread() and pwrite() if they are available */
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
# define HAVE_PREAD 1
|
||||
# define HAVE_PWRITE 1
|
||||
#endif
|
||||
@@ -3322,12 +3322,6 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
|
||||
** Seek to the offset passed as the second argument, then read cnt
|
||||
** bytes into pBuf. Return the number of bytes actually read.
|
||||
**
|
||||
** NB: If you define USE_PREAD or USE_PREAD64, then it might also
|
||||
** be necessary to define _XOPEN_SOURCE to be 500. This varies from
|
||||
** one system to another. Since SQLite does not define USE_PREAD
|
||||
** in any form by default, we will not attempt to define _XOPEN_SOURCE.
|
||||
** See tickets #2741 and #2681.
|
||||
**
|
||||
** To avoid stomping the errno value on a failed read the lastErrno value
|
||||
** is set before returning.
|
||||
*/
|
||||
|
||||
+19
-4
@@ -1524,7 +1524,7 @@ void sqlite3Pragma(
|
||||
zDb = db->aDb[iDb].zDbSName;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
|
||||
sqlite3TouchRegister(pParse, pTab->nCol+regRow);
|
||||
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
|
||||
sqlite3VdbeLoadString(v, regResult, pTab->zName);
|
||||
assert( IsOrdinaryTable(pTab) );
|
||||
@@ -1565,7 +1565,7 @@ void sqlite3Pragma(
|
||||
** regRow..regRow+n. If any of the child key values are NULL, this
|
||||
** row cannot cause an FK violation. Jump directly to addrOk in
|
||||
** this case. */
|
||||
if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
|
||||
sqlite3TouchRegister(pParse, regRow + pFK->nCol);
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
|
||||
@@ -1694,6 +1694,7 @@ void sqlite3Pragma(
|
||||
if( iDb>=0 && i!=iDb ) continue;
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
pParse->okConstFactor = 0; /* tag-20230327-1 */
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
**
|
||||
@@ -1729,7 +1730,7 @@ void sqlite3Pragma(
|
||||
aRoot[0] = cnt;
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
|
||||
sqlite3TouchRegister(pParse, 8+mxIdx);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
|
||||
/* Do the b-tree integrity checks */
|
||||
@@ -1879,15 +1880,29 @@ void sqlite3Pragma(
|
||||
labelOk = sqlite3VdbeMakeLabel(pParse);
|
||||
if( pCol->notNull ){
|
||||
/* (1) NOT NULL columns may not contain a NULL */
|
||||
int jmp3;
|
||||
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
|
||||
sqlite3VdbeChangeP5(v, 0x0f);
|
||||
VdbeCoverage(v);
|
||||
if( p1<0 ){
|
||||
sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
|
||||
jmp3 = jmp2;
|
||||
}else{
|
||||
sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
|
||||
/* OP_IsType does not detect NaN values in the database file
|
||||
** which should be treated as a NULL. So if the header type
|
||||
** is REAL, we have to load the actual data using OP_Column
|
||||
** to reliably determine if the value is a NULL. */
|
||||
sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
|
||||
jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
|
||||
pCol->zCnName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
if( doTypeCheck ){
|
||||
sqlite3VdbeGoto(v, labelError);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeJumpHere(v, jmp3);
|
||||
}else{
|
||||
/* VDBE byte code will fall thru */
|
||||
}
|
||||
|
||||
+3
-1
@@ -306,7 +306,9 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
|
||||
#else
|
||||
encoding = SQLITE_UTF8;
|
||||
#endif
|
||||
if( db->nVdbeActive>0 && encoding!=ENC(db) ){
|
||||
if( db->nVdbeActive>0 && encoding!=ENC(db)
|
||||
&& (db->mDbFlags & DBFLAG_Vacuum)==0
|
||||
){
|
||||
rc = SQLITE_LOCKED;
|
||||
goto initone_error_out;
|
||||
}else{
|
||||
|
||||
+26
-20
@@ -2318,7 +2318,7 @@ void sqlite3SubqueryColumnTypes(
|
||||
assert( (pSelect->selFlags & SF_Resolved)!=0 );
|
||||
assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
|
||||
assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
|
||||
if( db->mallocFailed ) return;
|
||||
if( db->mallocFailed || IN_RENAME_OBJECT ) return;
|
||||
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
||||
a = pSelect->pEList->a;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
@@ -2363,18 +2363,18 @@ void sqlite3SubqueryColumnTypes(
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( zType ){
|
||||
i64 m = sqlite3Strlen30(zType);
|
||||
n = sqlite3Strlen30(pCol->zCnName);
|
||||
pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
|
||||
if( pCol->zCnName ){
|
||||
memcpy(&pCol->zCnName[n+1], zType, m+1);
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}else{
|
||||
testcase( pCol->colFlags & COLFLAG_HASTYPE );
|
||||
pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
|
||||
}
|
||||
}
|
||||
if( zType ){
|
||||
i64 m = sqlite3Strlen30(zType);
|
||||
n = sqlite3Strlen30(pCol->zCnName);
|
||||
pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
|
||||
pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
|
||||
if( pCol->zCnName ){
|
||||
memcpy(&pCol->zCnName[n+1], zType, m+1);
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}else{
|
||||
testcase( pCol->colFlags & COLFLAG_HASTYPE );
|
||||
}
|
||||
}
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
@@ -5266,11 +5266,13 @@ static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
|
||||
** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
|
||||
return 0;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
if( pX->pWin ){
|
||||
/* This optimization does not work for subqueries that use window
|
||||
** functions. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
colUsed = pItem->colUsed;
|
||||
if( pSub->pOrderBy ){
|
||||
@@ -6446,12 +6448,13 @@ static void optimizeAggregateUseOfIndexedExpr(
|
||||
assert( pSelect->pGroupBy!=0 );
|
||||
pAggInfo->nColumn = pAggInfo->nAccumulator;
|
||||
if( ALWAYS(pAggInfo->nSortingColumn>0) ){
|
||||
if( pAggInfo->nColumn==0 ){
|
||||
pAggInfo->nSortingColumn = pSelect->pGroupBy->nExpr;
|
||||
}else{
|
||||
pAggInfo->nSortingColumn =
|
||||
pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
|
||||
int mx = pSelect->pGroupBy->nExpr - 1;
|
||||
int j, k;
|
||||
for(j=0; j<pAggInfo->nColumn; j++){
|
||||
k = pAggInfo->aCol[j].iSorterColumn;
|
||||
if( k>mx ) mx = k;
|
||||
}
|
||||
pAggInfo->nSortingColumn = mx+1;
|
||||
}
|
||||
analyzeAggFuncArgs(pAggInfo, pNC);
|
||||
#if TREETRACE_ENABLED
|
||||
@@ -6485,12 +6488,13 @@ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
|
||||
if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
|
||||
pAggInfo = pExpr->pAggInfo;
|
||||
if( pExpr->iAgg>=pAggInfo->nColumn ) return WRC_Continue;
|
||||
if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
|
||||
assert( pExpr->iAgg>=0 );
|
||||
pCol = &pAggInfo->aCol[pExpr->iAgg];
|
||||
pExpr->op = TK_AGG_COLUMN;
|
||||
pExpr->iTable = pCol->iTable;
|
||||
pExpr->iColumn = pCol->iColumn;
|
||||
ExprClearProperty(pExpr, EP_Skip|EP_Collate);
|
||||
return WRC_Prune;
|
||||
}
|
||||
|
||||
@@ -6871,6 +6875,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
|
||||
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
|
||||
if( p->pWhere ) return 0;
|
||||
if( p->pHaving ) return 0;
|
||||
if( p->pGroupBy ) return 0;
|
||||
if( p->pOrderBy ) return 0;
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
@@ -6890,7 +6895,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
||||
if( pSub->pWhere ) return 0; /* No WHERE clause */
|
||||
if( pSub->pLimit ) return 0; /* No LIMIT clause */
|
||||
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
|
||||
pSub = pSub->pPrior; /* Repeat over compound */
|
||||
assert( pSub->pHaving==0 ); /* Due to the previous */
|
||||
pSub = pSub->pPrior; /* Repeat over compound */
|
||||
}while( pSub );
|
||||
|
||||
/* If we reach this point then it is OK to perform the transformation */
|
||||
|
||||
+212
-28
@@ -228,6 +228,7 @@ typedef unsigned char u8;
|
||||
#if SQLITE_OS_WINRT
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
/* string conversion routines only needed on Win32 */
|
||||
@@ -442,11 +443,25 @@ static void endTimer(void){
|
||||
static int bail_on_error = 0;
|
||||
|
||||
/*
|
||||
** Threat stdin as an interactive input if the following variable
|
||||
** Treat stdin as an interactive input if the following variable
|
||||
** is true. Otherwise, assume stdin is connected to a file or pipe.
|
||||
*/
|
||||
static int stdin_is_interactive = 1;
|
||||
|
||||
#if (defined(_WIN32) || defined(WIN32)) && SHELL_USE_LOCAL_GETLINE \
|
||||
&& !defined(SHELL_OMIT_WIN_UTF8)
|
||||
# define SHELL_WIN_UTF8_OPT 1
|
||||
#else
|
||||
# define SHELL_WIN_UTF8_OPT 0
|
||||
#endif
|
||||
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
/*
|
||||
** Setup console for UTF-8 input/output when following variable true.
|
||||
*/
|
||||
static int console_utf8 = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** On Windows systems we have to know if standard output is a console
|
||||
** in order to translate UTF-8 into MBCS. The following variable is
|
||||
@@ -579,16 +594,146 @@ static char *dynamicContinuePrompt(void){
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_DYNAPROMPT) */
|
||||
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
/* Following struct is used for -utf8 operation. */
|
||||
static struct ConsoleState {
|
||||
int stdinEof; /* EOF has been seen on console input */
|
||||
int infsMode; /* Input file stream mode upon shell start */
|
||||
UINT inCodePage; /* Input code page upon shell start */
|
||||
UINT outCodePage; /* Output code page upon shell start */
|
||||
HANDLE hConsoleIn; /* Console input handle */
|
||||
DWORD consoleMode; /* Console mode upon shell start */
|
||||
} conState = { 0, 0, 0, 0, INVALID_HANDLE_VALUE, 0 };
|
||||
|
||||
/*
|
||||
** Prepare console, (if known to be a WIN32 console), for UTF-8
|
||||
** input (from either typing or suitable paste operations) and for
|
||||
** UTF-8 rendering. This may "fail" with a message to stderr, where
|
||||
** the preparation is not done and common "code page" issues occur.
|
||||
*/
|
||||
static void console_prepare(void){
|
||||
HANDLE hCI = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD consoleMode = 0;
|
||||
if( isatty(0) && GetFileType(hCI)==FILE_TYPE_CHAR
|
||||
&& GetConsoleMode( hCI, &consoleMode) ){
|
||||
if( !IsValidCodePage(CP_UTF8) ){
|
||||
fprintf(stderr, "Cannot use UTF-8 code page.\n");
|
||||
console_utf8 = 0;
|
||||
return;
|
||||
}
|
||||
conState.hConsoleIn = hCI;
|
||||
conState.consoleMode = consoleMode;
|
||||
conState.inCodePage = GetConsoleCP();
|
||||
conState.outCodePage = GetConsoleOutputCP();
|
||||
SetConsoleCP(CP_UTF8);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
consoleMode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||||
SetConsoleMode(conState.hConsoleIn, consoleMode);
|
||||
conState.infsMode = _setmode(_fileno(stdin), _O_U16TEXT);
|
||||
console_utf8 = 1;
|
||||
}else{
|
||||
console_utf8 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Undo the effects of console_prepare(), if any.
|
||||
*/
|
||||
static void SQLITE_CDECL console_restore(void){
|
||||
if( console_utf8 && conState.inCodePage!=0
|
||||
&& conState.hConsoleIn!=INVALID_HANDLE_VALUE ){
|
||||
_setmode(_fileno(stdin), conState.infsMode);
|
||||
SetConsoleCP(conState.inCodePage);
|
||||
SetConsoleOutputCP(conState.outCodePage);
|
||||
SetConsoleMode(conState.hConsoleIn, conState.consoleMode);
|
||||
/* Avoid multiple calls. */
|
||||
conState.hConsoleIn = INVALID_HANDLE_VALUE;
|
||||
conState.consoleMode = 0;
|
||||
console_utf8 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Collect input like fgets(...) with special provisions for input
|
||||
** from the Windows console to get around its strange coding issues.
|
||||
** Defers to plain fgets() when input is not interactive or when the
|
||||
** startup option, -utf8, has not been provided or taken effect.
|
||||
*/
|
||||
static char* utf8_fgets(char *buf, int ncmax, FILE *fin){
|
||||
if( fin==0 ) fin = stdin;
|
||||
if( fin==stdin && stdin_is_interactive && console_utf8 ){
|
||||
# define SQLITE_IALIM 150
|
||||
wchar_t wbuf[SQLITE_IALIM];
|
||||
int lend = 0;
|
||||
int noc = 0;
|
||||
if( ncmax==0 || conState.stdinEof ) return 0;
|
||||
buf[0] = 0;
|
||||
while( noc<ncmax-7-1 && !lend ){
|
||||
/* There is room for at least 2 more characters and a 0-terminator. */
|
||||
int na = (ncmax > SQLITE_IALIM*4+1 + noc)
|
||||
? SQLITE_IALIM : (ncmax-1 - noc)/4;
|
||||
# undef SQLITE_IALIM
|
||||
DWORD nbr = 0;
|
||||
BOOL bRC = ReadConsoleW(conState.hConsoleIn, wbuf, na, &nbr, 0);
|
||||
if( !bRC || (noc==0 && nbr==0) ) return 0;
|
||||
if( nbr > 0 ){
|
||||
int nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
|
||||
wbuf,nbr,0,0,0,0);
|
||||
if( nmb !=0 && noc+nmb <= ncmax ){
|
||||
int iseg = noc;
|
||||
nmb = WideCharToMultiByte(CP_UTF8,WC_COMPOSITECHECK|WC_DEFAULTCHAR,
|
||||
wbuf,nbr,buf+noc,nmb,0,0);
|
||||
noc += nmb;
|
||||
/* Fixup line-ends as coded by Windows for CR (or "Enter".)*/
|
||||
if( noc > 0 ){
|
||||
if( buf[noc-1]=='\n' ){
|
||||
lend = 1;
|
||||
if( noc > 1 && buf[noc-2]=='\r' ){
|
||||
buf[noc-2] = '\n';
|
||||
--noc;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Check for ^Z (anywhere in line) too. */
|
||||
while( iseg < noc ){
|
||||
if( buf[iseg]==0x1a ){
|
||||
conState.stdinEof = 1;
|
||||
noc = iseg; /* Chop ^Z and anything following. */
|
||||
break;
|
||||
}
|
||||
++iseg;
|
||||
}
|
||||
}else break; /* Drop apparent garbage in. (Could assert.) */
|
||||
}else break;
|
||||
}
|
||||
/* If got nothing, (after ^Z chop), must be at end-of-file. */
|
||||
if( noc == 0 ) return 0;
|
||||
buf[noc] = 0;
|
||||
return buf;
|
||||
}else{
|
||||
return fgets(buf, ncmax, fin);
|
||||
}
|
||||
}
|
||||
|
||||
# define fgets(b,n,f) utf8_fgets(b,n,f)
|
||||
#endif /* SHELL_WIN_UTF8_OPT */
|
||||
|
||||
/*
|
||||
** Render output like fprintf(). Except, if the output is going to the
|
||||
** console and if this is running on a Windows machine, translate the
|
||||
** output from UTF-8 into MBCS.
|
||||
** console and if this is running on a Windows machine, and if the -utf8
|
||||
** option is unavailable or (available and inactive), translate the
|
||||
** output from UTF-8 into MBCS for output through 8-bit stdout stream.
|
||||
** (With -utf8 active, no translation is needed and must not be done.)
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
void utf8_printf(FILE *out, const char *zFormat, ...){
|
||||
va_list ap;
|
||||
va_start(ap, zFormat);
|
||||
if( stdout_is_console && (out==stdout || out==stderr) ){
|
||||
if( stdout_is_console && (out==stdout || out==stderr)
|
||||
# if SHELL_WIN_UTF8_OPT
|
||||
&& !console_utf8
|
||||
# endif
|
||||
){
|
||||
char *z1 = sqlite3_vmprintf(zFormat, ap);
|
||||
char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0);
|
||||
sqlite3_free(z1);
|
||||
@@ -799,9 +944,14 @@ static char *local_getline(char *zLine, FILE *in){
|
||||
}
|
||||
}
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
/* For interactive input on Windows systems, translate the
|
||||
** multi-byte characterset characters into UTF-8. */
|
||||
if( stdin_is_interactive && in==stdin ){
|
||||
/* For interactive input on Windows systems, without -utf8,
|
||||
** translate the multi-byte characterset characters into UTF-8.
|
||||
** This is the translation that predates the -utf8 option. */
|
||||
if( stdin_is_interactive && in==stdin
|
||||
# if SHELL_WIN_UTF8_OPT
|
||||
&& !console_utf8
|
||||
# endif /* SHELL_WIN_UTF8_OPT */
|
||||
){
|
||||
char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0);
|
||||
if( zTrans ){
|
||||
i64 nTrans = strlen(zTrans)+1;
|
||||
@@ -842,10 +992,20 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
#if SHELL_USE_LOCAL_GETLINE
|
||||
printf("%s", zPrompt);
|
||||
fflush(stdout);
|
||||
zResult = local_getline(zPrior, stdin);
|
||||
do{
|
||||
zResult = local_getline(zPrior, stdin);
|
||||
/* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
|
||||
if( zResult==0 ) sqlite3_sleep(50);
|
||||
}while( zResult==0 && seenInterrupt>0 );
|
||||
#else
|
||||
free(zPrior);
|
||||
zResult = shell_readline(zPrompt);
|
||||
while( zResult==0 ){
|
||||
/* ^C trap creates a false EOF, so let "interrupt" thread catch up. */
|
||||
sqlite3_sleep(50);
|
||||
if( seenInterrupt==0 ) break;
|
||||
zResult = shell_readline("");
|
||||
}
|
||||
if( zResult && *zResult ) shell_add_history(zResult);
|
||||
#endif
|
||||
}
|
||||
@@ -1183,10 +1343,8 @@ INCLUDE ../ext/expert/sqlite3expert.c
|
||||
#endif
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
INCLUDE ../ext/recover/sqlite3recover.h
|
||||
# ifndef SQLITE_HAVE_SQLITE3R
|
||||
INCLUDE ../ext/recover/dbdata.c
|
||||
INCLUDE ../ext/recover/sqlite3recover.c
|
||||
# endif
|
||||
#endif
|
||||
#ifdef SQLITE_SHELL_EXTSRC
|
||||
# include SHELL_STRINGIFY(SQLITE_SHELL_EXTSRC)
|
||||
@@ -1954,8 +2112,7 @@ static void output_csv(ShellState *p, const char *z, int bSep){
|
||||
*/
|
||||
static void interrupt_handler(int NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
seenInterrupt++;
|
||||
if( seenInterrupt>2 ) exit(1);
|
||||
if( ++seenInterrupt>1 ) exit(1);
|
||||
if( globalDb ) sqlite3_interrupt(globalDb);
|
||||
}
|
||||
|
||||
@@ -2776,7 +2933,7 @@ static char *shell_error_context(const char *zSql, sqlite3 *db){
|
||||
if( db==0
|
||||
|| zSql==0
|
||||
|| (iOffset = sqlite3_error_offset(db))<0
|
||||
|| iOffset>=strlen(zSql)
|
||||
|| iOffset>=(int)strlen(zSql)
|
||||
){
|
||||
return sqlite3_mprintf("");
|
||||
}
|
||||
@@ -2788,7 +2945,7 @@ static char *shell_error_context(const char *zSql, sqlite3 *db){
|
||||
len = strlen(zSql);
|
||||
if( len>78 ){
|
||||
len = 78;
|
||||
while( (zSql[len]&0xc0)==0x80 ) len--;
|
||||
while( len>0 && (zSql[len]&0xc0)==0x80 ) len--;
|
||||
}
|
||||
zCode = sqlite3_mprintf("%.*s", len, zSql);
|
||||
shell_check_oom(zCode);
|
||||
@@ -5203,6 +5360,9 @@ static void open_db(ShellState *p, int openFlags){
|
||||
sqlite3_regexp_init(p->db, 0, 0);
|
||||
sqlite3_ieee_init(p->db, 0, 0);
|
||||
sqlite3_series_init(p->db, 0, 0);
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
sqlite3_dbdata_init(p->db, 0, 0);
|
||||
#endif
|
||||
#ifndef SQLITE_SHELL_FIDDLE
|
||||
sqlite3_fileio_init(p->db, 0, 0);
|
||||
sqlite3_completion_init(p->db, 0, 0);
|
||||
@@ -6018,7 +6178,7 @@ static int db_int(sqlite3 *db, const char *zSql){
|
||||
return res;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_SHELL_HAVE_RECOVER)
|
||||
#if SQLITE_SHELL_HAVE_RECOVER
|
||||
/*
|
||||
** Convert a 2-byte or 4-byte big-endian integer into a native integer
|
||||
*/
|
||||
@@ -9648,6 +9808,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}else{
|
||||
p->scanstatsOn = (u8)booleanValue(azArg[1]);
|
||||
}
|
||||
open_db(p, 0);
|
||||
sqlite3_db_config(
|
||||
p->db, SQLITE_DBCONFIG_STMT_SCANSTATUS, p->scanstatsOn, (int*)0
|
||||
);
|
||||
@@ -11583,6 +11744,9 @@ static const char zOptions[] =
|
||||
" -stats print memory stats before each finalize\n"
|
||||
" -table set output mode to 'table'\n"
|
||||
" -tabs set output mode to 'tabs'\n"
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
" -utf8 setup interactive console code page for UTF-8\n"
|
||||
#endif
|
||||
" -version show SQLite version\n"
|
||||
" -vfs NAME use NAME as the default VFS\n"
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
@@ -11675,6 +11839,10 @@ static char *cmdline_option_value(int argc, char **argv, int i){
|
||||
return argv[i];
|
||||
}
|
||||
|
||||
static void sayAbnormalExit(void){
|
||||
if( seenInterrupt ) fprintf(stderr, "Program interrupted.\n");
|
||||
}
|
||||
|
||||
#ifndef SQLITE_SHELL_IS_UTF8
|
||||
# if (defined(_WIN32) || defined(WIN32)) \
|
||||
&& (defined(_MSC_VER) || (defined(UNICODE) && defined(__GNUC__)))
|
||||
@@ -11695,7 +11863,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
char **argv;
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
sqlite3_int64 mem_main_enter = sqlite3_memory_used();
|
||||
sqlite3_int64 mem_main_enter = 0;
|
||||
#endif
|
||||
char *zErrMsg = 0;
|
||||
#ifdef SQLITE_SHELL_FIDDLE
|
||||
@@ -11716,9 +11884,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
char **argvToFree = 0;
|
||||
int argcToFree = 0;
|
||||
#endif
|
||||
|
||||
setBinaryMode(stdin, 0);
|
||||
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
|
||||
|
||||
#ifdef SQLITE_SHELL_FIDDLE
|
||||
stdin_is_interactive = 0;
|
||||
stdout_is_console = 1;
|
||||
@@ -11727,7 +11894,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
stdin_is_interactive = isatty(0);
|
||||
stdout_is_console = isatty(1);
|
||||
#endif
|
||||
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
atexit(console_restore); /* Needs revision for CLI as library call */
|
||||
#endif
|
||||
atexit(sayAbnormalExit);
|
||||
#ifdef SQLITE_DEBUG
|
||||
mem_main_enter = sqlite3_memory_used();
|
||||
#endif
|
||||
#if !defined(_WIN32_WCE)
|
||||
if( getenv("SQLITE_DEBUG_BREAK") ){
|
||||
if( isatty(0) && isatty(2) ){
|
||||
@@ -11748,6 +11921,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Register a valid signal handler early, before much else is done. */
|
||||
#ifdef SIGINT
|
||||
signal(SIGINT, interrupt_handler);
|
||||
#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
|
||||
if( !SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE) ){
|
||||
fprintf(stderr, "No ^C handler.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_SYSTEM_SQLITE+0!=1
|
||||
if( cli_strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
|
||||
@@ -11787,15 +11968,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
assert( argc>=1 && argv && argv[0] );
|
||||
Argv0 = argv[0];
|
||||
|
||||
/* Make sure we have a valid signal handler early, before anything
|
||||
** else is done.
|
||||
*/
|
||||
#ifdef SIGINT
|
||||
signal(SIGINT, interrupt_handler);
|
||||
#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SHELL_DBNAME_PROC
|
||||
{
|
||||
/* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
|
||||
@@ -12114,6 +12286,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
stdin_is_interactive = 1;
|
||||
}else if( cli_strcmp(z,"-batch")==0 ){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( cli_strcmp(z,"-utf8")==0 ){
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
console_utf8 = 1;
|
||||
#endif /* SHELL_WIN_UTF8_OPT */
|
||||
}else if( cli_strcmp(z,"-heap")==0 ){
|
||||
i++;
|
||||
}else if( cli_strcmp(z,"-pagecache")==0 ){
|
||||
@@ -12191,6 +12367,14 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
|
||||
}
|
||||
data.cMode = data.mode;
|
||||
}
|
||||
#if SHELL_WIN_UTF8_OPT
|
||||
if( console_utf8 && stdin_is_interactive ){
|
||||
console_prepare();
|
||||
}else{
|
||||
setBinaryMode(stdin, 0);
|
||||
console_utf8 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !readStdin ){
|
||||
/* Run all arguments that do not begin with '-' as if they were separate
|
||||
|
||||
+12
-2
@@ -2496,7 +2496,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
|
||||
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
|
||||
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
|
||||
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1080 /* int int* */
|
||||
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
|
||||
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
|
||||
#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
|
||||
|
||||
@@ -9606,18 +9606,28 @@ int sqlite3_vtab_config(sqlite3*, int op, ...);
|
||||
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
|
||||
** <dd>Calls of the form
|
||||
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
|
||||
** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
|
||||
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
|
||||
** identify that virtual table as being safe to use from within triggers
|
||||
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
|
||||
** virtual table can do no serious harm even if it is controlled by a
|
||||
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
|
||||
** flag unless absolutely necessary.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
|
||||
** <dd>Calls of the form
|
||||
** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
|
||||
** the [xConnect] or [xCreate] methods of a [virtual table] implementation
|
||||
** instruct the query planner to begin at least a read transaction on
|
||||
** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
|
||||
** virtual table is used.
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
|
||||
#define SQLITE_VTAB_INNOCUOUS 2
|
||||
#define SQLITE_VTAB_DIRECTONLY 3
|
||||
#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
|
||||
|
||||
/*
|
||||
** CAPI3REF: Determine The Virtual Table Conflict Policy
|
||||
|
||||
+16
-6
@@ -281,15 +281,22 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A macro to hint to the compiler that a function should not be
|
||||
** Macros to hint to the compiler that a function should or should not be
|
||||
** inlined.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
# define SQLITE_NOINLINE __attribute__((noinline))
|
||||
# define SQLITE_INLINE __attribute__((always_inline)) inline
|
||||
#elif defined(_MSC_VER) && _MSC_VER>=1310
|
||||
# define SQLITE_NOINLINE __declspec(noinline)
|
||||
# define SQLITE_INLINE __forceinline
|
||||
#else
|
||||
# define SQLITE_NOINLINE
|
||||
# define SQLITE_INLINE
|
||||
#endif
|
||||
#if defined(SQLITE_COVERAGE_TEST)
|
||||
# undef SQLITE_INLINE
|
||||
# define SQLITE_INLINE
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -2312,6 +2319,7 @@ struct VTable {
|
||||
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
|
||||
int nRef; /* Number of pointers to this structure */
|
||||
u8 bConstraint; /* True if constraints are supported */
|
||||
u8 bAllSchemas; /* True if might use any attached schema */
|
||||
u8 eVtabRisk; /* Riskiness of allowing hacker access */
|
||||
int iSavepoint; /* Depth of the SAVEPOINT stack */
|
||||
VTable *pNext; /* Next in linked list (see above) */
|
||||
@@ -4178,6 +4186,7 @@ struct Walker {
|
||||
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
|
||||
SrcItem *pSrcItem; /* A single FROM clause item */
|
||||
DbFixer *pFix; /* See sqlite3FixSelect() */
|
||||
Mem *aMem; /* See sqlite3BtreeCursorHint() */
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -4649,6 +4658,10 @@ void sqlite3ReleaseTempReg(Parse*,int);
|
||||
int sqlite3GetTempRange(Parse*,int);
|
||||
void sqlite3ReleaseTempRange(Parse*,int,int);
|
||||
void sqlite3ClearTempRegCache(Parse*);
|
||||
void sqlite3TouchRegister(Parse*,int);
|
||||
#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
|
||||
int sqlite3FirstAvailableRegister(Parse*,int);
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3NoTempsInRange(Parse*,int,int);
|
||||
#endif
|
||||
@@ -4799,7 +4812,7 @@ Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||
Expr*,ExprList*,u32,Expr*);
|
||||
void sqlite3SelectDelete(sqlite3*, Select*);
|
||||
Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, int);
|
||||
int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
|
||||
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
||||
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
|
||||
@@ -5336,10 +5349,7 @@ int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
|
||||
int sqlite3VtabBegin(sqlite3 *, VTable *);
|
||||
|
||||
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
||||
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
|
||||
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
|
||||
#endif
|
||||
void sqlite3VtabUsesAllSchemas(Parse*);
|
||||
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
||||
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||
|
||||
@@ -2391,6 +2391,7 @@ static int SQLITE_TCLAPI vfsCurrentTimeInt64(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Usage: create_null_module DB NAME
|
||||
*/
|
||||
@@ -2413,6 +2414,7 @@ static int SQLITE_TCLAPI test_create_null_module(
|
||||
sqlite3_create_module(db, zName, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
/*
|
||||
@@ -9005,7 +9007,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_register_cksumvfs", test_register_cksumvfs, 0 },
|
||||
{ "sqlite3_unregister_cksumvfs", test_unregister_cksumvfs, 0 },
|
||||
{ "number_of_cores", guess_number_of_cores, 0 },
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
{ "create_null_module", test_create_null_module, 0 },
|
||||
#endif
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
|
||||
|
||||
@@ -1453,6 +1453,9 @@ u32 sqlite3TriggerColmask(
|
||||
Trigger *p;
|
||||
|
||||
assert( isNew==1 || isNew==0 );
|
||||
if( IsView(pTab) ){
|
||||
return 0xffffffff;
|
||||
}
|
||||
for(p=pTrigger; p; p=p->pNext){
|
||||
if( p->op==op
|
||||
&& (tr_tm&p->tr_tm)
|
||||
|
||||
+1
-1
@@ -408,7 +408,7 @@ void sqlite3Update(
|
||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
|
||||
if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
|
||||
goto update_cleanup;
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -670,13 +670,15 @@ int sqlite3Int64ToText(i64 v, char *zOut){
|
||||
}
|
||||
i = sizeof(zTemp)-2;
|
||||
zTemp[sizeof(zTemp)-1] = 0;
|
||||
do{
|
||||
zTemp[i--] = (x%10) + '0';
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
zTemp[i] = (x%10) + '0';
|
||||
x = x/10;
|
||||
}while( x );
|
||||
if( v<0 ) zTemp[i--] = '-';
|
||||
memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
|
||||
return sizeof(zTemp)-2-i;
|
||||
if( x==0 ) break;
|
||||
i--;
|
||||
};
|
||||
if( v<0 ) zTemp[--i] = '-';
|
||||
memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
|
||||
return sizeof(zTemp)-1-i;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2626,6 +2626,12 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
||||
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
|
||||
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
|
||||
**
|
||||
** WARNING: This opcode does not reliably distinguish between NULL and REAL
|
||||
** when P1>=0. If the database contains a NaN value, this opcode will think
|
||||
** that the datatype is REAL when it should be NULL. When P1<0 and the value
|
||||
** is already stored in register P3, then this opcode does reliably
|
||||
** distinguish between NULL and REAL. The problem only arises then P1>=0.
|
||||
**
|
||||
** Take the jump to address P2 if and only if the datatype of the
|
||||
** value determined by P1 and P3 corresponds to one of the bits in the
|
||||
** P5 bitmask.
|
||||
|
||||
@@ -403,4 +403,8 @@ void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
|
||||
void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
|
||||
#endif
|
||||
|
||||
#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
|
||||
int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_VDBE_H */
|
||||
|
||||
+22
-13
@@ -271,7 +271,7 @@ int sqlite3_value_type(sqlite3_value* pVal){
|
||||
SQLITE_NULL, /* 0x1f (not possible) */
|
||||
SQLITE_FLOAT, /* 0x20 INTREAL */
|
||||
SQLITE_NULL, /* 0x21 (not possible) */
|
||||
SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
|
||||
SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
|
||||
SQLITE_NULL, /* 0x23 (not possible) */
|
||||
SQLITE_FLOAT, /* 0x24 (not possible) */
|
||||
SQLITE_NULL, /* 0x25 (not possible) */
|
||||
@@ -2138,15 +2138,24 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
void *pOut /* OUT: Write the answer here */
|
||||
){
|
||||
Vdbe *p = (Vdbe*)pStmt;
|
||||
ScanStatus *pScan;
|
||||
VdbeOp *aOp = p->aOp;
|
||||
int nOp = p->nOp;
|
||||
ScanStatus *pScan = 0;
|
||||
int idx;
|
||||
|
||||
if( p->pFrame ){
|
||||
VdbeFrame *pFrame;
|
||||
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
||||
aOp = pFrame->aOp;
|
||||
nOp = pFrame->nOp;
|
||||
}
|
||||
|
||||
if( iScan<0 ){
|
||||
int ii;
|
||||
if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
|
||||
i64 res = 0;
|
||||
for(ii=0; ii<p->nOp; ii++){
|
||||
res += p->aOp[ii].nCycle;
|
||||
for(ii=0; ii<nOp; ii++){
|
||||
res += aOp[ii].nCycle;
|
||||
}
|
||||
*(i64*)pOut = res;
|
||||
return 0;
|
||||
@@ -2172,7 +2181,7 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
switch( iScanStatusOp ){
|
||||
case SQLITE_SCANSTAT_NLOOP: {
|
||||
if( pScan->addrLoop>0 ){
|
||||
*(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
|
||||
*(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
|
||||
}else{
|
||||
*(sqlite3_int64*)pOut = -1;
|
||||
}
|
||||
@@ -2180,7 +2189,7 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
}
|
||||
case SQLITE_SCANSTAT_NVISIT: {
|
||||
if( pScan->addrVisit>0 ){
|
||||
*(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
|
||||
*(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
|
||||
}else{
|
||||
*(sqlite3_int64*)pOut = -1;
|
||||
}
|
||||
@@ -2202,7 +2211,7 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
}
|
||||
case SQLITE_SCANSTAT_EXPLAIN: {
|
||||
if( pScan->addrExplain ){
|
||||
*(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
|
||||
*(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
|
||||
}else{
|
||||
*(const char**)pOut = 0;
|
||||
}
|
||||
@@ -2210,7 +2219,7 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
}
|
||||
case SQLITE_SCANSTAT_SELECTID: {
|
||||
if( pScan->addrExplain ){
|
||||
*(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
|
||||
*(int*)pOut = aOp[ pScan->addrExplain ].p1;
|
||||
}else{
|
||||
*(int*)pOut = -1;
|
||||
}
|
||||
@@ -2218,7 +2227,7 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
}
|
||||
case SQLITE_SCANSTAT_PARENTID: {
|
||||
if( pScan->addrExplain ){
|
||||
*(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
|
||||
*(int*)pOut = aOp[ pScan->addrExplain ].p2;
|
||||
}else{
|
||||
*(int*)pOut = -1;
|
||||
}
|
||||
@@ -2236,18 +2245,18 @@ int sqlite3_stmt_scanstatus_v2(
|
||||
if( iIns==0 ) break;
|
||||
if( iIns>0 ){
|
||||
while( iIns<=iEnd ){
|
||||
res += p->aOp[iIns].nCycle;
|
||||
res += aOp[iIns].nCycle;
|
||||
iIns++;
|
||||
}
|
||||
}else{
|
||||
int iOp;
|
||||
for(iOp=0; iOp<p->nOp; iOp++){
|
||||
Op *pOp = &p->aOp[iOp];
|
||||
for(iOp=0; iOp<nOp; iOp++){
|
||||
Op *pOp = &aOp[iOp];
|
||||
if( pOp->p1!=iEnd ) continue;
|
||||
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
|
||||
continue;
|
||||
}
|
||||
res += p->aOp[iOp].nCycle;
|
||||
res += aOp[iOp].nCycle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-3
@@ -3326,6 +3326,8 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
db->flags &= ~(u64)SQLITE_DeferFKs;
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
}else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
|
||||
p->nChange = 0;
|
||||
}else{
|
||||
sqlite3RollbackAll(db, SQLITE_OK);
|
||||
p->nChange = 0;
|
||||
@@ -3644,9 +3646,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
||||
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||
sqlite3DbFree(db, p->zNormSql);
|
||||
{
|
||||
DblquoteStr *pThis, *pNext;
|
||||
for(pThis=p->pDblStr; pThis; pThis=pNext){
|
||||
pNext = pThis->pNextStr;
|
||||
DblquoteStr *pThis, *pNxt;
|
||||
for(pThis=p->pDblStr; pThis; pThis=pNxt){
|
||||
pNxt = pThis->pNextStr;
|
||||
sqlite3DbFree(db, pThis);
|
||||
}
|
||||
}
|
||||
@@ -5273,6 +5275,20 @@ int sqlite3NotPureFunc(sqlite3_context *pCtx){
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
|
||||
/*
|
||||
** This Walker callback is used to help verify that calls to
|
||||
** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
|
||||
** byte-code register values correctly initialized.
|
||||
*/
|
||||
int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
|
||||
if( pExpr->op==TK_REGISTER ){
|
||||
assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
|
||||
}
|
||||
return WRC_Continue;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*
|
||||
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
|
||||
|
||||
+12
-2
@@ -439,7 +439,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
||||
|
||||
vdbeMemRenderNum(nByte, pMem->z, pMem);
|
||||
assert( pMem->z!=0 );
|
||||
assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
|
||||
assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) );
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem->flags |= MEM_Str|MEM_Term;
|
||||
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
|
||||
@@ -1483,8 +1483,11 @@ static int valueFromFunction(
|
||||
if( pList ) nVal = pList->nExpr;
|
||||
assert( !ExprHasProperty(p, EP_IntValue) );
|
||||
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
|
||||
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
if( pFunc==0 ) return SQLITE_OK;
|
||||
#endif
|
||||
assert( pFunc );
|
||||
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|
||||
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|
||||
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
||||
){
|
||||
return SQLITE_OK;
|
||||
@@ -1587,6 +1590,13 @@ static int valueFromExpr(
|
||||
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
if( *ppVal ){
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
rc = ExpandBlob(*ppVal);
|
||||
#else
|
||||
/* zero-blobs only come from functions, not literal values. And
|
||||
** functions are only processed under STAT4 */
|
||||
assert( (ppVal[0][0].flags & MEM_Zero)==0 );
|
||||
#endif
|
||||
sqlite3VdbeMemCast(*ppVal, aff, enc);
|
||||
sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
|
||||
}
|
||||
|
||||
@@ -1331,6 +1331,10 @@ int sqlite3_vtab_config(sqlite3 *db, int op, ...){
|
||||
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
|
||||
break;
|
||||
}
|
||||
case SQLITE_VTAB_USES_ALL_SCHEMAS: {
|
||||
p->pVTable->bAllSchemas = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
rc = SQLITE_MISUSE_BKPT;
|
||||
break;
|
||||
|
||||
@@ -746,19 +746,40 @@ static void walChecksumBytes(
|
||||
assert( nByte>=8 );
|
||||
assert( (nByte&0x00000007)==0 );
|
||||
assert( nByte<=65536 );
|
||||
assert( nByte%4==0 );
|
||||
|
||||
if( nativeCksum ){
|
||||
do {
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
}while( aData<aEnd );
|
||||
}else{
|
||||
if( !nativeCksum ){
|
||||
do {
|
||||
s1 += BYTESWAP32(aData[0]) + s2;
|
||||
s2 += BYTESWAP32(aData[1]) + s1;
|
||||
aData += 2;
|
||||
}while( aData<aEnd );
|
||||
}else if( nByte%64==0 ){
|
||||
do {
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
}while( aData<aEnd );
|
||||
}else{
|
||||
do {
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
}while( aData<aEnd );
|
||||
}
|
||||
assert( aData==aEnd );
|
||||
|
||||
aOut[0] = s1;
|
||||
aOut[1] = s2;
|
||||
|
||||
+12
-9
@@ -963,7 +963,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
|
||||
** original table changes and the index and table cannot both be used
|
||||
** if they go out of sync.
|
||||
*/
|
||||
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
|
||||
if( IsView(pTable) ){
|
||||
extraCols = ALLBITS;
|
||||
}else{
|
||||
extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
|
||||
}
|
||||
mxBitCol = MIN(BMS-1,pTable->nCol);
|
||||
testcase( pTable->nCol==BMS-1 );
|
||||
testcase( pTable->nCol==BMS-2 );
|
||||
@@ -1483,6 +1487,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
|
||||
}
|
||||
}
|
||||
if( pTab->u.vtab.p->bAllSchemas ){
|
||||
sqlite3VtabUsesAllSchemas(pParse);
|
||||
}
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
pVtab->zErrMsg = 0;
|
||||
return rc;
|
||||
@@ -2013,7 +2020,7 @@ static int whereRangeScanEst(
|
||||
UNUSED_PARAMETER(pBuilder);
|
||||
assert( pLower || pUpper );
|
||||
#endif
|
||||
assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
|
||||
assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
|
||||
nNew = whereRangeAdjust(pLower, nOut);
|
||||
nNew = whereRangeAdjust(pUpper, nNew);
|
||||
|
||||
@@ -4114,8 +4121,6 @@ int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
|
||||
return pHidden->eDistinct;
|
||||
}
|
||||
|
||||
#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
|
||||
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||
/*
|
||||
** Cause the prepared statement that is associated with a call to
|
||||
** xBestIndex to potentially use all schemas. If the statement being
|
||||
@@ -4125,9 +4130,7 @@ int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
|
||||
**
|
||||
** This is used by the (built-in) sqlite_dbpage virtual table.
|
||||
*/
|
||||
void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
|
||||
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
||||
Parse *pParse = pHidden->pParse;
|
||||
void sqlite3VtabUsesAllSchemas(Parse *pParse){
|
||||
int nDb = pParse->db->nDb;
|
||||
int i;
|
||||
for(i=0; i<nDb; i++){
|
||||
@@ -4139,7 +4142,6 @@ void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for a table of the join identified by
|
||||
@@ -6696,7 +6698,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
k = pLevel->addrBody + 1;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( db->flags & SQLITE_VdbeAddopTrace ){
|
||||
printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
|
||||
printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
|
||||
pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
|
||||
}
|
||||
/* Proof that the "+1" on the k value above is safe */
|
||||
pOp = sqlite3VdbeGetOp(v, k - 1);
|
||||
|
||||
+12
-23
@@ -1011,11 +1011,12 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
int rc = WRC_Continue;
|
||||
int reg;
|
||||
struct CCurHint *pHint = pWalker->u.pCCurHint;
|
||||
if( pExpr->op==TK_COLUMN ){
|
||||
if( pExpr->iTable!=pHint->iTabCur ){
|
||||
int reg = ++pWalker->pParse->nMem; /* Register for column value */
|
||||
sqlite3ExprCode(pWalker->pParse, pExpr, reg);
|
||||
reg = ++pWalker->pParse->nMem; /* Register for column value */
|
||||
reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
|
||||
pExpr->op = TK_REGISTER;
|
||||
pExpr->iTable = reg;
|
||||
}else if( pHint->pIdx!=0 ){
|
||||
@@ -1023,15 +1024,12 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
||||
pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
|
||||
assert( pExpr->iColumn>=0 );
|
||||
}
|
||||
}else if( pExpr->op==TK_AGG_FUNCTION ){
|
||||
/* An aggregate function in the WHERE clause of a query means this must
|
||||
** be a correlated sub-query, and expression pExpr is an aggregate from
|
||||
** the parent context. Do not walk the function arguments in this case.
|
||||
**
|
||||
** todo: It should be possible to replace this node with a TK_REGISTER
|
||||
** expression, as the result of the expression must be stored in a
|
||||
** register at this point. The same holds for TK_AGG_COLUMN nodes. */
|
||||
}else if( pExpr->pAggInfo ){
|
||||
rc = WRC_Prune;
|
||||
reg = ++pWalker->pParse->nMem; /* Register for column value */
|
||||
reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
|
||||
pExpr->op = TK_REGISTER;
|
||||
pExpr->iTable = reg;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1133,7 +1131,7 @@ static void codeCursorHint(
|
||||
}
|
||||
if( pExpr!=0 ){
|
||||
sWalker.xExprCallback = codeCursorHintFixExpr;
|
||||
sqlite3WalkExpr(&sWalker, pExpr);
|
||||
if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr);
|
||||
sqlite3VdbeAddOp4(v, OP_CursorHint,
|
||||
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
|
||||
(const char*)pExpr, P4_EXPR);
|
||||
@@ -1927,7 +1925,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
** guess. */
|
||||
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
|
||||
(pIdx->aiRowLogEst[0]+9)/10);
|
||||
if( pRangeStart ){
|
||||
if( pRangeStart || pRangeEnd ){
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
|
||||
addrSeekScan = 0;
|
||||
@@ -1968,16 +1966,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
assert( pLevel->p2==0 );
|
||||
if( pRangeEnd ){
|
||||
Expr *pRight = pRangeEnd->pExpr->pRight;
|
||||
if( addrSeekScan ){
|
||||
/* For a seek-scan that has a range on the lowest term of the index,
|
||||
** we have to make the top of the loop be code that sets the end
|
||||
** condition of the range. Otherwise, the OP_SeekScan might jump
|
||||
** over that initialization, leaving the range-end value set to the
|
||||
** range-start value, resulting in a wrong answer.
|
||||
** See ticket 5981a8c041a3c2f3 (2021-11-02).
|
||||
*/
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
}
|
||||
assert( addrSeekScan==0 );
|
||||
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
|
||||
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
|
||||
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
|
||||
@@ -2011,7 +2000,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
|
||||
|
||||
/* Top of the loop body */
|
||||
if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
/* Check if the index cursor is past the end of the range. */
|
||||
if( nConstraint ){
|
||||
|
||||
@@ -785,6 +785,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
/* no break */ deliberate_fall_through
|
||||
|
||||
case TK_IF_NULL_ROW:
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_COLUMN: {
|
||||
int iCol = -1;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# 2023 March 30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix aggfault
|
||||
|
||||
|
||||
do_execsql_test 1 {
|
||||
CREATE TABLE t1(x);
|
||||
CREATE INDEX t1x ON t1(x, x=0);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2 -faults oom* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT * FROM sqlite_schema }
|
||||
} -body {
|
||||
execsql {
|
||||
SELECT * FROM t1 AS a1 WHERE (
|
||||
SELECT count(x AND 0=a1.x) FROM t1 GROUP BY abs(1)
|
||||
) AND x=(
|
||||
SELECT * FROM t1 AS a1
|
||||
WHERE (SELECT count(x IS 1 AND a1.x=0)
|
||||
FROM t1
|
||||
GROUP BY abs(1)) AND x=0
|
||||
);
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -981,4 +981,22 @@ do_catchsql_test 32.0 {
|
||||
ALTER TABLE t1 RENAME TO x;
|
||||
} {1 {error in trigger r1: no tables specified}}
|
||||
|
||||
# 2023-04-13 https://sqlite.org/forum/forumpost/ff3840145a
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 33.0 {
|
||||
CREATE TABLE t1(a TEXT);
|
||||
INSERT INTO t1(a) VALUES('abc'),('def'),(NULL);
|
||||
CREATE TABLE t2(b TEXT);
|
||||
CREATE TRIGGER r3 AFTER INSERT ON t1 BEGIN
|
||||
UPDATE t2 SET (b,a)=(SELECT 1) FROM t1 JOIN t2 ON (SELECT * FROM (SELECT a));
|
||||
END;
|
||||
}
|
||||
do_catchsql_test 33.1 {
|
||||
ALTER TABLE t1 RENAME COLUMN a TO b;
|
||||
} {1 {error in trigger r3 after rename: no such column: a}}
|
||||
do_execsql_test 33.2 {
|
||||
SELECT quote(a) FROM t1 ORDER BY +a;
|
||||
} {NULL 'abc' 'def'}
|
||||
|
||||
finish_test
|
||||
|
||||
+15
-1
@@ -275,6 +275,20 @@ do_execsql_test analyzeE-6.4 {
|
||||
SELECT count(*) FROM sqlite_stat4 WHERE idx='i1' AND neq<>'1 1 1 1 1 1';
|
||||
} 0
|
||||
|
||||
|
||||
# 2023-03-25 https://sqlite.org/forum/forumpost/5275207102
|
||||
# Correctly expand zeroblobs while processing STAT4 information
|
||||
# during query planning.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test analyzeE-7.0 {
|
||||
CREATE TABLE t1(a TEXT COLLATE binary);
|
||||
CREATE INDEX t1x ON t1(a);
|
||||
INSERT INTO t1(a) VALUES(0),('apple'),(NULL),(''),('banana');
|
||||
ANALYZE;
|
||||
SELECT format('(%s)',a) FROM t1 WHERE t1.a > CAST(zeroblob(5) AS TEXT);
|
||||
} {(0) (apple) (banana)}
|
||||
do_execsql_test analyzeE-7.1 {
|
||||
SELECT format('(%s)',a) FROM t1 WHERE t1.a <= CAST(zeroblob(5) AS TEXT);
|
||||
} {()}
|
||||
|
||||
finish_test
|
||||
|
||||
+6
-6
@@ -99,7 +99,7 @@ do_test corrupt2-1.4 {
|
||||
# of MemPage.nFree
|
||||
catchsql {PRAGMA quick_check} db2
|
||||
} {0 {{*** in database main ***
|
||||
Page 1: free space corruption}}}
|
||||
Tree 1 page 1: free space corruption}}}
|
||||
|
||||
do_test corrupt2-1.5 {
|
||||
db2 close
|
||||
@@ -120,7 +120,7 @@ do_test corrupt2-1.5 {
|
||||
sqlite3 db2 corrupt.db
|
||||
catchsql {PRAGMA quick_check} db2
|
||||
} {0 {{*** in database main ***
|
||||
Page 1: free space corruption}}}
|
||||
Tree 1 page 1: free space corruption}}}
|
||||
db2 close
|
||||
|
||||
# Corrupt a database by having 2 indices of the same name:
|
||||
@@ -248,8 +248,8 @@ do_test corrupt2-5.1 {
|
||||
}
|
||||
set result
|
||||
} {{*** in database main ***
|
||||
On tree page 2 cell 0: 2nd reference to page 10
|
||||
Page 4 is never used}}
|
||||
Tree 11 page 2 cell 0: 2nd reference to page 10
|
||||
Page 4: never used}}
|
||||
|
||||
db2 close
|
||||
|
||||
@@ -591,7 +591,7 @@ do_test 14.2 {
|
||||
do_execsql_test 14.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {{*** in database main ***
|
||||
Main freelist: size is 3 but should be 2}}
|
||||
Freelist: size is 3 but should be 2}}
|
||||
|
||||
# Use 2 of the free pages on the free-list.
|
||||
#
|
||||
@@ -603,7 +603,7 @@ do_execsql_test 14.4 {
|
||||
do_execsql_test 14.5 {
|
||||
PRAGMA integrity_check;
|
||||
} {{*** in database main ***
|
||||
Main freelist: size is 1 but should be 0}}
|
||||
Freelist: size is 1 but should be 0}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+5
-5
@@ -82,7 +82,7 @@ do_test corrupt3-1.8 {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 {{*** in database main ***
|
||||
On tree page 2 cell 0: 2nd reference to page 3}}}
|
||||
Tree 2 page 2 cell 0: 2nd reference to page 3}}}
|
||||
|
||||
# Change the pointer for the first page of the overflow
|
||||
# change to be a non-existant page.
|
||||
@@ -100,8 +100,8 @@ do_test corrupt3-1.10 {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 {{*** in database main ***
|
||||
On tree page 2 cell 0: invalid page number 4
|
||||
Page 3 is never used}}}
|
||||
Tree 2 page 2 cell 0: invalid page number 4
|
||||
Page 3: never used}}}
|
||||
do_test corrupt3-1.11 {
|
||||
db close
|
||||
hexio_write test.db 2044 [hexio_render_int32 0]
|
||||
@@ -115,7 +115,7 @@ do_test corrupt3-1.12 {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 {{*** in database main ***
|
||||
On tree page 2 cell 0: overflow list length is 0 but should be 1
|
||||
Page 3 is never used}}}
|
||||
Tree 2 page 2 cell 0: overflow list length is 0 but should be 1
|
||||
Page 3: never used}}}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -70,14 +70,14 @@ do_test corrupt7-2.1 {
|
||||
sqlite3 db test.db
|
||||
db eval {PRAGMA integrity_check(1)}
|
||||
} {{*** in database main ***
|
||||
On tree page 2 cell 15: Offset 65457 out of range 945..1020}}
|
||||
Tree 2 page 2 cell 15: Offset 65457 out of range 945..1020}}
|
||||
do_test corrupt7-2.2 {
|
||||
db close
|
||||
hexio_write test.db 1062 04
|
||||
sqlite3 db test.db
|
||||
db eval {PRAGMA integrity_check(1)}
|
||||
} {{*** in database main ***
|
||||
On tree page 2 cell 15: Offset 1201 out of range 945..1020}}
|
||||
Tree 2 page 2 cell 15: Offset 1201 out of range 945..1020}}
|
||||
|
||||
# The code path that was causing the buffer overrun that this test
|
||||
# case was checking for was removed.
|
||||
|
||||
+2
-2
@@ -98,7 +98,7 @@ do_test corruptC-2.1 {
|
||||
sqlite3 db test.db
|
||||
catchsql {PRAGMA integrity_check}
|
||||
} {0 {{*** in database main ***
|
||||
Page 3: free space corruption}}}
|
||||
Tree 3 page 3: free space corruption}}}
|
||||
|
||||
# test that a corrupt content offset size is handled (seed 5649)
|
||||
#
|
||||
@@ -165,7 +165,7 @@ do_test corruptC-2.5 {
|
||||
catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
|
||||
catchsql {PRAGMA integrity_check}
|
||||
} {0 {{*** in database main ***
|
||||
On tree page 4 cell 19: Extends off end of page} {database disk image is malformed}}}
|
||||
Tree 4 page 4 cell 19: Extends off end of page} {database disk image is malformed}}}
|
||||
|
||||
# {0 {{*** in database main ***
|
||||
# Corruption detected in cell 710 on page 4
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ do_test corruptD-1.1.1 {
|
||||
hexio_write test.db [expr 1024+1] FFFF
|
||||
catchsql { PRAGMA quick_check }
|
||||
} {0 {{*** in database main ***
|
||||
Page 2: free space corruption}}}
|
||||
Tree 2 page 2: free space corruption}}}
|
||||
do_test corruptD-1.1.2 {
|
||||
incr_change_counter
|
||||
hexio_write test.db [expr 1024+1] [hexio_render_int32 1021]
|
||||
|
||||
+1
-6
@@ -123,18 +123,13 @@ do_execsql_test 4.0 {
|
||||
set root [db one {SELECT rootpage FROM sqlite_master}]
|
||||
set offset [expr ($root-1) * 65536]
|
||||
|
||||
ifcapable oversize_cell_check {
|
||||
set res {1 {database disk image is malformed}}
|
||||
} else {
|
||||
set res {0 {}}
|
||||
}
|
||||
do_test 4.1 {
|
||||
db close
|
||||
hexio_write test.db [expr $offset + 8 + 2] 0000
|
||||
hexio_write test.db [expr $offset + 5] 0000
|
||||
sqlite3 db test.db
|
||||
catchsql { DELETE FROM t1 WHERE a=0 }
|
||||
} $res
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -76,4 +76,32 @@ do_execsql_test 4.1 {
|
||||
SELECT count(*) FROM t3 ORDER BY sum(a);
|
||||
} 1
|
||||
|
||||
# 2023-03-31 dbsqlfuzz 6a107e3055bd22afab31cfddabc2d9d54fcbaf69
|
||||
# Having clauses should disqualify count-of-view
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
INSERT INTO t1 VALUES(1,'one'),(4,'four');
|
||||
CREATE TABLE t2(c INTEGER PRIMARY KEY, d TEXT);
|
||||
INSERT INTO t2 VALUES(2,'two'),(5,'five');
|
||||
CREATE VIEW t3 AS SELECT a, b FROM t1 UNION ALL SELECT c, d FROM t2;
|
||||
SELECT count(*) FROM t3 HAVING count(*)>0;
|
||||
} 4
|
||||
do_execsql_test 5.2 {
|
||||
SELECT count(*) FROM t3 HAVING count(*)>5;
|
||||
} {}
|
||||
do_execsql_test 5.3 {
|
||||
SELECT count(*) FROM t3 HAVING max(b)>'mmm';
|
||||
} 4
|
||||
do_execsql_test 5.4 {
|
||||
SELECT count(*) FROM t3 HAVING min(b)>'mmm';
|
||||
} {}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT count(*) FROM (
|
||||
SELECT a, max(b) FROM t1 HAVING a<100 UNION ALL SELECT c, d FROM t2
|
||||
)
|
||||
} 3
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -180,4 +180,15 @@ do_execsql_test 5.1 {
|
||||
ORDER BY 1;
|
||||
}
|
||||
|
||||
# 2023-04-10 https://sqlite.org/forum/forumpost/0b53708c95
|
||||
#
|
||||
do_execsql_test 6.0 {
|
||||
CREATE TABLE t6(a TEXT UNIQUE, b TEXT);
|
||||
INSERT INTO t6(a,b) VALUES('uvw','xyz'),('abc','def');
|
||||
WITH v1(a) AS (SELECT a COLLATE NOCASE FROM t6)
|
||||
SELECT v1.a, count(*) FROM t6 LEFT JOIN v1 ON true
|
||||
GROUP BY 1
|
||||
HAVING (SELECT true FROM t6 AS aa LEFT JOIN t6 AS bb ON length(v1.a)>5);
|
||||
} {abc 2 uvw 2}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -272,4 +272,15 @@ do_catchsql_test 8.3 {
|
||||
REINDEX;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
# 2023-04-13 https://bugs.chromium.org/p/chromium/issues/detail?id=1405220
|
||||
# Avoid double-de-quoting of table names when processing foreign keys.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.1 {
|
||||
PRAGMA foreign_keys = ON;
|
||||
CREATE TABLE """1"("""2", """3" PRIMARY KEY);
|
||||
CREATE TABLE """4"("""5" REFERENCES """1" ON DELETE RESTRICT);
|
||||
DELETE FROM """1";
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+30
-2
@@ -829,7 +829,35 @@ do_execsql_test in-22.4 {
|
||||
SELECT * FROM t1 WHERE x IN ((((((SELECT a FROM t2))))));
|
||||
} {2 200 4 400 6 600}
|
||||
|
||||
|
||||
|
||||
# 2023-04-04 https://sqlite.org/forum/forumpost/dc16ec63d3
|
||||
# Faulty assert() statement in the IN optimization.
|
||||
#
|
||||
do_execsql_test in-23.0 {
|
||||
DROP TABLE IF EXISTS t4;
|
||||
CREATE TABLE t4(a TEXT, b INT);
|
||||
INSERT INTO t4(a,b) VALUES('abc',0),('ABC',1),('def',2);
|
||||
CREATE INDEX t4x ON t4(a, +a COLLATE NOCASE);
|
||||
SELECT a0.a, group_concat(a1.a) AS b
|
||||
FROM t4 AS a0 JOIN t4 AS a1
|
||||
GROUP BY a0.a
|
||||
HAVING (SELECT sum( (a1.a == +a0.a COLLATE NOCASE) IN (SELECT b FROM t4)));
|
||||
} {ABC abc,ABC,def abc abc,ABC,def def abc,ABC,def}
|
||||
do_execsql_test in-23.0-b {
|
||||
SELECT a0.a, group_concat(a1.a) AS b
|
||||
FROM t4 AS a0 JOIN t4 AS a1
|
||||
GROUP BY a0.a
|
||||
HAVING (SELECT sum( (a1.a GLOB +a0.a COLLATE NOCASE) IN (SELECT b FROM t4)));
|
||||
} {ABC abc,ABC,def abc abc,ABC,def def abc,ABC,def}
|
||||
#
|
||||
# Follow-up forum/forumpost/0713a16a44
|
||||
#
|
||||
do_execsql_test in-23.1 {
|
||||
CREATE VIEW t5 AS
|
||||
SELECT 1 AS b
|
||||
WHERE (SELECT count(0=NOT+a COLLATE NOCASE IN (SELECT 0))
|
||||
FROM t4
|
||||
GROUP BY a);
|
||||
SELECT * FROM t5;
|
||||
} 1
|
||||
|
||||
finish_test
|
||||
|
||||
+24
-1
@@ -591,6 +591,29 @@ do_execsql_test indexexpr1-2140 {
|
||||
SELECT b FROM t1;
|
||||
} 400
|
||||
|
||||
|
||||
# 2023-04-18 Forum post https://sqlite.org/forum/forumpost/f34e32d120 from
|
||||
# Alexis King.
|
||||
#
|
||||
# This problem originates at check-in b9190d3da70c4171 (2022-11-25).
|
||||
# A similar problem arose on 2023-03-04 at
|
||||
# https://sqlite.org/forum/forumpost/a68313d054 and was fixed at
|
||||
# check-in e06973876993926f. See the test case tkt-99378-400.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test indexexpr1-2200 {
|
||||
CREATE TABLE t1(id INTEGER PRIMARY KEY, tag INT);
|
||||
INSERT INTO t1 VALUES (0, 7), (1, 8);
|
||||
CREATE TABLE t2(type INT, t1_id INT, value INT);
|
||||
INSERT INTO t2 VALUES (0, 0, 100), (0, 1, 101);
|
||||
CREATE INDEX t1x ON t1(-tag);
|
||||
SELECT u.tag, v.max_value
|
||||
FROM (SELECT tag FROM t1 GROUP BY -tag) u
|
||||
JOIN (SELECT t1.tag AS "tag", t2.type AS "type",
|
||||
MAX(t2.value) AS "max_value"
|
||||
FROM t1
|
||||
JOIN t2 ON t2.t1_id = t1.id
|
||||
GROUP BY t2.type, t1.tag
|
||||
) v ON v.type = 0 AND v.tag = u.tag;
|
||||
} {7 100 8 101}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -386,4 +386,43 @@ do_execsql_test 9.0 {
|
||||
FROM t1 WHERE a=5;
|
||||
} {5 -5 205 5 20 220}
|
||||
|
||||
# 2023-04-03 https://sqlite.org/forum/forumpost/44270909bb
|
||||
# and https://sqlite.org/forum/forumpost/e45108732c which are the
|
||||
# same problem, namely the failure to omit the EP_Collate property
|
||||
# from an expression node when changing it from TK_COLLATE into
|
||||
# TK_AGG_COLUMN because it resolves to an indexed expression.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
|
||||
CREATE INDEX t1x ON t1 (b, +b COLLATE NOCASE);
|
||||
INSERT INTO t1(a,b) VALUES(1,'abcde');
|
||||
SELECT * FROM t1 AS a0
|
||||
WHERE (SELECT count(a0.b=+a0.b COLLATE NOCASE IN (b)) FROM t1 GROUP BY 2.5)
|
||||
ORDER BY a0.b;
|
||||
} {1 abcde}
|
||||
do_execsql_test 10.1 {
|
||||
CREATE TABLE t2(a TEXT);
|
||||
INSERT INTO t2 VALUES('alice'),('bob'),('cindy'),('david');
|
||||
CREATE INDEX t2x ON t2 (+a COLLATE NOCASE);
|
||||
SELECT count(+a COLLATE NOCASE IN (SELECT 1)) AS x
|
||||
FROM t2
|
||||
GROUP BY SUBSTR(0,0);
|
||||
} 4
|
||||
|
||||
# 2023-04-03 https://sqlite.org/forum/forumpost/409ebc7368
|
||||
# When a generated column appears in both an outer and an inner loop
|
||||
# (that is to say, the same table is used in both loops) and the
|
||||
# generated column is indexed and it is used inside an aggregate function,
|
||||
# make sure that the terms resolve to the correct aggregate.
|
||||
#
|
||||
do_execsql_test 11.0 {
|
||||
CREATE TABLE t3 (a INT, b AS (-a));
|
||||
CREATE INDEX t3x ON t3(b, a);
|
||||
INSERT INTO t3(a) VALUES(44);
|
||||
SELECT * FROM t3 AS a0
|
||||
WHERE (SELECT sum(-a0.a=b) FROM t3 GROUP BY b)
|
||||
GROUP BY b;
|
||||
} {44 -44}
|
||||
|
||||
finish_test
|
||||
|
||||
+48
-35
@@ -433,9 +433,9 @@ ifcapable attach {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_execsql_test pragma-3.9b {
|
||||
PRAGMA t2.integrity_check=t2;
|
||||
} {{row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
@@ -447,79 +447,79 @@ Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2
|
||||
PRAGMA integrity_check=1
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used}}
|
||||
Page 4: never used}}
|
||||
do_test pragma-3.11 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=5
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2}}
|
||||
do_test pragma-3.12 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=4
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
do_test pragma-3.13 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=3
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used}}
|
||||
do_test pragma-3.14 {
|
||||
execsql {
|
||||
PRAGMA integrity_check(2)
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used}}
|
||||
Page 4: never used
|
||||
Page 5: never used}}
|
||||
do_test pragma-3.15 {
|
||||
execsql {
|
||||
ATTACH 'testerr.db' AS t3;
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2}}
|
||||
do_test pragma-3.16 {
|
||||
execsql {
|
||||
PRAGMA integrity_check(10)
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
do_test pragma-3.17 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=8
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2} {row 2 missing from index i2} {wrong # of entries in index i2} {*** in database t3 ***
|
||||
Page 4: never used
|
||||
Page 5: never used}}
|
||||
do_test pragma-3.18 {
|
||||
execsql {
|
||||
PRAGMA integrity_check=4
|
||||
}
|
||||
} {{*** in database t2 ***
|
||||
Page 4 is never used
|
||||
Page 5 is never used
|
||||
Page 6 is never used} {row 1 missing from index i2}}
|
||||
Page 4: never used
|
||||
Page 5: never used
|
||||
Page 6: never used} {row 1 missing from index i2}}
|
||||
}
|
||||
do_test pragma-3.19 {
|
||||
catch {db close}
|
||||
@@ -2060,4 +2060,17 @@ ifcapable !has_codec {
|
||||
} {0 {{database disk image is malformed}}}
|
||||
}
|
||||
database_never_corrupt
|
||||
|
||||
# 2023-03-27. Register allocation issue in integrity_check discovered
|
||||
# by new assert() statements added in [6f8b97f31a4c8552].
|
||||
# dbsqlfuzz dc9ab26037cf5ef797d28cd1ae0855ade584216d
|
||||
# tag-20230327-1
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 25.0 {
|
||||
CREATE TABLE t1(a INT, b AS (a*2) NOT NULL);
|
||||
CREATE TEMP TABLE t2(a PRIMARY KEY, b, c UNIQUE) WITHOUT ROWID;
|
||||
CREATE UNIQUE INDEX t2x ON t2(c,b);
|
||||
PRAGMA integrity_check;
|
||||
} ok
|
||||
finish_test
|
||||
|
||||
@@ -414,6 +414,7 @@ do_execsql_test 17.0 {
|
||||
do_execsql_test 18.0 {
|
||||
CREATE TABLE v0(c1 INT);
|
||||
CREATE VIEW view_2(c1) AS SELECT CASE WHEN c1 COLLATE TRUE THEN TRUE ELSE TRUE END FROM v0;
|
||||
CREATE TRIGGER x1 INSTEAD OF INSERT ON view_2 BEGIN SELECT true; END;
|
||||
}
|
||||
do_catchsql_test 18.1 {
|
||||
INSERT INTO view_2 DEFAULT VALUES RETURNING *;
|
||||
|
||||
@@ -242,6 +242,34 @@ QUERY (nCycle=nnn)
|
||||
--SEARCH v1 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
ifcapable trace {
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
|
||||
SELECT 1;
|
||||
END;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
|
||||
proc trace {stmt sql} {
|
||||
array set A [sqlite3_stmt_scanstatus -flags complex [format %x $stmt] 0]
|
||||
lappend ::trace_explain $A(zExplain)
|
||||
}
|
||||
db trace_v2 trace
|
||||
|
||||
set ::trace_explain [list]
|
||||
do_execsql_test 5.1 {
|
||||
DELETE FROM t1 WHERE x=1;
|
||||
}
|
||||
|
||||
do_test 5.2 {
|
||||
set ::trace_explain
|
||||
} {{SCAN t1} {SCAN t1} {SCAN t1}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ do_execsql_test 1.0 {
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
SELECT a,b,c FROM t1
|
||||
WHERE b IN (234, 345) AND c BETWEEN 6 AND 6.5 AND a='abc'
|
||||
@@ -59,5 +60,9 @@ do_execsql_test 1.4 {
|
||||
abc 345 7
|
||||
}
|
||||
|
||||
do_execsql_test 1.5 {
|
||||
SELECT a,b,c FROM t1 WHERE b IN (235, 345) AND c<=3 AND a='abc' ORDER BY a, b;
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+9
-1
@@ -12,6 +12,7 @@ static const char zHelp[] =
|
||||
" --checkpoint Run PRAGMA wal_checkpoint after each test case\n"
|
||||
" --exclusive Enable locking_mode=EXCLUSIVE\n"
|
||||
" --explain Like --sqlonly but with added EXPLAIN keywords\n"
|
||||
" --fullfsync Enable fullfsync=TRUE\n"
|
||||
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
|
||||
" --incrvacuum Enable incremenatal vacuum mode\n"
|
||||
" --journal M Set the journal_mode to M\n"
|
||||
@@ -2203,6 +2204,7 @@ int main(int argc, char **argv){
|
||||
int doAutovac = 0; /* True for --autovacuum */
|
||||
int cacheSize = 0; /* Desired cache size. 0 means default */
|
||||
int doExclusive = 0; /* True for --exclusive */
|
||||
int doFullFSync = 0; /* True for --fullfsync */
|
||||
int nHeap = 0, mnHeap = 0; /* Heap size from --heap */
|
||||
int doIncrvac = 0; /* True for --incrvacuum */
|
||||
const char *zJMode = 0; /* Journal mode */
|
||||
@@ -2267,6 +2269,8 @@ int main(int argc, char **argv){
|
||||
cacheSize = integerValue(argv[++i]);
|
||||
}else if( strcmp(z,"exclusive")==0 ){
|
||||
doExclusive = 1;
|
||||
}else if( strcmp(z,"fullfsync")==0 ){
|
||||
doFullFSync = 1;
|
||||
}else if( strcmp(z,"checkpoint")==0 ){
|
||||
g.doCheckpoint = 1;
|
||||
}else if( strcmp(z,"explain")==0 ){
|
||||
@@ -2511,7 +2515,11 @@ int main(int argc, char **argv){
|
||||
if( cacheSize ){
|
||||
speedtest1_exec("PRAGMA cache_size=%d", cacheSize);
|
||||
}
|
||||
if( noSync ) speedtest1_exec("PRAGMA synchronous=OFF");
|
||||
if( noSync ){
|
||||
speedtest1_exec("PRAGMA synchronous=OFF");
|
||||
}else if( doFullFSync ){
|
||||
speedtest1_exec("PRAGMA fullfsync=ON");
|
||||
}
|
||||
if( doExclusive ){
|
||||
speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE");
|
||||
}
|
||||
|
||||
@@ -178,6 +178,8 @@ do_execsql_test tkt-99378-310 {
|
||||
|
||||
# 2023-03-04 https://sqlite.org/forum/forumpost/a68313d054
|
||||
#
|
||||
# See also indexexpr1-2200 added on 2023-03-18.
|
||||
#
|
||||
do_execsql_test tkt-99378-400 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t0(w);
|
||||
|
||||
+2
-8
@@ -177,8 +177,6 @@
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
/* Forward declarations */
|
||||
typedef struct vt02_vtab vt02_vtab;
|
||||
typedef struct vt02_cur vt02_cur;
|
||||
@@ -381,7 +379,7 @@ static int vt02Filter(
|
||||
sqlite3_int64 v;
|
||||
pVal = 0;
|
||||
if( sqlite3_vtab_in_first(0, &pVal)!=SQLITE_MISUSE
|
||||
|| sqlite3_vtab_in_first(argv[iArg], &pVal)!=SQLITE_MISUSE
|
||||
|| sqlite3_vtab_in_first(argv[iArg], &pVal)!=SQLITE_ERROR
|
||||
){
|
||||
vt02ErrMsg(pCursor->pVtab,
|
||||
"unexpected success from sqlite3_vtab_in_first()");
|
||||
@@ -420,7 +418,7 @@ static int vt02Filter(
|
||||
}
|
||||
if( bUseOffset ){
|
||||
int nSkip = sqlite3_value_int(argv[iArg]);
|
||||
while( nSkip-- > 0 ) vt02Next(pCursor);
|
||||
while( nSkip-- > 0 && pCur->i<pCur->iEof ) vt02Next(pCursor);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
@@ -1001,10 +999,6 @@ static void vt02CoreInit(sqlite3 *db){
|
||||
sqlite3_create_module(db, "vt02pkabcd", &vt02Module, (void*)zPkABCDSchema);
|
||||
}
|
||||
|
||||
#else
|
||||
# define vt02CoreInit(db)
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef TH3_VERSION
|
||||
static void vt02_init(th3state *p, int iDb, char *zArg){
|
||||
vt02CoreInit(th3dbPointer(p, iDb));
|
||||
|
||||
@@ -2225,5 +2225,142 @@ do_execsql_test 72.1 {
|
||||
WHERE ('1' IS NOT ('abcde' NOTNULL));
|
||||
} {1}
|
||||
|
||||
# 2023-03-28 https://sqlite.org/forum/forumpost/dc3b92cfa0 (Song Liu)
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 73.0 {
|
||||
CREATE TABLE t1(a INT);
|
||||
INSERT INTO t1(a) VALUES(1),(2),(4);
|
||||
CREATE VIEW t2(b,c) AS SELECT * FROM t1 JOIN t1 A ORDER BY sum(0) OVER(PARTITION BY 0);
|
||||
CREATE TRIGGER x1 INSTEAD OF UPDATE ON t2 BEGIN SELECT true; END;
|
||||
}
|
||||
do_execsql_test 73.1 {
|
||||
SELECT * FROM t2;
|
||||
} {1 1 1 2 1 4 2 1 2 2 2 4 4 1 4 2 4 4}
|
||||
do_execsql_test 73.2 {
|
||||
UPDATE t2 SET c=99 WHERE b=4 RETURNING *;
|
||||
} {4 99 4 99 4 99}
|
||||
do_execsql_test 73.3 {
|
||||
SELECT *, nth_value(15,2) OVER() FROM t2, t1 WHERE b=4;
|
||||
} {
|
||||
4 1 1 15
|
||||
4 2 1 15
|
||||
4 4 1 15
|
||||
4 1 2 15
|
||||
4 2 2 15
|
||||
4 4 2 15
|
||||
4 1 4 15
|
||||
4 2 4 15
|
||||
4 4 4 15
|
||||
}
|
||||
do_execsql_test 73.4 {
|
||||
UPDATE t2 SET c=nth_value(15,2) OVER() FROM (SELECT * FROM t1) WHERE b=4 RETURNING *;
|
||||
} {
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
4 15
|
||||
}
|
||||
do_execsql_test 73.5 {
|
||||
DROP TRIGGER x1;
|
||||
}
|
||||
do_catchsql_test 73.6 {
|
||||
UPDATE t2 SET c=99 WHERE b=4 RETURNING *;
|
||||
} {1 {cannot modify t2 because it is a view}}
|
||||
do_catchsql_test 73.7 {
|
||||
UPDATE t2 SET c=nth_value(15,2) OVER() FROM (SELECT * FROM t1) WHERE b=4 RETURNING *;
|
||||
} {1 {cannot modify t2 because it is a view}}
|
||||
|
||||
# 2023-03-28 https://sqlite.org/forum/forumpost/bad532820c
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 74.0 {
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
CREATE TABLE t2 (c INT, d INT);
|
||||
CREATE INDEX idx ON t1(abs(a));
|
||||
INSERT INTO t1 VALUES(1,2),(3,4);
|
||||
INSERT INTO t2 VALUES(5,6),(7,8);
|
||||
}
|
||||
do_execsql_test 74.1 {
|
||||
SELECT (
|
||||
SELECT count( a ) FROM t2 LIMIT 1
|
||||
)
|
||||
FROM t1;
|
||||
} {2} ;# Verified using PG 14.2
|
||||
do_execsql_test 74.2 {
|
||||
SELECT (
|
||||
SELECT count( a+c ) FROM t2 LIMIT 1
|
||||
)
|
||||
FROM t1;
|
||||
} {2 2} ;# verified on PG 14.2. Crashes PG 9.6!
|
||||
do_execsql_test 74.3 {
|
||||
SELECT (
|
||||
SELECT count( ( SELECT(sum(0) OVER(ORDER BY c, abs(a))) ) )
|
||||
FROM t2 GROUP BY c LIMIT 1
|
||||
)
|
||||
FROM t1;
|
||||
} {1 1} ;# verified on PG 14.2
|
||||
do_execsql_test 74.4 {
|
||||
/* Original test case reported in https://sqlite.org/forum/forumpost/bad532820c
|
||||
CREATE TABLE v0 (c1);
|
||||
CREATE INDEX i ON v0 (c1, c1=1);
|
||||
SELECT 0 FROM v0 AS a1
|
||||
WHERE (SELECT count((SELECT(sum(0) OVER(PARTITION BY(c1), (a1.c1=1) ))))
|
||||
FROM v0
|
||||
GROUP BY hex(0))
|
||||
AND a1.c1=0;
|
||||
} {}
|
||||
|
||||
# 2023-04-11 https://sqlite.org/forum/forumpost/6c5678e3da
|
||||
# An ALWAYS() turns out to be sometimes false.
|
||||
#
|
||||
do_execsql_test 75.0 {
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
CREATE INDEX t1x ON t1(a+b);
|
||||
}
|
||||
do_catchsql_test 75.1 {
|
||||
SELECT count((SELECT count(a0.a+a0.b) ORDER BY sum(0) OVER (PARTITION BY 0)))
|
||||
FROM t1 AS a0 JOIN t1 AS a1
|
||||
GROUP BY a1.a;
|
||||
} {1 {misuse of aggregate: count()}}
|
||||
|
||||
# 2023-04-13 https://sqlite.org/forum/forumpost/0d48347967
|
||||
reset_db
|
||||
do_execsql_test 76.0 {
|
||||
CREATE TABLE t1(a INT, b INT);
|
||||
INSERT INTO t1(a,b) VALUES (111,222),(111,223),(118,229);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
CREATE TABLE t2(x INT);
|
||||
INSERT INTO t2 VALUES (333),(444),(555);
|
||||
}
|
||||
do_execsql_test 76.1 {
|
||||
SELECT c, (SELECT c + sum(1) OVER ()) AS "res"
|
||||
FROM t2 LEFT JOIN (SELECT +a AS c FROM t1) AS v1 ON true
|
||||
GROUP BY c
|
||||
ORDER by c;
|
||||
} {111 112 118 119}
|
||||
# ^^^^^^^^^^^^^^^^^-- results verified against PG 14.2
|
||||
|
||||
do_execsql_test 76.2 {
|
||||
CREATE TABLE t3(x);
|
||||
CREATE TABLE t4(y);
|
||||
INSERT INTO t3 VALUES(100), (200), (400);
|
||||
INSERT INTO t4 VALUES(100), (300), (400);
|
||||
}
|
||||
do_execsql_test 76.3 {
|
||||
SELECT (SELECT y+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y;
|
||||
} {100 {} 400}
|
||||
do_execsql_test 76.4 {
|
||||
SELECT (SELECT y+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y GROUP BY x;
|
||||
} {100 {} 400}
|
||||
do_execsql_test 76.5 {
|
||||
SELECT (SELECT max(y)+sum(0) OVER ()) FROM t3 LEFT JOIN t4 ON x=y GROUP BY x;
|
||||
} {100 {} 400}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -596,7 +596,7 @@ int main(int argc, char **argv){
|
||||
printf("/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0\n");
|
||||
printf("** then the i-th keyword has no more hash collisions. Otherwise,\n");
|
||||
printf("** the next keyword with the same hash is aKWHash[i]-1. */\n");
|
||||
printf("static const unsigned char aKWNext[%d] = {\n", nKeyword);
|
||||
printf("static const unsigned char aKWNext[%d] = {0,\n", nKeyword+1);
|
||||
for(i=j=0; i<nKeyword; i++){
|
||||
if( j==0 ) printf(" ");
|
||||
printf(" %3d,", aKeywordTable[i].iNext);
|
||||
@@ -609,7 +609,7 @@ int main(int argc, char **argv){
|
||||
printf("%s};\n", j==0 ? "" : "\n");
|
||||
|
||||
printf("/* aKWLen[i] is the length (in bytes) of the i-th keyword */\n");
|
||||
printf("static const unsigned char aKWLen[%d] = {\n", nKeyword);
|
||||
printf("static const unsigned char aKWLen[%d] = {0,\n", nKeyword+1);
|
||||
for(i=j=0; i<nKeyword; i++){
|
||||
if( j==0 ) printf(" ");
|
||||
printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
|
||||
@@ -623,7 +623,7 @@ int main(int argc, char **argv){
|
||||
|
||||
printf("/* aKWOffset[i] is the index into zKWText[] of the start of\n");
|
||||
printf("** the text for the i-th keyword. */\n");
|
||||
printf("static const unsigned short int aKWOffset[%d] = {\n", nKeyword);
|
||||
printf("static const unsigned short int aKWOffset[%d] = {0,\n", nKeyword+1);
|
||||
for(i=j=0; i<nKeyword; i++){
|
||||
if( j==0 ) printf(" ");
|
||||
printf(" %3d,", aKeywordTable[i].offset);
|
||||
@@ -636,7 +636,7 @@ int main(int argc, char **argv){
|
||||
printf("%s};\n", j==0 ? "" : "\n");
|
||||
|
||||
printf("/* aKWCode[i] is the parser symbol code for the i-th keyword */\n");
|
||||
printf("static const unsigned char aKWCode[%d] = {\n", nKeyword);
|
||||
printf("static const unsigned char aKWCode[%d] = {0,\n", nKeyword+1);
|
||||
for(i=j=0; i<nKeyword; i++){
|
||||
char *zToken = aKeywordTable[i].zTokenType;
|
||||
if( j==0 ) printf(" ");
|
||||
@@ -669,7 +669,7 @@ int main(int argc, char **argv){
|
||||
printf(" i = ((charMap(z[0])*%d) %c", HASH_C0, HASH_CC);
|
||||
printf(" (charMap(z[n-1])*%d) %c", HASH_C1, HASH_CC);
|
||||
printf(" n*%d) %% %d;\n", HASH_C2, bestSize);
|
||||
printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n");
|
||||
printf(" for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){\n");
|
||||
printf(" if( aKWLen[i]!=n ) continue;\n");
|
||||
printf(" zKW = &zKWText[aKWOffset[i]];\n");
|
||||
printf("#ifdef SQLITE_ASCII\n");
|
||||
@@ -687,7 +687,7 @@ int main(int argc, char **argv){
|
||||
printf(" if( j<n ) continue;\n");
|
||||
for(i=0; i<nKeyword; i++){
|
||||
printf(" testcase( i==%d ); /* %s */\n",
|
||||
i, aKeywordTable[i].zOrigName);
|
||||
i+1, aKeywordTable[i].zOrigName);
|
||||
}
|
||||
printf(" *pType = aKWCode[i];\n");
|
||||
printf(" break;\n");
|
||||
@@ -703,6 +703,7 @@ int main(int argc, char **argv){
|
||||
printf("#define SQLITE_N_KEYWORD %d\n", nKeyword);
|
||||
printf("int sqlite3_keyword_name(int i,const char **pzName,int *pnName){\n");
|
||||
printf(" if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;\n");
|
||||
printf(" i++;\n");
|
||||
printf(" *pzName = zKWText + aKWOffset[i];\n");
|
||||
printf(" *pnName = aKWLen[i];\n");
|
||||
printf(" return SQLITE_OK;\n");
|
||||
|
||||
Reference in New Issue
Block a user