Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5e35dc1ffadfe7fa47673d052501ee79 |
User & Date: | drh 2006-09-18 02:12:48.000 |
Context
2006-09-18
| ||
20:24 | Convert all names to lower case before sending them to the xFindFunction method of a virtual table. In FTS1, use strcmp instead of strcasecmp. Ticket #1981. (CVS 3428) (check-in: efa8fb32a5 user: drh tags: trunk) | |
02:12 | 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) (check-in: 5e35dc1ffa user: drh tags: trunk) | |
2006-09-16
| ||
21:45 | Add the sqlite3_overload_function() API - part of the virtual table interface. (CVS 3426) (check-in: aa7728f9f5 user: drh tags: trunk) | |
Changes
Changes to ext/fts1/fts1.c.
︙ | ︙ | |||
1744 1745 1746 1747 1748 1749 1750 | tokenListToIdList(pSpec->azTokenizer); return SQLITE_OK; } /* ** Generate a CREATE TABLE statement that describes the schema of | | < < < | > | | 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 | tokenListToIdList(pSpec->azTokenizer); return SQLITE_OK; } /* ** Generate a CREATE TABLE statement that describes the schema of ** 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 *zTableName /* Name of the table */ ){ int i; char *zSchema, *zNext; const char *zSep = "("; zSchema = sqlite3_mprintf("CREATE TABLE x"); for(i=0; i<nColumn; i++){ zNext = sqlite3_mprintf("%s%s%Q", zSchema, zSep, azColumn[i]); sqlite3_free(zSchema); zSchema = zNext; zSep = ","; } zNext = sqlite3_mprintf("%s,%Q)", zSchema, zTableName); sqlite3_free(zSchema); return zNext; } /* ** Build a new sqlite3_vtab structure that will describe the ** fulltext index defined by spec. |
︙ | ︙ | |||
1822 1823 1824 1825 1826 1827 1828 | rc = m->xCreate(0, 0, &v->pTokenizer); } if( rc!=SQLITE_OK ) goto err; v->pTokenizer->pModule = m; /* TODO: verify the existence of backing tables foo_content, foo_term */ | | > | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | rc = m->xCreate(0, 0, &v->pTokenizer); } if( rc!=SQLITE_OK ) goto err; v->pTokenizer->pModule = m; /* TODO: verify the existence of backing tables foo_content, foo_term */ 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; memset(v->pFulltextStatements, 0, sizeof(v->pFulltextStatements)); *ppVTab = &v->base; |
︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 | fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); if( idxCol<v->nColumn ){ sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1); sqlite3_result_value(pContext, pVal); }else if( idxCol==v->nColumn ){ | | > > | < < < < < < | 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 | fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); if( idxCol<v->nColumn ){ sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1); sqlite3_result_value(pContext, pVal); }else if( idxCol==v->nColumn ){ /* 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; } /* This is the xRowid method. The SQLite core calls this routine to ** retrive the rowid for the current row of the result set. The ** rowid should be written to *pRowid. |
︙ | ︙ | |||
2829 2830 2831 2832 2833 2834 2835 | } /* ppArg[1] = rowid * ppArg[2..2+v->nColumn-1] = values * ppArg[2+v->nColumn] = value for _all (we ignore this) * ppArg[3+v->nColumn] = value of offset (we ignore this too) */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > | | > | 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 | } /* ppArg[1] = rowid * ppArg[2..2+v->nColumn-1] = values * 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+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, /* xConnect */ fulltextConnect, /* xBestIndex */ fulltextBestIndex, /* xDisconnect */ fulltextDisconnect, /* xDestroy */ fulltextDestroy, /* xOpen */ fulltextOpen, /* xClose */ fulltextClose, /* xFilter */ fulltextFilter, /* xNext */ fulltextNext, /* xEof */ fulltextEof, /* xColumn */ fulltextColumn, /* xRowid */ fulltextRowid, /* xUpdate */ fulltextUpdate, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ fulltextFindFunction, }; int sqlite3Fts1Init(sqlite3 *db){ 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){ int rc; SQLITE_EXTENSION_INIT2(pApi) rc = sqlite3Fts1Init(db); if( rc ) return rc; } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */ |
Changes to test/fts1b.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2006 September 13 # # 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. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2006 September 13 # # 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. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # # $Id: fts1b.test,v 1.4 2006/09/18 02:12:48 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS1 is defined, omit this file. ifcapable !fts1 { |
︙ | ︙ | |||
65 66 67 68 69 70 71 | do_test fts1b-1.2 { execsql {SELECT rowid FROM t1 WHERE spanish MATCH 'one'} } {} do_test fts1b-1.3 { execsql {SELECT rowid FROM t1 WHERE german MATCH 'one'} } {} do_test fts1b-1.4 { | | | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | do_test fts1b-1.2 { execsql {SELECT rowid FROM t1 WHERE spanish MATCH 'one'} } {} 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 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 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 t1 MATCH '"one un"'} } {} do_test fts1b-2.1 { execsql { CREATE VIRTUAL TABLE t2 USING fts1(from,to); INSERT INTO t2([from],[to]) VALUES ('one two three', 'four five six'); SELECT [from], [to] FROM t2 |
︙ | ︙ | |||
112 113 114 115 116 117 118 | } for {set i 1} {$i<=15} {incr i} { set vset [list [wordset $i] [wordset [expr {$i+1}]] [wordset [expr {~$i}]]] db eval "INSERT INTO t4(norm,plusone,invert) VALUES([join $vset ,]);" } do_test fts1b-4.1 { | | | | | | | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | } for {set i 1} {$i<=15} {incr i} { set vset [list [wordset $i] [wordset [expr {$i+1}]] [wordset [expr {~$i}]]] db eval "INSERT INTO t4(norm,plusone,invert) VALUES([join $vset ,]);" } do_test fts1b-4.1 { 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 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 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 t4 MATCH 'norm:one plusone:two'} } {1 5 9 13} do_test fts1b-4.7 { 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 t4 MATCH 'plusone:two norm:one'} } {1 5 9 13} do_test fts1b-4.9 { execsql {SELECT rowid FROM t4 WHERE t4 MATCH 'two norm:one'} } {1 3 5 7 9 11 13 15} finish_test |
Changes to test/fts1c.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2006 September 14 # # 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. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2006 September 14 # # 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. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS1 module. # # $Id: fts1c.test,v 1.6 2006/09/18 02:12:48 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS1 is defined, omit this file. ifcapable !fts1 { |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | ############################################################################### # Everything above just builds an interesting test database. The actual # tests come after this comment. ############################################################################### do_test fts1c-1.2 { execsql { | | | | | | | | | | | | | | | | | | | | | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | ############################################################################### # Everything above just builds an interesting test database. The actual # tests come after this comment. ############################################################################### do_test fts1c-1.2 { execsql { 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 email MATCH 'susan' } } {24 40} do_test fts1c-1.4 { execsql { SELECT rowid FROM email WHERE email MATCH 'mark susan' } } {40} do_test fts1c-1.5 { execsql { SELECT rowid FROM email WHERE email MATCH 'susan mark' } } {40} do_test fts1c-1.6 { execsql { SELECT rowid FROM email WHERE email MATCH '"mark susan"' } } {} do_test fts1c-1.7 { execsql { 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 email MATCH '-mark susan' } } {24} do_test fts1c-1.9 { execsql { 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 "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, 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, 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, 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, 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, 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 offsets(email) list. # do_test fts1c-3.1 { execsql { 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, 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}} finish_test |