diff --git a/ext/fts1/fts1.c b/ext/fts1/fts1.c index 389b12163e..d50808e3ff 100644 --- a/ext/fts1/fts1.c +++ b/ext/fts1/fts1.c @@ -1748,17 +1748,15 @@ int parseSpec(TableSpec *pSpec, int argc, const char *const*argv, char**pzErr){ /* ** Generate a CREATE TABLE statement that describes the schema of -** the virtual table. Return a pointer to this schema. -** -** If the addAllColumn parameter is true, then add a column named -** "_all" to the end of the schema. Also add the "offset" column. +** the virtual table. Return a pointer to this schema string. ** ** Space is obtained from sqlite3_mprintf() and should be freed ** using sqlite3_free(). */ static char *fulltextSchema( int nColumn, /* Number of columns */ - const char *const* azColumn /* List of columns */ + const char *const* azColumn, /* List of columns */ + const char *zTableName /* Name of the table */ ){ int i; char *zSchema, *zNext; @@ -1770,7 +1768,7 @@ static char *fulltextSchema( zSchema = zNext; zSep = ","; } - zNext = sqlite3_mprintf("%s,_all,offset)", zSchema); + zNext = sqlite3_mprintf("%s,%Q)", zSchema, zTableName); sqlite3_free(zSchema); return zNext; } @@ -1826,7 +1824,8 @@ static int constructVtab( /* TODO: verify the existence of backing tables foo_content, foo_term */ - schema = fulltextSchema(v->nColumn, (const char*const*)v->azColumn); + schema = fulltextSchema(v->nColumn, (const char*const*)v->azColumn, + spec->zName); rc = sqlite3_declare_vtab(db, schema); sqlite3_free(schema); if( rc!=SQLITE_OK ) goto err; @@ -2603,14 +2602,10 @@ static int fulltextColumn(sqlite3_vtab_cursor *pCursor, sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1); sqlite3_result_value(pContext, pVal); }else if( idxCol==v->nColumn ){ - /* The _all column */ - sqlite3_result_null(pContext); - }else if( idxCol==v->nColumn+1 ){ - /* The offset column */ - snippetAllOffsets(c); - snippetOffsetText(&c->snippet); - sqlite3_result_text(pContext, c->snippet.zOffset, c->snippet.nOffset, - SQLITE_STATIC); + /* The extra column whose name is the same as the table. + ** Return a blob which is a pointer to the cursor + */ + sqlite3_result_blob(pContext, &c, sizeof(c), SQLITE_TRANSIENT); } return SQLITE_OK; } @@ -2833,11 +2828,74 @@ static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, * ppArg[2+v->nColumn] = value for _all (we ignore this) * ppArg[3+v->nColumn] = value of offset (we ignore this too) */ - assert( nArg==2+v->nColumn+2); + assert( nArg==2+v->nColumn+1); return index_insert(v, ppArg[1], &ppArg[2], pRowid); } +/* +** Implementation of the snippet() function for FTS1 +*/ +static void snippetFunc( + sqlite3_context *pContext, + int argc, + sqlite3_value **argv +){ + fulltext_cursor *pCursor; + if( argc<1 ) return; + if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || + sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ + sqlite3_result_error(pContext, "illegal first argument to html_snippet",-1); + }else{ + memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); + /* TODO: Return the snippet */ + } +} + +/* +** Implementation of the offsets() function for FTS1 +*/ +static void snippetOffsetsFunc( + sqlite3_context *pContext, + int argc, + sqlite3_value **argv +){ + fulltext_cursor *pCursor; + if( argc<1 ) return; + if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || + sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ + sqlite3_result_error(pContext, "illegal first argument to offsets",-1); + }else{ + memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); + snippetAllOffsets(pCursor); + snippetOffsetText(&pCursor->snippet); + sqlite3_result_text(pContext, + pCursor->snippet.zOffset, pCursor->snippet.nOffset, + SQLITE_STATIC); + } +} + +/* +** This routine implements the xFindFunction method for the FTS1 +** virtual table. +*/ +static int fulltextFindFunction( + sqlite3_vtab *pVtab, + int nArg, + const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg +){ + if( strcasecmp(zName,"snippet")==0 ){ + *pxFunc = snippetFunc; + return 1; + }else if( strcasecmp(zName,"offsets")==0 ){ + *pxFunc = snippetOffsetsFunc; + return 1; + } + return 0; +} + static const sqlite3_module fulltextModule = { /* iVersion */ 0, /* xCreate */ fulltextCreate, @@ -2857,18 +2915,22 @@ static const sqlite3_module fulltextModule = { /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, - /* xFindFunction */ 0, + /* xFindFunction */ fulltextFindFunction, }; int sqlite3Fts1Init(sqlite3 *db){ - return sqlite3_create_module(db, "fts1", &fulltextModule, 0); + sqlite3_overload_function(db, "snippet", -1); + sqlite3_overload_function(db, "offsets", -1); + return sqlite3_create_module(db, "fts1", &fulltextModule, 0); } #if !SQLITE_CORE int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi) - return sqlite3Fts1Init(db); + int rc; + SQLITE_EXTENSION_INIT2(pApi) + rc = sqlite3Fts1Init(db); + if( rc ) return rc; } #endif diff --git a/manifest b/manifest index 9263f99918..b93cabb377 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_overload_function()\sAPI\s-\spart\sof\sthe\svirtual\stable\ninterface.\s(CVS\s3426) -D 2006-09-16T21:45:14 +C Modify\sFTS1\sso\sthat\sthe\s"magic"\scolumn\shas\sthe\ssame\sname\sas\sthe\svirtual\ntable.\s\sOffsets\sare\sretrieved\susing\sa\sspecial\s"offsets"\sfunction\swhose\nfirst\sargument\sis\sthe\smagic\scolumn.\s\sSnippets\swill\sultimately\sbe\sretrieved\nin\sthe\ssame\sway.\s(CVS\s3427) +D 2006-09-18T02:12:48 F Makefile.in cabd42d34340f49260bc2a7668c38eba8d4cfd99 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -21,7 +21,7 @@ F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 1a35e654a235c2c662d3ca0dfc3138ad60b8b7d5 -F ext/fts1/fts1.c 10d0c351fb1ee51ef3b8bd3eb29d1f7f91773ddb +F ext/fts1/fts1.c 298a1b77f51083cf76fae406971c6a2312315409 F ext/fts1/fts1.h 6060b8f62c1d925ea8356cb1a6598073eb9159a6 F ext/fts1/fts1_hash.c 3196cee866edbebb1c0521e21672e6d599965114 F ext/fts1/fts1_hash.h 957d378355ed29f672cd5add012ce8b088a5e089 @@ -191,8 +191,8 @@ F test/expr.test c78843f730ccbe973d0c2ad1c99978f936893131 F test/fkey1.test 153004438d51e6769fb1ce165f6313972d6263ce F test/format4.test bf3bed3b13c63abfb3cfec232597a319a31d0bcc F test/fts1a.test 54fd9451c00fb91074d5abdc207b05dcba6d2d65 -F test/fts1b.test 5742c32c69ec9667c8d32df5bc79aa416d5f363a -F test/fts1c.test 65a4e5a900ca0e0c9cd05612f9baf958d67a9d44 +F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5 +F test/fts1c.test 4d84cfcacce229e4802fd676462f4616fabadad3 F test/func.test 0ed54b5aeaad319f68016c033acfebef56f5874a F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d @@ -399,7 +399,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P a6b3f6bed209dc27d36cd4e159159f73266e9911 -R 41c034b9dce9d7c6fde9c3e87e61b1e4 +P aa7728f9f5b80dbb1b3db124f84b9166bf72bdd3 +R 5f7b3fdccab6ce661c65210783a1bcaa U drh -Z 9301301f42636d8c9fe0c165b69e993c +Z 772a57c08cf67baf90fc0fd4a8945191 diff --git a/manifest.uuid b/manifest.uuid index 4b286c870d..a4bf5c5889 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa7728f9f5b80dbb1b3db124f84b9166bf72bdd3 \ No newline at end of file +5e35dc1ffadfe7fa47673d052501ee79903eead9 \ No newline at end of file diff --git a/test/fts1b.test b/test/fts1b.test index 3c9f0cbc18..2bbe1aab80 100644 --- a/test/fts1b.test +++ b/test/fts1b.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # -# $Id: fts1b.test,v 1.3 2006/09/13 16:02:44 drh Exp $ +# $Id: fts1b.test,v 1.4 2006/09/18 02:12:48 drh Exp $ # set testdir [file dirname $argv0] @@ -69,16 +69,16 @@ do_test fts1b-1.3 { execsql {SELECT rowid FROM t1 WHERE german MATCH 'one'} } {} do_test fts1b-1.4 { - execsql {SELECT rowid FROM t1 WHERE _all MATCH 'one'} + execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'one'} } {1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31} do_test fts1b-1.5 { - execsql {SELECT rowid FROM t1 WHERE _all MATCH 'one dos drei'} + execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'one dos drei'} } {7 15 23 31} do_test fts1b-1.6 { execsql {SELECT english, spanish, german FROM t1 WHERE rowid=1} } {one un eine} do_test fts1b-1.7 { - execsql {SELECT rowid FROM t1 WHERE _all MATCH '"one un"'} + execsql {SELECT rowid FROM t1 WHERE t1 MATCH '"one un"'} } {} do_test fts1b-2.1 { @@ -116,31 +116,31 @@ for {set i 1} {$i<=15} {incr i} { } do_test fts1b-4.1 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'norm:one'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one'} } {1 3 5 7 9 11 13 15} do_test fts1b-4.2 { execsql {SELECT rowid FROM t4 WHERE norm MATCH 'one'} } {1 3 5 7 9 11 13 15} do_test fts1b-4.3 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'one'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'one'} } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15} do_test fts1b-4.4 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'plusone:one'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'plusone:one'} } {2 4 6 8 10 12 14} do_test fts1b-4.5 { execsql {SELECT rowid FROM t4 WHERE plusone MATCH 'one'} } {2 4 6 8 10 12 14} do_test fts1b-4.6 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'norm:one plusone:two'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one plusone:two'} } {1 5 9 13} do_test fts1b-4.7 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'norm:one two'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'norm:one two'} } {1 3 5 7 9 11 13 15} do_test fts1b-4.8 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'plusone:two norm:one'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'plusone:two norm:one'} } {1 5 9 13} do_test fts1b-4.9 { - execsql {SELECT rowid FROM t4 WHERE _all MATCH 'two norm:one'} + execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'two norm:one'} } {1 3 5 7 9 11 13 15} diff --git a/test/fts1c.test b/test/fts1c.test index db0f19e0f6..b62fc5ff18 100644 --- a/test/fts1c.test +++ b/test/fts1c.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # -# $Id: fts1c.test,v 1.5 2006/09/16 21:45:14 drh Exp $ +# $Id: fts1c.test,v 1.6 2006/09/18 02:12:48 drh Exp $ # set testdir [file dirname $argv0] @@ -1027,93 +1027,93 @@ http://home.enron.com:84/messaging/litebytztoolzprint.jpg'); do_test fts1c-1.2 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'mark' + SELECT rowid FROM email WHERE email MATCH 'mark' } } {6 17 25 38 40 42 73 74} do_test fts1c-1.3 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'susan' + SELECT rowid FROM email WHERE email MATCH 'susan' } } {24 40} do_test fts1c-1.4 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'mark susan' + SELECT rowid FROM email WHERE email MATCH 'mark susan' } } {40} do_test fts1c-1.5 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'susan mark' + SELECT rowid FROM email WHERE email MATCH 'susan mark' } } {40} do_test fts1c-1.6 { execsql { - SELECT rowid FROM email WHERE _all MATCH '"mark susan"' + SELECT rowid FROM email WHERE email MATCH '"mark susan"' } } {} do_test fts1c-1.7 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'mark -susan' + SELECT rowid FROM email WHERE email MATCH 'mark -susan' } } {6 17 25 38 42 73 74} do_test fts1c-1.8 { execsql { - SELECT rowid FROM email WHERE _all MATCH '-mark susan' + SELECT rowid FROM email WHERE email MATCH '-mark susan' } } {24} do_test fts1c-1.9 { execsql { - SELECT rowid FROM email WHERE _all MATCH 'mark OR susan' + SELECT rowid FROM email WHERE email MATCH 'mark OR susan' } } {6 17 24 25 38 40 42 73 74} -# Some simple tests of the automatic "offset" column. In the sample +# Some simple tests of the automatic "offsets(email)" column. In the sample # data set above, only one message, number 20, contains the words # "gas" and "reminder" in both body and subject. # do_test fts1c-2.1 { execsql { - SELECT rowid, offset FROM email - WHERE _all MATCH 'gas reminder' + SELECT rowid, offsets(email) FROM email + WHERE email MATCH 'gas reminder' } } {20 {2 0 42 3 2 1 54 8 3 0 42 3 3 1 54 8 3 0 129 3 3 0 143 3 3 0 240 3}} do_test fts1c-2.2 { execsql { - SELECT rowid, offset FROM email - WHERE _all MATCH 'subject:gas reminder' + SELECT rowid, offsets(email) FROM email + WHERE email MATCH 'subject:gas reminder' } } {20 {2 0 42 3 2 1 54 8 3 1 54 8}} do_test fts1c-2.3 { execsql { - SELECT rowid, offset FROM email - WHERE _all MATCH 'body:gas reminder' + SELECT rowid, offsets(email) FROM email + WHERE email MATCH 'body:gas reminder' } } {20 {2 1 54 8 3 0 42 3 3 1 54 8 3 0 129 3 3 0 143 3 3 0 240 3}} do_test fts1c-2.4 { execsql { - SELECT rowid, offset FROM email + SELECT rowid, offsets(email) FROM email WHERE subject MATCH 'gas reminder' } } {20 {2 0 42 3 2 1 54 8}} do_test fts1c-2.5 { execsql { - SELECT rowid, offset FROM email + SELECT rowid, offsets(email) FROM email WHERE body MATCH 'gas reminder' } } {20 {3 0 42 3 3 1 54 8 3 0 129 3 3 0 143 3 3 0 240 3}} # Document 32 contains 5 instances of the world "child". But only # 3 of them are paired with "product". Make sure only those instances -# that match the phrase appear in the offset list. +# that match the phrase appear in the offsets(email) list. # do_test fts1c-3.1 { execsql { - SELECT rowid, offset FROM email + SELECT rowid, offsets(email) FROM email WHERE body MATCH 'child product' AND +rowid=32 } } {32 {3 0 94 5 3 0 114 5 3 0 207 5 3 1 213 7 3 0 245 5 3 1 251 7 3 0 409 5 3 1 415 7 3 1 493 7}} do_test fts1c-3.2 { execsql { - SELECT rowid, offset FROM email + SELECT rowid, offsets(email) FROM email WHERE body MATCH '"child product"' } } {32 {3 0 207 5 3 1 213 7 3 0 245 5 3 1 251 7 3 0 409 5 3 1 415 7}}