From deb9473250318fd3f361d59178df39129d6bd810 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 5 Oct 2011 15:11:30 +0000 Subject: [PATCH] Change FTS4 so that if both the content=xxx option and column names are specified, the virtual table assumes that the named columns correspond to columns of table xxx. FossilOrigin-Name: 289ee43179369fce2fde50870d72c445e184e896 --- ext/fts3/fts3.c | 105 +++++++++++++++++++++++++----------------- ext/fts3/fts3_write.c | 17 +++++-- manifest | 16 +++---- manifest.uuid | 2 +- test/fts4content.test | 45 ++++++++++++++---- 5 files changed, 121 insertions(+), 64 deletions(-) diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 624221f979..6fa06907bf 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1182,20 +1182,19 @@ static int fts3InitVtab( ** ** 1. Ignore any compress= and uncompress= options. ** - ** 2. Ignore any column names that were specified as part of the - ** the CREATE VIRTUAL TABLE statement. - ** - ** 3. Determine the actual column names to use for the FTS table - ** based on the columns of the content= table. + ** 2. If no column names were specified as part of the CREATE VIRTUAL + ** TABLE statement, use all columns from the content table. */ if( rc==SQLITE_OK && zContent ){ - sqlite3_free(aCol); sqlite3_free(zCompress); sqlite3_free(zUncompress); zCompress = 0; zUncompress = 0; - aCol = 0; - rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); + if( nCol==0 ){ + sqlite3_free(aCol); + aCol = 0; + rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); + } assert( rc!=SQLITE_OK || nCol>0 ); } if( rc!=SQLITE_OK ) goto fts3_init_out; @@ -1457,40 +1456,64 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){ return SQLITE_OK; } +/* +** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then +** compose and prepare an SQL statement of the form: +** +** "SELECT FROM %_content WHERE rowid = ?" +** +** (or the equivalent for a content=xxx table) and set pCsr->pStmt to +** it. If an error occurs, return an SQLite error code. +** +** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK. +*/ +static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ + int rc = SQLITE_OK; + if( pCsr->pStmt==0 ){ + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; + char *zSql; + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); + if( !zSql ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + } + *ppStmt = pCsr->pStmt; + return rc; +} + /* ** Position the pCsr->pStmt statement so that it is on the row ** of the %_content table that contains the last match. Return ** SQLITE_OK on success. */ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ + int rc = SQLITE_OK; if( pCsr->isRequireSeek ){ - sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); - pCsr->isRequireSeek = 0; - if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ - return SQLITE_OK; - }else{ - int rc = sqlite3_reset(pCsr->pStmt); - if( rc==SQLITE_OK ){ - Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; - if( p->zContentTbl==0 ){ + sqlite3_stmt *pStmt = 0; + + rc = fts3CursorSeekStmt(pCsr, &pStmt); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); + pCsr->isRequireSeek = 0; + if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ + return SQLITE_OK; + }else{ + rc = sqlite3_reset(pCsr->pStmt); + if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ /* If no row was found and no error has occured, then the %_content ** table is missing a row that is present in the full-text index. - ** The data structures are corrupt. - */ + ** The data structures are corrupt. */ rc = SQLITE_CORRUPT_VTAB; - }else{ - return SQLITE_OK; + pCsr->isEof = 1; } } - pCsr->isEof = 1; - if( pContext ){ - sqlite3_result_error_code(pContext, rc); - } - return rc; } - }else{ - return SQLITE_OK; } + + if( rc!=SQLITE_OK && pContext ){ + sqlite3_result_error_code(pContext, rc); + } + return rc; } /* @@ -2848,24 +2871,24 @@ static int fts3FilterMethod( ** row by docid. */ if( idxNum==FTS3_FULLSCAN_SEARCH ){ - const char *zTmpl = "SELECT %s ORDER BY rowid %s"; - zSql = sqlite3_mprintf(zTmpl, + zSql = sqlite3_mprintf( + "SELECT %s ORDER BY rowid %s", p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") ); - }else{ - const char *zTmpl = "SELECT %s WHERE rowid = ?"; - zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist); + if( zSql ){ + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); + sqlite3_free(zSql); + }else{ + rc = SQLITE_NOMEM; + } + }else if( idxNum==FTS3_DOCID_SEARCH ){ + rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt); + if( rc==SQLITE_OK ){ + rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); + } } - if( !zSql ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); - sqlite3_free(zSql); if( rc!=SQLITE_OK ) return rc; - if( idxNum==FTS3_DOCID_SEARCH ){ - rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); - if( rc!=SQLITE_OK ) return rc; - } - return fts3NextMethod(pCursor); } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 591f31f081..47bed0dd5e 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -409,17 +409,24 @@ static void fts3SqlExec( ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can ** still happen if the user reads data directly from the %_segments or ** %_segdir tables instead of going through FTS3 though. +** +** This reasoning does not apply to a content=xxx table. */ int sqlite3Fts3ReadLock(Fts3Table *p){ int rc; /* Return code */ sqlite3_stmt *pStmt; /* Statement used to obtain lock */ - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); - if( rc==SQLITE_OK ){ - sqlite3_bind_null(pStmt, 1); - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); + if( p->zContentTbl==0 ){ + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_null(pStmt, 1); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + }else{ + rc = SQLITE_OK; } + return rc; } diff --git a/manifest b/manifest index b582707f76..0c36a83a5c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sIO\serror\shandling\sin\sthe\srebuild-index\scode. -D 2011-10-05T06:07:00.875 +C Change\sFTS4\sso\sthat\sif\sboth\sthe\scontent=xxx\soption\sand\scolumn\snames\sare\sspecified,\sthe\svirtual\stable\sassumes\sthat\sthe\snamed\scolumns\scorrespond\sto\scolumns\sof\stable\sxxx. +D 2011-10-05T15:11:30.760 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -62,7 +62,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 6d6f3d331ed785d2e68608443eff66448ea95354 +F ext/fts3/fts3.c f2ed0ae669534e0c9c8ba95b60b6c137544e7e49 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe F ext/fts3/fts3Int.h 06f442ce096e6254432a6b16a56b6fe7b24bd372 F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691 @@ -77,7 +77,7 @@ F ext/fts3/fts3_test.c 24fa13f330db011500acb95590da9eee24951894 F ext/fts3/fts3_tokenizer.c 9ff7ec66ae3c5c0340fa081958e64f395c71a106 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3 F ext/fts3/fts3_tokenizer1.c 0dde8f307b8045565cf63797ba9acfaff1c50c68 -F ext/fts3/fts3_write.c 16fba93fc840f15421ebf1a783a8c3395700bbf9 +F ext/fts3/fts3_write.c 06520aa8a0a32a7bed08b29a9004fde1cb7f0318 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9 @@ -486,7 +486,7 @@ F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2 F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2 F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659 F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68 -F test/fts4content.test 5c226c7c666e250c175bcbdfbdd4be3f275c73ba +F test/fts4content.test c5f531ecfc3d446b90032cae212549dbbb18dd78 F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a @@ -966,7 +966,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5 F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2 -P 0f439944ab49a5691615bc170fdcf652055573df -R 29197ea13db81f2ba07fe324b03117e5 +P c6ba81fcad32192674bd510e607f787adc1f7038 +R 0217fe49810be9d8f9417ba3c648ab3e U dan -Z a28913360f741831433fc7b43c93a8a9 +Z 1eb4f36513f7844867f45162778888e7 diff --git a/manifest.uuid b/manifest.uuid index 5039f9295e..b8efcec3d4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c6ba81fcad32192674bd510e607f787adc1f7038 \ No newline at end of file +289ee43179369fce2fde50870d72c445e184e896 \ No newline at end of file diff --git a/test/fts4content.test b/test/fts4content.test index 7925ed218d..8295d91d61 100644 --- a/test/fts4content.test +++ b/test/fts4content.test @@ -40,13 +40,13 @@ ifcapable !fts3 { # creating a content=xxx FTS index. # -do_execsql_test 1.1 { +do_execsql_test 1.1.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('w x', 'x y', 'y z'); CREATE VIRTUAL TABLE ft1 USING fts4(content=t1); } -do_execsql_test 1.2 { +do_execsql_test 1.1.2 { PRAGMA table_info(ft1); } { 0 a {} 0 {} 0 @@ -54,12 +54,23 @@ do_execsql_test 1.2 { 2 c {} 0 {} 0 } -do_execsql_test 1.3 { SELECT *, rowid FROM ft1 } {{w x} {x y} {y z} 1} -do_execsql_test 1.4 { SELECT a, c FROM ft1 WHERE rowid=1 } {{w x} {y z}} +do_execsql_test 1.1.3 { SELECT *, rowid FROM ft1 } {{w x} {x y} {y z} 1} +do_execsql_test 1.1.4 { SELECT a, c FROM ft1 WHERE rowid=1 } {{w x} {y z}} -do_execsql_test 1.5 { INSERT INTO ft1(ft1) VALUES('rebuild') } {} -do_execsql_test 1.6 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'x' } {1} -do_execsql_test 1.7 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'a' } {} +do_execsql_test 1.1.5 { INSERT INTO ft1(ft1) VALUES('rebuild') } {} +do_execsql_test 1.1.6 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'x' } {1} +do_execsql_test 1.1.7 { SELECT rowid FROM ft1 WHERE ft1 MATCH 'a' } {} + +do_execsql_test 1.2.1 { + DROP TABLE ft1; + CREATE VIRTUAL TABLE ft1 USING fts4(content=t1, b); + PRAGMA table_info(ft1); +} { + 0 b {} 0 {} 0 +} +do_execsql_test 1.2.2 { + SELECT *, rowid FROM ft1 +} {{x y} 1} #------------------------------------------------------------------------- # The following block of tests - 2.* - test that a content=xxx FTS table @@ -433,10 +444,10 @@ do_execsql_test 6.2.7 { CREATE TABLE t7(x); } do_catchsql_test 6.2.8 { - SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"'; + SELECT * FROM ft7 WHERE ft7 MATCH '"A A"'; } {1 {SQL logic error or missing database}} do_catchsql_test 6.2.9 { - SELECT rowid FROM ft7 WHERE ft7 MATCH '"A A"'; + SELECT * FROM ft7 WHERE ft7 MATCH '"A A"'; } {1 {SQL logic error or missing database}} db close @@ -448,4 +459,20 @@ do_catchsql_test 6.2.11 { SELECT rowid, * FROM ft7 WHERE ft7 MATCH '"A A"'; } {0 {2 {}}} +#------------------------------------------------------------------------- +# Test cases 7.* +# +do_execsql_test 7.1.1 { + CREATE VIRTUAL TABLE ft8 USING fts4(content=nosuchtable, x); + INSERT INTO ft8(docid, x) VALUES(13, 'U O N X G'); + INSERT INTO ft8(docid, x) VALUES(14, 'C J J U B'); + INSERT INTO ft8(docid, x) VALUES(15, 'N J Y G X'); + INSERT INTO ft8(docid, x) VALUES(16, 'R Y D O R'); + INSERT INTO ft8(docid, x) VALUES(17, 'I Y T Q O'); +} + +do_execsql_test 7.1.2 { + SELECT docid FROM ft8 WHERE ft8 MATCH 'N'; +} {13 15} + finish_test -- 2.47.2