OLD | NEW |
1 /* | 1 /* |
2 ** 2012 April 10 | 2 ** 2012 April 10 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 ** | 349 ** |
350 ** If pnMatch is not NULL, then *pnMatch is set to the number of bytes | 350 ** If pnMatch is not NULL, then *pnMatch is set to the number of bytes |
351 ** of zB that matched the pattern in zA. If zA does not end with a '*', | 351 ** of zB that matched the pattern in zA. If zA does not end with a '*', |
352 ** then this value is always the number of bytes in zB (i.e. strlen(zB)). | 352 ** then this value is always the number of bytes in zB (i.e. strlen(zB)). |
353 ** If zA does end in a '*', then it is the number of bytes in the prefix | 353 ** If zA does end in a '*', then it is the number of bytes in the prefix |
354 ** of zB that was deemed to match zA. | 354 ** of zB that was deemed to match zA. |
355 */ | 355 */ |
356 static int editdist1(const char *zA, const char *zB, int *pnMatch){ | 356 static int editdist1(const char *zA, const char *zB, int *pnMatch){ |
357 int nA, nB; /* Number of characters in zA[] and zB[] */ | 357 int nA, nB; /* Number of characters in zA[] and zB[] */ |
358 int xA, xB; /* Loop counters for zA[] and zB[] */ | 358 int xA, xB; /* Loop counters for zA[] and zB[] */ |
359 char cA, cB; /* Current character of zA and zB */ | 359 char cA = 0, cB; /* Current character of zA and zB */ |
360 char cAprev, cBprev; /* Previous character of zA and zB */ | 360 char cAprev, cBprev; /* Previous character of zA and zB */ |
361 char cAnext, cBnext; /* Next character in zA and zB */ | 361 char cAnext, cBnext; /* Next character in zA and zB */ |
362 int d; /* North-west cost value */ | 362 int d; /* North-west cost value */ |
363 int dc = 0; /* North-west character value */ | 363 int dc = 0; /* North-west character value */ |
364 int res; /* Final result */ | 364 int res; /* Final result */ |
365 int *m; /* The cost matrix */ | 365 int *m; /* The cost matrix */ |
366 char *cx; /* Corresponding character values */ | 366 char *cx; /* Corresponding character values */ |
367 int *toFree = 0; /* Malloced space */ | 367 int *toFree = 0; /* Malloced space */ |
368 int mStack[60+15]; /* Stack space to use if not too much is needed */ | 368 int mStack[60+15]; /* Stack space to use if not too much is needed */ |
369 int nMatch = 0; | 369 int nMatch = 0; |
(...skipping 1340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1710 sqlite3_value **argv | 1710 sqlite3_value **argv |
1711 ){ | 1711 ){ |
1712 const unsigned char *zIn = sqlite3_value_text(argv[0]); | 1712 const unsigned char *zIn = sqlite3_value_text(argv[0]); |
1713 int nIn = sqlite3_value_bytes(argv[0]); | 1713 int nIn = sqlite3_value_bytes(argv[0]); |
1714 int c, sz; | 1714 int c, sz; |
1715 int scriptMask = 0; | 1715 int scriptMask = 0; |
1716 int res; | 1716 int res; |
1717 # define SCRIPT_LATIN 0x0001 | 1717 # define SCRIPT_LATIN 0x0001 |
1718 # define SCRIPT_CYRILLIC 0x0002 | 1718 # define SCRIPT_CYRILLIC 0x0002 |
1719 # define SCRIPT_GREEK 0x0004 | 1719 # define SCRIPT_GREEK 0x0004 |
| 1720 # define SCRIPT_HEBREW 0x0008 |
| 1721 # define SCRIPT_ARABIC 0x0010 |
1720 | 1722 |
1721 while( nIn>0 ){ | 1723 while( nIn>0 ){ |
1722 c = utf8Read(zIn, nIn, &sz); | 1724 c = utf8Read(zIn, nIn, &sz); |
1723 zIn += sz; | 1725 zIn += sz; |
1724 nIn -= sz; | 1726 nIn -= sz; |
1725 if( c<0x02af ){ | 1727 if( c<0x02af && (c>=0x80 || midClass[c&0x7f]<CCLASS_DIGIT) ){ |
1726 scriptMask |= SCRIPT_LATIN; | 1728 scriptMask |= SCRIPT_LATIN; |
1727 }else if( c>=0x0400 && c<=0x04ff ){ | 1729 }else if( c>=0x0400 && c<=0x04ff ){ |
1728 scriptMask |= SCRIPT_CYRILLIC; | 1730 scriptMask |= SCRIPT_CYRILLIC; |
1729 }else if( c>=0x0386 && c<=0x03ce ){ | 1731 }else if( c>=0x0386 && c<=0x03ce ){ |
1730 scriptMask |= SCRIPT_GREEK; | 1732 scriptMask |= SCRIPT_GREEK; |
| 1733 }else if( c>=0x0590 && c<=0x05ff ){ |
| 1734 scriptMask |= SCRIPT_HEBREW; |
| 1735 }else if( c>=0x0600 && c<=0x06ff ){ |
| 1736 scriptMask |= SCRIPT_ARABIC; |
1731 } | 1737 } |
1732 } | 1738 } |
1733 switch( scriptMask ){ | 1739 switch( scriptMask ){ |
1734 case 0: res = 999; break; | 1740 case 0: res = 999; break; |
1735 case SCRIPT_LATIN: res = 215; break; | 1741 case SCRIPT_LATIN: res = 215; break; |
1736 case SCRIPT_CYRILLIC: res = 220; break; | 1742 case SCRIPT_CYRILLIC: res = 220; break; |
1737 case SCRIPT_GREEK: res = 200; break; | 1743 case SCRIPT_GREEK: res = 200; break; |
| 1744 case SCRIPT_HEBREW: res = 125; break; |
| 1745 case SCRIPT_ARABIC: res = 160; break; |
1738 default: res = 998; break; | 1746 default: res = 998; break; |
1739 } | 1747 } |
1740 sqlite3_result_int(context, res); | 1748 sqlite3_result_int(context, res); |
1741 } | 1749 } |
1742 | 1750 |
1743 /* End transliterate | 1751 /* End transliterate |
1744 ****************************************************************************** | 1752 ****************************************************************************** |
1745 ****************************************************************************** | 1753 ****************************************************************************** |
1746 ** Begin spellfix1 virtual table. | 1754 ** Begin spellfix1 virtual table. |
1747 */ | 1755 */ |
(...skipping 15 matching lines...) Expand all Loading... |
1763 char *zTableName; /* Name of the virtual table */ | 1771 char *zTableName; /* Name of the virtual table */ |
1764 char *zCostTable; /* Table holding edit-distance cost numbers */ | 1772 char *zCostTable; /* Table holding edit-distance cost numbers */ |
1765 EditDist3Config *pConfig3; /* Parsed edit distance costs */ | 1773 EditDist3Config *pConfig3; /* Parsed edit distance costs */ |
1766 }; | 1774 }; |
1767 | 1775 |
1768 /* Fuzzy-search cursor object */ | 1776 /* Fuzzy-search cursor object */ |
1769 struct spellfix1_cursor { | 1777 struct spellfix1_cursor { |
1770 sqlite3_vtab_cursor base; /* Base class - must be first */ | 1778 sqlite3_vtab_cursor base; /* Base class - must be first */ |
1771 spellfix1_vtab *pVTab; /* The table to which this cursor belongs */ | 1779 spellfix1_vtab *pVTab; /* The table to which this cursor belongs */ |
1772 char *zPattern; /* rhs of MATCH clause */ | 1780 char *zPattern; /* rhs of MATCH clause */ |
| 1781 int idxNum; /* idxNum value passed to xFilter() */ |
1773 int nRow; /* Number of rows of content */ | 1782 int nRow; /* Number of rows of content */ |
1774 int nAlloc; /* Number of allocated rows */ | 1783 int nAlloc; /* Number of allocated rows */ |
1775 int iRow; /* Current row of content */ | 1784 int iRow; /* Current row of content */ |
1776 int iLang; /* Value of the langid= constraint */ | 1785 int iLang; /* Value of the langid= constraint */ |
1777 int iTop; /* Value of the top= constraint */ | 1786 int iTop; /* Value of the top= constraint */ |
1778 int iScope; /* Value of the scope= constraint */ | 1787 int iScope; /* Value of the scope= constraint */ |
1779 int nSearch; /* Number of vocabulary items checked */ | 1788 int nSearch; /* Number of vocabulary items checked */ |
1780 sqlite3_stmt *pFullScan; /* Shadow query for a full table scan */ | 1789 sqlite3_stmt *pFullScan; /* Shadow query for a full table scan */ |
1781 struct spellfix1_row { /* For each row of content */ | 1790 struct spellfix1_row { /* For each row of content */ |
1782 sqlite3_int64 iRowid; /* Rowid for this row */ | 1791 sqlite3_int64 iRowid; /* Rowid for this row */ |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1843 } | 1852 } |
1844 | 1853 |
1845 /* | 1854 /* |
1846 ** Make a copy of a string. Remove leading and trailing whitespace | 1855 ** Make a copy of a string. Remove leading and trailing whitespace |
1847 ** and dequote it. | 1856 ** and dequote it. |
1848 */ | 1857 */ |
1849 static char *spellfix1Dequote(const char *zIn){ | 1858 static char *spellfix1Dequote(const char *zIn){ |
1850 char *zOut; | 1859 char *zOut; |
1851 int i, j; | 1860 int i, j; |
1852 char c; | 1861 char c; |
1853 while( isspace(zIn[0]) ) zIn++; | 1862 while( isspace((unsigned char)zIn[0]) ) zIn++; |
1854 zOut = sqlite3_mprintf("%s", zIn); | 1863 zOut = sqlite3_mprintf("%s", zIn); |
1855 if( zOut==0 ) return 0; | 1864 if( zOut==0 ) return 0; |
1856 i = (int)strlen(zOut); | 1865 i = (int)strlen(zOut); |
1857 #if 0 /* The parser will never leave spaces at the end */ | 1866 #if 0 /* The parser will never leave spaces at the end */ |
1858 while( i>0 && isspace(zOut[i-1]) ){ i--; } | 1867 while( i>0 && isspace(zOut[i-1]) ){ i--; } |
1859 #endif | 1868 #endif |
1860 zOut[i] = 0; | 1869 zOut[i] = 0; |
1861 c = zOut[0]; | 1870 c = zOut[0]; |
1862 if( c=='\'' || c=='"' ){ | 1871 if( c=='\'' || c=='"' ){ |
1863 for(i=1, j=0; ALWAYS(zOut[i]); i++){ | 1872 for(i=1, j=0; ALWAYS(zOut[i]); i++){ |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2033 */ | 2042 */ |
2034 static int spellfix1Close(sqlite3_vtab_cursor *cur){ | 2043 static int spellfix1Close(sqlite3_vtab_cursor *cur){ |
2035 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; | 2044 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; |
2036 spellfix1ResetCursor(pCur); | 2045 spellfix1ResetCursor(pCur); |
2037 spellfix1ResizeCursor(pCur, 0); | 2046 spellfix1ResizeCursor(pCur, 0); |
2038 sqlite3_free(pCur->zPattern); | 2047 sqlite3_free(pCur->zPattern); |
2039 sqlite3_free(pCur); | 2048 sqlite3_free(pCur); |
2040 return SQLITE_OK; | 2049 return SQLITE_OK; |
2041 } | 2050 } |
2042 | 2051 |
| 2052 #define SPELLFIX_IDXNUM_MATCH 0x01 /* word MATCH $str */ |
| 2053 #define SPELLFIX_IDXNUM_LANGID 0x02 /* langid == $langid */ |
| 2054 #define SPELLFIX_IDXNUM_TOP 0x04 /* top = $top */ |
| 2055 #define SPELLFIX_IDXNUM_SCOPE 0x08 /* scope = $scope */ |
| 2056 #define SPELLFIX_IDXNUM_DISTLT 0x10 /* distance < $distance */ |
| 2057 #define SPELLFIX_IDXNUM_DISTLE 0x20 /* distance <= $distance */ |
| 2058 #define SPELLFIX_IDXNUM_ROWID 0x40 /* rowid = $rowid */ |
| 2059 #define SPELLFIX_IDXNUM_DIST (0x10|0x20) /* DISTLT and DISTLE */ |
| 2060 |
2043 /* | 2061 /* |
2044 ** Search for terms of these forms: | |
2045 ** | 2062 ** |
2046 ** (A) word MATCH $str | 2063 ** The plan number is a bitmask of the SPELLFIX_IDXNUM_* values defined |
2047 ** (B) langid == $langid | 2064 ** above. |
2048 ** (C) top = $top | |
2049 ** (D) scope = $scope | |
2050 ** (E) distance < $distance | |
2051 ** (F) distance <= $distance | |
2052 ** (G) rowid = $rowid | |
2053 ** | |
2054 ** The plan number is a bit mask formed with these bits: | |
2055 ** | |
2056 ** 0x01 (A) is found | |
2057 ** 0x02 (B) is found | |
2058 ** 0x04 (C) is found | |
2059 ** 0x08 (D) is found | |
2060 ** 0x10 (E) is found | |
2061 ** 0x20 (F) is found | |
2062 ** 0x40 (G) is found | |
2063 ** | 2065 ** |
2064 ** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid | 2066 ** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid |
2065 ** if specified and in that order. | 2067 ** if specified and in that order. |
2066 */ | 2068 */ |
2067 static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ | 2069 static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ |
2068 int iPlan = 0; | 2070 int iPlan = 0; |
2069 int iLangTerm = -1; | 2071 int iLangTerm = -1; |
2070 int iTopTerm = -1; | 2072 int iTopTerm = -1; |
2071 int iScopeTerm = -1; | 2073 int iScopeTerm = -1; |
2072 int iDistTerm = -1; | 2074 int iDistTerm = -1; |
2073 int iRowidTerm = -1; | 2075 int iRowidTerm = -1; |
2074 int i; | 2076 int i; |
2075 const struct sqlite3_index_constraint *pConstraint; | 2077 const struct sqlite3_index_constraint *pConstraint; |
2076 pConstraint = pIdxInfo->aConstraint; | 2078 pConstraint = pIdxInfo->aConstraint; |
2077 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ | 2079 for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ |
2078 if( pConstraint->usable==0 ) continue; | 2080 if( pConstraint->usable==0 ) continue; |
2079 | 2081 |
2080 /* Terms of the form: word MATCH $str */ | 2082 /* Terms of the form: word MATCH $str */ |
2081 if( (iPlan & 1)==0 | 2083 if( (iPlan & SPELLFIX_IDXNUM_MATCH)==0 |
2082 && pConstraint->iColumn==SPELLFIX_COL_WORD | 2084 && pConstraint->iColumn==SPELLFIX_COL_WORD |
2083 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH | 2085 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH |
2084 ){ | 2086 ){ |
2085 iPlan |= 1; | 2087 iPlan |= SPELLFIX_IDXNUM_MATCH; |
2086 pIdxInfo->aConstraintUsage[i].argvIndex = 1; | 2088 pIdxInfo->aConstraintUsage[i].argvIndex = 1; |
2087 pIdxInfo->aConstraintUsage[i].omit = 1; | 2089 pIdxInfo->aConstraintUsage[i].omit = 1; |
2088 } | 2090 } |
2089 | 2091 |
2090 /* Terms of the form: langid = $langid */ | 2092 /* Terms of the form: langid = $langid */ |
2091 if( (iPlan & 2)==0 | 2093 if( (iPlan & SPELLFIX_IDXNUM_LANGID)==0 |
2092 && pConstraint->iColumn==SPELLFIX_COL_LANGID | 2094 && pConstraint->iColumn==SPELLFIX_COL_LANGID |
2093 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ | 2095 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ |
2094 ){ | 2096 ){ |
2095 iPlan |= 2; | 2097 iPlan |= SPELLFIX_IDXNUM_LANGID; |
2096 iLangTerm = i; | 2098 iLangTerm = i; |
2097 } | 2099 } |
2098 | 2100 |
2099 /* Terms of the form: top = $top */ | 2101 /* Terms of the form: top = $top */ |
2100 if( (iPlan & 4)==0 | 2102 if( (iPlan & SPELLFIX_IDXNUM_TOP)==0 |
2101 && pConstraint->iColumn==SPELLFIX_COL_TOP | 2103 && pConstraint->iColumn==SPELLFIX_COL_TOP |
2102 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ | 2104 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ |
2103 ){ | 2105 ){ |
2104 iPlan |= 4; | 2106 iPlan |= SPELLFIX_IDXNUM_TOP; |
2105 iTopTerm = i; | 2107 iTopTerm = i; |
2106 } | 2108 } |
2107 | 2109 |
2108 /* Terms of the form: scope = $scope */ | 2110 /* Terms of the form: scope = $scope */ |
2109 if( (iPlan & 8)==0 | 2111 if( (iPlan & SPELLFIX_IDXNUM_SCOPE)==0 |
2110 && pConstraint->iColumn==SPELLFIX_COL_SCOPE | 2112 && pConstraint->iColumn==SPELLFIX_COL_SCOPE |
2111 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ | 2113 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ |
2112 ){ | 2114 ){ |
2113 iPlan |= 8; | 2115 iPlan |= SPELLFIX_IDXNUM_SCOPE; |
2114 iScopeTerm = i; | 2116 iScopeTerm = i; |
2115 } | 2117 } |
2116 | 2118 |
2117 /* Terms of the form: distance < $dist or distance <= $dist */ | 2119 /* Terms of the form: distance < $dist or distance <= $dist */ |
2118 if( (iPlan & (16|32))==0 | 2120 if( (iPlan & SPELLFIX_IDXNUM_DIST)==0 |
2119 && pConstraint->iColumn==SPELLFIX_COL_DISTANCE | 2121 && pConstraint->iColumn==SPELLFIX_COL_DISTANCE |
2120 && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT | 2122 && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT |
2121 || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE) | 2123 || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE) |
2122 ){ | 2124 ){ |
2123 iPlan |= pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ? 16 : 32; | 2125 if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){ |
| 2126 iPlan |= SPELLFIX_IDXNUM_DISTLT; |
| 2127 }else{ |
| 2128 iPlan |= SPELLFIX_IDXNUM_DISTLE; |
| 2129 } |
2124 iDistTerm = i; | 2130 iDistTerm = i; |
2125 } | 2131 } |
2126 | 2132 |
2127 /* Terms of the form: distance < $dist or distance <= $dist */ | 2133 /* Terms of the form: distance < $dist or distance <= $dist */ |
2128 if( (iPlan & 64)==0 | 2134 if( (iPlan & SPELLFIX_IDXNUM_ROWID)==0 |
2129 && pConstraint->iColumn<0 | 2135 && pConstraint->iColumn<0 |
2130 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ | 2136 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ |
2131 ){ | 2137 ){ |
2132 iPlan |= 64; | 2138 iPlan |= SPELLFIX_IDXNUM_ROWID; |
2133 iRowidTerm = i; | 2139 iRowidTerm = i; |
2134 } | 2140 } |
2135 } | 2141 } |
2136 if( iPlan&1 ){ | 2142 if( iPlan&SPELLFIX_IDXNUM_MATCH ){ |
2137 int idx = 2; | 2143 int idx = 2; |
2138 pIdxInfo->idxNum = iPlan; | 2144 pIdxInfo->idxNum = iPlan; |
2139 if( pIdxInfo->nOrderBy==1 | 2145 if( pIdxInfo->nOrderBy==1 |
2140 && pIdxInfo->aOrderBy[0].iColumn==SPELLFIX_COL_SCORE | 2146 && pIdxInfo->aOrderBy[0].iColumn==SPELLFIX_COL_SCORE |
2141 && pIdxInfo->aOrderBy[0].desc==0 | 2147 && pIdxInfo->aOrderBy[0].desc==0 |
2142 ){ | 2148 ){ |
2143 pIdxInfo->orderByConsumed = 1; /* Default order by iScore */ | 2149 pIdxInfo->orderByConsumed = 1; /* Default order by iScore */ |
2144 } | 2150 } |
2145 if( iPlan&2 ){ | 2151 if( iPlan&SPELLFIX_IDXNUM_LANGID ){ |
2146 pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++; | 2152 pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++; |
2147 pIdxInfo->aConstraintUsage[iLangTerm].omit = 1; | 2153 pIdxInfo->aConstraintUsage[iLangTerm].omit = 1; |
2148 } | 2154 } |
2149 if( iPlan&4 ){ | 2155 if( iPlan&SPELLFIX_IDXNUM_TOP ){ |
2150 pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++; | 2156 pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++; |
2151 pIdxInfo->aConstraintUsage[iTopTerm].omit = 1; | 2157 pIdxInfo->aConstraintUsage[iTopTerm].omit = 1; |
2152 } | 2158 } |
2153 if( iPlan&8 ){ | 2159 if( iPlan&SPELLFIX_IDXNUM_SCOPE ){ |
2154 pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++; | 2160 pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++; |
2155 pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1; | 2161 pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1; |
2156 } | 2162 } |
2157 if( iPlan&(16|32) ){ | 2163 if( iPlan&SPELLFIX_IDXNUM_DIST ){ |
2158 pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++; | 2164 pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++; |
2159 pIdxInfo->aConstraintUsage[iDistTerm].omit = 1; | 2165 pIdxInfo->aConstraintUsage[iDistTerm].omit = 1; |
2160 } | 2166 } |
2161 pIdxInfo->estimatedCost = 1e5; | 2167 pIdxInfo->estimatedCost = 1e5; |
2162 }else if( (iPlan & 64) ){ | 2168 }else if( (iPlan & SPELLFIX_IDXNUM_ROWID) ){ |
2163 pIdxInfo->idxNum = 64; | 2169 pIdxInfo->idxNum = SPELLFIX_IDXNUM_ROWID; |
2164 pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; | 2170 pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; |
2165 pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; | 2171 pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; |
2166 pIdxInfo->estimatedCost = 5; | 2172 pIdxInfo->estimatedCost = 5; |
2167 }else{ | 2173 }else{ |
2168 pIdxInfo->idxNum = 0; | 2174 pIdxInfo->idxNum = 0; |
2169 pIdxInfo->estimatedCost = 1e50; | 2175 pIdxInfo->estimatedCost = 1e50; |
2170 } | 2176 } |
2171 return SQLITE_OK; | 2177 return SQLITE_OK; |
2172 } | 2178 } |
2173 | 2179 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2304 }else{ | 2310 }else{ |
2305 zK1 = (const char*)sqlite3_column_text(pStmt, 3); | 2311 zK1 = (const char*)sqlite3_column_text(pStmt, 3); |
2306 if( zK1==0 ) continue; | 2312 if( zK1==0 ) continue; |
2307 iDist = editdist1(p->zPattern, zK1, 0); | 2313 iDist = editdist1(p->zPattern, zK1, 0); |
2308 } | 2314 } |
2309 if( iDist<0 ){ | 2315 if( iDist<0 ){ |
2310 p->rc = SQLITE_NOMEM; | 2316 p->rc = SQLITE_NOMEM; |
2311 break; | 2317 break; |
2312 } | 2318 } |
2313 pCur->nSearch++; | 2319 pCur->nSearch++; |
2314 iScore = spellfix1Score(iDist,iRank); | 2320 |
| 2321 /* If there is a "distance < $dist" or "distance <= $dist" constraint, |
| 2322 ** check if this row meets it. If not, jump back up to the top of the |
| 2323 ** loop to process the next row. Otherwise, if the row does match the |
| 2324 ** distance constraint, check if the pCur->a[] array is already full. |
| 2325 ** If it is and no explicit "top = ?" constraint was present in the |
| 2326 ** query, grow the array to ensure there is room for the new entry. */ |
| 2327 assert( (p->iMaxDist>=0)==((pCur->idxNum & SPELLFIX_IDXNUM_DIST) ? 1 : 0) ); |
2315 if( p->iMaxDist>=0 ){ | 2328 if( p->iMaxDist>=0 ){ |
2316 if( iDist>p->iMaxDist ) continue; | 2329 if( iDist>p->iMaxDist ) continue; |
2317 if( pCur->nRow>=pCur->nAlloc-1 ){ | 2330 if( pCur->nRow>=pCur->nAlloc && (pCur->idxNum & SPELLFIX_IDXNUM_TOP)==0 ){ |
2318 spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10); | 2331 spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10); |
2319 if( pCur->a==0 ) break; | 2332 if( pCur->a==0 ) break; |
2320 } | 2333 } |
2321 idx = pCur->nRow; | 2334 } |
2322 }else if( pCur->nRow<pCur->nAlloc ){ | 2335 |
| 2336 iScore = spellfix1Score(iDist,iRank); |
| 2337 if( pCur->nRow<pCur->nAlloc ){ |
2323 idx = pCur->nRow; | 2338 idx = pCur->nRow; |
2324 }else if( iScore<iWorst ){ | 2339 }else if( iScore<iWorst ){ |
2325 idx = idxWorst; | 2340 idx = idxWorst; |
2326 sqlite3_free(pCur->a[idx].zWord); | 2341 sqlite3_free(pCur->a[idx].zWord); |
2327 }else{ | 2342 }else{ |
2328 continue; | 2343 continue; |
2329 } | 2344 } |
| 2345 |
2330 pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); | 2346 pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); |
2331 if( pCur->a[idx].zWord==0 ){ | 2347 if( pCur->a[idx].zWord==0 ){ |
2332 p->rc = SQLITE_NOMEM; | 2348 p->rc = SQLITE_NOMEM; |
2333 break; | 2349 break; |
2334 } | 2350 } |
2335 pCur->a[idx].iRowid = sqlite3_column_int64(pStmt, 0); | 2351 pCur->a[idx].iRowid = sqlite3_column_int64(pStmt, 0); |
2336 pCur->a[idx].iRank = iRank; | 2352 pCur->a[idx].iRank = iRank; |
2337 pCur->a[idx].iDistance = iDist; | 2353 pCur->a[idx].iDistance = iDist; |
2338 pCur->a[idx].iScore = iScore; | 2354 pCur->a[idx].iScore = iScore; |
2339 pCur->a[idx].iMatchlen = iMatchlen; | 2355 pCur->a[idx].iMatchlen = iMatchlen; |
(...skipping 14 matching lines...) Expand all Loading... |
2354 rc = sqlite3_reset(pStmt); | 2370 rc = sqlite3_reset(pStmt); |
2355 if( rc ) p->rc = rc; | 2371 if( rc ) p->rc = rc; |
2356 } | 2372 } |
2357 | 2373 |
2358 /* | 2374 /* |
2359 ** This version of the xFilter method work if the MATCH term is present | 2375 ** This version of the xFilter method work if the MATCH term is present |
2360 ** and we are doing a scan. | 2376 ** and we are doing a scan. |
2361 */ | 2377 */ |
2362 static int spellfix1FilterForMatch( | 2378 static int spellfix1FilterForMatch( |
2363 spellfix1_cursor *pCur, | 2379 spellfix1_cursor *pCur, |
2364 int idxNum, | |
2365 int argc, | 2380 int argc, |
2366 sqlite3_value **argv | 2381 sqlite3_value **argv |
2367 ){ | 2382 ){ |
| 2383 int idxNum = pCur->idxNum; |
2368 const unsigned char *zMatchThis; /* RHS of the MATCH operator */ | 2384 const unsigned char *zMatchThis; /* RHS of the MATCH operator */ |
2369 EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */ | 2385 EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */ |
2370 char *zPattern; /* Transliteration of zMatchThis */ | 2386 char *zPattern; /* Transliteration of zMatchThis */ |
2371 int nPattern; /* Length of zPattern */ | 2387 int nPattern; /* Length of zPattern */ |
2372 int iLimit = 20; /* Max number of rows of output */ | 2388 int iLimit = 20; /* Max number of rows of output */ |
2373 int iScope = 3; /* Use this many characters of zClass */ | 2389 int iScope = 3; /* Use this many characters of zClass */ |
2374 int iLang = 0; /* Language code */ | 2390 int iLang = 0; /* Language code */ |
2375 char *zSql; /* SQL of shadow table query */ | 2391 char *zSql; /* SQL of shadow table query */ |
2376 sqlite3_stmt *pStmt = 0; /* Shadow table query */ | 2392 sqlite3_stmt *pStmt = 0; /* Shadow table query */ |
2377 int rc; /* Result code */ | 2393 int rc; /* Result code */ |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2469 sqlite3_finalize(pStmt); | 2485 sqlite3_finalize(pStmt); |
2470 editDist3FromStringDelete(pMatchStr3); | 2486 editDist3FromStringDelete(pMatchStr3); |
2471 return x.rc; | 2487 return x.rc; |
2472 } | 2488 } |
2473 | 2489 |
2474 /* | 2490 /* |
2475 ** This version of xFilter handles a full-table scan case | 2491 ** This version of xFilter handles a full-table scan case |
2476 */ | 2492 */ |
2477 static int spellfix1FilterForFullScan( | 2493 static int spellfix1FilterForFullScan( |
2478 spellfix1_cursor *pCur, | 2494 spellfix1_cursor *pCur, |
2479 int idxNum, | |
2480 int argc, | 2495 int argc, |
2481 sqlite3_value **argv | 2496 sqlite3_value **argv |
2482 ){ | 2497 ){ |
2483 int rc = SQLITE_OK; | 2498 int rc = SQLITE_OK; |
| 2499 int idxNum = pCur->idxNum; |
2484 char *zSql; | 2500 char *zSql; |
2485 spellfix1_vtab *pVTab = pCur->pVTab; | 2501 spellfix1_vtab *pVTab = pCur->pVTab; |
2486 spellfix1ResetCursor(pCur); | 2502 spellfix1ResetCursor(pCur); |
2487 assert( idxNum==0 || idxNum==64 ); | 2503 assert( idxNum==0 || idxNum==64 ); |
2488 zSql = sqlite3_mprintf( | 2504 zSql = sqlite3_mprintf( |
2489 "SELECT word, rank, NULL, langid, id FROM \"%w\".\"%w_vocab\"%s", | 2505 "SELECT word, rank, NULL, langid, id FROM \"%w\".\"%w_vocab\"%s", |
2490 pVTab->zDbName, pVTab->zTableName, | 2506 pVTab->zDbName, pVTab->zTableName, |
2491 ((idxNum & 64) ? " WHERE rowid=?" : "") | 2507 ((idxNum & 64) ? " WHERE rowid=?" : "") |
2492 ); | 2508 ); |
2493 if( zSql==0 ) return SQLITE_NOMEM; | 2509 if( zSql==0 ) return SQLITE_NOMEM; |
(...skipping 20 matching lines...) Expand all Loading... |
2514 ** it starts its output over again. Always called at least once | 2530 ** it starts its output over again. Always called at least once |
2515 ** prior to any spellfix1Column, spellfix1Rowid, or spellfix1Eof call. | 2531 ** prior to any spellfix1Column, spellfix1Rowid, or spellfix1Eof call. |
2516 */ | 2532 */ |
2517 static int spellfix1Filter( | 2533 static int spellfix1Filter( |
2518 sqlite3_vtab_cursor *cur, | 2534 sqlite3_vtab_cursor *cur, |
2519 int idxNum, const char *idxStr, | 2535 int idxNum, const char *idxStr, |
2520 int argc, sqlite3_value **argv | 2536 int argc, sqlite3_value **argv |
2521 ){ | 2537 ){ |
2522 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; | 2538 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; |
2523 int rc; | 2539 int rc; |
| 2540 pCur->idxNum = idxNum; |
2524 if( idxNum & 1 ){ | 2541 if( idxNum & 1 ){ |
2525 rc = spellfix1FilterForMatch(pCur, idxNum, argc, argv); | 2542 rc = spellfix1FilterForMatch(pCur, argc, argv); |
2526 }else{ | 2543 }else{ |
2527 rc = spellfix1FilterForFullScan(pCur, idxNum, argc, argv); | 2544 rc = spellfix1FilterForFullScan(pCur, argc, argv); |
2528 } | 2545 } |
2529 return rc; | 2546 return rc; |
2530 } | 2547 } |
2531 | 2548 |
2532 | 2549 |
2533 /* | 2550 /* |
2534 ** Advance a cursor to its next row of output | 2551 ** Advance a cursor to its next row of output |
2535 */ | 2552 */ |
2536 static int spellfix1Next(sqlite3_vtab_cursor *cur){ | 2553 static int spellfix1Next(sqlite3_vtab_cursor *cur){ |
2537 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; | 2554 spellfix1_cursor *pCur = (spellfix1_cursor *)cur; |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2649 spellfix1_cursor *pCur = (spellfix1_cursor*)cur; | 2666 spellfix1_cursor *pCur = (spellfix1_cursor*)cur; |
2650 if( pCur->pFullScan ){ | 2667 if( pCur->pFullScan ){ |
2651 *pRowid = sqlite3_column_int64(pCur->pFullScan, 4); | 2668 *pRowid = sqlite3_column_int64(pCur->pFullScan, 4); |
2652 }else{ | 2669 }else{ |
2653 *pRowid = pCur->a[pCur->iRow].iRowid; | 2670 *pRowid = pCur->a[pCur->iRow].iRowid; |
2654 } | 2671 } |
2655 return SQLITE_OK; | 2672 return SQLITE_OK; |
2656 } | 2673 } |
2657 | 2674 |
2658 /* | 2675 /* |
| 2676 ** This function is called by the xUpdate() method. It returns a string |
| 2677 ** containing the conflict mode that xUpdate() should use for the current |
| 2678 ** operation. One of: "ROLLBACK", "IGNORE", "ABORT" or "REPLACE". |
| 2679 */ |
| 2680 static const char *spellfix1GetConflict(sqlite3 *db){ |
| 2681 static const char *azConflict[] = { |
| 2682 /* Note: Instead of "FAIL" - "ABORT". */ |
| 2683 "ROLLBACK", "IGNORE", "ABORT", "ABORT", "REPLACE" |
| 2684 }; |
| 2685 int eConflict = sqlite3_vtab_on_conflict(db); |
| 2686 |
| 2687 assert( eConflict==SQLITE_ROLLBACK || eConflict==SQLITE_IGNORE |
| 2688 || eConflict==SQLITE_FAIL || eConflict==SQLITE_ABORT |
| 2689 || eConflict==SQLITE_REPLACE |
| 2690 ); |
| 2691 assert( SQLITE_ROLLBACK==1 ); |
| 2692 assert( SQLITE_IGNORE==2 ); |
| 2693 assert( SQLITE_FAIL==3 ); |
| 2694 assert( SQLITE_ABORT==4 ); |
| 2695 assert( SQLITE_REPLACE==5 ); |
| 2696 |
| 2697 return azConflict[eConflict-1]; |
| 2698 } |
| 2699 |
| 2700 /* |
2659 ** The xUpdate() method. | 2701 ** The xUpdate() method. |
2660 */ | 2702 */ |
2661 static int spellfix1Update( | 2703 static int spellfix1Update( |
2662 sqlite3_vtab *pVTab, | 2704 sqlite3_vtab *pVTab, |
2663 int argc, | 2705 int argc, |
2664 sqlite3_value **argv, | 2706 sqlite3_value **argv, |
2665 sqlite_int64 *pRowid | 2707 sqlite_int64 *pRowid |
2666 ){ | 2708 ){ |
2667 int rc = SQLITE_OK; | 2709 int rc = SQLITE_OK; |
2668 sqlite3_int64 rowid, newRowid; | 2710 sqlite3_int64 rowid, newRowid; |
(...skipping 10 matching lines...) Expand all Loading... |
2679 const unsigned char *zWord = sqlite3_value_text(argv[SPELLFIX_COL_WORD+2]); | 2721 const unsigned char *zWord = sqlite3_value_text(argv[SPELLFIX_COL_WORD+2]); |
2680 int nWord = sqlite3_value_bytes(argv[SPELLFIX_COL_WORD+2]); | 2722 int nWord = sqlite3_value_bytes(argv[SPELLFIX_COL_WORD+2]); |
2681 int iLang = sqlite3_value_int(argv[SPELLFIX_COL_LANGID+2]); | 2723 int iLang = sqlite3_value_int(argv[SPELLFIX_COL_LANGID+2]); |
2682 int iRank = sqlite3_value_int(argv[SPELLFIX_COL_RANK+2]); | 2724 int iRank = sqlite3_value_int(argv[SPELLFIX_COL_RANK+2]); |
2683 const unsigned char *zSoundslike = | 2725 const unsigned char *zSoundslike = |
2684 sqlite3_value_text(argv[SPELLFIX_COL_SOUNDSLIKE+2]); | 2726 sqlite3_value_text(argv[SPELLFIX_COL_SOUNDSLIKE+2]); |
2685 int nSoundslike = sqlite3_value_bytes(argv[SPELLFIX_COL_SOUNDSLIKE+2]); | 2727 int nSoundslike = sqlite3_value_bytes(argv[SPELLFIX_COL_SOUNDSLIKE+2]); |
2686 char *zK1, *zK2; | 2728 char *zK1, *zK2; |
2687 int i; | 2729 int i; |
2688 char c; | 2730 char c; |
| 2731 const char *zConflict = spellfix1GetConflict(db); |
2689 | 2732 |
2690 if( zWord==0 ){ | 2733 if( zWord==0 ){ |
2691 /* Inserts of the form: INSERT INTO table(command) VALUES('xyzzy'); | 2734 /* Inserts of the form: INSERT INTO table(command) VALUES('xyzzy'); |
2692 ** cause zWord to be NULL, so we look at the "command" column to see | 2735 ** cause zWord to be NULL, so we look at the "command" column to see |
2693 ** what special actions to take */ | 2736 ** what special actions to take */ |
2694 const char *zCmd = | 2737 const char *zCmd = |
2695 (const char*)sqlite3_value_text(argv[SPELLFIX_COL_COMMAND+2]); | 2738 (const char*)sqlite3_value_text(argv[SPELLFIX_COL_COMMAND+2]); |
2696 if( zCmd==0 ){ | 2739 if( zCmd==0 ){ |
2697 pVTab->zErrMsg = sqlite3_mprintf("NOT NULL constraint failed: %s.word", | 2740 pVTab->zErrMsg = sqlite3_mprintf("NOT NULL constraint failed: %s.word", |
2698 p->zTableName); | 2741 p->zTableName); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2739 if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ | 2782 if( sqlite3_value_type(argv[1])==SQLITE_NULL ){ |
2740 spellfix1DbExec(&rc, db, | 2783 spellfix1DbExec(&rc, db, |
2741 "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " | 2784 "INSERT INTO \"%w\".\"%w_vocab\"(rank,langid,word,k1,k2) " |
2742 "VALUES(%d,%d,%Q,%Q,%Q)", | 2785 "VALUES(%d,%d,%Q,%Q,%Q)", |
2743 p->zDbName, p->zTableName, | 2786 p->zDbName, p->zTableName, |
2744 iRank, iLang, zWord, zK1, zK2 | 2787 iRank, iLang, zWord, zK1, zK2 |
2745 ); | 2788 ); |
2746 }else{ | 2789 }else{ |
2747 newRowid = sqlite3_value_int64(argv[1]); | 2790 newRowid = sqlite3_value_int64(argv[1]); |
2748 spellfix1DbExec(&rc, db, | 2791 spellfix1DbExec(&rc, db, |
2749 "INSERT INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) " | 2792 "INSERT OR %s INTO \"%w\".\"%w_vocab\"(id,rank,langid,word,k1,k2) " |
2750 "VALUES(%lld,%d,%d,%Q,%Q,%Q)", | 2793 "VALUES(%lld,%d,%d,%Q,%Q,%Q)", |
2751 p->zDbName, p->zTableName, | 2794 zConflict, p->zDbName, p->zTableName, |
2752 newRowid, iRank, iLang, zWord, zK1, zK2 | 2795 newRowid, iRank, iLang, zWord, zK1, zK2 |
2753 ); | 2796 ); |
2754 } | 2797 } |
2755 *pRowid = sqlite3_last_insert_rowid(db); | 2798 *pRowid = sqlite3_last_insert_rowid(db); |
2756 }else{ | 2799 }else{ |
2757 rowid = sqlite3_value_int64(argv[0]); | 2800 rowid = sqlite3_value_int64(argv[0]); |
2758 newRowid = *pRowid = sqlite3_value_int64(argv[1]); | 2801 newRowid = *pRowid = sqlite3_value_int64(argv[1]); |
2759 spellfix1DbExec(&rc, db, | 2802 spellfix1DbExec(&rc, db, |
2760 "UPDATE \"%w\".\"%w_vocab\" SET id=%lld, rank=%d, langid=%d," | 2803 "UPDATE OR %s \"%w\".\"%w_vocab\" SET id=%lld, rank=%d, langid=%d," |
2761 " word=%Q, k1=%Q, k2=%Q WHERE id=%lld", | 2804 " word=%Q, k1=%Q, k2=%Q WHERE id=%lld", |
2762 p->zDbName, p->zTableName, newRowid, iRank, iLang, | 2805 zConflict, p->zDbName, p->zTableName, newRowid, iRank, iLang, |
2763 zWord, zK1, zK2, rowid | 2806 zWord, zK1, zK2, rowid |
2764 ); | 2807 ); |
2765 } | 2808 } |
2766 sqlite3_free(zK1); | 2809 sqlite3_free(zK1); |
2767 sqlite3_free(zK2); | 2810 sqlite3_free(zK2); |
2768 } | 2811 } |
2769 return rc; | 2812 return rc; |
2770 } | 2813 } |
2771 | 2814 |
2772 /* | 2815 /* |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2867 sqlite3 *db, | 2910 sqlite3 *db, |
2868 char **pzErrMsg, | 2911 char **pzErrMsg, |
2869 const sqlite3_api_routines *pApi | 2912 const sqlite3_api_routines *pApi |
2870 ){ | 2913 ){ |
2871 SQLITE_EXTENSION_INIT2(pApi); | 2914 SQLITE_EXTENSION_INIT2(pApi); |
2872 #ifndef SQLITE_OMIT_VIRTUALTABLE | 2915 #ifndef SQLITE_OMIT_VIRTUALTABLE |
2873 return spellfix1Register(db); | 2916 return spellfix1Register(db); |
2874 #endif | 2917 #endif |
2875 return SQLITE_OK; | 2918 return SQLITE_OK; |
2876 } | 2919 } |
OLD | NEW |