1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge the latest trunk changes into the reuse-schema branch.

FossilOrigin-Name: 3d1b0403d657cf147cda58eee0f05f5e2837a10f1741375db77e11cc53c4a476
This commit is contained in:
drh
2023-12-28 14:07:27 +00:00
61 changed files with 1944 additions and 430 deletions

View File

@@ -88,8 +88,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
** This function attempts to retrieve the text of column iCol of the
** current document. If successful, (*pz) is set to point to a buffer
** If parameter iCol is less than zero, or greater than or equal to the
** number of columns in the table, SQLITE_RANGE is returned.
**
** Otherwise, this function attempts to retrieve the text of column iCol of
** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -99,8 +102,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
** Returns the number of tokens in phrase iPhrase of the query. Phrases
** are numbered starting from zero.
** If parameter iCol is less than zero, or greater than or equal to the
** number of phrases in the current query, as returned by xPhraseCount,
** 0 is returned. Otherwise, this function returns the number of tokens in
** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -116,12 +121,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
** output by xInstCount().
** output by xInstCount(). If iIdx is less than zero or greater than
** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
** first token of the phrase. Returns SQLITE_OK if successful, or an error
** code (i.e. SQLITE_NOMEM) if an error occurs.
** first token of the phrase. SQLITE_OK is returned if successful, or an
** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -147,6 +153,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
** If parameter iPhrase is less than zero, or greater than or equal to
** the number of phrases in the query, as returned by xPhraseCount(),
** this function returns SQLITE_RANGE.
**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -268,17 +278,25 @@ struct Fts5PhraseIter {
** to a buffer containing the requested token, and *pnToken to the
** size of this buffer in bytes.
**
** If iPhrase or iToken are less than zero, or if iPhrase is greater than
** or equal to the number of phrases in the query as reported by
** xPhraseCount(), or if iToken is equal to or greater than the number of
** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
are both zeroed.
**
** The output text is not a copy of the query text that specified the
** token. It is the output of the tokenizer module. For tokendata=1
** tables, this includes any embedded 0x00 and trailing data.
**
** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
** This is used to access token iToken of phrase hit iIdx within the
** current row. Output variable (*ppToken) is set to point to a buffer
** containing the matching document token, and (*pnToken) to the size
** of that buffer in bytes. This API is not available if the specified
** token matches a prefix query term. In that case both output variables
** are always set to 0.
** current row. If iIdx is less than zero or greater than or equal to the
** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
** output variable (*ppToken) is set to point to a buffer containing the
** matching document token, and (*pnToken) to the size of that buffer in
** bytes. This API is not available if the specified token matches a
** prefix query term. In that case both output variables are always set
** to 0.
**
** The output text is not a copy of the document text that was tokenized.
** It is the output of the tokenizer module. For tokendata=1 tables, this

View File

@@ -252,8 +252,10 @@ static void fts5HighlightFunction(
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
if( ctx.zIn ){
if( rc==SQLITE_RANGE ){
sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
rc = SQLITE_OK;
}else if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}

View File

@@ -68,6 +68,7 @@ void sqlite3Fts5BufferAppendBlob(
){
if( nData ){
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
assert( pBuf->p!=0 );
memcpy(&pBuf->p[pBuf->n], pData, nData);
pBuf->n += nData;
}
@@ -169,6 +170,7 @@ int sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
){
int i = *pi;
assert( a!=0 || i==0 );
if( i>=n ){
/* EOF */
*piOff = -1;
@@ -176,6 +178,7 @@ int sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
u32 iVal;
assert( a!=0 );
fts5FastGetVarint32(a, i, iVal);
if( iVal<=1 ){
if( iVal==0 ){

View File

@@ -1740,7 +1740,9 @@ static int fts5ParseTokenize(
memset(pSyn, 0, (size_t)nByte);
pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
if( pCtx->pConfig->bTokendata ) pSyn->nQueryTerm = strlen(pSyn->pTerm);
if( pCtx->pConfig->bTokendata ){
pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
}
memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
@@ -1769,7 +1771,7 @@ static int fts5ParseTokenize(
pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
pTerm->nQueryTerm = strlen(pTerm->pTerm);
pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
}
}
}
@@ -1888,8 +1890,12 @@ int sqlite3Fts5ExprClonePhrase(
Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
pOrig = pExpr->apExprPhrase[iPhrase];
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
rc = SQLITE_RANGE;
}else{
pOrig = pExpr->apExprPhrase[iPhrase];
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
}
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
@@ -1916,25 +1922,27 @@ int sqlite3Fts5ExprClonePhrase(
}
}
if( pOrig->nTerm ){
int i; /* Used to iterate through phrase terms */
sCtx.pConfig = pExpr->pConfig;
for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
int tflags = 0;
Fts5ExprTerm *p;
for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
rc = fts5ParseTokenize((void*)&sCtx, tflags, p->pTerm,p->nFullTerm,0,0);
tflags = FTS5_TOKEN_COLOCATED;
}
if( rc==SQLITE_OK ){
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
if( rc==SQLITE_OK ){
if( pOrig->nTerm ){
int i; /* Used to iterate through phrase terms */
sCtx.pConfig = pExpr->pConfig;
for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
int tflags = 0;
Fts5ExprTerm *p;
for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
tflags = FTS5_TOKEN_COLOCATED;
}
if( rc==SQLITE_OK ){
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
}
}
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
@@ -3247,4 +3255,3 @@ void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
}
}
}

View File

@@ -360,6 +360,7 @@ struct Fts5Index {
/* Error state. */
int rc; /* Current error code */
int flushRc;
/* State used by the fts5DataXXX() functions. */
sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
@@ -1546,9 +1547,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}
if( iOff<pData->nn ){
i64 iVal;
u64 iVal;
pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
iOff += fts5GetVarint(&pData->p[iOff], &iVal);
pLvl->iRowid += iVal;
pLvl->iOff = iOff;
}else{
@@ -4120,6 +4121,7 @@ static void fts5IndexDiscardData(Fts5Index *p){
sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
p->nPendingRow = 0;
p->flushRc = SQLITE_OK;
}
p->nContentlessDelete = 0;
}
@@ -5701,6 +5703,10 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
if( p->flushRc ){
p->rc = p->flushRc;
return;
}
if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
fts5FlushOneHash(p);
@@ -5709,6 +5715,8 @@ static void fts5IndexFlush(Fts5Index *p){
p->nPendingData = 0;
p->nPendingRow = 0;
p->nContentlessDelete = 0;
}else if( p->nPendingData || p->nContentlessDelete ){
p->flushRc = p->rc;
}
}
}
@@ -6879,7 +6887,7 @@ static Fts5Iter *fts5SetupTokendataIter(
fts5IndexFlush(p);
pStruct = fts5StructureRead(p);
while( 1 ){
while( p->rc==SQLITE_OK ){
Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
Fts5Iter *pNew = 0;
Fts5SegIter *pNewIter = 0;
@@ -6888,14 +6896,16 @@ static Fts5Iter *fts5SetupTokendataIter(
int iLvl, iSeg, ii;
pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
if( pNew==0 ) break;
if( pSmall ){
fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
}else{
fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
}
if( p->rc ){
sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
break;
}
pNewIter = &pNew->aSeg[0];
pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
@@ -6930,6 +6940,7 @@ static Fts5Iter *fts5SetupTokendataIter(
pNewIter++;
if( pPrevIter ) pPrevIter++;
if( p->rc ) break;
}
}
fts5TokendataSetTermIfEof(pPrev, pSmall);
@@ -7021,6 +7032,10 @@ int sqlite3Fts5IndexQuery(
int bTokendata = pConfig->bTokendata;
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
bTokendata = 0;
}
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
@@ -7032,7 +7047,6 @@ int sqlite3Fts5IndexQuery(
** for internal sanity checking by the integrity-check in debug
** mode only. */
#ifdef SQLITE_DEBUG
if( flags & FTS5INDEX_QUERY_NOTOKENDATA ) bTokendata = 0;
if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
assert( flags & FTS5INDEX_QUERY_PREFIX );
iIdx = 1+pConfig->nPrefix;
@@ -7211,7 +7225,7 @@ int sqlite3Fts5IterToken(
*/
void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
if( pIter->pTokenDataIter ){
if( pIter && pIter->pTokenDataIter ){
pIter->pTokenDataIter->nMap = 0;
}
}
@@ -7930,7 +7944,7 @@ static void fts5IndexIntegrityCheckEmpty(
}
static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
int iTermOff = 0;
i64 iTermOff = 0;
int ii;
Fts5Buffer buf1 = {0,0,0};
@@ -7939,7 +7953,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
ii = pLeaf->szLeaf;
while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
int res;
int iOff;
i64 iOff;
int nIncr;
ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);

View File

@@ -118,7 +118,7 @@ struct Fts5FullTable {
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
int iSavepoint; /* Successful xSavepoint()+1 */
int bInSavepoint;
#ifdef SQLITE_DEBUG
struct Fts5TransactionState ts;
#endif
@@ -1911,7 +1911,10 @@ static int fts5ApiColumnText(
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
if( iCol<0 || iCol>=pTab->pConfig->nCol ){
rc = SQLITE_RANGE;
}else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|| pCsr->ePlan==FTS5_PLAN_SPECIAL
){
*pz = 0;
@@ -1936,8 +1939,9 @@ static int fts5CsrPoslist(
int rc = SQLITE_OK;
int bLive = (pCsr->pSorter==0);
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
rc = SQLITE_RANGE;
}else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
@@ -1961,15 +1965,21 @@ static int fts5CsrPoslist(
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
}
if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
Fts5Sorter *pSorter = pCsr->pSorter;
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
*pn = pSorter->aIdx[iPhrase] - i1;
*pa = &pSorter->aPoslist[i1];
if( rc==SQLITE_OK ){
if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
Fts5Sorter *pSorter = pCsr->pSorter;
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
*pn = pSorter->aIdx[iPhrase] - i1;
*pa = &pSorter->aPoslist[i1];
}else{
*pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
}
}else{
*pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
*pa = 0;
*pn = 0;
}
return rc;
}
@@ -2667,9 +2677,7 @@ static int fts5RenameMethod(
){
int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
pTab->bInSavepoint = 1;
rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
pTab->bInSavepoint = 0;
return rc;
}
@@ -2686,26 +2694,12 @@ int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
int rc = SQLITE_OK;
char *zSql = 0;
fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
if( pTab->bInSavepoint==0 ){
zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName
);
if( zSql ){
pTab->bInSavepoint = 1;
rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0);
pTab->bInSavepoint = 0;
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
pTab->iSavepoint = iSavepoint+1;
}
rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
if( rc==SQLITE_OK ){
pTab->iSavepoint = iSavepoint+1;
}
return rc;
}
@@ -2966,7 +2960,7 @@ static int fts5ShadowName(const char *zName){
** if anything is found amiss. Return a NULL pointer if everything is
** OK.
*/
static int fts5Integrity(
static int fts5IntegrityMethod(
sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
const char *zSchema, /* Name of schema in which this table lives */
const char *zTabname, /* Name of the table itself */
@@ -3024,7 +3018,7 @@ static int fts5Init(sqlite3 *db){
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
/* xShadowName */ fts5ShadowName,
/* xIntegrity */ fts5Integrity
/* xIntegrity */ fts5IntegrityMethod
};
int rc;

View File

@@ -673,7 +673,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){

View File

@@ -629,7 +629,7 @@ static int fts5VocabFilterMethod(
if( pEq ){
zTerm = (const char *)sqlite3_value_text(pEq);
nTerm = sqlite3_value_bytes(pEq);
f = 0;
f = FTS5INDEX_QUERY_NOTOKENDATA;
}else{
if( pGe ){
zTerm = (const char *)sqlite3_value_text(pGe);

View File

@@ -61,6 +61,12 @@ proc fts5_test_collist {cmd} {
set res
}
proc fts5_collist {cmd iPhrase} {
set res [list]
$cmd xPhraseColumnForeach $iPhrase c { lappend res $c }
set res
}
proc fts5_test_columnsize {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -69,6 +75,10 @@ proc fts5_test_columnsize {cmd} {
set res
}
proc fts5_columntext {cmd iCol} {
$cmd xColumnText $iCol
}
proc fts5_test_columntext {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -125,6 +135,13 @@ proc fts5_test_queryphrase {cmd} {
set res
}
proc fts5_queryphrase {cmd iPhrase} {
set cnt [list]
for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 }
$cmd xQueryPhrase $iPhrase [list test_queryphrase_cb cnt]
set cnt
}
proc fts5_test_phrasecount {cmd} {
$cmd xPhraseCount
}
@@ -154,6 +171,9 @@ proc fts5_aux_test_functions {db} {
fts5_test_queryphrase
fts5_test_phrasecount
fts5_columntext
fts5_queryphrase
fts5_collist
} {
sqlite3_fts5_create_function $db $f $f
}

View File

@@ -334,4 +334,47 @@ do_execsql_test 11.2 {
SELECT fts5_hitcount(x1) FROM x1('one') LIMIT 1;
} {5}
#-------------------------------------------------------------------------
# Test that xColumnText returns SQLITE_RANGE when it should.
#
reset_db
fts5_aux_test_functions db
do_execsql_test 12.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
INSERT INTO t1 VALUES('one', 'two', 'three');
INSERT INTO t1 VALUES('one', 'one', 'one');
INSERT INTO t1 VALUES('two', 'two', 'two');
INSERT INTO t1 VALUES('three', 'three', 'three');
}
do_catchsql_test 12.1.1 {
SELECT fts5_columntext(t1, -1) FROM t1('two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.1.2 {
SELECT fts5_columntext(t1, 3) FROM t1('two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.1.2 {
SELECT fts5_columntext(t1, 1) FROM t1('one AND two');
} {0 two}
do_catchsql_test 12.2.1 {
SELECT fts5_queryphrase(t1, -1) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.2.2 {
SELECT fts5_queryphrase(t1, 2) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.2.3 {
SELECT fts5_queryphrase(t1, 1) FROM t1('one AND two');
} {0 {{1 2 1}}}
do_catchsql_test 12.3.1 {
SELECT fts5_collist(t1, -1) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.3.2 {
SELECT fts5_collist(t1, 2) FROM t1('one AND two');
} {1 SQLITE_RANGE}
do_catchsql_test 12.3.3 {
SELECT fts5_collist(t1, 1) FROM t1('one AND two');
} {0 1}
finish_test

View File

@@ -293,4 +293,39 @@ do_catchsql_test 7.2.5 {
SELECT * FROM t1('abc') ORDER BY rank;
} {1 {recursively defined fts5 content table}}
#---------------------------------------------------------------------------
# Check that if the content table is a view, and that view contains an
# error, a reasonable error message is returned if the user tries to
# read from the view via the fts5 table.
#
reset_db
do_execsql_test 8.1 {
CREATE VIEW a1 AS
SELECT 1 AS r, text_value(1) AS t
UNION ALL
SELECT 2 AS r, text_value(2) AS t;
CREATE VIRTUAL TABLE t1 USING fts5(t, content='a1', content_rowid='r');
}
foreach {tn sql} {
1 "SELECT * FROM t1"
2 "INSERT INTO t1(t1) VALUES('rebuild')"
3 "SELECT * FROM t1 WHERE rowid=1"
} {
do_catchsql_test 8.2.$tn $sql {1 {no such function: text_value}}
}
proc text_value {i} {
if {$i==1} { return "one" }
if {$i==2} { return "two" }
return "many"
}
db func text_value text_value
do_execsql_test 8.3.1 { SELECT * FROM t1 } {one two}
do_execsql_test 8.3.2 { INSERT INTO t1(t1) VALUES('rebuild') }
do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one}
do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2}
finish_test

View File

@@ -966,6 +966,262 @@ do_catchsql_test 6.2 {
UPDATE t1 SET content=randomblob(500) WHERE t1;
} {1 {constraint failed}}
#-------------------------------------------------------------------------
reset_db
do_test 7.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 40960 pagesize 4096 filename crash-d8b4a99207c10b.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 0a .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 0d 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 96: 00 00 00 00 0d 00 00 00 0d 0b 62 00 0f 97 0f 40 ..........b....@
| 112: 0e d5 0e 75 0e 18 0d c0 0d 66 0d 0f 0c a4 0c 44 ...u.....f.....D
| 128: 0b ec 0b a7 0b 62 00 00 00 00 00 00 00 00 00 00 .....b..........
| 2912: 00 00 43 0d 06 17 11 11 08 75 74 61 62 6c 65 74 ..C......utablet
| 2928: 34 74 34 43 52 45 41 54 45 20 56 49 52 54 55 41 4t4CREATE VIRTUA
| 2944: 4c 20 54 41 42 4c 45 20 74 34 20 55 53 49 4e 47 L TABLE t4 USING
| 2960: 20 66 74 73 35 76 6f 63 61 62 28 27 74 32 27 2c fts5vocab('t2',
| 2976: 20 27 72 6f 77 27 29 43 0c 06 17 11 11 08 75 74 'row')C......ut
| 2992: 61 62 6c 65 74 33 74 33 43 52 45 41 54 45 20 56 ablet3t3CREATE V
| 3008: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 33 20 IRTUAL TABLE t3
| 3024: 55 53 49 4e 47 20 66 74 73 35 76 6f 63 61 62 28 USING fts5vocab(
| 3040: 27 74 31 27 2c 20 27 72 6f 77 27 29 56 0b 06 17 't1', 'row')V...
| 3056: 1f 1f 01 7d 74 61 62 6c 65 74 32 5f 63 6f 6e 66 ....tablet2_conf
| 3072: 69 67 74 32 5f 63 6f 6e 66 69 67 0a 43 52 45 41 igt2_config.CREA
| 3088: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 63 6f 6e TE TABLE 't2_con
| 3104: 66 69 67 27 28 6b 20 50 52 49 4d 41 52 59 20 4b fig'(k PRIMARY K
| 3120: 45 59 2c 20 76 29 20 57 49 54 48 4f 55 54 20 52 EY, v) WITHOUT R
| 3136: 4f 57 49 44 5e 0a 07 17 21 21 01 81 07 74 61 62 OWID^...!!...tab
| 3152: 6c 65 74 32 5f 63 6f 6e 74 65 6e 74 74 32 5f 63 let2_contentt2_c
| 3168: 6f 6e 74 65 6e 74 09 43 52 45 41 54 45 20 54 41 ontent.CREATE TA
| 3184: 42 4c 45 20 27 74 32 5f 63 6f 6e 74 65 6e 74 27 BLE 't2_content'
| 3200: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 3216: 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 2c ARY KEY, c0, c1,
| 3232: 20 63 32 29 69 09 07 17 19 19 01 81 2d 74 61 62 c2)i.......-tab
| 3248: 6c 65 74 32 5f 69 64 78 74 32 5f 69 64 78 08 43 let2_idxt2_idx.C
| 3264: 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 32 5f REATE TABLE 't2_
| 3280: 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d idx'(segid, term
| 3296: 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 , pgno, PRIMARY
| 3312: 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 KEY(segid, term)
| 3328: 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 ) WITHOUT ROWIDU
| 3344: 08 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 32 5f ........tablet2_
| 3360: 64 61 74 61 74 32 5f 64 61 74 61 07 43 52 45 41 datat2_data.CREA
| 3376: 54 45 20 54 41 42 4c 45 20 27 74 32 5f 64 61 74 TE TABLE 't2_dat
| 3392: 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 a'(id INTEGER PR
| 3408: 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b IMARY KEY, block
| 3424: 20 42 4c 4f 42 29 58 07 07 17 11 11 08 81 1d 74 BLOB)X........t
| 3440: 61 62 6c 65 74 32 74 32 43 52 45 41 54 45 20 56 ablet2t2CREATE V
| 3456: 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 32 20 IRTUAL TABLE t2
| 3472: 55 53 49 4e 47 20 66 74 73 35 28 27 61 27 2c 5b USING fts5('a',[
| 3488: 62 5d 2c 22 63 22 2c 64 65 74 61 69 6c 3d 6e 6f b],.c.,detail=no
| 3504: 6e 65 2c 63 6f 6c 75 6d 6e 73 69 7a 65 3d 30 29 ne,columnsize=0)
| 3520: 56 06 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f V.......tablet1_
| 3536: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 06 configt1_config.
| 3552: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
| 3568: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41 _config'(k PRIMA
| 3584: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f RY KEY, v) WITHO
| 3600: 55 54 20 52 4f 57 49 44 5b 05 07 17 21 21 01 81 UT ROWID[...!!..
| 3616: 01 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65 .tablet1_docsize
| 3632: 74 31 5f 64 6f 63 73 69 7a 65 05 43 52 45 41 54 t1_docsize.CREAT
| 3648: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73 E TABLE 't1_docs
| 3664: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20 ize'(id INTEGER
| 3680: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20 PRIMARY KEY, sz
| 3696: 42 4c 4f 42 29 5e 04 07 17 21 21 01 81 07 74 61 BLOB)^...!!...ta
| 3712: 62 6c 65 74 31 5f 63 6f 6e 74 65 6e 74 74 31 5f blet1_contentt1_
| 3728: 63 6f 6e 74 65 6e 74 04 43 52 45 41 54 45 20 54 content.CREATE T
| 3744: 41 42 4c 45 20 27 74 31 5f 63 6f 6e 74 65 6e 74 ABLE 't1_content
| 3760: 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 '(id INTEGER PRI
| 3776: 4d 41 52 59 20 4b 45 59 2c 20 63 30 2c 20 63 31 MARY KEY, c0, c1
| 3792: 2c 20 63 32 29 69 03 07 17 19 19 01 81 2d 74 61 , c2)i.......-ta
| 3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03 blet1_idxt1_idx.
| 3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
| 3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 _idx'(segid, ter
| 3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 m, pgno, PRIMARY
| 3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d KEY(segid, term
| 3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 )) WITHOUT ROWID
| 3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 U........tablet1
| 3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45 _datat1_data.CRE
| 3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61 ATE TABLE 't1_da
| 3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 ta'(id INTEGER P
| 3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 RIMARY KEY, bloc
| 3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b k BLOB)g.......;
| 4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20 tablet1t1CREATE
| 4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31 VIRTUAL TABLE t1
| 4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 62 20 USING fts5(a,b
| 4048: 75 6e 69 6e 64 65 78 65 64 2c 63 2c 74 6f 6b 65 unindexed,c,toke
| 4064: 6e 69 7a 65 3d 22 70 6f 72 74 65 72 20 61 73 63 nize=.porter asc
| 4080: 69 69 22 2c 74 6f 6b 65 6e 64 61 74 61 3d 31 29 ii.,tokendata=1)
| page 2 offset 4096
| 0: 0d 0f 68 00 05 0f 13 00 0f e6 0f 13 0f a8 0f 7c ..h............|
| 16: 0f 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .*..............
| 3856: 00 00 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 .......0........
| 3872: 03 01 01 01 02 01 01 03 01 01 37 8c 80 80 80 80 ..........7.....
| 3888: 01 03 00 74 00 00 00 2e 02 30 61 03 02 02 01 01 ...t.....0a.....
| 3904: 62 03 02 03 01 01 63 03 02 04 01 01 67 03 06 01 b.....c.....g...
| 3920: 02 02 01 01 68 03 06 01 02 03 01 01 69 03 06 01 ....h.......i...
| 3936: 02 04 04 06 06 06 08 08 0f ef 00 14 2a 00 00 00 ............*...
| 3952: 00 01 02 02 00 02 01 01 01 02 01 01 25 88 80 80 ............%...
| 3968: 80 80 01 03 00 50 00 00 00 1f 02 30 67 02 08 02 .....P.....0g...
| 3984: 01 02 02 01 01 68 02 08 03 01 02 03 01 01 69 02 .....h........i.
| 4000: 08 04 01 02 04 04 09 09 37 84 80 80 80 7f f1 03 ........7.......
| 4016: 00 74 00 00 00 2e 02 30 61 01 02 02 01 01 62 01 .t.....0a.....b.
| 4032: 02 03 01 01 63 01 02 04 01 01 67 01 06 01 02 02 ....c.....g.....
| 4048: 01 01 68 01 06 01 02 03 01 01 69 01 06 01 02 04 ..h.......i.....
| 4064: 04 06 06 06 08 08 07 01 03 00 14 03 09 00 09 00 ................
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 03 0f ec 00 0f fa 0f f3 0f ec 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
| 4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69 h i.......g h i
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
| page 5 offset 16384
| 0: 0d 00 00 00 03 0f e8 00 0f f8 0f f0 0f e8 00 00 ................
| 4064: 00 00 00 00 00 00 00 00 06 03 03 00 12 03 00 03 ................
| 4080: 06 02 03 00 12 03 00 03 06 01 03 00 12 03 00 03 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| page 7 offset 24576
| 0: 0d 00 00 00 03 0f 9e 00 0f e6 0f ef 0f 9e 00 00 ................
| 3984: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 84 ..............A.
| 4000: 80 80 80 80 01 04 00 81 06 00 00 00 34 02 30 61 ............4.0a
| 4016: 01 01 01 01 01 62 01 01 01 01 01 63 01 01 01 01 .....b.....c....
| 4032: 01 64 01 01 01 65 01 01 01 66 01 01 01 67 01 01 .d...e...f...g..
| 4048: 01 01 01 68 01 01 01 01 01 69 01 01 01 04 06 06 ...h.....i......
| 4064: 06 04 04 04 06 06 07 01 03 00 14 03 09 09 09 0f ................
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 8 offset 28672
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 9 offset 32768
| 0: 0d 00 00 00 03 0f be 00 0f ea 0f d4 0f be 00 00 ................
| 4016: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 03 ................
| 4032: 05 00 17 17 17 61 20 62 20 63 67 20 68 20 69 67 .....a b cg h ig
| 4048: 20 68 20 69 14 02 05 00 17 17 17 67 20 68 20 69 h i.......g h i
| 4064: 61 20 62 20 63 67 20 68 20 69 14 01 05 00 17 17 a b cg h i......
| 4080: 17 61 20 62 20 63 64 20 65 20 66 67 20 68 20 69 .a b cd e fg h i
| page 10 offset 36864
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end crash-d8b4a99207c10b.db
}]} {}
do_catchsql_test 7.1 {
SELECT snippet(t1, -1, '.', '..', '[', ']'),
highlight(t1, 2, '[', ']')
FROM t1('g + h')
WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 8.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
.open --hexdb
| size 20480 pagesize 4096 filename crash-d57c01958e48ab.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 05 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 04 ................
| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 96: 00 00 00 00 0d 00 00 00 05 0e 10 00 0f 97 0f 40 ...............@
| 112: 0e d5 0e 68 0e 10 01 00 00 00 00 00 00 00 00 00 ...h............
| 3600: 56 05 06 17 1f 1f 01 7d 74 61 62 6c 65 74 31 5f V.......tablet1_
| 3616: 63 6f 6e 66 69 67 74 31 5f 63 6f 6e 66 69 67 05 configt1_config.
| 3632: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
| 3648: 5f 63 6f 6e 66 69 67 27 28 6b 20 50 52 49 4d 41 _config'(k PRIMA
| 3664: 52 59 20 4b 45 59 2c 20 76 29 20 57 49 54 48 4f RY KEY, v) WITHO
| 3680: 55 54 20 52 4f 57 49 44 6b 04 07 17 21 21 01 81 UT ROWIDk...!!..
| 3696: 21 74 61 62 6c 65 74 31 5f 64 6f 63 73 69 7a 65 !tablet1_docsize
| 3712: 74 31 5f 64 6f 63 73 69 7a 65 04 43 52 45 41 54 t1_docsize.CREAT
| 3728: 45 20 54 41 42 4c 45 20 27 74 31 5f 64 6f 63 73 E TABLE 't1_docs
| 3744: 69 7a 65 27 28 69 64 20 49 4e 54 45 47 45 52 20 ize'(id INTEGER
| 3760: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 73 7a 20 PRIMARY KEY, sz
| 3776: 42 4c 4f 42 2c 20 6f 72 69 67 69 6e 20 49 4e 54 BLOB, origin INT
| 3792: 45 47 45 52 29 69 03 07 17 19 19 01 81 2d 74 61 EGER)i.......-ta
| 3808: 62 6c 65 74 31 5f 69 64 78 74 31 5f 69 64 78 03 blet1_idxt1_idx.
| 3824: 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 CREATE TABLE 't1
| 3840: 5f 69 64 78 27 28 73 65 67 69 64 2c 20 74 65 72 _idx'(segid, ter
| 3856: 6d 2c 20 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 m, pgno, PRIMARY
| 3872: 20 4b 45 59 28 73 65 67 69 64 2c 20 74 65 72 6d KEY(segid, term
| 3888: 29 29 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 )) WITHOUT ROWID
| 3904: 55 02 07 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 U........tablet1
| 3920: 5f 64 61 74 61 74 31 5f 64 61 74 61 02 43 52 45 _datat1_data.CRE
| 3936: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 64 61 ATE TABLE 't1_da
| 3952: 74 61 27 28 69 64 20 49 4e 54 45 47 45 52 20 50 ta'(id INTEGER P
| 3968: 52 49 4d 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 RIMARY KEY, bloc
| 3984: 6b 20 42 4c 4f 42 29 67 01 07 17 11 11 08 81 3b k BLOB)g.......;
| 4000: 74 61 62 6c 65 74 31 74 31 43 52 45 41 54 45 20 tablet1t1CREATE
| 4016: 56 49 52 54 55 41 4c 20 54 41 42 4c 45 20 74 31 VIRTUAL TABLE t1
| 4032: 20 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 USING fts5(a, b
| 4048: 2c 20 63 6f 6e 74 65 6e 74 3d 27 27 2c 20 63 6f , content='', co
| 4064: 6e 74 65 6e 74 6c 65 73 73 5f 64 65 6c 65 74 65 ntentless_delete
| 4080: 3d 31 2c 20 74 6f 6b 65 6e 64 61 74 61 3d 31 29 =1, tokendata=1)
| page 2 offset 4096
| 0: 0d 0f eb 00 03 0e 17 00 0f e2 0e 17 0e 31 00 00 .............1..
| 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 3600: 00 00 00 00 00 00 00 18 0a 03 00 36 00 00 00 00 ...........6....
| 3616: ff 00 00 01 01 01 01 00 01 01 01 01 01 01 00 00 ................
| 3632: 07 83 29 84 80 80 80 80 01 04 00 86 56 00 00 01 ..).........V...
| 3648: 96 04 30 61 61 61 01 02 02 01 04 02 04 01 08 02 ..0aaa..........
| 3664: 04 04 04 01 10 02 04 04 04 04 04 04 04 01 20 02 .............. .
| 3680: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 01 ................
| 3696: 40 02 04 04 04 04 04 04 04 04 04 04 04 04 04 04 @...............
| 3712: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
| 3728: 04 01 81 00 02 04 04 04 04 04 04 04 04 04 04 04 ................
| 3744: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
| 3760: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
| 3776: 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 04 ................
| 3792: 04 04 04 04 02 02 62 63 01 06 01 01 02 01 03 62 ......bc.......b
| 3808: 62 62 02 02 03 01 04 03 06 01 08 03 06 06 06 01 bb..............
| 3824: 10 03 06 06 06 06 06 06 06 01 20 03 06 06 06 06 .......... .....
| 3840: 06 06 06 06 06 06 06 06 06 06 06 01 40 03 06 06 ............@...
| 3856: 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06 06 ................
| 3872: 06 06 06 06 06 06 06 06 06 06 16 06 06 02 02 63 ...............c
| 3888: 64 02 06 01 01 02 01 03 63 63 63 03 02 05 01 04 d.......ccc.....
| 3904: 05 0a 01 08 05 0a 0a 0a 01 10 05 0a 0a 0a 0a 0a ................
| 3920: 0a 0a 01 20 05 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ... ............
| 3936: 0a 0a 0a 0a 02 02 64 65 03 06 01 01 02 01 03 64 ......de.......d
| 3952: 64 64 04 02 09 01 04 09 12 01 08 09 12 12 12 01 dd..............
| 3968: 10 09 12 12 12 12 12 12 12 02 02 65 66 04 06 01 ...........ef...
| 3984: 01 02 01 03 65 65 65 05 02 11 01 04 11 22 01 08 ....eee.........
| 4000: 11 22 22 22 02 02 66 67 05 06 01 01 02 01 03 66 ......fg.......f
| 4016: 56 66 06 02 21 01 04 21 42 02 02 67 68 06 06 01 Vf..!..!B..gh...
| 4032: 01 02 cb 03 67 67 67 07 02 41 02 02 68 69 07 06 ....ggg..A..hi..
| 4048: 01 01 02 04 81 13 09 50 09 2e 09 1c 09 12 09 0c .......P........
| 4064: 09 08 07 01 03 00 14 07 81 77 07 00 00 00 15 22 .........w......
| 4080: 00 00 00 00 ff 00 00 01 00 00 00 00 00 00 05 0c ................
| page 3 offset 8192
| 0: 0a 00 00 00 01 0f fa 00 0f fa 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0c 01 02 ................
| page 4 offset 12288
| 0: 0d 00 00 00 07 0f c8 00 0f f8 0f f0 0f e8 0f e0 ................
| 16: 0f d8 0f d0 0f c8 00 00 00 00 00 00 00 00 00 00 ................
| 4032: 00 00 00 00 00 00 00 00 06 07 04 00 10 09 7f 01 ................
| 4048: 06 06 04 00 10 09 3f 01 06 05 04 00 10 09 1f 01 ......?.........
| 4064: 06 04 04 00 10 09 0f 01 06 03 04 00 10 09 07 01 ................
| 4080: 06 02 04 00 10 09 03 01 06 01 04 00 10 09 01 01 ................
| page 5 offset 16384
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| end crash-d57c01958e48ab.db
}]} {}
do_catchsql_test 8.1 {
SELECT rowid FROM t1('a* NOT ý‘') ;
} {0 {1 2 3 4 5 6 7}}
sqlite3_fts5_may_be_corrupt 0
finish_test

View File

@@ -88,6 +88,54 @@ do_faultsim_test 2 -faults oom* -prep {
faultsim_test_result {0 {10 24}}
}
reset_db
sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(
x, tokenize="origintext unicode61", tokendata=1
);
INSERT INTO t1(t1, rank) VALUES('pgsz', 64);
INSERT INTO t1(rowid, x) VALUES(9, 'bbb Bbb BBB');
BEGIN;
INSERT INTO t1(rowid, x) VALUES(10, 'aaa bbb BBB');
INSERT INTO t1(rowid, x) VALUES(11, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(12, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(13, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(14, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(15, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(16, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(17, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(18, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(19, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(20, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(21, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(22, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(23, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(24, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(25, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(26, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(27, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(28, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(29, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(30, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(31, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(32, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(33, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(34, 'bbb Bbb BBB');
INSERT INTO t1(rowid, x) VALUES(35, 'aaa bbb BBB');
COMMIT;
}
do_faultsim_test 3 -faults oom* -prep {
} -body {
execsql {
SELECT rowid FROM t1('BBB AND AAA');
}
} -test {
faultsim_integrity_check
faultsim_test_result {0 {10 35}}
}
finish_test

View File

@@ -91,7 +91,6 @@ do_execsql_test 2.2.1 {
INSERT INTO vt0(c0) VALUES ('xyz');
}
breakpoint
do_execsql_test 2.2.2 {
ALTER TABLE t0 RENAME TO t1;
}
@@ -500,6 +499,21 @@ do_execsql_test 17.5 {
SELECT c0 FROM t0 WHERE c0 GLOB '*faul*';
} {assertionfaultproblem}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 18.0 {
BEGIN;
CREATE VIRTUAL TABLE t1 USING fts5(text);
ALTER TABLE t1 RENAME TO t2;
}
do_execsql_test 18.1 {
DROP TABLE t2;
}
do_execsql_test 18.2 {
COMMIT;
}
finish_test

View File

@@ -21,6 +21,19 @@ ifcapable !fts5 {
return
}
# The tests below verify that a doclist-index is used to limit the number
# of pages loaded into the cache. It does this by querying sqlite3_db_status()
# for the amount of memory used by the pager cache.
#
# memsubsys1 effectively limits the page-cache to 24 pages. Which masks
# the effect tested by the tests in this file. And "mmap" prevents the
# cache from being used, also preventing these tests from working.
#
if {[permutation]=="memsubsys1" || [permutation]=="mmap"} {
finish_test
return
}
sqlite3_fts5_register_origintext db
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE ft USING fts5(

View File

@@ -86,71 +86,76 @@ do_execsql_test 2.8 {
# 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])]]
foreach {tn cfg} {
1 ""
2 "INSERT INTO fff(fff, rank) VALUES('secure-delete', 1)"
} {
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
}
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');
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.$tn.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;
}
execsql $cfg
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.$tn.1.$iTest.$ii {
DELETE FROM fff WHERE rowid=$ii;
}
#if {$iTest==1} { dump fff }
if {($iTest % 20)==0} {
do_execsql_test 3.$tn.1.$iTest.$ii.ic {
INSERT INTO fff(fff) VALUES('integrity-check');
}
}
#if {$iTest==1} { break }
incr iTest
}
#if {$iTest==1} { break }
incr iTest
}
#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }

View File

@@ -42,7 +42,7 @@ proc fts5_test_bothlist {cmd} {
}
sqlite3_fts5_create_function db fts5_test_bothlist fts5_test_bothlist
proc fts5_rowid {cmd} { expr [$cmd xColumnText -1] }
proc fts5_rowid {cmd} { expr [$cmd xRowid] }
sqlite3_fts5_create_function db fts5_rowid fts5_rowid
do_execsql_test 1.$tok.0.1 "

View File

@@ -280,6 +280,30 @@ do_catchsql_test 5.2 {
INSERT INTO t1 SELECT randomblob(3000) FROM v1
} {1 {query aborted}}
#-------------------------------------------------------------------------
reset_db
sqlite3_fts5_may_be_corrupt 1
do_execsql_test 6.0 {
BEGIN TRANSACTION;
CREATE VIRTUAL TABLE t1 USING fts5(a,b unindexed,c,tokenize="porter ascii",tokendata=1);
REPLACE INTO t1_data VALUES(1,X'03090009');
REPLACE INTO t1_data VALUES(10,X'000000000103030003010101020101030101');
REPLACE INTO t1_data VALUES(137438953473,X'0000002e023061010202010162010203010163010204010167010601020201016801060102030101690106010204040606060808');
REPLACE INTO t1_data VALUES(274877906945,X'0000001f013067020802010202010168020803010203010169020804010204040909');
REPLACE INTO t1_data VALUES(412316860417,X'0000002e023061030202010162030203010163030204010167030601020201016803060102030101690306010204040606060808');
COMMIT;
}
do_execsql_test 6.1 {
CREATE VIRTUAL TABLE t3 USING fts5vocab('t1', 'row');
}
do_catchsql_test 6.2 {
SELECT * FROM t3;
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test

View File

@@ -107,6 +107,12 @@
# undef SQLITE_OMIT_UTF16 1
#endif
/**********************************************************************/
/* SQLITE_S... */
#ifndef SQLITE_STRICT_SUBTYPE
# define SQLITE_STRICT_SUBTYPE 1
#endif
/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE

View File

@@ -26,9 +26,14 @@
**
** .load ./randomjson
** SELECT random_json(1);
** SELECT random_json5(1);
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#ifdef SQLITE_STATIC_RANDOMJSON
# include "sqlite3.h"
#else
# include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#endif
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -51,17 +56,18 @@ static unsigned int prngInt(Prng *p){
return p->x ^ p->y;
}
static const char *azJsonAtoms[] = {
/* JSON /* JSON-5 */
static char *azJsonAtoms[] = {
/* JSON JSON-5 */
"0", "0",
"1", "1",
"-1", "-1",
"2", "+2",
"3", "3",
"2.5", "2.5",
"3DDDD", "3DDDD",
"2.5DD", "2.5DD",
"0.75", ".75",
"-4.0e2", "-4.e2",
"5.0e-3", "+5e-3",
"6.DDe+0DD", "6.DDe+0DD",
"0", "0x0",
"512", "0x200",
"256", "+0x100",
@@ -73,12 +79,14 @@ static const char *azJsonAtoms[] = {
"-9.0e999", "-Infinity",
"9.0e999", "+Infinity",
"null", "NaN",
"-0.0005123", "-0.0005123",
"-0.0005DD", "-0.0005DD",
"4.35e-3", "+4.35e-3",
"\"gem\\\"hay\"", "\"gem\\\"hay\"",
"\"icy'joy\"", "'icy\\'joy\'",
"\"keylog\"", "\"key\\\nlog\"",
"\"mix\\\\\\tnet\"", "\"mix\\\\\\tnet\"",
"\"oat\\r\\n\"", "\"oat\\r\\n\"",
"\"\\fpan\\b\"", "\"\\fpan\\b\"",
"{}", "{}",
"[]", "[]",
"[]", "[/*empty*/]",
@@ -89,19 +97,20 @@ static const char *azJsonAtoms[] = {
"\"day\"", "\"day\"",
"\"end\"", "'end'",
"\"fly\"", "\"fly\"",
"\"\\u00XX\\u00XX\"", "\"\\xXX\\xXX\"",
"\"y\\uXXXXz\"", "\"y\\uXXXXz\"",
"\"\"", "\"\"",
};
static const char *azJsonTemplate[] = {
static char *azJsonTemplate[] = {
/* JSON JSON-5 */
"{\"a\":%,\"b\":%,\"c\":%}", "{a:%,b:%,c:%}",
"{\"a\":%,\"b\":%,\"cDD\":%}", "{a:%,b:%,cDD:%}",
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"e\":%}", "{a:%,b:%,c:%,d:%,e:%}",
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,\"\":%}",
"{\"a\":%,\"b\":%,\"c\":%,\"d\":%,\"\":%}", "{a:%,b:%,c:%,d:%,'':%}",
"{\"d\":%}", "{d:%}",
"{\"eeee\":%, \"ffff\":%}", "{eeee:% /*and*/, ffff:%}",
"{\"$g\":%,\"_h_\":%}", "{$g:%,_h_:%,}",
"{\"$g\":%,\"_h_\":%,\"a b c d\":%}", "{$g:%,_h_:%,\"a b c d\":%}",
"{\"x\":%,\n \"y\":%}", "{\"x\":%,\n \"y\":%}",
"{\"a b c d\":%,\"e\":%,\"f\":%,\"x\":%,\"y\":%}",
"{\"a b c d\":%,e:%,f:%,x:%,y:%}",
"{\"\\u00XX\":%,\"\\uXXXX\":%}", "{\"\\xXX\":%,\"\\uXXXX\":%}",
"{\"Z\":%}", "{Z:%,}",
"[%]", "[%,]",
"[%,%]", "[%,%]",
@@ -122,15 +131,13 @@ static void jsonExpand(
unsigned int r /* Growth probability 0..1000. 0 means no growth */
){
unsigned int i, j, k;
const char *z;
char *z;
char *zX;
size_t n;
char zBuf[200];
j = 0;
if( zSrc==0 ){
k = prngInt(p)%(count(azJsonTemplate)/2);
k = k*2 + eType;
zSrc = azJsonTemplate[k];
}
if( zSrc==0 ) zSrc = "%";
if( strlen(zSrc)>=STRSZ/10 ) r = 0;
for(i=0; zSrc[i]; i++){
if( zSrc[i]!='%' ){
@@ -149,9 +156,36 @@ static void jsonExpand(
z = azJsonTemplate[k];
}
n = strlen(z);
if( (zX = strstr(z,"XX"))!=0 ){
unsigned int y = prngInt(p);
if( (y&0xff)==((y>>8)&0xff) ) y += 0x100;
while( (y&0xff)==((y>>16)&0xff) || ((y>>8)&0xff)==((y>>16)&0xff) ){
y += 0x10000;
}
memcpy(zBuf, z, n+1);
z = zBuf;
zX = strstr(z,"XX");
while( zX!=0 ){
zX[0] = "0123456789abcdef"[y%16]; y /= 16;
zX[1] = "0123456789abcdef"[y%16]; y /= 16;
zX = strstr(zX, "XX");
}
}else if( (zX = strstr(z,"DD"))!=0 ){
unsigned int y = prngInt(p);
memcpy(zBuf, z, n+1);
z = zBuf;
zX = strstr(z,"DD");
while( zX!=0 ){
zX[0] = "0123456789"[y%10]; y /= 10;
zX[1] = "0123456789"[y%10]; y /= 10;
zX = strstr(zX, "DD");
}
}
assert( strstr(z, "XX")==0 );
assert( strstr(z, "DD")==0 );
if( j+n<STRSZ ){
memcpy(&zDest[j], z, n);
j += n;
j += (int)n;
}
}
zDest[STRSZ-1] = 0;
@@ -178,7 +212,7 @@ static void randJsonFunc(
}
#ifdef _WIN32
__declspec(dllexport)
__declspec(dllexport)
#endif
int sqlite3_randomjson_init(
sqlite3 *db,
@@ -188,7 +222,11 @@ int sqlite3_randomjson_init(
static int cOne = 1;
static int cZero = 0;
int rc = SQLITE_OK;
#ifdef SQLITE_STATIC_RANDOMJSON
(void)pApi; /* Unused parameter */
#else
SQLITE_EXTENSION_INIT2(pApi);
#endif
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "random_json", 1,
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,

View File

@@ -1087,4 +1087,4 @@ endif
# Run local web server for the test/demo pages.
httpd:
althttpd -max-age 1 -enable-sab -page index.html
althttpd -max-age 1 -enable-sab 1 -page index.html

View File

@@ -147,6 +147,12 @@
# define SQLITE_OS_KV_OPTIONAL 1
#endif
/**********************************************************************/
/* SQLITE_S... */
#ifndef SQLITE_STRICT_SUBTYPE
# define SQLITE_STRICT_SUBTYPE 1
#endif
/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE