Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improve test coverage of fts5. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | fts5 |
Files: | files | file ages | folders |
SHA1: |
df5ccea80e8f0da83af5e595b5396870 |
User & Date: | dan 2015-06-23 18:47:55.733 |
Context
2015-06-25
| ||
20:10 | Add a script to combine all fts5 code into a single file - fts5.c - that can be used to build an SQLite loadable extension. (check-in: 46e86b0637 user: dan tags: fts5) | |
2015-06-23
| ||
18:47 | Improve test coverage of fts5. (check-in: df5ccea80e user: dan tags: fts5) | |
15:06 | Merge latest trunk changes with this branch. Add tests for columnsize=0. (check-in: ef44c71a22 user: dan tags: fts5) | |
Changes
Changes to ext/fts5/fts5.c.
︙ | ︙ | |||
823 824 825 826 827 828 829 | /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that ** is not possible as SQLite reference counts the virtual table objects. ** And since the statement required here reads from this very virtual ** table, saving it creates a circular reference. ** ** If SQLite a built-in statement cache, this wouldn't be a problem. */ | > | | < < | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that ** is not possible as SQLite reference counts the virtual table objects. ** And since the statement required here reads from this very virtual ** table, saving it creates a circular reference. ** ** If SQLite a built-in statement cache, this wouldn't be a problem. */ zSql = sqlite3Fts5Mprintf(&rc, "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), (zRankArgs ? zRankArgs : ""), bDesc ? "DESC" : "ASC" ); if( zSql ){ rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pSorter->pStmt, 0); sqlite3_free(zSql); } pCsr->pSorter = pSorter; if( rc==SQLITE_OK ){ assert( pTab->pSortCsr==0 ); |
︙ | ︙ | |||
926 927 928 929 930 931 932 | Fts5Config *pConfig = pTab->pConfig; int rc = SQLITE_OK; Fts5Auxiliary *pAux = 0; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; if( zRankArgs ){ | | | < < | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 | Fts5Config *pConfig = pTab->pConfig; int rc = SQLITE_OK; Fts5Auxiliary *pAux = 0; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; if( zRankArgs ){ char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs); if( zSql ){ sqlite3_stmt *pStmt = 0; rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 ); if( rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ int nByte; |
︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 1216 | return SQLITE_OK; } /* ** If the cursor requires seeking (bSeekRequired flag is set), seek it. ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. */ | > > > | | > | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | return SQLITE_OK; } /* ** If the cursor requires seeking (bSeekRequired flag is set), seek it. ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. ** ** If argument bErrormsg is true and an error occurs, an error message may ** be left in sqlite3_vtab.zErrMsg. */ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){ int rc = SQLITE_OK; /* If the cursor does not yet have a statement handle, obtain one now. */ if( pCsr->pStmt==0 ){ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); int eStmt = fts5StmtType(pCsr); rc = sqlite3Fts5StorageStmt( pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0) ); assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 ); assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ); } if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){ assert( pCsr->pExpr ); sqlite3_reset(pCsr->pStmt); sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); |
︙ | ︙ | |||
1614 1615 1616 1617 1618 1619 1620 | ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ *pz = 0; *pn = 0; }else{ | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 | ){ int rc = SQLITE_OK; Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){ *pz = 0; *pn = 0; }else{ rc = fts5SeekCursor(pCsr, 0); if( rc==SQLITE_OK ){ *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); } } return rc; } |
︙ | ︙ | |||
1958 1959 1960 1961 1962 1963 1964 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH ){ if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } }else if( !fts5IsContentless(pTab) ){ | | | 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH ){ if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); } } }else if( !fts5IsContentless(pTab) ){ rc = fts5SeekCursor(pCsr, 1); if( rc==SQLITE_OK ){ sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); } } return rc; } |
︙ | ︙ |
Changes to ext/fts5/fts5_config.c.
︙ | ︙ | |||
294 295 296 297 298 299 300 | if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){ if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ *pzErr = sqlite3_mprintf("multiple content=... directives"); rc = SQLITE_ERROR; }else{ if( zArg[0] ){ pConfig->eContent = FTS5_CONTENT_EXTERNAL; | | < | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){ if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){ *pzErr = sqlite3_mprintf("multiple content=... directives"); rc = SQLITE_ERROR; }else{ if( zArg[0] ){ pConfig->eContent = FTS5_CONTENT_EXTERNAL; pConfig->zContent = sqlite3Fts5Mprintf(&rc, "%Q.%Q", pConfig->zDb,zArg); }else{ pConfig->eContent = FTS5_CONTENT_NONE; } } return rc; } |
︙ | ︙ | |||
597 598 599 600 601 602 603 | /* ** Call sqlite3_declare_vtab() based on the contents of the configuration ** object passed as the only argument. Return SQLITE_OK if successful, or ** an SQLite error code if an error occurs. */ int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ int i; | | | < | | < < < | | | < | | | < < | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 | /* ** Call sqlite3_declare_vtab() based on the contents of the configuration ** object passed as the only argument. Return SQLITE_OK if successful, or ** an SQLite error code if an error occurs. */ int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){ int i; int rc = SQLITE_OK; char *zSql; char *zOld; zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x("); for(i=0; zSql && i<pConfig->nCol; i++){ const char *zSep = (i==0?"":", "); zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]); } zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", zSql, pConfig->zName, FTS5_RANK_NAME ); assert( zSql || rc==SQLITE_NOMEM ); if( zSql ){ rc = sqlite3_declare_vtab(pConfig->db, zSql); sqlite3_free(zSql); } return rc; } |
︙ | ︙ | |||
819 820 821 822 823 824 825 | /* ** Load the contents of the %_config table into memory. */ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; char *zSql; sqlite3_stmt *p = 0; | | | | < < | 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | /* ** Load the contents of the %_config table into memory. */ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){ const char *zSelect = "SELECT k, v FROM %Q.'%q_config'"; char *zSql; sqlite3_stmt *p = 0; int rc = SQLITE_OK; int iVersion = 0; /* Set default values */ pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE; pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE; pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE; zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName); if( zSql ){ rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0); sqlite3_free(zSql); } assert( rc==SQLITE_OK || p==0 ); if( rc==SQLITE_OK ){ while( SQLITE_ROW==sqlite3_step(p) ){ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
787 788 789 790 791 792 793 | /* ** INSERT OR REPLACE a record into the %_data table. */ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ if( p->rc!=SQLITE_OK ) return; if( p->pWriter==0 ){ | | | | < < | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | /* ** INSERT OR REPLACE a record into the %_data table. */ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){ if( p->rc!=SQLITE_OK ) return; if( p->pWriter==0 ){ int rc = SQLITE_OK; Fts5Config *pConfig = p->pConfig; char *zSql = sqlite3Fts5Mprintf(&rc, "REPLACE INTO '%q'.%Q(id, block) VALUES(?,?)", pConfig->zDb, p->zDataTbl ); if( zSql ){ rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pWriter, 0); sqlite3_free(zSql); } if( rc!=SQLITE_OK ){ p->rc = rc; return; } |
︙ | ︙ | |||
4214 4215 4216 4217 4218 4219 4220 | Fts5Index *p; /* New object */ *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index)); if( rc==SQLITE_OK ){ p->pConfig = pConfig; p->nWorkUnit = FTS5_WORK_UNIT; p->nMaxPendingData = 1024*1024; | | | < < | 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 | Fts5Index *p; /* New object */ *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index)); if( rc==SQLITE_OK ){ p->pConfig = pConfig; p->nWorkUnit = FTS5_WORK_UNIT; p->nMaxPendingData = 1024*1024; p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName); if( p->zDataTbl && bCreate ){ rc = sqlite3Fts5CreateTable( pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr ); if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexReinit(p); } } |
︙ | ︙ |
Changes to ext/fts5/fts5_vocab.c.
︙ | ︙ | |||
246 247 248 249 250 251 252 | int nCol = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; int nByte; | | | < < | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | int nCol = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; int nByte; zSql = sqlite3Fts5Mprintf(&rc, "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'", pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl ); if( zSql ){ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); } sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); if( rc==SQLITE_ERROR ) rc = SQLITE_OK; if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ |
︙ | ︙ |
Changes to ext/fts5/test/fts5columnsize.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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 { | > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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) } 9 2 { CREATE VIRTUAL TABLE t1 USING fts5(x, columnsize=11) } } { execsql { DROP TABLE IF EXISTS t1; } if {$outcome==2} { do_catchsql_test 1.$tn.1 $stmt {1 {malformed columnsize=... directive}} } else { |
︙ | ︙ | |||
94 95 96 97 98 99 100 | } #------------------------------------------------------------------------- # Test the xColumnSize() API # fts5_aux_test_functions db | | | | > > > > > > > > > > > > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | } #------------------------------------------------------------------------- # Test the xColumnSize() API # fts5_aux_test_functions db do_execsql_test 3.1.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.1 { SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a' } { 1 {2 0 1} 2 {3 0 0} } do_execsql_test 3.1.2 { INSERT INTO t3 VALUES(NULL, NULL, 'a a a a'); DELETE FROM t3 WHERE rowid = 1; SELECT rowid, fts5_test_columnsize(t3) FROM t3 WHERE t3 MATCH 'a' } { 2 {3 0 0} 3 {0 0 4} } do_execsql_test 3.2.0 { CREATE VIRTUAL TABLE t4 USING fts5(x, y UNINDEXED, z, columnsize=0, content=''); INSERT INTO t4(rowid, x, y, z) VALUES(1, 'a a', 'b b b', 'c'); INSERT INTO t4(rowid, x, y, z) VALUES(2, 'x a x', 'b b b y', ''); } do_execsql_test 3.2.1 { SELECT rowid, fts5_test_columnsize(t4) FROM t4 WHERE t4 MATCH 'a' } { 1 {-1 0 -1} 2 {-1 0 -1} } finish_test |