mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Experimental changes to fts4 to try to selectively avoid loading very large doclists.
FossilOrigin-Name: 5ae0ba447a561e3b6637b52f9b83a9fc683d2572
This commit is contained in:
858
ext/fts3/fts3.c
858
ext/fts3/fts3.c
File diff suppressed because it is too large
Load Diff
@ -96,8 +96,12 @@ typedef struct Fts3Table Fts3Table;
|
|||||||
typedef struct Fts3Cursor Fts3Cursor;
|
typedef struct Fts3Cursor Fts3Cursor;
|
||||||
typedef struct Fts3Expr Fts3Expr;
|
typedef struct Fts3Expr Fts3Expr;
|
||||||
typedef struct Fts3Phrase Fts3Phrase;
|
typedef struct Fts3Phrase Fts3Phrase;
|
||||||
typedef struct Fts3SegReader Fts3SegReader;
|
typedef struct Fts3PhraseToken Fts3PhraseToken;
|
||||||
|
|
||||||
typedef struct Fts3SegFilter Fts3SegFilter;
|
typedef struct Fts3SegFilter Fts3SegFilter;
|
||||||
|
typedef struct Fts3DeferredToken Fts3DeferredToken;
|
||||||
|
typedef struct Fts3SegReader Fts3SegReader;
|
||||||
|
typedef struct Fts3SegReaderArray Fts3SegReaderArray;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A connection to a fulltext index is an instance of the following
|
** A connection to a fulltext index is an instance of the following
|
||||||
@ -120,17 +124,8 @@ struct Fts3Table {
|
|||||||
*/
|
*/
|
||||||
sqlite3_stmt *aStmt[25];
|
sqlite3_stmt *aStmt[25];
|
||||||
|
|
||||||
/* Pointer to string containing the SQL:
|
char *zSegmentsTbl; /* Name of %_segments table */
|
||||||
**
|
int nPgsz; /* Page size for host database */
|
||||||
** "SELECT block FROM %_segments WHERE blockid BETWEEN ? AND ?
|
|
||||||
** ORDER BY blockid"
|
|
||||||
*/
|
|
||||||
char *zSelectLeaves;
|
|
||||||
int nLeavesStmt; /* Valid statements in aLeavesStmt */
|
|
||||||
int nLeavesTotal; /* Total number of prepared leaves stmts */
|
|
||||||
int nLeavesAlloc; /* Allocated size of aLeavesStmt */
|
|
||||||
sqlite3_stmt **aLeavesStmt; /* Array of prepared zSelectLeaves stmts */
|
|
||||||
|
|
||||||
int nNodeSize; /* Soft limit for node size */
|
int nNodeSize; /* Soft limit for node size */
|
||||||
u8 bHasContent; /* True if %_content table exists */
|
u8 bHasContent; /* True if %_content table exists */
|
||||||
u8 bHasDocsize; /* True if %_docsize table exists */
|
u8 bHasDocsize; /* True if %_docsize table exists */
|
||||||
@ -160,12 +155,16 @@ struct Fts3Cursor {
|
|||||||
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
|
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
|
||||||
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
|
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
|
||||||
Fts3Expr *pExpr; /* Parsed MATCH query string */
|
Fts3Expr *pExpr; /* Parsed MATCH query string */
|
||||||
|
Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */
|
||||||
sqlite3_int64 iPrevId; /* Previous id read from aDoclist */
|
sqlite3_int64 iPrevId; /* Previous id read from aDoclist */
|
||||||
char *pNextId; /* Pointer into the body of aDoclist */
|
char *pNextId; /* Pointer into the body of aDoclist */
|
||||||
char *aDoclist; /* List of docids for full-text queries */
|
char *aDoclist; /* List of docids for full-text queries */
|
||||||
int nDoclist; /* Size of buffer at aDoclist */
|
int nDoclist; /* Size of buffer at aDoclist */
|
||||||
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
|
int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */
|
||||||
u32 *aMatchinfo; /* Information about most recent match */
|
u32 *aMatchinfo; /* Information about most recent match */
|
||||||
|
|
||||||
|
int doDeferred;
|
||||||
|
int nRowAvg; /* Average size of database rows, in pages */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -190,18 +189,23 @@ struct Fts3Cursor {
|
|||||||
/*
|
/*
|
||||||
** A "phrase" is a sequence of one or more tokens that must match in
|
** A "phrase" is a sequence of one or more tokens that must match in
|
||||||
** sequence. A single token is the base case and the most common case.
|
** sequence. A single token is the base case and the most common case.
|
||||||
** For a sequence of tokens contained in "...", nToken will be the number
|
** For a sequence of tokens contained in double-quotes (i.e. "one two three")
|
||||||
** of tokens in the string.
|
** nToken will be the number of tokens in the string.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct Fts3PhraseToken {
|
||||||
|
char *z; /* Text of the token */
|
||||||
|
int n; /* Number of bytes in buffer z */
|
||||||
|
int isPrefix; /* True if token ends with a "*" character */
|
||||||
|
Fts3SegReaderArray *pArray;
|
||||||
|
Fts3DeferredToken *pDeferred;
|
||||||
|
};
|
||||||
|
|
||||||
struct Fts3Phrase {
|
struct Fts3Phrase {
|
||||||
int nToken; /* Number of tokens in the phrase */
|
int nToken; /* Number of tokens in the phrase */
|
||||||
int iColumn; /* Index of column this phrase must match */
|
int iColumn; /* Index of column this phrase must match */
|
||||||
int isNot; /* Phrase prefixed by unary not (-) operator */
|
int isNot; /* Phrase prefixed by unary not (-) operator */
|
||||||
struct PhraseToken {
|
Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
|
||||||
char *z; /* Text of the token */
|
|
||||||
int n; /* Number of bytes in buffer pointed to by z */
|
|
||||||
int isPrefix; /* True if token ends in with a "*" character */
|
|
||||||
} aToken[1]; /* One entry for each token in the phrase */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -225,6 +229,8 @@ struct Fts3Expr {
|
|||||||
Fts3Expr *pRight; /* Right operand */
|
Fts3Expr *pRight; /* Right operand */
|
||||||
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
|
Fts3Phrase *pPhrase; /* Valid if eType==FTSQUERY_PHRASE */
|
||||||
|
|
||||||
|
int bDeferred;
|
||||||
|
|
||||||
int isLoaded; /* True if aDoclist/nDoclist are initialized. */
|
int isLoaded; /* True if aDoclist/nDoclist are initialized. */
|
||||||
char *aDoclist; /* Buffer containing doclist */
|
char *aDoclist; /* Buffer containing doclist */
|
||||||
int nDoclist; /* Size of aDoclist in bytes */
|
int nDoclist; /* Size of aDoclist in bytes */
|
||||||
@ -275,6 +281,12 @@ int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
|
|||||||
int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
|
int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
|
||||||
int sqlite3Fts3ReadLock(Fts3Table *);
|
int sqlite3Fts3ReadLock(Fts3Table *);
|
||||||
|
|
||||||
|
void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
|
||||||
|
int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
|
||||||
|
int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
|
||||||
|
void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
|
||||||
|
char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);
|
||||||
|
|
||||||
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
|
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
|
||||||
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
|
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
|
||||||
#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
|
#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
|
||||||
@ -297,7 +309,7 @@ int sqlite3Fts3VarintLen(sqlite3_uint64);
|
|||||||
void sqlite3Fts3Dequote(char *);
|
void sqlite3Fts3Dequote(char *);
|
||||||
|
|
||||||
char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
|
char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
|
||||||
int sqlite3Fts3ExprLoadDoclist(Fts3Table *, Fts3Expr *);
|
int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *);
|
||||||
int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
|
int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
|
||||||
|
|
||||||
/* fts3_tokenizer.c */
|
/* fts3_tokenizer.c */
|
||||||
|
@ -223,7 +223,7 @@ static int getNextString(
|
|||||||
rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
|
rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
||||||
p = fts3ReallocOrFree(p, nByte+ii*sizeof(struct PhraseToken));
|
p = fts3ReallocOrFree(p, nByte+ii*sizeof(Fts3PhraseToken));
|
||||||
zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
|
zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
|
||||||
if( !p || !zTemp ){
|
if( !p || !zTemp ){
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
@ -235,6 +235,8 @@ static int getNextString(
|
|||||||
p->pPhrase = (Fts3Phrase *)&p[1];
|
p->pPhrase = (Fts3Phrase *)&p[1];
|
||||||
p->pPhrase->nToken = ii+1;
|
p->pPhrase->nToken = ii+1;
|
||||||
p->pPhrase->aToken[ii].n = nToken;
|
p->pPhrase->aToken[ii].n = nToken;
|
||||||
|
p->pPhrase->aToken[ii].pDeferred = 0;
|
||||||
|
p->pPhrase->aToken[ii].pArray = 0;
|
||||||
memcpy(&zTemp[nTemp], zToken, nToken);
|
memcpy(&zTemp[nTemp], zToken, nToken);
|
||||||
nTemp += nToken;
|
nTemp += nToken;
|
||||||
if( iEnd<nInput && zInput[iEnd]=='*' ){
|
if( iEnd<nInput && zInput[iEnd]=='*' ){
|
||||||
@ -254,7 +256,7 @@ static int getNextString(
|
|||||||
char *zNew = NULL;
|
char *zNew = NULL;
|
||||||
int nNew = 0;
|
int nNew = 0;
|
||||||
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
|
||||||
nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(struct PhraseToken);
|
nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(Fts3PhraseToken);
|
||||||
p = fts3ReallocOrFree(p, nByte + nTemp);
|
p = fts3ReallocOrFree(p, nByte + nTemp);
|
||||||
if( !p ){
|
if( !p ){
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
typedef struct LoadDoclistCtx LoadDoclistCtx;
|
typedef struct LoadDoclistCtx LoadDoclistCtx;
|
||||||
struct LoadDoclistCtx {
|
struct LoadDoclistCtx {
|
||||||
Fts3Table *pTab; /* FTS3 Table */
|
Fts3Cursor *pCsr; /* FTS3 Cursor */
|
||||||
int nPhrase; /* Number of phrases seen so far */
|
int nPhrase; /* Number of phrases seen so far */
|
||||||
int nToken; /* Number of tokens seen so far */
|
int nToken; /* Number of tokens seen so far */
|
||||||
};
|
};
|
||||||
@ -218,7 +218,7 @@ static int fts3ExprLoadDoclistsCb1(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|||||||
p->nToken += pExpr->pPhrase->nToken;
|
p->nToken += pExpr->pPhrase->nToken;
|
||||||
|
|
||||||
if( pExpr->isLoaded==0 ){
|
if( pExpr->isLoaded==0 ){
|
||||||
rc = sqlite3Fts3ExprLoadDoclist(p->pTab, pExpr);
|
rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
|
||||||
pExpr->isLoaded = 1;
|
pExpr->isLoaded = 1;
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = fts3ExprNearTrim(pExpr);
|
rc = fts3ExprNearTrim(pExpr);
|
||||||
@ -261,7 +261,7 @@ static int fts3ExprLoadDoclists(
|
|||||||
){
|
){
|
||||||
int rc; /* Return Code */
|
int rc; /* Return Code */
|
||||||
LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
|
LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
|
||||||
sCtx.pTab = (Fts3Table *)pCsr->base.pVtab;
|
sCtx.pCsr = pCsr;
|
||||||
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
|
rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb1, (void *)&sCtx);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
|
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
|
||||||
|
@ -42,6 +42,17 @@ struct PendingList {
|
|||||||
sqlite3_int64 iLastPos;
|
sqlite3_int64 iLastPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Each cursor has a (possibly empty) linked list of the following objects.
|
||||||
|
*/
|
||||||
|
struct Fts3DeferredToken {
|
||||||
|
Fts3PhraseToken *pToken; /* Pointer to corresponding expr token */
|
||||||
|
int iCol; /* Column token must occur in */
|
||||||
|
Fts3DeferredToken *pNext; /* Next in list of deferred tokens */
|
||||||
|
PendingList *pList; /* Doclist is assembled here */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of this structure is used to iterate through the terms on
|
** An instance of this structure is used to iterate through the terms on
|
||||||
** a contiguous set of segment b-tree leaf nodes. Although the details of
|
** a contiguous set of segment b-tree leaf nodes. Although the details of
|
||||||
@ -51,6 +62,7 @@ struct PendingList {
|
|||||||
**
|
**
|
||||||
** sqlite3Fts3SegReaderNew()
|
** sqlite3Fts3SegReaderNew()
|
||||||
** sqlite3Fts3SegReaderFree()
|
** sqlite3Fts3SegReaderFree()
|
||||||
|
** sqlite3Fts3SegReaderCost()
|
||||||
** sqlite3Fts3SegReaderIterate()
|
** sqlite3Fts3SegReaderIterate()
|
||||||
**
|
**
|
||||||
** Methods used to manipulate Fts3SegReader structures:
|
** Methods used to manipulate Fts3SegReader structures:
|
||||||
@ -61,9 +73,13 @@ struct PendingList {
|
|||||||
*/
|
*/
|
||||||
struct Fts3SegReader {
|
struct Fts3SegReader {
|
||||||
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
|
int iIdx; /* Index within level, or 0x7FFFFFFF for PT */
|
||||||
sqlite3_int64 iStartBlock;
|
|
||||||
sqlite3_int64 iEndBlock;
|
sqlite3_int64 iStartBlock; /* Rowid of first leaf block to traverse */
|
||||||
sqlite3_stmt *pStmt; /* SQL Statement to access leaf nodes */
|
sqlite3_int64 iLeafEndBlock; /* Rowid of final leaf block to traverse */
|
||||||
|
sqlite3_int64 iEndBlock; /* Rowid of final block in segment (or 0) */
|
||||||
|
sqlite3_int64 iCurrentBlock; /* Current leaf block (or 0) */
|
||||||
|
sqlite3_blob *pBlob; /* Blob open on iStartBlock */
|
||||||
|
|
||||||
char *aNode; /* Pointer to node data (or NULL) */
|
char *aNode; /* Pointer to node data (or NULL) */
|
||||||
int nNode; /* Size of buffer at aNode (or 0) */
|
int nNode; /* Size of buffer at aNode (or 0) */
|
||||||
int nTermAlloc; /* Allocated size of zTerm buffer */
|
int nTermAlloc; /* Allocated size of zTerm buffer */
|
||||||
@ -85,6 +101,7 @@ struct Fts3SegReader {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0)
|
#define fts3SegReaderIsPending(p) ((p)->ppNextElem!=0)
|
||||||
|
#define fts3SegReaderIsRootOnly(p) ((p)->aNode==(char *)&(p)[1])
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An instance of this structure is used to create a segment b-tree in the
|
** An instance of this structure is used to create a segment b-tree in the
|
||||||
@ -490,10 +507,10 @@ static int fts3PendingListAppend(
|
|||||||
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
|
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
|
||||||
*/
|
*/
|
||||||
static int fts3PendingTermsAdd(
|
static int fts3PendingTermsAdd(
|
||||||
Fts3Table *p, /* FTS table into which text will be inserted */
|
Fts3Table *p, /* Table into which text will be inserted */
|
||||||
const char *zText, /* Text of document to be inseted */
|
const char *zText, /* Text of document to be inserted */
|
||||||
int iCol, /* Column number into which text is inserted */
|
int iCol, /* Column into which text is being inserted */
|
||||||
u32 *pnWord /* OUT: Number of tokens inserted */
|
u32 *pnWord /* OUT: Number of tokens inserted */
|
||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
int iStart;
|
int iStart;
|
||||||
@ -786,12 +803,42 @@ static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The %_segments table is declared as follows:
|
||||||
|
**
|
||||||
|
** CREATE TABLE %_segments(blockid INTEGER PRIMARY KEY, block BLOB)
|
||||||
|
**
|
||||||
|
** This function opens a read-only blob handle on the "block" column of
|
||||||
|
** row iSegment of the %_segments table associated with FTS3 table p.
|
||||||
|
**
|
||||||
|
** If all goes well, SQLITE_OK is returned and *ppBlob set to the
|
||||||
|
** read-only blob handle. It is the responsibility of the caller to call
|
||||||
|
** sqlite3_blob_close() on the blob handle. Or, if an error occurs, an
|
||||||
|
** SQLite error code is returned and *ppBlob is either not modified or
|
||||||
|
** set to 0.
|
||||||
|
*/
|
||||||
|
static int fts3OpenSegmentsBlob(
|
||||||
|
Fts3Table *p, /* FTS3 table handle */
|
||||||
|
sqlite3_int64 iSegment, /* Rowid in %_segments table */
|
||||||
|
sqlite3_blob **ppBlob /* OUT: Read-only blob handle */
|
||||||
|
){
|
||||||
|
if( 0==p->zSegmentsTbl
|
||||||
|
&& 0==(p->zSegmentsTbl = sqlite3_mprintf("%s_segments", p->zName))
|
||||||
|
) {
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
return sqlite3_blob_open(
|
||||||
|
p->db, p->zDb, p->zSegmentsTbl, "block", iSegment, 0, ppBlob
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Move the iterator passed as the first argument to the next term in the
|
** Move the iterator passed as the first argument to the next term in the
|
||||||
** segment. If successful, SQLITE_OK is returned. If there is no next term,
|
** segment. If successful, SQLITE_OK is returned. If there is no next term,
|
||||||
** SQLITE_DONE. Otherwise, an SQLite error code.
|
** SQLITE_DONE. Otherwise, an SQLite error code.
|
||||||
*/
|
*/
|
||||||
static int fts3SegReaderNext(Fts3SegReader *pReader){
|
static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
|
||||||
char *pNext; /* Cursor variable */
|
char *pNext; /* Cursor variable */
|
||||||
int nPrefix; /* Number of bytes in term prefix */
|
int nPrefix; /* Number of bytes in term prefix */
|
||||||
int nSuffix; /* Number of bytes in term suffix */
|
int nSuffix; /* Number of bytes in term suffix */
|
||||||
@ -803,7 +850,9 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
|
if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
|
||||||
|
sqlite3_blob *pBlob;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if( fts3SegReaderIsPending(pReader) ){
|
if( fts3SegReaderIsPending(pReader) ){
|
||||||
Fts3HashElem *pElem = *(pReader->ppNextElem);
|
Fts3HashElem *pElem = *(pReader->ppNextElem);
|
||||||
if( pElem==0 ){
|
if( pElem==0 ){
|
||||||
@ -819,17 +868,33 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){
|
|||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
if( !pReader->pStmt ){
|
|
||||||
pReader->aNode = 0;
|
if( !fts3SegReaderIsRootOnly(pReader) ){
|
||||||
|
sqlite3_free(pReader->aNode);
|
||||||
|
}
|
||||||
|
pReader->aNode = 0;
|
||||||
|
|
||||||
|
/* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
||||||
|
** blocks have already been traversed. */
|
||||||
|
if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
rc = sqlite3_step(pReader->pStmt);
|
|
||||||
if( rc!=SQLITE_ROW ){
|
rc = fts3OpenSegmentsBlob(p, ++pReader->iCurrentBlock, &pBlob);
|
||||||
pReader->aNode = 0;
|
if( rc==SQLITE_OK ){
|
||||||
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
|
pReader->nNode = sqlite3_blob_bytes(pBlob);
|
||||||
|
pReader->aNode = (char *)sqlite3_malloc(pReader->nNode);
|
||||||
|
if( pReader->aNode ){
|
||||||
|
rc = sqlite3_blob_read(pBlob, pReader->aNode, pReader->nNode, 0);
|
||||||
|
}else{
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
sqlite3_blob_close(pBlob);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
pReader->nNode = sqlite3_column_bytes(pReader->pStmt, 0);
|
|
||||||
pReader->aNode = (char *)sqlite3_column_blob(pReader->pStmt, 0);
|
|
||||||
pNext = pReader->aNode;
|
pNext = pReader->aNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,25 +979,104 @@ static void fts3SegReaderNextDocid(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is called to estimate the amount of data that will be
|
||||||
|
** loaded from the disk If SegReaderIterate() is called on this seg-reader,
|
||||||
|
** in units of average document size.
|
||||||
|
**
|
||||||
|
** This can be used as follows: If the caller has a small doclist that
|
||||||
|
** contains references to N documents, and is considering merging it with
|
||||||
|
** a large doclist (size X "average documents"), it may opt not to load
|
||||||
|
** the large doclist if X>N.
|
||||||
|
*/
|
||||||
|
int sqlite3Fts3SegReaderCost(
|
||||||
|
Fts3Cursor *pCsr, /* FTS3 cursor handle */
|
||||||
|
Fts3SegReader *pReader, /* Segment-reader handle */
|
||||||
|
int *pnCost /* IN/OUT: Number of bytes read */
|
||||||
|
){
|
||||||
|
Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
|
||||||
|
int rc = SQLITE_OK; /* Return code */
|
||||||
|
int nCost = 0; /* Cost in bytes to return */
|
||||||
|
sqlite3_int64 iLeaf; /* Used to iterate through required leaves */
|
||||||
|
int pgsz = p->nPgsz; /* Database page size */
|
||||||
|
|
||||||
|
/* If this seg-reader is reading the pending-terms table, or if all data
|
||||||
|
** for the segment is stored on the root page of the b-tree, then the cost
|
||||||
|
** is zero. In this case all required data is already in main memory.
|
||||||
|
*/
|
||||||
|
if( p->bHasDocsize
|
||||||
|
&& !fts3SegReaderIsPending(pReader)
|
||||||
|
&& !fts3SegReaderIsRootOnly(pReader)
|
||||||
|
){
|
||||||
|
sqlite3_blob *pBlob = 0;
|
||||||
|
|
||||||
|
if( pCsr->nRowAvg==0 ){
|
||||||
|
/* The average document size, which is required to calculate the cost
|
||||||
|
** of each doclist, has not yet been determined. Read the required
|
||||||
|
** data from the %_stat table to calculate it.
|
||||||
|
**
|
||||||
|
** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3
|
||||||
|
** varints, where nCol is the number of columns in the FTS3 table.
|
||||||
|
** The first varint is the number of documents currently stored in
|
||||||
|
** the table. The following nCol varints contain the total amount of
|
||||||
|
** data stored in all rows of each column of the table, from left
|
||||||
|
** to right.
|
||||||
|
*/
|
||||||
|
sqlite3_stmt *pStmt;
|
||||||
|
rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
|
||||||
|
if( rc ) return rc;
|
||||||
|
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||||
|
sqlite3_int64 nDoc = 0;
|
||||||
|
sqlite3_int64 nByte = 0;
|
||||||
|
const char *a = sqlite3_column_blob(pStmt, 0);
|
||||||
|
if( a ){
|
||||||
|
const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||||
|
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||||
|
while( a<pEnd ){
|
||||||
|
sqlite3_int64 nVarint;
|
||||||
|
a += sqlite3Fts3GetVarint(a, &nVarint);
|
||||||
|
nByte += nVarint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pCsr->nRowAvg = (((nByte / nDoc) + pgsz - 1) / pgsz);
|
||||||
|
}
|
||||||
|
rc = sqlite3_reset(pStmt);
|
||||||
|
if( rc!=SQLITE_OK || pCsr->nRowAvg==0 ) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fts3OpenSegmentsBlob(p, pReader->iStartBlock, &pBlob);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
/* Assume that a blob flows over onto overflow pages if it is larger
|
||||||
|
** than (pgsz-35) bytes in size (the file-format documentation
|
||||||
|
** confirms this).
|
||||||
|
*/
|
||||||
|
int nBlob = sqlite3_blob_bytes(pBlob);
|
||||||
|
if( (nBlob+35)>pgsz ){
|
||||||
|
int nOvfl = (nBlob + 34)/pgsz;
|
||||||
|
nCost += ((nOvfl + pCsr->nRowAvg - 1)/pCsr->nRowAvg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert( rc==SQLITE_OK || pBlob==0 );
|
||||||
|
sqlite3_blob_close(pBlob);
|
||||||
|
}
|
||||||
|
|
||||||
|
*pnCost += nCost;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Free all allocations associated with the iterator passed as the
|
** Free all allocations associated with the iterator passed as the
|
||||||
** second argument.
|
** second argument.
|
||||||
*/
|
*/
|
||||||
void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
|
void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
|
||||||
if( pReader ){
|
if( pReader && !fts3SegReaderIsPending(pReader) ){
|
||||||
if( pReader->pStmt ){
|
sqlite3_free(pReader->zTerm);
|
||||||
/* Move the leaf-range SELECT statement to the aLeavesStmt[] array,
|
if( !fts3SegReaderIsRootOnly(pReader) ){
|
||||||
** so that it can be reused when required by another query.
|
sqlite3_free(pReader->aNode);
|
||||||
*/
|
|
||||||
assert( p->nLeavesStmt<p->nLeavesTotal );
|
|
||||||
sqlite3_reset(pReader->pStmt);
|
|
||||||
p->aLeavesStmt[p->nLeavesStmt++] = pReader->pStmt;
|
|
||||||
}
|
}
|
||||||
if( !fts3SegReaderIsPending(pReader) ){
|
|
||||||
sqlite3_free(pReader->zTerm);
|
|
||||||
}
|
|
||||||
sqlite3_free(pReader);
|
|
||||||
}
|
}
|
||||||
|
sqlite3_free(pReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -961,8 +1105,9 @@ int sqlite3Fts3SegReaderNew(
|
|||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
memset(pReader, 0, sizeof(Fts3SegReader));
|
memset(pReader, 0, sizeof(Fts3SegReader));
|
||||||
pReader->iStartBlock = iStartLeaf;
|
|
||||||
pReader->iIdx = iAge;
|
pReader->iIdx = iAge;
|
||||||
|
pReader->iStartBlock = iStartLeaf;
|
||||||
|
pReader->iLeafEndBlock = iEndLeaf;
|
||||||
pReader->iEndBlock = iEndBlock;
|
pReader->iEndBlock = iEndBlock;
|
||||||
|
|
||||||
if( nExtra ){
|
if( nExtra ){
|
||||||
@ -971,52 +1116,9 @@ int sqlite3Fts3SegReaderNew(
|
|||||||
pReader->nNode = nRoot;
|
pReader->nNode = nRoot;
|
||||||
memcpy(pReader->aNode, zRoot, nRoot);
|
memcpy(pReader->aNode, zRoot, nRoot);
|
||||||
}else{
|
}else{
|
||||||
/* If the text of the SQL statement to iterate through a contiguous
|
pReader->iCurrentBlock = iStartLeaf-1;
|
||||||
** set of entries in the %_segments table has not yet been composed,
|
|
||||||
** compose it now.
|
|
||||||
*/
|
|
||||||
if( !p->zSelectLeaves ){
|
|
||||||
p->zSelectLeaves = sqlite3_mprintf(
|
|
||||||
"SELECT block FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ? "
|
|
||||||
"ORDER BY blockid", p->zDb, p->zName
|
|
||||||
);
|
|
||||||
if( !p->zSelectLeaves ){
|
|
||||||
rc = SQLITE_NOMEM;
|
|
||||||
goto finished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are no free statements in the aLeavesStmt[] array, prepare
|
|
||||||
** a new statement now. Otherwise, reuse a prepared statement from
|
|
||||||
** aLeavesStmt[].
|
|
||||||
*/
|
|
||||||
if( p->nLeavesStmt==0 ){
|
|
||||||
if( p->nLeavesTotal==p->nLeavesAlloc ){
|
|
||||||
int nNew = p->nLeavesAlloc + 16;
|
|
||||||
sqlite3_stmt **aNew = (sqlite3_stmt **)sqlite3_realloc(
|
|
||||||
p->aLeavesStmt, nNew*sizeof(sqlite3_stmt *)
|
|
||||||
);
|
|
||||||
if( !aNew ){
|
|
||||||
rc = SQLITE_NOMEM;
|
|
||||||
goto finished;
|
|
||||||
}
|
|
||||||
p->nLeavesAlloc = nNew;
|
|
||||||
p->aLeavesStmt = aNew;
|
|
||||||
}
|
|
||||||
rc = sqlite3_prepare_v2(p->db, p->zSelectLeaves, -1, &pReader->pStmt, 0);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
goto finished;
|
|
||||||
}
|
|
||||||
p->nLeavesTotal++;
|
|
||||||
}else{
|
|
||||||
pReader->pStmt = p->aLeavesStmt[--p->nLeavesStmt];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bind the start and end leaf blockids to the prepared SQL statement. */
|
|
||||||
sqlite3_bind_int64(pReader->pStmt, 1, iStartLeaf);
|
|
||||||
sqlite3_bind_int64(pReader->pStmt, 2, iEndLeaf);
|
|
||||||
}
|
}
|
||||||
rc = fts3SegReaderNext(pReader);
|
rc = fts3SegReaderNext(p, pReader);
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
@ -1113,7 +1215,7 @@ int sqlite3Fts3SegReaderPending(
|
|||||||
pReader->iIdx = 0x7FFFFFFF;
|
pReader->iIdx = 0x7FFFFFFF;
|
||||||
pReader->ppNextElem = (Fts3HashElem **)&pReader[1];
|
pReader->ppNextElem = (Fts3HashElem **)&pReader[1];
|
||||||
memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *));
|
memcpy(pReader->ppNextElem, aElem, nElem*sizeof(Fts3HashElem *));
|
||||||
fts3SegReaderNext(pReader);
|
fts3SegReaderNext(p, pReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1991,7 +2093,7 @@ int sqlite3Fts3SegReaderIterate(
|
|||||||
for(i=0; i<nSegment; i++){
|
for(i=0; i<nSegment; i++){
|
||||||
Fts3SegReader *pSeg = apSegment[i];
|
Fts3SegReader *pSeg = apSegment[i];
|
||||||
while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
|
while( fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 ){
|
||||||
rc = fts3SegReaderNext(pSeg);
|
rc = fts3SegReaderNext(p, pSeg);
|
||||||
if( rc!=SQLITE_OK ) goto finished; }
|
if( rc!=SQLITE_OK ) goto finished; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2102,7 +2204,7 @@ int sqlite3Fts3SegReaderIterate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i<nMerge; i++){
|
for(i=0; i<nMerge; i++){
|
||||||
rc = fts3SegReaderNext(apSegment[i]);
|
rc = fts3SegReaderNext(p, apSegment[i]);
|
||||||
if( rc!=SQLITE_OK ) goto finished;
|
if( rc!=SQLITE_OK ) goto finished;
|
||||||
}
|
}
|
||||||
fts3SegReaderSort(apSegment, nSegment, nMerge, fts3SegReaderCmp);
|
fts3SegReaderSort(apSegment, nSegment, nMerge, fts3SegReaderCmp);
|
||||||
@ -2520,6 +2622,153 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the deferred doclist associated with deferred token pDeferred.
|
||||||
|
** This function assumes that sqlite3Fts3CacheDeferredDoclists() has already
|
||||||
|
** been called to allocate and populate the doclist.
|
||||||
|
*/
|
||||||
|
char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *pDeferred, int *pnByte){
|
||||||
|
if( pDeferred->pList ){
|
||||||
|
*pnByte = pDeferred->pList->nData;
|
||||||
|
return pDeferred->pList->aData;
|
||||||
|
}
|
||||||
|
*pnByte = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Helper fucntion for FreeDeferredDoclists(). This function removes all
|
||||||
|
** references to deferred doclists from within the tree of Fts3Expr
|
||||||
|
** structures headed by
|
||||||
|
*/
|
||||||
|
static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
|
||||||
|
if( pExpr ){
|
||||||
|
fts3DeferredDoclistClear(pExpr->pLeft);
|
||||||
|
fts3DeferredDoclistClear(pExpr->pRight);
|
||||||
|
if( pExpr->bDeferred && pExpr->isLoaded ){
|
||||||
|
sqlite3_free(pExpr->aDoclist);
|
||||||
|
pExpr->isLoaded = 0;
|
||||||
|
pExpr->aDoclist = 0;
|
||||||
|
pExpr->nDoclist = 0;
|
||||||
|
pExpr->pCurrent = 0;
|
||||||
|
pExpr->iCurrent = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete all cached deferred doclists. Deferred doclists are cached
|
||||||
|
** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function.
|
||||||
|
*/
|
||||||
|
void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
|
||||||
|
Fts3DeferredToken *pDef;
|
||||||
|
for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){
|
||||||
|
sqlite3_free(pDef->pList);
|
||||||
|
pDef->pList = 0;
|
||||||
|
}
|
||||||
|
fts3DeferredDoclistClear(pCsr->pExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Free all entries in the pCsr->pDeffered list. Entries are added to
|
||||||
|
** this list using sqlite3Fts3DeferToken().
|
||||||
|
*/
|
||||||
|
void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
|
||||||
|
Fts3DeferredToken *pDef;
|
||||||
|
Fts3DeferredToken *pNext;
|
||||||
|
for(pDef=pCsr->pDeferred; pDef; pDef=pNext){
|
||||||
|
pNext = pDef->pNext;
|
||||||
|
sqlite3_free(pDef->pList);
|
||||||
|
sqlite3_free(pDef);
|
||||||
|
}
|
||||||
|
pCsr->pDeferred = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Generate deferred-doclists for all tokens in the pCsr->pDeferred list
|
||||||
|
** based on the row that pCsr currently points to.
|
||||||
|
**
|
||||||
|
** A deferred-doclist is like any other doclist with position information
|
||||||
|
** included, except that it only contains entries for a single row of the
|
||||||
|
** table, not for all rows.
|
||||||
|
*/
|
||||||
|
int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
||||||
|
int rc = SQLITE_OK; /* Return code */
|
||||||
|
if( pCsr->pDeferred ){
|
||||||
|
int i; /* Used to iterate through table columns */
|
||||||
|
sqlite3_int64 iDocid; /* Docid of the row pCsr points to */
|
||||||
|
Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */
|
||||||
|
|
||||||
|
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
|
||||||
|
sqlite3_tokenizer *pT = p->pTokenizer;
|
||||||
|
sqlite3_tokenizer_module const *pModule = pT->pModule;
|
||||||
|
|
||||||
|
assert( pCsr->isRequireSeek==0 );
|
||||||
|
iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
|
||||||
|
|
||||||
|
for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
|
||||||
|
const char *zText = sqlite3_column_text(pCsr->pStmt, i+1);
|
||||||
|
sqlite3_tokenizer_cursor *pTC = 0;
|
||||||
|
|
||||||
|
rc = pModule->xOpen(pT, zText, -1, &pTC);
|
||||||
|
while( rc==SQLITE_OK ){
|
||||||
|
char const *zToken; /* Buffer containing token */
|
||||||
|
int nToken; /* Number of bytes in token */
|
||||||
|
int iDum1, iDum2; /* Dummy variables */
|
||||||
|
int iPos; /* Position of token in zText */
|
||||||
|
|
||||||
|
pTC->pTokenizer = pT;
|
||||||
|
rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
|
||||||
|
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||||
|
Fts3PhraseToken *pPT = pDef->pToken;
|
||||||
|
if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
|
||||||
|
&& (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
|
||||||
|
&& (0==memcmp(zToken, pPT->z, pPT->n))
|
||||||
|
){
|
||||||
|
fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pTC ) pModule->xClose(pTC);
|
||||||
|
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
|
||||||
|
if( pDef->pList ){
|
||||||
|
rc = fts3PendingListAppendVarint(&pDef->pList, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Add an entry for token pToken to the pCsr->pDeferred list.
|
||||||
|
*/
|
||||||
|
int sqlite3Fts3DeferToken(
|
||||||
|
Fts3Cursor *pCsr, /* Fts3 table cursor */
|
||||||
|
Fts3PhraseToken *pToken, /* Token to defer */
|
||||||
|
int iCol /* Column that token must appear in (or -1) */
|
||||||
|
){
|
||||||
|
Fts3DeferredToken *pDeferred;
|
||||||
|
pDeferred = sqlite3_malloc(sizeof(*pDeferred));
|
||||||
|
if( !pDeferred ){
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
memset(pDeferred, 0, sizeof(*pDeferred));
|
||||||
|
pDeferred->pToken = pToken;
|
||||||
|
pDeferred->pNext = pCsr->pDeferred;
|
||||||
|
pDeferred->iCol = iCol;
|
||||||
|
pCsr->pDeferred = pDeferred;
|
||||||
|
|
||||||
|
assert( pToken->pDeferred==0 );
|
||||||
|
pToken->pDeferred = pDeferred;
|
||||||
|
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function does the work for the xUpdate method of FTS3 virtual
|
** This function does the work for the xUpdate method of FTS3 virtual
|
||||||
** tables.
|
** tables.
|
||||||
|
123
ext/fts3/fts3speed.tcl
Normal file
123
ext/fts3/fts3speed.tcl
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# This script contains several sub-programs used to test FTS3/FTS4
|
||||||
|
# performance. It does not run the queries directly, but generates SQL
|
||||||
|
# scripts that can be run using the shell tool.
|
||||||
|
#
|
||||||
|
# The following cases are tested:
|
||||||
|
#
|
||||||
|
# 1. Inserting documents into an FTS3 table.
|
||||||
|
# 2. Optimizing an FTS3 table (i.e. "INSERT INTO t1 VALUES('optimize')").
|
||||||
|
# 3. Deleting documents from an FTS3 table.
|
||||||
|
# 4. Querying FTS3 tables.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Number of tokens in vocabulary. And number of tokens in each document.
|
||||||
|
#
|
||||||
|
set VOCAB_SIZE 2000
|
||||||
|
set DOC_SIZE 100
|
||||||
|
|
||||||
|
set NUM_INSERTS 1000
|
||||||
|
set NUM_SELECTS 1000
|
||||||
|
|
||||||
|
# Force everything in this script to be deterministic.
|
||||||
|
#
|
||||||
|
expr {srand(0)}
|
||||||
|
|
||||||
|
proc usage {} {
|
||||||
|
puts stderr "Usage: $::argv0 <rows> <selects>"
|
||||||
|
exit -1
|
||||||
|
}
|
||||||
|
|
||||||
|
proc sql {sql} {
|
||||||
|
puts $::fd $sql
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Return a list of $nWord randomly generated tokens each between 2 and 10
|
||||||
|
# characters in length.
|
||||||
|
#
|
||||||
|
proc build_vocab {nWord} {
|
||||||
|
set ret [list]
|
||||||
|
set chars [list a b c d e f g h i j k l m n o p q r s t u v w x y z]
|
||||||
|
for {set i 0} {$i<$nWord} {incr i} {
|
||||||
|
set len [expr {int((rand()*9.0)+2)}]
|
||||||
|
set term ""
|
||||||
|
for {set j 0} {$j<$len} {incr j} {
|
||||||
|
append term [lindex $chars [expr {int(rand()*[llength $chars])}]]
|
||||||
|
}
|
||||||
|
lappend ret $term
|
||||||
|
}
|
||||||
|
set ret
|
||||||
|
}
|
||||||
|
|
||||||
|
proc select_term {} {
|
||||||
|
set n [llength $::vocab]
|
||||||
|
set t [expr int(rand()*$n*3)]
|
||||||
|
if {$t>=2*$n} { set t [expr {($t-2*$n)/100}] }
|
||||||
|
if {$t>=$n} { set t [expr {($t-$n)/10}] }
|
||||||
|
lindex $::vocab $t
|
||||||
|
}
|
||||||
|
|
||||||
|
proc select_doc {nTerm} {
|
||||||
|
set ret [list]
|
||||||
|
for {set i 0} {$i<$nTerm} {incr i} {
|
||||||
|
lappend ret [select_term]
|
||||||
|
}
|
||||||
|
set ret
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_1 {nInsert} {
|
||||||
|
sql "PRAGMA synchronous = OFF;"
|
||||||
|
sql "DROP TABLE IF EXISTS t1;"
|
||||||
|
sql "CREATE VIRTUAL TABLE t1 USING fts4;"
|
||||||
|
for {set i 0} {$i < $nInsert} {incr i} {
|
||||||
|
set doc [select_doc $::DOC_SIZE]
|
||||||
|
#sql "INSERT INTO t1 VALUES('$doc');"
|
||||||
|
sql "\"$doc\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_2 {} {
|
||||||
|
sql "INSERT INTO t1(t1) VALUES('optimize');"
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_3 {nSelect} {
|
||||||
|
for {set i 0} {$i < $nSelect} {incr i} {
|
||||||
|
sql "SELECT count(*) FROM t1 WHERE t1 MATCH '[select_term]';"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_4 {nSelect} {
|
||||||
|
for {set i 0} {$i < $nSelect} {incr i} {
|
||||||
|
sql "SELECT count(*) FROM t1 WHERE t1 MATCH '[select_term] [select_term]';"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if {[llength $argv]!=0} usage
|
||||||
|
|
||||||
|
set ::vocab [build_vocab $::VOCAB_SIZE]
|
||||||
|
|
||||||
|
set ::fd [open fts3speed_insert.sql w]
|
||||||
|
test_1 $NUM_INSERTS
|
||||||
|
close $::fd
|
||||||
|
|
||||||
|
set ::fd [open fts3speed_select.sql w]
|
||||||
|
test_3 $NUM_SELECTS
|
||||||
|
close $::fd
|
||||||
|
|
||||||
|
set ::fd [open fts3speed_select2.sql w]
|
||||||
|
test_4 $NUM_SELECTS
|
||||||
|
close $::fd
|
||||||
|
|
||||||
|
set ::fd [open fts3speed_optimize.sql w]
|
||||||
|
test_2
|
||||||
|
close $::fd
|
||||||
|
|
||||||
|
puts "Success. Created files:"
|
||||||
|
puts " fts3speed_insert.sql"
|
||||||
|
puts " fts3speed_select.sql"
|
||||||
|
puts " fts3speed_select2.sql"
|
||||||
|
puts " fts3speed_optimize.sql"
|
||||||
|
|
46
manifest
46
manifest
@ -1,8 +1,5 @@
|
|||||||
-----BEGIN PGP SIGNED MESSAGE-----
|
C Experimental\schanges\sto\sfts4\sto\stry\sto\sselectively\savoid\sloading\svery\slarge\sdoclists.
|
||||||
Hash: SHA1
|
D 2010-10-19T14:08:00
|
||||||
|
|
||||||
C Avoid\staking\slocks\son\sunused\sdatabase\sconnections\swhen\scommitting\sa\nread\stransaction.
|
|
||||||
D 2010-10-14T01:17:30
|
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in b01fdfcfecf8a0716c29867a67959f6148b79961
|
F Makefile.in b01fdfcfecf8a0716c29867a67959f6148b79961
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@ -64,19 +61,20 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
|
|||||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||||
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
|
||||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||||
F ext/fts3/fts3.c 03be86c59ac1a60d448c6eda460a8975ff2f170d
|
F ext/fts3/fts3.c 9d4ccf3b7bbfbeeef03dba91377c4d72b757dcb9
|
||||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||||
F ext/fts3/fts3Int.h b4f0b05ccafe1e5b4be2f052e9840dbd78a0395f
|
F ext/fts3/fts3Int.h a640e4fbdb2fcab1457f87993ca3f4ceaa31e776
|
||||||
F ext/fts3/fts3_expr.c 42d5697731cd30fbeabd081bb3e6d3df5531f606
|
F ext/fts3/fts3_expr.c a5aee50edde20e5c9116199bd58be869a3a22c9f
|
||||||
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
|
||||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||||
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
|
||||||
F ext/fts3/fts3_porter.c 8df6f6efcc4e9e31f8bf73a4007c2e9abca1dfba
|
F ext/fts3/fts3_porter.c 8df6f6efcc4e9e31f8bf73a4007c2e9abca1dfba
|
||||||
F ext/fts3/fts3_snippet.c 2c4c921155e4b6befd272041fb903d999ac07d30
|
F ext/fts3/fts3_snippet.c 474c11e718610cade73e6009f75ffc173d4c42c5
|
||||||
F ext/fts3/fts3_tokenizer.c b4f2d01c24573852755bc92864816785dae39318
|
F ext/fts3/fts3_tokenizer.c b4f2d01c24573852755bc92864816785dae39318
|
||||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||||
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
||||||
F ext/fts3/fts3_write.c 97a583b9e1d23d5af4278f3ee3c16a37c3e077f4
|
F ext/fts3/fts3_write.c 29b63a98de55d4eb34b7fc6fd90b3224d6cdc7ff
|
||||||
|
F ext/fts3/fts3speed.tcl 71b9cdc8f499822124a9eef42003e31a88f26f16
|
||||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||||
@ -422,7 +420,7 @@ F test/fts3ad.test e40570cb6f74f059129ad48bcef3d7cbc20dda49
|
|||||||
F test/fts3ae.test ce32a13b34b0260928e4213b4481acf801533bda
|
F test/fts3ae.test ce32a13b34b0260928e4213b4481acf801533bda
|
||||||
F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c
|
F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c
|
||||||
F test/fts3ag.test 0b7d303f61ae5d620c4efb5e825713ea34ff9441
|
F test/fts3ag.test 0b7d303f61ae5d620c4efb5e825713ea34ff9441
|
||||||
F test/fts3ah.test ba181d6a3dee0c929f0d69df67cac9c47cda6bff
|
F test/fts3ah.test 3c5a1bd49979d7b5b5ed9fdbcdd14a7bfe5a5ff9
|
||||||
F test/fts3ai.test d29cee6ed653e30de478066881cec8aa766531b2
|
F test/fts3ai.test d29cee6ed653e30de478066881cec8aa766531b2
|
||||||
F test/fts3aj.test 584facbc9ac4381a7ec624bfde677340ffc2a5a4
|
F test/fts3aj.test 584facbc9ac4381a7ec624bfde677340ffc2a5a4
|
||||||
F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||||
@ -433,8 +431,9 @@ F test/fts3ao.test 8fee868a0e131b98ce3e8907dc69936278e8b29a
|
|||||||
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
|
||||||
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
|
||||||
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
|
||||||
F test/fts3cov.test 3a9d8618a3107166530c447e808f8992372e0415
|
F test/fts3cov.test 6f1ff88ff6b5abcfff6979098cb9d0c68a69202e
|
||||||
F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
|
F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
|
||||||
|
F test/fts3defer.test a9f81bba6e1132dd6a2ad3cf11e4628733975c8c
|
||||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||||
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||||
@ -535,7 +534,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
|||||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||||
F test/malloc_common.tcl cda732c0d2365a058c2a73778cf6b6da6db54452
|
F test/malloc_common.tcl 9dfb33f12173f9a8b029dae0443c569b59b980b6
|
||||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||||
@ -570,7 +569,7 @@ F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
|||||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||||
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
||||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||||
F test/permutations.test ca1c985cf68c692096d0325b33c62f2b576446a5
|
F test/permutations.test ec9b2ebd52ff43c5a3bec4723098fab1ef29d944
|
||||||
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
||||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||||
@ -876,14 +875,11 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||||
P ea8c2f5f8a890dcb422e9e46298ae6ca378c74b7
|
P c0ee614fd988f445c4884a37f494479bdd669185
|
||||||
R 03d2b3a92f9647a3db71aa9ca75489f4
|
R 0c4aebbf44d624104504e37bec992917
|
||||||
U drh
|
T *bgcolor * #c0ffc0
|
||||||
Z c2cdb52e62b9c570a5e1c8427f4ce5c4
|
T *branch * experimental
|
||||||
-----BEGIN PGP SIGNATURE-----
|
T *sym-experimental *
|
||||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
iD8DBQFMtlotoxKgR168RlERAuf0AJ96F+hVDOt4y4GU2wooqTHtO4kKZgCeKIVj
|
Z c2b99a58ccad27405ff8b0fcedef5c33
|
||||||
dUPTQwgWJgqAaN5BweGLucY=
|
|
||||||
=QYIr
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
|
@ -1 +1 @@
|
|||||||
c0ee614fd988f445c4884a37f494479bdd669185
|
5ae0ba447a561e3b6637b52f9b83a9fc683d2572
|
@ -1,37 +1,32 @@
|
|||||||
# 2006 October 31 (scaaarey)
|
# 2006 October 31
|
||||||
#
|
#
|
||||||
# The author disclaims copyright to this source code.
|
# 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
|
# This file implements regression tests for SQLite library. The focus
|
||||||
# here is testing correct handling of excessively long terms.
|
# here is testing correct handling of very long terms.
|
||||||
#
|
|
||||||
# $Id: fts3ah.test,v 1.1 2007/08/20 17:38:42 shess Exp $
|
|
||||||
#
|
#
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
|
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||||
ifcapable !fts3 {
|
ifcapable !fts3 {
|
||||||
finish_test
|
finish_test
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate a term of len copies of char.
|
|
||||||
proc bigterm {char len} {
|
|
||||||
for {set term ""} {$len>0} {incr len -1} {
|
|
||||||
append term $char
|
|
||||||
}
|
|
||||||
return $term
|
|
||||||
}
|
|
||||||
|
|
||||||
# Generate a document of bigterms based on characters from the list
|
# Generate a document of bigterms based on characters from the list
|
||||||
# chars.
|
# chars.
|
||||||
proc bigtermdoc {chars len} {
|
proc bigtermdoc {chars len} {
|
||||||
set doc ""
|
set doc ""
|
||||||
foreach char $chars {
|
foreach char $chars {
|
||||||
append doc " " [bigterm $char $len]
|
append doc " " [string repeat $char $len]
|
||||||
}
|
}
|
||||||
return $doc
|
return $doc
|
||||||
}
|
}
|
||||||
@ -41,9 +36,9 @@ set doc1 [bigtermdoc {a b c d} $len]
|
|||||||
set doc2 [bigtermdoc {b d e f} $len]
|
set doc2 [bigtermdoc {b d e f} $len]
|
||||||
set doc3 [bigtermdoc {a c e} $len]
|
set doc3 [bigtermdoc {a c e} $len]
|
||||||
|
|
||||||
set aterm [bigterm a $len]
|
set aterm [string repeat a $len]
|
||||||
set bterm [bigterm b $len]
|
set bterm [string repeat b $len]
|
||||||
set xterm [bigterm x $len]
|
set xterm [string repeat x $len]
|
||||||
|
|
||||||
db eval {
|
db eval {
|
||||||
CREATE VIRTUAL TABLE t1 USING fts3(content);
|
CREATE VIRTUAL TABLE t1 USING fts3(content);
|
||||||
|
@ -82,27 +82,28 @@ do_test fts3cov-2.1 {
|
|||||||
INSERT INTO t1 VALUES('And she in the midnight wood will pray');
|
INSERT INTO t1 VALUES('And she in the midnight wood will pray');
|
||||||
INSERT INTO t1 VALUES('For the weal of her lover that''s far away.');
|
INSERT INTO t1 VALUES('For the weal of her lover that''s far away.');
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
INSERT INTO t1(t1) VALUES('optimize');
|
INSERT INTO t1(t1) VALUES('optimize');
|
||||||
SELECT substr(hex(root), 1, 2) FROM t1_segdir;
|
SELECT substr(hex(root), 1, 2) FROM t1_segdir;
|
||||||
}
|
}
|
||||||
} {03}
|
} {03}
|
||||||
|
|
||||||
# Test the "missing entry" case:
|
# Test the "missing entry" case:
|
||||||
do_test fts3cov-2.1 {
|
do_test fts3cov-2.2 {
|
||||||
set root [db one {SELECT root FROM t1_segdir}]
|
set root [db one {SELECT root FROM t1_segdir}]
|
||||||
read_fts3varint [string range $root 1 end] left_child
|
read_fts3varint [string range $root 1 end] left_child
|
||||||
execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
|
execsql { DELETE FROM t1_segments WHERE blockid = $left_child }
|
||||||
} {}
|
} {}
|
||||||
do_error_test fts3cov-2.2 {
|
do_error_test fts3cov-2.3 {
|
||||||
SELECT * FROM t1 WHERE t1 MATCH 'c*'
|
SELECT * FROM t1 WHERE t1 MATCH 'c*'
|
||||||
} {database disk image is malformed}
|
} {database disk image is malformed}
|
||||||
|
|
||||||
# Test the "replaced with NULL" case:
|
# Test the "replaced with NULL" case:
|
||||||
do_test fts3cov-2.3 {
|
do_test fts3cov-2.4 {
|
||||||
execsql { INSERT INTO t1_segments VALUES($left_child, NULL) }
|
execsql { INSERT INTO t1_segments VALUES($left_child, NULL) }
|
||||||
} {}
|
} {}
|
||||||
do_error_test fts3cov-2.4 {
|
do_error_test fts3cov-2.5 {
|
||||||
SELECT * FROM t1 WHERE t1 MATCH 'cloud'
|
SELECT * FROM t1 WHERE t1 MATCH 'cloud'
|
||||||
} {database disk image is malformed}
|
} {database disk image is malformed}
|
||||||
|
|
||||||
|
360
test/fts3defer.test
Normal file
360
test/fts3defer.test
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
# 2010 October 15
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
source $testdir/malloc_common.tcl
|
||||||
|
|
||||||
|
ifcapable !fts3 {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
set ::testprefix fts3defer
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# Test cases fts3defer-1.* are the "warm body" cases. The database contains
|
||||||
|
# one row with 15000 instances of the token "a". This makes the doclist for
|
||||||
|
# "a" so large that FTS3 will avoid loading it in most cases.
|
||||||
|
#
|
||||||
|
# To show this, test cases fts3defer-1.2.* execute a bunch of FTS3 queries
|
||||||
|
# involving token "a". Then, fts3defer-1.3.* replaces the doclist for token
|
||||||
|
# "a" with all zeroes and fts3defer-1.4.* repeats the tests from 1.2. If
|
||||||
|
# the tests still work, we can conclude that the doclist for "a" was not
|
||||||
|
# used.
|
||||||
|
#
|
||||||
|
|
||||||
|
set aaa [string repeat "a " 15000]
|
||||||
|
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
CREATE VIRTUAL TABLE t1 USING fts4;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES('this is a dog');
|
||||||
|
INSERT INTO t1 VALUES('an instance of a phrase');
|
||||||
|
INSERT INTO t1 VALUES('an instance of a longer phrase');
|
||||||
|
INSERT INTO t1 VALUES($aaa);
|
||||||
|
COMMIT;
|
||||||
|
} {}
|
||||||
|
|
||||||
|
set tests {
|
||||||
|
1 {SELECT rowid FROM t1 WHERE t1 MATCH '"a dog"'} {1}
|
||||||
|
2 {SELECT rowid FROM t1 WHERE t1 MATCH '"is a dog"'} {1}
|
||||||
|
3 {SELECT rowid FROM t1 WHERE t1 MATCH '"a longer phrase"'} {3}
|
||||||
|
4 {SELECT snippet(t1) FROM t1 WHERE t1 MATCH '"a longer phrase"'}
|
||||||
|
{"an instance of <b>a</b> <b>longer</b> <b>phrase</b>"}
|
||||||
|
5 {SELECT rowid FROM t1 WHERE t1 MATCH 'a dog'} {1}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_select_tests 1.2 $tests
|
||||||
|
|
||||||
|
do_execsql_test 1.3 {
|
||||||
|
SELECT count(*) FROM t1_segments WHERE length(block)>10000;
|
||||||
|
UPDATE t1_segments
|
||||||
|
SET block = zeroblob(length(block))
|
||||||
|
WHERE length(block)>10000;
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_select_tests 1.4 $tests
|
||||||
|
|
||||||
|
# Drop the table. It is corrupt now anyhow, so not useful for subsequent tests.
|
||||||
|
#
|
||||||
|
do_execsql_test 1.5 { DROP TABLE t1 }
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# These tests - fts3defer-2.* - are more rigorous. They test that for a
|
||||||
|
# variety of queries, FTS3 and FTS4 return the same results. And that
|
||||||
|
# zeroing the very large doclists that FTS4 does not load does not change
|
||||||
|
# the results.
|
||||||
|
#
|
||||||
|
# They use the following pseudo-randomly generated document data. The
|
||||||
|
# tokens "zm" and "jk" are especially common in this dataset. Additionally,
|
||||||
|
# two documents are added to the pseudo-random data before it is loaded
|
||||||
|
# into FTS4 containing 100,000 instances of the "zm" and "jk" tokens. This
|
||||||
|
# makes the doclists for those tokens so large that FTS4 avoids loading them
|
||||||
|
# into memory if possible.
|
||||||
|
#
|
||||||
|
set data [list]
|
||||||
|
lappend data [string repeat "zm " 100000]
|
||||||
|
lappend data [string repeat "jk " 100000]
|
||||||
|
lappend data {*}{
|
||||||
|
"zm zm agmckuiu uhzq nsab jk rrkx duszemmzl hyq jk"
|
||||||
|
"jk uhzq zm zm rgpzmlnmd zm zk jk jk zm"
|
||||||
|
"duszemmzl zm jk xldlpy zm jk sbptoa xh jk xldlpy"
|
||||||
|
"zm xh zm xqf azavwm jk jk trqd rgpzmlnmd jk"
|
||||||
|
"zm vwq urvysbnykk ubwrfqnbjf zk lsz jk doiwavhwwo jk jk"
|
||||||
|
"jk xduvfhk orpfawpx zkhdvkw jk mjpavjuhw zm jk duszemmzl zm"
|
||||||
|
"jk igju jk jk zm hmjf xh zm gwdfhwurx zk"
|
||||||
|
"vgsld jk jk zm hrlipdm jn zm zsmhnf vgsld duszemmzl"
|
||||||
|
"gtuiexzsu aayxpmve zm zm zm drir scpgna xh azavwm uhzq"
|
||||||
|
"farlehdhq hkfoudzftq igju duszemmzl xnxhf ewle zm hrlipdm urvysbnykk kn"
|
||||||
|
"xnxhf jk jk agmckuiu duszemmzl jk zm zm jk vgsld"
|
||||||
|
"zm zm zm jk jk urvysbnykk ogttbykvt zm zm jk"
|
||||||
|
"iasrqgqv zm azavwm zidhxhbtv jk jk mjpavjuhw zm zm ajmvcydy"
|
||||||
|
"rgpzmlnmd tmt mjpavjuhw xh igju jk azavwm fibokdry vgsld ofm"
|
||||||
|
"zm jk vgsld jk xh jk csjqxhgj drir jk pmrb"
|
||||||
|
"xh jk jk zm rrkx duszemmzl mjpavjuhw xldlpy igju zm"
|
||||||
|
"jk hkfoudzftq zf rrkx wdmy jupk jk zm urvysbnykk npywgdvgz"
|
||||||
|
"zm jk zm zm zhbrzadb uenvbm aayxpmve urvysbnykk duszemmzl jk"
|
||||||
|
"uenvbm jk zm fxw xh bdilwmjw mjpavjuhw uv jk zm"
|
||||||
|
"nk jk bnhc pahlds jk igju dzadnqzprr jk jk jk"
|
||||||
|
"uhzq uv zm duszemmzl tlqix jk jk xh jk zm"
|
||||||
|
"jk zm agmckuiu urvysbnykk jk jk zm zm jk jk"
|
||||||
|
"azavwm mjpavjuhw lsgshn trqd xldlpy ogyavjvv agmckuiu ryvwwhlbc jk jk"
|
||||||
|
"tmt jk zk zm azavwm ofm acpgim bvgimjik iasrqgqv wuvajhwqz"
|
||||||
|
"igju ogyavjvv xrbdak rrkx fibokdry zf ujfhmrllq jk zm hxgwvib"
|
||||||
|
"zm pahlds jk uenvbm aayxpmve iaf hmjf xph vnlyvtkgx zm"
|
||||||
|
"jk xnxhf igju jk xh jk nvfasfh zm js jk"
|
||||||
|
"zm zm rwaj igju xr rrkx xnxhf nvfasfh skxbsqzvmt xatbxeqq"
|
||||||
|
"vgsld zm ujfhmrllq uhzq ogyavjvv nsab azavwm zm vgsld jmfiqhwnjg"
|
||||||
|
"ymjoym duszemmzl urvysbnykk azavwm jk jmfiqhwnjg bu qcdziqomqk vnlyvtkgx"
|
||||||
|
"zm nbilqcnz dzadnqzprr xh bkfgzsxn urvysbnykk xrujfzxqf zm zf agmckuiu"
|
||||||
|
"jk urvysbnykk nvfasfh zf xh zm zm qcdziqomqk qvxtclg wdmy"
|
||||||
|
"fibokdry jk urvysbnykk jk xr osff zm cvnnsl zm vgsld"
|
||||||
|
"jk mjpavjuhw hkfoudzftq jk zm xh xqf urvysbnykk jk iasrqgqv"
|
||||||
|
"jk csjqxhgj duszemmzl iasrqgqv aayxpmve zm brsuoqww jk qpmhtvl wluvgsw"
|
||||||
|
"jk mj azavwm jk zm jn dzadnqzprr zm jk uhzq"
|
||||||
|
"zk xqf jupk fxw nbilqcnz zm jk jcpiwj tznlvbfcv nvfasfh"
|
||||||
|
"jk jcpiwj zm xnxhf zm mjpavjuhw mj drir pa pvjrjlas"
|
||||||
|
"duszemmzl dzadnqzprr jk swc duszemmzl tmt jk jk pahlds jk"
|
||||||
|
"zk zm jk zm zm eczkjblu zm hi pmrb jk"
|
||||||
|
"azavwm zm iz agmckuiu jk sntk jk duszemmzl duszemmzl zm"
|
||||||
|
"jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf"
|
||||||
|
"jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh"
|
||||||
|
"wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw"
|
||||||
|
"gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh"
|
||||||
|
"zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm"
|
||||||
|
"sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju"
|
||||||
|
"vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj ithtir"
|
||||||
|
"zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk"
|
||||||
|
"zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk"
|
||||||
|
"zm zf uenvbm jk azavwm zm zm agmckuiu zm jk"
|
||||||
|
"rrkx jk zf jt zm oacaxgjoo fibokdry wdmy igju csjqxhgj"
|
||||||
|
"hi igju zm jk zidhxhbtv dzadnqzprr jk jk trqd duszemmzl"
|
||||||
|
"zm zm mjpavjuhw xrbdak qrvbjruc jk qzzqdxq guwq cvnnsl zm"
|
||||||
|
"ithtir jk jk qcdziqomqk zm farlehdhq zm zm xrbdak jk"
|
||||||
|
"ixfipk csjqxhgj azavwm sokcyf ttvgf vgsld jk sk xh zk"
|
||||||
|
"nvfasfh azavwm zm zm zm fxw nvfasfh zk gnl trqd"
|
||||||
|
"zm fibokdry csjqxhgj ofm dzadnqzprr jk akmikrqyt orpfawpx duszemmzl vwq"
|
||||||
|
"csjqxhgj jk jk vgsld urvysbnykk jk nxum jk jk nxum"
|
||||||
|
"zm hkfoudzftq jk ryvwwhlbc mjpavjuhw ephknonq jk zm ogyavjvv zm"
|
||||||
|
"lwa hi xnxhf qdyerbws zk njtc jk uhzq zm jk"
|
||||||
|
"trqd zm dzadnqzprr zm urvysbnykk jk lsz jk mjpavjuhw cmnnkna"
|
||||||
|
"duszemmzl zk jk jk fibokdry jseuhjnzo zm aayxpmve zk jk"
|
||||||
|
"fibokdry jk sviq qvxtclg wdmy jk doiwavhwwo zexh jk zm"
|
||||||
|
"jupk zm xh jk mjpavjuhw zm jk nsab npywgdvgz duszemmzl"
|
||||||
|
"zm igju zm zm nvfasfh eh hkfoudzftq fibokdry fxw xkblf"
|
||||||
|
"jk zm jk jk zm xh zk abthnzcv zf csjqxhgj"
|
||||||
|
"zm zm jk nkaotm urvysbnykk sbptoa bq jk ktxdty ubwrfqnbjf"
|
||||||
|
"nvfasfh aayxpmve xdcuz zm tugflixoex jcpiwj zm mjpavjuhw fibokdry doiwavhwwo"
|
||||||
|
"iaf jk mjpavjuhw zm duszemmzl jk jk uhzq pahlds fibokdry"
|
||||||
|
"ddjj zk azavwm jk swc zm gjtexkv jk xh jk"
|
||||||
|
"igju jk csjqxhgj zm jk dzadnqzprr duszemmzl ulvcbv jk jk"
|
||||||
|
"jk fibokdry zm csjqxhgj jn zm zm zm zf uhzq"
|
||||||
|
"duszemmzl jk xkblf zk hrlipdm aayxpmve uenvbm uhzq jk zf"
|
||||||
|
"dzadnqzprr jk zm zdu nvfasfh zm jk urvysbnykk hmjf jk"
|
||||||
|
"jk aayxpmve aserrdxm acpgim fibokdry jk drir wxe brsuoqww rrkx"
|
||||||
|
"uhzq csjqxhgj nvfasfh jk rrkx qbamok trqd uenvbm sntk zm"
|
||||||
|
"ps azavwm zkhdvkw jk zm jk jk zm csjqxhgj xedlrcfo"
|
||||||
|
"jk jk ogyavjvv jk zm farlehdhq duszemmzl jk agitgxamxe jk"
|
||||||
|
"qzzqdxq rwaj jk jk zm xqf jk uenvbm jk zk"
|
||||||
|
"zm hxgwvib akmikrqyt zf agmckuiu uenvbm bq npywgdvgz azavwm jk"
|
||||||
|
"zf jmfiqhwnjg js igju zm aayxpmve zm mbxnljomiv csjqxhgj nvfasfh"
|
||||||
|
"zm jk jk gazrt jk jk lkc jk nvfasfh jk"
|
||||||
|
"xldlpy orpfawpx zkhdvkw jk zm igju zm urvysbnykk dzadnqzprr mbxnljomiv"
|
||||||
|
"urvysbnykk jk zk igju zm uenvbm jk zm ithtir jk"
|
||||||
|
"zm zk zm zf ofm zm xdcuz dzadnqzprr zm vgsld"
|
||||||
|
"sbptoa jk tugflixoex jk zm zm vgsld zm xh zm"
|
||||||
|
"uhzq jk zk evvivo vgsld vniqnuynvf agmckuiu jk zm zm"
|
||||||
|
"zm nvfasfh zm zm zm abthnzcv uenvbm jk zk dzadnqzprr"
|
||||||
|
"zm azavwm igju qzzqdxq jk xnxhf abthnzcv jk nvfasfh zm"
|
||||||
|
"qbamok fxw vgsld igju cmnnkna xnxhf vniqnuynvf zk xh zm"
|
||||||
|
"nvfasfh zk zm mjpavjuhw dzadnqzprr jk jk duszemmzl xldlpy nvfasfh"
|
||||||
|
"xnxhf sviq nsab npywgdvgz osff vgsld farlehdhq fibokdry wjbkhzsa hhac"
|
||||||
|
"zm azavwm scpgna jk jk bq jk duszemmzl fibokdry ovkyevlgv"
|
||||||
|
"csjqxhgj zm jk jk duszemmzl zk xh zm jk zf"
|
||||||
|
"urvysbnykk dzadnqzprr csjqxhgj mjpavjuhw ubwrfqnbjf nkaotm jk jk zm drir"
|
||||||
|
"nvfasfh xh igju zm wluvgsw jk zm srwwnezqk ewle ovnq"
|
||||||
|
"jk nvfasfh eh ktxdty urvysbnykk vgsld zm jk eh uenvbm"
|
||||||
|
"orpfawpx pahlds jk uhzq hi zm zm zf jk dzadnqzprr"
|
||||||
|
"srwwnezqk csjqxhgj rbwzuf nvfasfh jcpiwj xldlpy nvfasfh jk vgsld wjybxmieki"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach {tn setup} {
|
||||||
|
1 {
|
||||||
|
set dmt_modes 0
|
||||||
|
execsql { CREATE VIRTUAL TABLE t1 USING FTS3 }
|
||||||
|
foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
|
||||||
|
}
|
||||||
|
2 {
|
||||||
|
set dmt_modes 0
|
||||||
|
execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
|
||||||
|
foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
|
||||||
|
}
|
||||||
|
3 {
|
||||||
|
set dmt_modes {0 1 2}
|
||||||
|
execsql { CREATE VIRTUAL TABLE t1 USING FTS4 }
|
||||||
|
foreach doc $data { execsql { INSERT INTO t1 VALUES($doc) } }
|
||||||
|
execsql {
|
||||||
|
UPDATE t1_segments
|
||||||
|
SET block = zeroblob(length(block))
|
||||||
|
WHERE length(block)>10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
|
||||||
|
execsql { DROP TABLE IF EXISTS t1 }
|
||||||
|
eval $setup
|
||||||
|
set ::testprefix fts3defer-2.$tn
|
||||||
|
set DO_MALLOC_TEST 0
|
||||||
|
|
||||||
|
do_execsql_test 0 {
|
||||||
|
SELECT count(*) FROM t1_segments WHERE length(block)>10000
|
||||||
|
} {2}
|
||||||
|
|
||||||
|
do_select_test 1.1 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'jk xnxhf'
|
||||||
|
} {13 29 40 47 48 52 63 92}
|
||||||
|
do_select_test 1.2 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'jk eh'
|
||||||
|
} {100}
|
||||||
|
do_select_test 1.3 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'jk ubwrfqnbjf'
|
||||||
|
} {7 70 98}
|
||||||
|
do_select_test 1.4 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'duszemmzl jk'
|
||||||
|
} {3 5 8 10 13 18 20 23 32 37 41 43 55 60 65 67 72 74 76 81 94 96 97}
|
||||||
|
do_select_test 1.5 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'ubwrfqnbjf jk'
|
||||||
|
} {7 70 98}
|
||||||
|
do_select_test 1.6 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'jk ubwrfqnbjf jk jk jk jk'
|
||||||
|
} {7 70 98}
|
||||||
|
do_select_test 1.7 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'zm xnxhf'
|
||||||
|
} {12 13 29 30 40 47 48 52 63 92 93}
|
||||||
|
do_select_test 1.8 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'zm eh'
|
||||||
|
} {68 100}
|
||||||
|
do_select_test 1.9 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'zm ubwrfqnbjf'
|
||||||
|
} {7 70 98}
|
||||||
|
|
||||||
|
do_select_test 2.1 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"zm agmckuiu"'
|
||||||
|
} {3 24 52 53}
|
||||||
|
do_select_test 2.2 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"zm zf"'
|
||||||
|
} {33 53 75 88 101}
|
||||||
|
do_select_test 2.3 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"zm aayxpmve"'
|
||||||
|
} {48 65 84}
|
||||||
|
do_select_test 2.4 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"aayxpmve zm"'
|
||||||
|
} {11 37 84}
|
||||||
|
do_select_test 2.5 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"jk azavwm"'
|
||||||
|
} {16 53}
|
||||||
|
do_select_test 2.6 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"xh jk jk"'
|
||||||
|
} {18}
|
||||||
|
do_select_test 2.7 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"zm jk vgsld"'
|
||||||
|
} {13 17}
|
||||||
|
|
||||||
|
do_select_test 3.1 {
|
||||||
|
SELECT snippet(t1, '[', ']') FROM t1 WHERE t1 MATCH '"zm agmckuiu"'
|
||||||
|
} {
|
||||||
|
{zm [zm] [agmckuiu] uhzq nsab jk rrkx duszemmzl hyq jk}
|
||||||
|
{jk [zm] [agmckuiu] urvysbnykk jk jk zm zm jk jk}
|
||||||
|
{[zm] [agmckuiu] zexh fibokdry jk uhzq bu tugflixoex xnxhf sk}
|
||||||
|
{zm zf uenvbm jk azavwm zm [zm] [agmckuiu] zm jk}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_select_test 3.2 {
|
||||||
|
SELECT snippet(t1, '[', ']') FROM t1 WHERE t1 MATCH 'xnxhf jk'
|
||||||
|
} {
|
||||||
|
{[xnxhf] [jk] [jk] agmckuiu duszemmzl [jk] zm zm [jk] vgsld}
|
||||||
|
{[jk] [xnxhf] igju [jk] xh [jk] nvfasfh zm js [jk]}
|
||||||
|
{[jk] jcpiwj zm [xnxhf] zm mjpavjuhw mj drir pa pvjrjlas}
|
||||||
|
{gazrt [jk] ephknonq myjp uenvbm wuvajhwqz [jk] zm [xnxhf] nvfasfh}
|
||||||
|
{zm aayxpmve csjqxhgj [xnxhf] xr [jk] aayxpmve [xnxhf] zm zm}
|
||||||
|
{zm agmckuiu zexh fibokdry [jk] uhzq bu tugflixoex [xnxhf] sk}
|
||||||
|
{lwa hi [xnxhf] qdyerbws zk njtc [jk] uhzq zm [jk]}
|
||||||
|
{zm azavwm igju qzzqdxq [jk] [xnxhf] abthnzcv [jk] nvfasfh zm}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_select_test 4.1 {
|
||||||
|
SELECT offsets(t1) FROM t1 WHERE t1 MATCH '"jk uenvbm"'
|
||||||
|
} {
|
||||||
|
{0 0 10 2 0 1 13 6} {0 0 26 2 0 1 29 6}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_select_test 4.2 {
|
||||||
|
SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'duszemmzl jk fibokdry'
|
||||||
|
} {
|
||||||
|
{0 2 3 8 0 1 36 2 0 0 58 9}
|
||||||
|
{0 0 0 9 0 1 13 2 0 1 16 2 0 2 19 8 0 1 53 2}
|
||||||
|
{0 1 4 2 0 0 20 9 0 1 30 2 0 1 33 2 0 2 48 8}
|
||||||
|
{0 1 17 2 0 1 20 2 0 1 26 2 0 0 29 9 0 2 39 8}
|
||||||
|
}
|
||||||
|
|
||||||
|
# The following block of tests runs normally with FTS3 or FTS4 without the
|
||||||
|
# long doclists zeroed. And with OOM-injection for FTS4 with long doclists
|
||||||
|
# zeroed. Change this by messing with the [set dmt_modes] commands above.
|
||||||
|
#
|
||||||
|
foreach DO_MALLOC_TEST $dmt_modes {
|
||||||
|
|
||||||
|
# Phrase search.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.1 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH '"jk mjpavjuhw"'
|
||||||
|
} {8 15 36 64 67 72}
|
||||||
|
|
||||||
|
# Multiple tokens search.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.2 {
|
||||||
|
SELECT rowid FROM t1 WHERE t1 MATCH 'duszemmzl zm'
|
||||||
|
} {3 5 8 10 12 13 18 20 23 37 43 55 60 65 67 72 74 81 94 96 97}
|
||||||
|
|
||||||
|
# snippet() function with phrase.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.3 {
|
||||||
|
SELECT snippet(t1, '[', ']') FROM t1 WHERE t1 MATCH '"zm aayxpmve"'
|
||||||
|
} {
|
||||||
|
{[zm] [aayxpmve] csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm}
|
||||||
|
{duszemmzl zk jk jk fibokdry jseuhjnzo [zm] [aayxpmve] zk jk}
|
||||||
|
{zf jmfiqhwnjg js igju [zm] [aayxpmve] zm mbxnljomiv csjqxhgj nvfasfh}
|
||||||
|
}
|
||||||
|
|
||||||
|
# snippet() function with multiple tokens.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.4 {
|
||||||
|
SELECT snippet(t1, '[', ']') FROM t1 WHERE t1 MATCH 'zm zhbrzadb'
|
||||||
|
} {
|
||||||
|
{[zm] jk [zm] [zm] [zhbrzadb] uenvbm aayxpmve urvysbnykk duszemmzl jk}
|
||||||
|
}
|
||||||
|
|
||||||
|
# snippet() function with phrase.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.5 {
|
||||||
|
SELECT offsets(t1) FROM t1 WHERE t1 MATCH '"zm aayxpmve"'
|
||||||
|
} {
|
||||||
|
{0 0 0 2 0 1 3 8} {0 0 38 2 0 1 41 8} {0 0 22 2 0 1 25 8}
|
||||||
|
}
|
||||||
|
|
||||||
|
# snippet() function with multiple tokens.
|
||||||
|
do_select_test 5.$DO_MALLOC_TEST.6 {
|
||||||
|
SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'zm zhbrzadb'
|
||||||
|
} {
|
||||||
|
{0 0 0 2 0 0 6 2 0 0 9 2 0 1 12 8}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
@ -526,7 +526,7 @@ proc do_malloc_test {tn args} {
|
|||||||
# match the expected results passed via parameter $result.
|
# match the expected results passed via parameter $result.
|
||||||
#
|
#
|
||||||
proc do_select_test {name sql result} {
|
proc do_select_test {name sql result} {
|
||||||
uplevel [list doPassiveTest 0 $name $sql [list 0 $result]]
|
uplevel [list doPassiveTest 0 $name $sql [list 0 [list {*}$result]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
proc do_restart_select_test {name sql result} {
|
proc do_restart_select_test {name sql result} {
|
||||||
@ -540,6 +540,12 @@ proc do_error_test {name sql error} {
|
|||||||
proc doPassiveTest {isRestart name sql catchres} {
|
proc doPassiveTest {isRestart name sql catchres} {
|
||||||
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
|
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
|
||||||
|
|
||||||
|
if {[info exists ::testprefix]
|
||||||
|
&& [string is integer [string range $name 0 0]]
|
||||||
|
} {
|
||||||
|
set name $::testprefix.$name
|
||||||
|
}
|
||||||
|
|
||||||
switch $::DO_MALLOC_TEST {
|
switch $::DO_MALLOC_TEST {
|
||||||
0 { # No malloc failures.
|
0 { # No malloc failures.
|
||||||
do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
|
do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
|
||||||
|
@ -166,7 +166,7 @@ test_suite "fts3" -prefix "" -description {
|
|||||||
fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test
|
fts3ak.test fts3al.test fts3am.test fts3an.test fts3ao.test
|
||||||
fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test
|
fts3atoken.test fts3b.test fts3c.test fts3cov.test fts3d.test
|
||||||
fts3e.test fts3expr.test fts3expr2.test fts3near.test
|
fts3e.test fts3expr.test fts3expr2.test fts3near.test
|
||||||
fts3query.test fts3snippet.test
|
fts3query.test fts3snippet.test fts3defer.test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user