Modify FTS1 so that the "magic" column has the same name as the virtual

table.  Offsets are retrieved using a special "offsets" function whose
first argument is the magic column.  Snippets will ultimately be retrieved
in the same way. (CVS 3427)

FossilOrigin-Name: 5e35dc1ffadfe7fa47673d052501ee79903eead9
This commit is contained in:
drh 2006-09-18 02:12:47 +00:00
parent b7481e70c5
commit b08249ced3
5 changed files with 123 additions and 61 deletions

View File

@ -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

View File

@ -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

View File

@ -1 +1 @@
aa7728f9f5b80dbb1b3db124f84b9166bf72bdd3
5e35dc1ffadfe7fa47673d052501ee79903eead9

View File

@ -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}

View File

@ -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}}