mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Add the "columnsize=" option to fts5, similar to fts4's "matchinfo=fts3".
FossilOrigin-Name: aa12f9d9b79c2f523fd6b00e47bcb66dba09ce0c
This commit is contained in:
@ -1039,6 +1039,7 @@ static int fts5FilterMethod(
|
||||
sqlite3_value **apVal /* Arguments for the indexing scheme */
|
||||
){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
||||
int rc = SQLITE_OK; /* Error code */
|
||||
int iVal = 0; /* Counter for apVal[] */
|
||||
@ -1049,7 +1050,7 @@ static int fts5FilterMethod(
|
||||
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
|
||||
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
|
||||
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
|
||||
char **pzErrmsg = pTab->pConfig->pzErrmsg;
|
||||
char **pzErrmsg = pConfig->pzErrmsg;
|
||||
|
||||
assert( pCsr->pStmt==0 );
|
||||
assert( pCsr->pExpr==0 );
|
||||
@ -1059,7 +1060,7 @@ static int fts5FilterMethod(
|
||||
assert( pCsr->zRankArgs==0 );
|
||||
|
||||
assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
|
||||
pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
pConfig->pzErrmsg = &pTab->base.zErrMsg;
|
||||
|
||||
/* Decode the arguments passed through to this function.
|
||||
**
|
||||
@ -1107,7 +1108,7 @@ static int fts5FilterMethod(
|
||||
}else if( pMatch ){
|
||||
const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
|
||||
|
||||
rc = fts5CursorParseRank(pTab->pConfig, pCsr, pRank);
|
||||
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( zExpr[0]=='*' ){
|
||||
/* The user has issued a query of the form "MATCH '*...'". This
|
||||
@ -1116,7 +1117,7 @@ static int fts5FilterMethod(
|
||||
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
|
||||
}else{
|
||||
char **pzErr = &pTab->base.zErrMsg;
|
||||
rc = sqlite3Fts5ExprNew(pTab->pConfig, zExpr, &pCsr->pExpr, pzErr);
|
||||
rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bOrderByRank ){
|
||||
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
|
||||
@ -1128,6 +1129,11 @@ static int fts5FilterMethod(
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if( pConfig->zContent==0 ){
|
||||
*pConfig->pzErrmsg = sqlite3_mprintf(
|
||||
"%s: table does not support scanning", pConfig->zName
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
|
||||
** by rowid (ePlan==FTS5_PLAN_ROWID). */
|
||||
@ -1146,7 +1152,7 @@ static int fts5FilterMethod(
|
||||
}
|
||||
}
|
||||
|
||||
pTab->pConfig->pzErrmsg = pzErrmsg;
|
||||
pConfig->pzErrmsg = pzErrmsg;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1621,23 +1627,58 @@ static int fts5ApiColumnText(
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fts5ColumnSizeCb(
|
||||
void *pContext, /* Pointer to int */
|
||||
const char *pToken, /* Buffer containing token */
|
||||
int nToken, /* Size of token in bytes */
|
||||
int iStart, /* Start offset of token */
|
||||
int iEnd /* End offset of token */
|
||||
){
|
||||
int *pCnt = (int*)pContext;
|
||||
*pCnt = *pCnt + 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
Fts5Config *pConfig = pTab->pConfig;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
|
||||
i64 iRowid = fts5CursorRowid(pCsr);
|
||||
rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
|
||||
if( pConfig->bColumnsize ){
|
||||
i64 iRowid = fts5CursorRowid(pCsr);
|
||||
rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
|
||||
}else if( pConfig->zContent==0 ){
|
||||
int i;
|
||||
for(i=0; i<pConfig->nCol; i++){
|
||||
if( pConfig->abUnindexed[i]==0 ){
|
||||
pCsr->aColumnSize[i] = -1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
int i;
|
||||
for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
|
||||
if( pConfig->abUnindexed[i]==0 ){
|
||||
const char *z; int n;
|
||||
void *p = (void*)(&pCsr->aColumnSize[i]);
|
||||
pCsr->aColumnSize[i] = 0;
|
||||
rc = fts5ApiColumnText(pCtx, i, &z, &n);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5Tokenize(pConfig, z, n, p, fts5ColumnSizeCb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
|
||||
}
|
||||
if( iCol<0 ){
|
||||
int i;
|
||||
*pnToken = 0;
|
||||
for(i=0; i<pTab->pConfig->nCol; i++){
|
||||
for(i=0; i<pConfig->nCol; i++){
|
||||
*pnToken += pCsr->aColumnSize[i];
|
||||
}
|
||||
}else if( iCol<pTab->pConfig->nCol ){
|
||||
}else if( iCol<pConfig->nCol ){
|
||||
*pnToken = pCsr->aColumnSize[iCol];
|
||||
}else{
|
||||
*pnToken = 0;
|
||||
@ -1956,7 +1997,7 @@ static int fts5FindFunctionMethod(
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of FTS3 xRename method. Rename an fts5 table.
|
||||
** Implementation of FTS5 xRename method. Rename an fts5 table.
|
||||
*/
|
||||
static int fts5RenameMethod(
|
||||
sqlite3_vtab *pVtab, /* Virtual table handle */
|
||||
|
@ -105,6 +105,9 @@ typedef struct Fts5Config Fts5Config;
|
||||
** decent error message if it encounters a file-format version it does
|
||||
** not understand.
|
||||
**
|
||||
** bColumnsize:
|
||||
** True if the %_docsize table is created.
|
||||
**
|
||||
*/
|
||||
struct Fts5Config {
|
||||
sqlite3 *db; /* Database handle */
|
||||
@ -118,6 +121,7 @@ struct Fts5Config {
|
||||
int eContent; /* An FTS5_CONTENT value */
|
||||
char *zContent; /* content table */
|
||||
char *zContentRowid; /* "content_rowid=" option value */
|
||||
int bColumnsize; /* "columnsize=" option value (dflt==1) */
|
||||
char *zContentExprlist;
|
||||
Fts5Tokenizer *pTok;
|
||||
fts5_tokenizer *pTokApi;
|
||||
@ -196,6 +200,8 @@ void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
|
||||
void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
|
||||
void sqlite3Fts5BufferAppend32(int*, Fts5Buffer*, int);
|
||||
|
||||
char *sqlite3Fts5Mprintf(int *pRc, char *zFmt, ...);
|
||||
|
||||
#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
|
||||
#define fts5BufferGrow(a,b,c) sqlite3Fts5BufferGrow(a,b,c)
|
||||
#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
|
||||
|
@ -125,6 +125,21 @@ void sqlite3Fts5BufferAppendPrintf(
|
||||
}
|
||||
}
|
||||
|
||||
char *sqlite3Fts5Mprintf(int *pRc, char *zFmt, ...){
|
||||
char *zRet = 0;
|
||||
if( *pRc==SQLITE_OK ){
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
zRet = sqlite3_vmprintf(zFmt, ap);
|
||||
va_end(ap);
|
||||
if( zRet==0 ){
|
||||
*pRc = SQLITE_NOMEM;
|
||||
}
|
||||
}
|
||||
return zRet;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Free any buffer allocated by pBuf. Zero the structure before returning.
|
||||
*/
|
||||
|
@ -196,7 +196,7 @@ void sqlite3Fts5Dequote(char *z){
|
||||
}
|
||||
|
||||
/*
|
||||
** Parse the "special" CREATE VIRTUAL TABLE directive and update
|
||||
** Parse a "special" CREATE VIRTUAL TABLE directive and update
|
||||
** configuration object pConfig as appropriate.
|
||||
**
|
||||
** If successful, object pConfig is updated and SQLITE_OK returned. If
|
||||
@ -211,10 +211,10 @@ static int fts5ConfigParseSpecial(
|
||||
const char *zArg, /* Argument to parse */
|
||||
char **pzErr /* OUT: Error message */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
int nCmd = strlen(zCmd);
|
||||
if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
|
||||
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
|
||||
int rc = SQLITE_OK;
|
||||
const char *p;
|
||||
if( pConfig->aPrefix ){
|
||||
*pzErr = sqlite3_mprintf("multiple prefix=... directives");
|
||||
@ -248,7 +248,6 @@ static int fts5ConfigParseSpecial(
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
|
||||
int rc = SQLITE_OK;
|
||||
const char *p = (const char*)zArg;
|
||||
int nArg = strlen(zArg) + 1;
|
||||
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
|
||||
@ -293,7 +292,6 @@ static int fts5ConfigParseSpecial(
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){
|
||||
int rc = SQLITE_OK;
|
||||
if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
|
||||
*pzErr = sqlite3_mprintf("multiple content=... directives");
|
||||
rc = SQLITE_ERROR;
|
||||
@ -301,19 +299,15 @@ static int fts5ConfigParseSpecial(
|
||||
if( zArg[0] ){
|
||||
pConfig->eContent = FTS5_CONTENT_EXTERNAL;
|
||||
pConfig->zContent = sqlite3_mprintf("%Q.%Q", pConfig->zDb, zArg);
|
||||
if( pConfig->zContent==0 ) rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pConfig->eContent = FTS5_CONTENT_NONE;
|
||||
pConfig->zContent = sqlite3_mprintf(
|
||||
"%Q.'%q_docsize'", pConfig->zDb, pConfig->zName
|
||||
);
|
||||
}
|
||||
if( pConfig->zContent==0 ) rc = SQLITE_NOMEM;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
|
||||
int rc = SQLITE_OK;
|
||||
if( pConfig->zContentRowid ){
|
||||
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
|
||||
rc = SQLITE_ERROR;
|
||||
@ -323,6 +317,16 @@ static int fts5ConfigParseSpecial(
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){
|
||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
|
||||
*pzErr = sqlite3_mprintf("malformed columnsize=... directive");
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
pConfig->bColumnsize = (zArg[0]=='1');
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
*pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
@ -477,6 +481,7 @@ int sqlite3Fts5ConfigParse(
|
||||
pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
|
||||
pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
|
||||
pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
|
||||
pRet->bColumnsize = 1;
|
||||
if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
|
||||
*pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
|
||||
rc = SQLITE_ERROR;
|
||||
@ -530,15 +535,24 @@ int sqlite3Fts5ConfigParse(
|
||||
}
|
||||
|
||||
/* If no zContent option was specified, fill in the default values. */
|
||||
if( rc==SQLITE_OK && pRet->eContent==FTS5_CONTENT_NORMAL ){
|
||||
pRet->zContent = sqlite3_mprintf("%Q.'%q_content'", pRet->zDb, pRet->zName);
|
||||
if( pRet->zContent==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_free(pRet->zContentRowid);
|
||||
pRet->zContentRowid = 0;
|
||||
if( rc==SQLITE_OK && pRet->zContent==0 ){
|
||||
const char *zTail = 0;
|
||||
assert( pRet->eContent==FTS5_CONTENT_NORMAL
|
||||
|| pRet->eContent==FTS5_CONTENT_NONE
|
||||
);
|
||||
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
|
||||
zTail = "content";
|
||||
}else if( pRet->bColumnsize ){
|
||||
zTail = "docsize";
|
||||
}
|
||||
|
||||
if( zTail ){
|
||||
pRet->zContent = sqlite3Fts5Mprintf(
|
||||
&rc, "%Q.'%q_%s'", pRet->zDb, pRet->zName, zTail
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && pRet->zContentRowid==0 ){
|
||||
pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1);
|
||||
}
|
||||
|
@ -39,15 +39,11 @@ struct Fts5Storage {
|
||||
|
||||
#define FTS5_STMT_INSERT_CONTENT 3
|
||||
#define FTS5_STMT_REPLACE_CONTENT 4
|
||||
|
||||
#define FTS5_STMT_DELETE_CONTENT 5
|
||||
#define FTS5_STMT_REPLACE_DOCSIZE 6
|
||||
#define FTS5_STMT_DELETE_DOCSIZE 7
|
||||
|
||||
#define FTS5_STMT_LOOKUP_DOCSIZE 8
|
||||
|
||||
#define FTS5_STMT_REPLACE_CONFIG 9
|
||||
|
||||
#define FTS5_STMT_SCAN 10
|
||||
|
||||
/*
|
||||
@ -64,6 +60,14 @@ static int fts5StorageGetStmt(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
/* If there is no %_docsize table, there should be no requests for
|
||||
** statements to operate on it. */
|
||||
assert( p->pConfig->bColumnsize || (
|
||||
eStmt!=FTS5_STMT_REPLACE_DOCSIZE
|
||||
&& eStmt!=FTS5_STMT_DELETE_DOCSIZE
|
||||
&& eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
|
||||
));
|
||||
|
||||
assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
|
||||
if( p->aStmt[eStmt]==0 ){
|
||||
const char *azStmt[] = {
|
||||
@ -175,12 +179,16 @@ static int fts5ExecPrintf(
|
||||
int sqlite3Fts5DropAll(Fts5Config *pConfig){
|
||||
int rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DROP TABLE IF EXISTS %Q.'%q_data';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_docsize';"
|
||||
"DROP TABLE IF EXISTS %Q.'%q_config';",
|
||||
pConfig->zDb, pConfig->zName,
|
||||
pConfig->zDb, pConfig->zName,
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DROP TABLE IF EXISTS %Q.'%q_docsize';",
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
||||
rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DROP TABLE IF EXISTS %Q.'%q_content';",
|
||||
@ -266,7 +274,7 @@ int sqlite3Fts5StorageOpen(
|
||||
sqlite3_free(zDefn);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
rc = sqlite3Fts5CreateTable(
|
||||
pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
|
||||
);
|
||||
@ -374,19 +382,25 @@ static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
|
||||
** Insert a record into the %_docsize table. Specifically, do:
|
||||
**
|
||||
** INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf);
|
||||
**
|
||||
** If there is no %_docsize table (as happens if the columnsize=0 option
|
||||
** is specified when the FTS5 table is created), this function is a no-op.
|
||||
*/
|
||||
static int fts5StorageInsertDocsize(
|
||||
Fts5Storage *p, /* Storage module to write to */
|
||||
i64 iRowid, /* id value */
|
||||
Fts5Buffer *pBuf /* sz value */
|
||||
){
|
||||
sqlite3_stmt *pReplace = 0;
|
||||
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pReplace, 1, iRowid);
|
||||
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
int rc = SQLITE_OK;
|
||||
if( p->pConfig->bColumnsize ){
|
||||
sqlite3_stmt *pReplace = 0;
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pReplace, 1, iRowid);
|
||||
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -455,6 +469,7 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
|
||||
** Remove a row from the FTS table.
|
||||
*/
|
||||
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
int rc;
|
||||
sqlite3_stmt *pDel;
|
||||
|
||||
@ -466,7 +481,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
|
||||
}
|
||||
|
||||
/* Delete the %_docsize record */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -528,13 +543,15 @@ int sqlite3Fts5StorageSpecialDelete(
|
||||
}
|
||||
|
||||
/* Delete the %_docsize record */
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pDel, 1, iDel);
|
||||
sqlite3_step(pDel);
|
||||
rc = sqlite3_reset(pDel);
|
||||
if( pConfig->bColumnsize ){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pDel, 1, iDel);
|
||||
sqlite3_step(pDel);
|
||||
rc = sqlite3_reset(pDel);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the averages record */
|
||||
@ -554,11 +571,15 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
|
||||
|
||||
/* Delete the contents of the %_data and %_docsize tables. */
|
||||
rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DELETE FROM %Q.'%q_data';"
|
||||
"DELETE FROM %Q.'%q_docsize';",
|
||||
pConfig->zDb, pConfig->zName,
|
||||
"DELETE FROM %Q.'%q_data';",
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
||||
rc = fts5ExecPrintf(pConfig->db, 0,
|
||||
"DELETE FROM %Q.'%q_docsize';",
|
||||
pConfig->zDb, pConfig->zName
|
||||
);
|
||||
}
|
||||
|
||||
/* Reinitialize the %_data table. This call creates the initial structure
|
||||
** and averages records. */
|
||||
@ -635,18 +656,24 @@ int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
|
||||
** a NULL value is inserted into the rowid column. The new rowid is allocated
|
||||
** by inserting a dummy row into the %_docsize table. The dummy will be
|
||||
** overwritten later.
|
||||
**
|
||||
** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In
|
||||
** this case the user is required to provide a rowid explicitly.
|
||||
*/
|
||||
static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
|
||||
sqlite3_stmt *pReplace = 0;
|
||||
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_null(pReplace, 1);
|
||||
sqlite3_bind_null(pReplace, 2);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
*piRowid = sqlite3_last_insert_rowid(p->pConfig->db);
|
||||
int rc = SQLITE_MISMATCH;
|
||||
if( p->pConfig->bColumnsize ){
|
||||
sqlite3_stmt *pReplace = 0;
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_null(pReplace, 1);
|
||||
sqlite3_bind_null(pReplace, 2);
|
||||
sqlite3_step(pReplace);
|
||||
rc = sqlite3_reset(pReplace);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
*piRowid = sqlite3_last_insert_rowid(p->pConfig->db);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -958,6 +985,7 @@ int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
|
||||
rc = FTS5_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ do_execsql_test 5.2 {
|
||||
1 {4 6}
|
||||
}
|
||||
|
||||
do_execsql_test 5.2 {
|
||||
do_execsql_test 5.3 {
|
||||
SELECT rowid, fts5_test_columntext(t5) FROM t5 WHERE t5 MATCH 'a'
|
||||
ORDER BY rowid DESC;
|
||||
} {
|
||||
@ -157,7 +157,7 @@ do_execsql_test 5.2 {
|
||||
1 {{a b c d} {e f g h i j}}
|
||||
}
|
||||
|
||||
do_execsql_test 5.3 {
|
||||
do_execsql_test 5.4 {
|
||||
SELECT rowid, fts5_test_columntotalsize(t5) FROM t5 WHERE t5 MATCH 'a'
|
||||
ORDER BY rowid DESC;
|
||||
} {
|
||||
@ -166,7 +166,7 @@ do_execsql_test 5.3 {
|
||||
1 {5 7}
|
||||
}
|
||||
|
||||
do_execsql_test 5.4 {
|
||||
do_execsql_test 5.5 {
|
||||
INSERT INTO t5 VALUES('x y z', 'v w x y z');
|
||||
SELECT rowid, fts5_test_columntotalsize(t5) FROM t5 WHERE t5 MATCH 'a'
|
||||
ORDER BY rowid DESC;
|
||||
|
112
ext/fts5/test/fts5columnsize.test
Normal file
112
ext/fts5/test/fts5columnsize.test
Normal file
@ -0,0 +1,112 @@
|
||||
# 2015 Jun 10
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests focusing on fts5 tables with the columnsize=0 option.
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5columnsize
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that the option can be parsed and that the %_docsize table is
|
||||
# only created if it is set to true.
|
||||
#
|
||||
foreach {tn outcome stmt} {
|
||||
1 0 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=0) }
|
||||
2 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=1) }
|
||||
3 0 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='0') }
|
||||
4 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='1') }
|
||||
5 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize='') }
|
||||
6 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=2) }
|
||||
7 1 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=0, columnsize=1) }
|
||||
8 1 { CREATE VIRTUAL TABLE t1 USING fts5(x) }
|
||||
} {
|
||||
execsql {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
}
|
||||
if {$outcome==2} {
|
||||
do_catchsql_test 1.$tn.1 $stmt {1 {malformed columnsize=... directive}}
|
||||
} else {
|
||||
do_execsql_test 1.$tn.2 $stmt
|
||||
do_execsql_test 1.$tn.3 {
|
||||
SELECT count(*) FROM sqlite_master WHERE name = 't1_docsize'
|
||||
} $outcome
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Run tests on a table with no %_content or %_docsize backing store.
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(x, columnsize=0, content='');
|
||||
}
|
||||
do_catchsql_test 2.1 {
|
||||
INSERT INTO t2 VALUES('a b c d e f');
|
||||
} {1 {datatype mismatch}}
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO t2(rowid, x) VALUES(1, 'c d e f');
|
||||
INSERT INTO t2(rowid, x) VALUES(2, 'c d e f g h');
|
||||
INSERT INTO t2(rowid, x) VALUES(3, 'a b c d e f g h');
|
||||
} {}
|
||||
do_execsql_test 2.3 {
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'h';
|
||||
} {3 :: 1 2 3 :: 2 3}
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO t2(t2, rowid, x) VALUES('delete', 2, 'c d e f g h');
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'h';
|
||||
} {3 :: 1 3 :: 3}
|
||||
do_execsql_test 2.5 {
|
||||
INSERT INTO t2(t2) VALUES('delete-all');
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'b'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'e'; SELECT '::';
|
||||
SELECT rowid FROM t2 WHERE t2 MATCH 'h';
|
||||
} {:: ::}
|
||||
do_execsql_test 2.6 {
|
||||
INSERT INTO t2(rowid, x) VALUES(1, 'o t t f');
|
||||
INSERT INTO t2(rowid, x) VALUES(2, 'f s s e');
|
||||
INSERT INTO t2(rowid, x) VALUES(3, 'n t e t');
|
||||
}
|
||||
|
||||
do_catchsql_test 2.7.1 {
|
||||
SELECT rowid FROM t2
|
||||
} {1 {t2: table does not support scanning}}
|
||||
do_catchsql_test 2.7.2 {
|
||||
SELECT rowid FROM t2 WHERE rowid=2
|
||||
} {1 {t2: table does not support scanning}}
|
||||
do_catchsql_test 2.7.3 {
|
||||
SELECT rowid FROM t2 WHERE rowid BETWEEN 1 AND 3
|
||||
} {1 {t2: table does not support scanning}}
|
||||
|
||||
do_execsql_test 2.X {
|
||||
DROP TABLE t2
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the xColumnSize() API
|
||||
#
|
||||
fts5_aux_test_functions db
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts5(x, y UNINDEXED, z, columnsize=0);
|
||||
INSERT INTO t3 VALUES('a a', 'b b b', 'c');
|
||||
INSERT INTO t3 VALUES('x a x', 'b b b y', '');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a'
|
||||
} {
|
||||
1 {2 0 1} 2 {3 0 0}
|
||||
}
|
||||
|
||||
finish_test
|
Reference in New Issue
Block a user