Tests and fixes for fts5 external content tables.

FossilOrigin-Name: 047aaf830d1e72f0fdad3832a0b617e769d66468
This commit is contained in:
dan 2015-01-05 20:41:39 +00:00
parent 0fbc269fef
commit ded4f41d1a
8 changed files with 254 additions and 101 deletions

View File

@ -256,6 +256,12 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
# define fts5CheckTransactionState(x,y,z)
#endif
/*
** Return true if pTab is a contentless table.
*/
static int fts5IsContentless(Fts5Table *pTab){
return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
}
/*
** Close a virtual table handle opened by fts5InitVtab(). If the bDestroy
@ -917,7 +923,9 @@ static int fts5FilterMethod(
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
** by rowid (ePlan==FTS5_PLAN_ROWID). */
int eStmt = fts5StmtType(idxNum);
rc = sqlite3Fts5StorageStmt(pTab->pStorage, eStmt, &pCsr->pStmt);
rc = sqlite3Fts5StorageStmt(
pTab->pStorage, eStmt, &pCsr->pStmt, &pTab->base.zErrMsg
);
if( rc==SQLITE_OK ){
if( ePlan==FTS5_PLAN_ROWID ){
sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
@ -995,7 +1003,9 @@ static int fts5SeekCursor(Fts5Cursor *pCsr){
if( pCsr->pStmt==0 ){
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
int eStmt = fts5StmtType(pCsr->idxNum);
rc = sqlite3Fts5StorageStmt(pTab->pStorage, eStmt, &pCsr->pStmt);
rc = sqlite3Fts5StorageStmt(
pTab->pStorage, eStmt, &pCsr->pStmt, &pTab->base.zErrMsg
);
assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
}
@ -1100,18 +1110,6 @@ static int fts5UpdateMethod(
*/
assert( nArg==1 || nArg==(2 + pConfig->nCol + 2) );
if( nArg>1 ){
sqlite3_value *pCmd = sqlite3_value_type(apVal[2 + pConfig->nCol]);
if( SQLITE_NULL!=sqlite3_value_type(pCmd) ){
const char *z = sqlite3_value_text(pCmd);
if( pConfig->bExternalContent && sqlite3_stricmp("delete", z) ){
return fts5SpecialDelete(pTab, apVal, pRowid);
}else{
return fts5SpecialInsert(pTab, pCmd, apVal[2 + pConfig->nCol + 1]);
}
}
}
eType0 = sqlite3_value_type(apVal[0]);
eConflict = sqlite3_vtab_on_conflict(pConfig->db);
@ -1119,10 +1117,31 @@ static int fts5UpdateMethod(
assert( pVtab->zErrMsg==0 );
if( rc==SQLITE_OK && eType0==SQLITE_INTEGER ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
if( fts5IsContentless(pTab) ){
pTab->base.zErrMsg = sqlite3_mprintf(
"cannot %s contentless fts5 table: %s",
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
);
rc = SQLITE_ERROR;
}else{
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
}
}else if( nArg>1 ){
sqlite3_value *pCmd = apVal[2 + pConfig->nCol];
if( SQLITE_NULL!=sqlite3_value_type(pCmd) ){
const char *z = sqlite3_value_text(pCmd);
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlite3_stricmp("delete", z)
){
return fts5SpecialDelete(pTab, apVal, pRowid);
}else{
return fts5SpecialInsert(pTab, pCmd, apVal[2 + pConfig->nCol + 1]);
}
}
}
if( rc==SQLITE_OK && nArg>1 ){
rc = sqlite3Fts5StorageInsert(pTab->pStorage, apVal, eConflict, pRowid);
}
@ -1328,11 +1347,17 @@ static int fts5ApiColumnText(
const char **pz,
int *pn
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
int rc = fts5SeekCursor(pCsr);
if( rc==SQLITE_OK ){
*pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
*pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
*pz = 0;
*pn = 0;
}else{
rc = fts5SeekCursor(pCsr);
if( rc==SQLITE_OK ){
*pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
*pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
}
}
return rc;
}
@ -1566,7 +1591,8 @@ static int fts5ColumnMethod(
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
int iCol /* Index of column to read value from */
){
Fts5Config *pConfig = ((Fts5Table*)(pCursor->pVtab))->pConfig;
Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
Fts5Config *pConfig = pTab->pConfig;
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int rc = SQLITE_OK;
@ -1597,7 +1623,7 @@ static int fts5ColumnMethod(
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
}
}
}else{
}else if( !fts5IsContentless(pTab) ){
rc = fts5SeekCursor(pCsr);
if( rc==SQLITE_OK ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));

View File

@ -76,9 +76,9 @@ struct Fts5Config {
char **azCol; /* Column names */
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int bExternalContent; /* Content is external */
char *zContent; /* "content=" option value (or NULL) */
char *zContentRowid; /* "content_rowid=" option value (or NULL) */
int eContent; /* An FTS5_CONTENT value */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
@ -90,6 +90,12 @@ struct Fts5Config {
char *zRankArgs; /* Arguments to rank function */
};
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
#define FTS5_CONTENT_EXTERNAL 2
int sqlite3Fts5ConfigParse(
Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
);
@ -401,7 +407,7 @@ int sqlite3Fts5StorageInsert(Fts5Storage *p, sqlite3_value **apVal, int, i64*);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt **);
int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);

View File

@ -222,21 +222,23 @@ static void fts5HighlightFunction(
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx, fts5HighlightCb);
}
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
}else{
sqlite3_result_error_code(pCtx, rc);
if( rc==SQLITE_OK ){
sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
}else{
sqlite3_result_error_code(pCtx, rc);
}
sqlite3_free(ctx.zOut);
}
sqlite3_free(ctx.zOut);
}
/*
** End of highlight() implementation.
@ -275,7 +277,6 @@ static void fts5SnippetFunction(
memset(&ctx, 0, sizeof(HighlightContext));
iCol = sqlite3_value_int(apVal[0]);
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
zEllips = (const char*)sqlite3_value_text(apVal[3]);
@ -328,39 +329,41 @@ static void fts5SnippetFunction(
if( rc==SQLITE_OK ){
rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
}
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
if( (iBestStart+nToken-1)>iBestLast ){
iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
}
if( iBestStart+nToken>nColSize ){
iBestStart = nColSize - nToken;
}
if( iBestStart<0 ) iBestStart = 0;
if( (iBestStart+nToken-1)>iBestLast ){
iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
}
if( iBestStart+nToken>nColSize ){
iBestStart = nColSize - nToken;
}
if( iBestStart<0 ) iBestStart = 0;
ctx.iRangeStart = iBestStart;
ctx.iRangeEnd = iBestStart + nToken - 1;
ctx.iRangeStart = iBestStart;
ctx.iRangeEnd = iBestStart + nToken - 1;
if( iBestStart>0 ){
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx, fts5HighlightCb);
}
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
if( iBestStart>0 ){
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
if( rc==SQLITE_OK ){
sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
}else{
sqlite3_result_error_code(pCtx, rc);
if( rc==SQLITE_OK ){
sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
}else{
sqlite3_result_error_code(pCtx, rc);
}
sqlite3_free(ctx.zOut);
}
sqlite3_free(ctx.zOut);
sqlite3_free(aSeen);
}

View File

@ -334,12 +334,19 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){
int rc = SQLITE_OK;
if( pConfig->zContent ){
if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
*pzErr = sqlite3_mprintf("multiple content=... directives");
rc = SQLITE_ERROR;
}else{
pConfig->zContent = sqlite3_mprintf("%Q.%Q", pConfig->zDb, zArg);
pConfig->bExternalContent = 1;
if( zArg[0] ){
pConfig->eContent = FTS5_CONTENT_EXTERNAL;
pConfig->zContent = sqlite3_mprintf("%Q.%Q", pConfig->zDb, zArg);
}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;
@ -473,7 +480,7 @@ int sqlite3Fts5ConfigParse(
}
/* If no zContent option was specified, fill in the default values. */
if( rc==SQLITE_OK && pRet->zContent==0 ){
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;

View File

@ -54,7 +54,8 @@ struct Fts5Storage {
static int fts5StorageGetStmt(
Fts5Storage *p, /* Storage handle */
int eStmt, /* FTS5_STMT_XXX constant */
sqlite3_stmt **ppStmt /* OUT: Prepared statement handle */
sqlite3_stmt **ppStmt, /* OUT: Prepared statement handle */
char **pzErrMsg /* OUT: Error message (if any) */
){
int rc = SQLITE_OK;
@ -117,6 +118,9 @@ static int fts5StorageGetStmt(
}else{
rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK && pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
}
}
}
@ -205,7 +209,7 @@ int sqlite3Fts5StorageOpen(
p->pIndex = pIndex;
if( bCreate ){
if( pConfig->bExternalContent==0 ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
@ -254,7 +258,9 @@ int sqlite3Fts5StorageClose(Fts5Storage *p, int bDestroy){
/* If required, remove the shadow tables from the database */
if( bDestroy ){
rc = sqlite3Fts5DropTable(p->pConfig, "content");
if( p->pConfig->eContent==FTS5_CONTENT_NORMAL ){
rc = sqlite3Fts5DropTable(p->pConfig, "content");
}
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "docsize");
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "config");
}
@ -298,7 +304,7 @@ static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */
int rc; /* Return code */
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek);
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int64(pSeek, 1, iDel);
@ -338,7 +344,7 @@ static int fts5StorageInsertDocsize(
Fts5Buffer *pBuf /* sz value */
){
sqlite3_stmt *pReplace = 0;
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace);
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);
@ -424,7 +430,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
/* Delete the %_docsize record */
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel);
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
}
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDel, 1, iDel);
@ -434,7 +440,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
/* Delete the %_content record */
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel);
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
}
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDel, 1, iDel);
@ -459,7 +465,7 @@ int sqlite3Fts5StorageSpecialDelete(
int rc;
sqlite3_stmt *pDel;
assert( p->pConfig->bExternalContent );
assert( p->pConfig->eContent!=FTS5_CONTENT_NORMAL );
rc = fts5StorageLoadTotals(p, 1);
/* Delete the index records */
@ -477,14 +483,14 @@ int sqlite3Fts5StorageSpecialDelete(
(void*)&ctx,
fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
p->aTotalSize[iCol] -= (i64)ctx.szCol;
}
p->nTotalRow--;
}
/* Delete the %_docsize record */
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel);
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
}
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDel, 1, iDel);
@ -509,7 +515,7 @@ int sqlite3Fts5StorageSpecialDelete(
*/
static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
sqlite3_stmt *pReplace = 0;
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace);
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_null(pReplace, 1);
sqlite3_bind_null(pReplace, 2);
@ -543,8 +549,8 @@ int sqlite3Fts5StorageInsert(
rc = fts5StorageLoadTotals(p, 1);
/* Insert the new row into the %_content table. */
if( rc==SQLITE_OK && pConfig->bExternalContent==0 ){
if( pConfig->bExternalContent ){
if( rc==SQLITE_OK ){
if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
@ -560,7 +566,7 @@ int sqlite3Fts5StorageInsert(
eStmt = FTS5_STMT_INSERT_CONTENT;
}
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, eStmt, &pInsert);
rc = fts5StorageGetStmt(p, eStmt, &pInsert, 0);
}
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
rc = sqlite3_bind_value(pInsert, i, apVal[i]);
@ -682,7 +688,7 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
/* Generate the expected index checksum based on the contents of the
** %_content table. This block stores the checksum in ctx.cksum. */
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN_ASC, &pScan);
rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN_ASC, &pScan, 0);
if( rc==SQLITE_OK ){
int rc2;
while( SQLITE_ROW==sqlite3_step(pScan) ){
@ -745,13 +751,18 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
** Obtain an SQLite statement handle that may be used to read data from the
** %_content table.
*/
int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt **pp){
int sqlite3Fts5StorageStmt(
Fts5Storage *p,
int eStmt,
sqlite3_stmt **pp,
char **pzErrMsg
){
int rc;
assert( eStmt==FTS5_STMT_SCAN_ASC
|| eStmt==FTS5_STMT_SCAN_DESC
|| eStmt==FTS5_STMT_LOOKUP
);
rc = fts5StorageGetStmt(p, eStmt, pp);
rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg);
if( rc==SQLITE_OK ){
assert( p->aStmt[eStmt]==*pp );
p->aStmt[eStmt] = 0;
@ -805,7 +816,7 @@ static int fts5StorageDecodeSizeArray(
int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
int nCol = p->pConfig->nCol;
sqlite3_stmt *pLookup = 0;
int rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup);
int rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
if( rc==SQLITE_OK ){
int bCorrupt = 1;
sqlite3_bind_int64(pLookup, 1, iRowid);
@ -873,7 +884,7 @@ int sqlite3Fts5StorageConfigValue(
sqlite3_value *pVal
){
sqlite3_stmt *pReplace = 0;
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace);
int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_TRANSIENT);
sqlite3_bind_value(pReplace, 2, pVal);

View File

@ -0,0 +1,99 @@
# 2014 Dec 20
#
# 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.
#
#***********************************************************************
#
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. .. test]
}
source $testdir/tester.tcl
set testprefix fts5content
do_execsql_test 1.1 {
CREATE VIRTUAL TABLE f1 USING fts5(a, b, content='');
INSERT INTO f1(rowid, a, b) VALUES(1, 'one', 'o n e');
INSERT INTO f1(rowid, a, b) VALUES(2, 'two', 't w o');
INSERT INTO f1(rowid, a, b) VALUES(3, 'three', 't h r e e');
}
do_execsql_test 1.2 {
SELECT rowid FROM f1 WHERE f1 MATCH 'o';
} {2 1}
do_execsql_test 1.3 {
INSERT INTO f1(a, b) VALUES('four', 'f o u r');
SELECT rowid FROM f1 WHERE f1 MATCH 'o';
} {4 2 1}
do_execsql_test 1.4 {
SELECT rowid, a, b FROM f1 WHERE f1 MATCH 'o';
} {4 {} {} 2 {} {} 1 {} {}}
do_execsql_test 1.5 {
SELECT rowid, highlight(f1, 0, '[', ']') FROM f1 WHERE f1 MATCH 'o';
} {4 {} 2 {} 1 {}}
do_execsql_test 1.6 {
SELECT rowid, highlight(f1, 0, '[', ']') IS NULL FROM f1 WHERE f1 MATCH 'o';
} {4 1 2 1 1 1}
do_execsql_test 1.7 {
SELECT rowid, snippet(f1, -1, '[', ']', '...', 5) IS NULL
FROM f1 WHERE f1 MATCH 'o';
} {4 1 2 1 1 1}
do_execsql_test 1.8 {
SELECT rowid, snippet(f1, 1, '[', ']', '...', 5) IS NULL
FROM f1 WHERE f1 MATCH 'o';
} {4 1 2 1 1 1}
do_execsql_test 1.9 {
SELECT rowid FROM f1;
} {4 3 2 1}
do_execsql_test 1.10 {
SELECT * FROM f1;
} {{} {} {} {} {} {} {} {}}
do_execsql_test 1.11 {
SELECT rowid, a, b FROM f1 ORDER BY rowid ASC;
} {1 {} {} 2 {} {} 3 {} {} 4 {} {}}
do_execsql_test 1.12 {
SELECT a IS NULL FROM f1;
} {1 1 1 1}
do_catchsql_test 1.13 {
DELETE FROM f1 WHERE rowid = 2;
} {1 {cannot DELETE from contentless fts5 table: f1}}
do_catchsql_test 1.14 {
UPDATE f1 SET a = 'a b c' WHERE rowid = 2;
} {1 {cannot UPDATE contentless fts5 table: f1}}
do_execsql_test 1.15 {
INSERT INTO f1(f1, rowid, a, b) VALUES('delete', 2, 'two', 't w o');
} {}
db eval { SELECT fts5_decode(id, block) AS d FROM f1_data } { puts $d }
breakpoint
do_execsql_test 1.16 {
SELECT rowid FROM f1 WHERE f1 MATCH 'o';
} {4 1}
do_execsql_test 1.17 {
SELECT rowid FROM f1;
} {4 3 1}
finish_test

View File

@ -1,5 +1,5 @@
C Add\ssupport\sfor\sexternal\scontent\stables\sto\sfts5.
D 2015-01-03T20:44:58.134
C Tests\sand\sfixes\sfor\sfts5\sexternal\scontent\stables.
D 2015-01-05T20:41:39.791
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 7cd23e4fc91004a6bd081623e1bc6932e44828c0
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -104,16 +104,16 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl 4199cb887040ee3c3cd59a5171ddb0566904586e
F ext/fts5/extract_api_docs.tcl 6320db4a1d0722a4e2069e661381ad75e9889786
F ext/fts5/fts5.c 16177d7f81af1852cf7f477b5ae119215ad6044a
F ext/fts5/fts5.c e2c19b2c5ab96650732bb6904892a6fb9a27ab42
F ext/fts5/fts5.h 4f9d2c477c0ee1907164642471329a82cb6b203b
F ext/fts5/fts5Int.h 8062dc2363c863dc8a5b2e5651cb8c966bd6c4cb
F ext/fts5/fts5_aux.c 445e54031ff94174673f4f5aac6c064df20a2a6b
F ext/fts5/fts5Int.h 9aafe97064e9c3380991abad4f51bee51021d18d
F ext/fts5/fts5_aux.c a74523025a553f57c99c699b9e2d83c4506503b4
F ext/fts5/fts5_buffer.c 1bc5c762bb2e9b4a40b2e8a820a31b809e72eec1
F ext/fts5/fts5_config.c 16d647c7bfe50d4e823267188e12e2d001d655e0
F ext/fts5/fts5_config.c 630f92bb0a301c0b4e37a05ec4e38dc51ceeba37
F ext/fts5/fts5_expr.c 317093f00a2ccdaaee0a5290f9f228c600189c41
F ext/fts5/fts5_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
F ext/fts5/fts5_index.c 4a8e8535b4303400ddb5f6fb08152da0d88ebf6f
F ext/fts5/fts5_storage.c b95fcca70f94656854e7afcfbb9896455f6b034d
F ext/fts5/fts5_storage.c 68ce8ec98b009cbd350ff73df06a97b1a012e122
F ext/fts5/fts5_tcl.c 664e710e2bbeed505cb91848772ca7538623a67f
F ext/fts5/fts5_tokenize.c 5a0ad46408d09bcda2bf0addb5af42fdb75ebabb
F ext/fts5/fts5_unicode2.c 9c7dd640d1f014bf5c3ee029759adfbb4d7e95a9
@ -131,6 +131,7 @@ F ext/fts5/test/fts5aj.test 1a64ab4144f54bd12a520683950bf8460dd74fb3
F ext/fts5/test/fts5ak.test df2669fb76684f03d03918dfb2cf692012251b1f
F ext/fts5/test/fts5al.test bc873766fec3baae05ba6e76b379bc2f5e8eaf75
F ext/fts5/test/fts5auxdata.test fec4c9113176d351e567eab65fe9917e5ea0ab05
F ext/fts5/test/fts5content.test 0f267ba2086f2dff81484c8ee71fa0d3990c41f7
F ext/fts5/test/fts5ea.test 0ef2c89e14c6360ad3905fae44409420d6b5a5c8
F ext/fts5/test/fts5fault1.test b95ed600b88bbbce5390f9097a5a5b7b01b3b9f7
F ext/fts5/test/fts5porter.test d8f7591b733bcc1f02ca0dd313bc891a4b289562
@ -1270,7 +1271,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 1cd15a1759004d5d321056905dbb6acff20dc7d9
R d21eb6bee3b06e51f22d32d1e0bd7016
P 17ef5b59f789e9fa35c4f053246d819987fd06f8
R 6bfe2a49f6feaf1db299d5e29da25a24
U dan
Z e88e77f44b464406d3184a89736eaa7d
Z 3d2200ed8057fd64a39f743bdc333945

View File

@ -1 +1 @@
17ef5b59f789e9fa35c4f053246d819987fd06f8
047aaf830d1e72f0fdad3832a0b617e769d66468