Fossil SCM
Update the built-in SQLite to the latest 3.7.9 beta.
Commit
ccf43e1882d8994253aaf8c8c7f11fe294bbb46b
Parent
e161670939b93ec…
2 files changed
+573
-170
+3
-3
+573
-170
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -656,11 +656,11 @@ | ||
| 656 | 656 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 657 | 657 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 658 | 658 | */ |
| 659 | 659 | #define SQLITE_VERSION "3.7.9" |
| 660 | 660 | #define SQLITE_VERSION_NUMBER 3007009 |
| 661 | -#define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe" | |
| 661 | +#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486" | |
| 662 | 662 | |
| 663 | 663 | /* |
| 664 | 664 | ** CAPI3REF: Run-Time Library Version Numbers |
| 665 | 665 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 666 | 666 | ** |
| @@ -1951,12 +1951,12 @@ | ||
| 1951 | 1951 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1952 | 1952 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1953 | 1953 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1954 | 1954 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1955 | 1955 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1956 | -** The minimum allocation size is capped at 2^12. Reasonable values | |
| 1957 | -** for the minimum allocation size are 2^5 through 2^8.</dd> | |
| 1956 | +** The minimum allocation size is capped at 2**12. Reasonable values | |
| 1957 | +** for the minimum allocation size are 2**5 through 2**8.</dd> | |
| 1958 | 1958 | ** |
| 1959 | 1959 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1960 | 1960 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1961 | 1961 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1962 | 1962 | ** alternative low-level mutex routines to be used in place |
| @@ -20969,11 +20969,11 @@ | ||
| 20969 | 20969 | }else if( *z=='+' ){ |
| 20970 | 20970 | z+=incr; |
| 20971 | 20971 | } |
| 20972 | 20972 | /* copy digits to exponent */ |
| 20973 | 20973 | while( z<zEnd && sqlite3Isdigit(*z) ){ |
| 20974 | - e = e*10 + (*z - '0'); | |
| 20974 | + e = e<10000 ? (e*10 + (*z - '0')) : 10000; | |
| 20975 | 20975 | z+=incr; |
| 20976 | 20976 | eValid = 1; |
| 20977 | 20977 | } |
| 20978 | 20978 | } |
| 20979 | 20979 | |
| @@ -21020,10 +21020,16 @@ | ||
| 21020 | 21020 | result /= 1.0e+308; |
| 21021 | 21021 | }else{ |
| 21022 | 21022 | result = s * scale; |
| 21023 | 21023 | result *= 1.0e+308; |
| 21024 | 21024 | } |
| 21025 | + }else if( e>=342 ){ | |
| 21026 | + if( esign<0 ){ | |
| 21027 | + result = 0.0*s; | |
| 21028 | + }else{ | |
| 21029 | + result = 1e308*1e308*s; /* Infinity */ | |
| 21030 | + } | |
| 21025 | 21031 | }else{ |
| 21026 | 21032 | /* 1.0e+22 is the largest power of 10 than can be |
| 21027 | 21033 | ** represented exactly. */ |
| 21028 | 21034 | while( e%22 ) { scale *= 1.0e+1; e -= 1; } |
| 21029 | 21035 | while( e>0 ) { scale *= 1.0e+22; e -= 22; } |
| @@ -68962,11 +68968,11 @@ | ||
| 68962 | 68968 | |
| 68963 | 68969 | /* Do not allow a transition to journal_mode=WAL for a database |
| 68964 | 68970 | ** in temporary storage or if the VFS does not support shared memory |
| 68965 | 68971 | */ |
| 68966 | 68972 | if( u.ch.eNew==PAGER_JOURNALMODE_WAL |
| 68967 | - && (u.ch.zFilename[0]==0 /* Temp file */ | |
| 68973 | + && (sqlite3Strlen30(u.ch.zFilename)==0 /* Temp file */ | |
| 68968 | 68974 | || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */ |
| 68969 | 68975 | ){ |
| 68970 | 68976 | u.ch.eNew = u.ch.eOld; |
| 68971 | 68977 | } |
| 68972 | 68978 | |
| @@ -69397,14 +69403,19 @@ | ||
| 69397 | 69403 | u.co.pName = &aMem[pOp->p1]; |
| 69398 | 69404 | assert( u.co.pVtab->pModule->xRename ); |
| 69399 | 69405 | assert( memIsValid(u.co.pName) ); |
| 69400 | 69406 | REGISTER_TRACE(pOp->p1, u.co.pName); |
| 69401 | 69407 | assert( u.co.pName->flags & MEM_Str ); |
| 69402 | - rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z); | |
| 69403 | - importVtabErrMsg(p, u.co.pVtab); | |
| 69404 | - p->expired = 0; | |
| 69405 | - | |
| 69408 | + testcase( u.co.pName->enc==SQLITE_UTF8 ); | |
| 69409 | + testcase( u.co.pName->enc==SQLITE_UTF16BE ); | |
| 69410 | + testcase( u.co.pName->enc==SQLITE_UTF16LE ); | |
| 69411 | + rc = sqlite3VdbeChangeEncoding(u.co.pName, SQLITE_UTF8); | |
| 69412 | + if( rc==SQLITE_OK ){ | |
| 69413 | + rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z); | |
| 69414 | + importVtabErrMsg(p, u.co.pVtab); | |
| 69415 | + p->expired = 0; | |
| 69416 | + } | |
| 69406 | 69417 | break; |
| 69407 | 69418 | } |
| 69408 | 69419 | #endif |
| 69409 | 69420 | |
| 69410 | 69421 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| @@ -71758,10 +71769,28 @@ | ||
| 71758 | 71769 | ExprSetProperty(pExpr, EP_Static); |
| 71759 | 71770 | sqlite3ExprDelete(db, pExpr); |
| 71760 | 71771 | memcpy(pExpr, pDup, sizeof(*pExpr)); |
| 71761 | 71772 | sqlite3DbFree(db, pDup); |
| 71762 | 71773 | } |
| 71774 | + | |
| 71775 | + | |
| 71776 | +/* | |
| 71777 | +** Return TRUE if the name zCol occurs anywhere in the USING clause. | |
| 71778 | +** | |
| 71779 | +** Return FALSE if the USING clause is NULL or if it does not contain | |
| 71780 | +** zCol. | |
| 71781 | +*/ | |
| 71782 | +static int nameInUsingClause(IdList *pUsing, const char *zCol){ | |
| 71783 | + if( pUsing ){ | |
| 71784 | + int k; | |
| 71785 | + for(k=0; k<pUsing->nId; k++){ | |
| 71786 | + if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; | |
| 71787 | + } | |
| 71788 | + } | |
| 71789 | + return 0; | |
| 71790 | +} | |
| 71791 | + | |
| 71763 | 71792 | |
| 71764 | 71793 | /* |
| 71765 | 71794 | ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up |
| 71766 | 71795 | ** that name in the set of source tables in pSrcList and make the pExpr |
| 71767 | 71796 | ** expression node refer back to that source column. The following changes |
| @@ -71850,38 +71879,25 @@ | ||
| 71850 | 71879 | pSchema = pTab->pSchema; |
| 71851 | 71880 | pMatch = pItem; |
| 71852 | 71881 | } |
| 71853 | 71882 | for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ |
| 71854 | 71883 | if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ |
| 71855 | - IdList *pUsing; | |
| 71884 | + /* If there has been exactly one prior match and this match | |
| 71885 | + ** is for the right-hand table of a NATURAL JOIN or is in a | |
| 71886 | + ** USING clause, then skip this match. | |
| 71887 | + */ | |
| 71888 | + if( cnt==1 ){ | |
| 71889 | + if( pItem->jointype & JT_NATURAL ) continue; | |
| 71890 | + if( nameInUsingClause(pItem->pUsing, zCol) ) continue; | |
| 71891 | + } | |
| 71856 | 71892 | cnt++; |
| 71857 | 71893 | pExpr->iTable = pItem->iCursor; |
| 71858 | 71894 | pExpr->pTab = pTab; |
| 71859 | 71895 | pMatch = pItem; |
| 71860 | 71896 | pSchema = pTab->pSchema; |
| 71861 | 71897 | /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ |
| 71862 | 71898 | pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; |
| 71863 | - if( i<pSrcList->nSrc-1 ){ | |
| 71864 | - if( pItem[1].jointype & JT_NATURAL ){ | |
| 71865 | - /* If this match occurred in the left table of a natural join, | |
| 71866 | - ** then skip the right table to avoid a duplicate match */ | |
| 71867 | - pItem++; | |
| 71868 | - i++; | |
| 71869 | - }else if( (pUsing = pItem[1].pUsing)!=0 ){ | |
| 71870 | - /* If this match occurs on a column that is in the USING clause | |
| 71871 | - ** of a join, skip the search of the right table of the join | |
| 71872 | - ** to avoid a duplicate match there. */ | |
| 71873 | - int k; | |
| 71874 | - for(k=0; k<pUsing->nId; k++){ | |
| 71875 | - if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){ | |
| 71876 | - pItem++; | |
| 71877 | - i++; | |
| 71878 | - break; | |
| 71879 | - } | |
| 71880 | - } | |
| 71881 | - } | |
| 71882 | - } | |
| 71883 | 71899 | break; |
| 71884 | 71900 | } |
| 71885 | 71901 | } |
| 71886 | 71902 | } |
| 71887 | 71903 | } |
| @@ -102501,10 +102517,11 @@ | ||
| 102501 | 102517 | tempWC.pParse = pWC->pParse; |
| 102502 | 102518 | tempWC.pMaskSet = pWC->pMaskSet; |
| 102503 | 102519 | tempWC.pOuter = pWC; |
| 102504 | 102520 | tempWC.op = TK_AND; |
| 102505 | 102521 | tempWC.a = pOrTerm; |
| 102522 | + tempWC.wctrlFlags = 0; | |
| 102506 | 102523 | tempWC.nTerm = 1; |
| 102507 | 102524 | bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); |
| 102508 | 102525 | }else{ |
| 102509 | 102526 | continue; |
| 102510 | 102527 | } |
| @@ -114528,10 +114545,11 @@ | ||
| 114528 | 114545 | const char *zDb; /* logical database name */ |
| 114529 | 114546 | const char *zName; /* virtual table name */ |
| 114530 | 114547 | int nColumn; /* number of named columns in virtual table */ |
| 114531 | 114548 | char **azColumn; /* column names. malloced */ |
| 114532 | 114549 | sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ |
| 114550 | + char *zContentTbl; /* content=xxx option, or NULL */ | |
| 114533 | 114551 | |
| 114534 | 114552 | /* Precompiled statements used by the implementation. Each of these |
| 114535 | 114553 | ** statements is run and reset within a single virtual table API call. |
| 114536 | 114554 | */ |
| 114537 | 114555 | sqlite3_stmt *aStmt[27]; |
| @@ -114568,11 +114586,11 @@ | ||
| 114568 | 114586 | } *aIndex; |
| 114569 | 114587 | int nMaxPendingData; /* Max pending data before flush to disk */ |
| 114570 | 114588 | int nPendingData; /* Current bytes of pending data */ |
| 114571 | 114589 | sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ |
| 114572 | 114590 | |
| 114573 | -#if defined(SQLITE_DEBUG) | |
| 114591 | +#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) | |
| 114574 | 114592 | /* State variables used for validating that the transaction control |
| 114575 | 114593 | ** methods of the virtual table are called at appropriate times. These |
| 114576 | 114594 | ** values do not contribution to the FTS computation; they are used for |
| 114577 | 114595 | ** verifying the SQLite core. |
| 114578 | 114596 | */ |
| @@ -114653,10 +114671,11 @@ | ||
| 114653 | 114671 | */ |
| 114654 | 114672 | struct Fts3PhraseToken { |
| 114655 | 114673 | char *z; /* Text of the token */ |
| 114656 | 114674 | int n; /* Number of bytes in buffer z */ |
| 114657 | 114675 | int isPrefix; /* True if token ends with a "*" character */ |
| 114676 | + int bFirst; /* True if token must appear at position 0 */ | |
| 114658 | 114677 | |
| 114659 | 114678 | /* Variables above this point are populated when the expression is |
| 114660 | 114679 | ** parsed (by code in fts3_expr.c). Below this point the variables are |
| 114661 | 114680 | ** used when evaluating the expression. */ |
| 114662 | 114681 | Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ |
| @@ -114771,10 +114790,11 @@ | ||
| 114771 | 114790 | #define FTS3_SEGMENT_REQUIRE_POS 0x00000001 |
| 114772 | 114791 | #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 |
| 114773 | 114792 | #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 |
| 114774 | 114793 | #define FTS3_SEGMENT_PREFIX 0x00000008 |
| 114775 | 114794 | #define FTS3_SEGMENT_SCAN 0x00000010 |
| 114795 | +#define FTS3_SEGMENT_FIRST 0x00000020 | |
| 114776 | 114796 | |
| 114777 | 114797 | /* Type passed as 4th argument to SegmentReaderIterate() */ |
| 114778 | 114798 | struct Fts3SegFilter { |
| 114779 | 114799 | const char *zTerm; |
| 114780 | 114800 | int nTerm; |
| @@ -114810,12 +114830,12 @@ | ||
| 114810 | 114830 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 114811 | 114831 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 114812 | 114832 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 114813 | 114833 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 114814 | 114834 | SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); |
| 114815 | - | |
| 114816 | 114835 | SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); |
| 114836 | +SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); | |
| 114817 | 114837 | |
| 114818 | 114838 | /* fts3_tokenizer.c */ |
| 114819 | 114839 | SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); |
| 114820 | 114840 | SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); |
| 114821 | 114841 | SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, |
| @@ -114830,11 +114850,11 @@ | ||
| 114830 | 114850 | ); |
| 114831 | 114851 | SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); |
| 114832 | 114852 | |
| 114833 | 114853 | /* fts3_expr.c */ |
| 114834 | 114854 | SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, |
| 114835 | - char **, int, int, const char *, int, Fts3Expr ** | |
| 114855 | + char **, int, int, int, const char *, int, Fts3Expr ** | |
| 114836 | 114856 | ); |
| 114837 | 114857 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 114838 | 114858 | #ifdef SQLITE_TEST |
| 114839 | 114859 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 114840 | 114860 | SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); |
| @@ -115031,10 +115051,11 @@ | ||
| 115031 | 115051 | sqlite3_finalize(p->aStmt[i]); |
| 115032 | 115052 | } |
| 115033 | 115053 | sqlite3_free(p->zSegmentsTbl); |
| 115034 | 115054 | sqlite3_free(p->zReadExprlist); |
| 115035 | 115055 | sqlite3_free(p->zWriteExprlist); |
| 115056 | + sqlite3_free(p->zContentTbl); | |
| 115036 | 115057 | |
| 115037 | 115058 | /* Invoke the tokenizer destructor to free the tokenizer. */ |
| 115038 | 115059 | p->pTokenizer->pModule->xDestroy(p->pTokenizer); |
| 115039 | 115060 | |
| 115040 | 115061 | sqlite3_free(p); |
| @@ -115070,20 +115091,23 @@ | ||
| 115070 | 115091 | |
| 115071 | 115092 | /* |
| 115072 | 115093 | ** The xDestroy() virtual table method. |
| 115073 | 115094 | */ |
| 115074 | 115095 | static int fts3DestroyMethod(sqlite3_vtab *pVtab){ |
| 115075 | - int rc = SQLITE_OK; /* Return code */ | |
| 115076 | 115096 | Fts3Table *p = (Fts3Table *)pVtab; |
| 115077 | - sqlite3 *db = p->db; | |
| 115097 | + int rc = SQLITE_OK; /* Return code */ | |
| 115098 | + const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ | |
| 115099 | + sqlite3 *db = p->db; /* Database handle */ | |
| 115078 | 115100 | |
| 115079 | 115101 | /* Drop the shadow tables */ |
| 115080 | - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName); | |
| 115081 | - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName); | |
| 115082 | - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName); | |
| 115083 | - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName); | |
| 115084 | - fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName); | |
| 115102 | + if( p->zContentTbl==0 ){ | |
| 115103 | + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); | |
| 115104 | + } | |
| 115105 | + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); | |
| 115106 | + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); | |
| 115107 | + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); | |
| 115108 | + fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); | |
| 115085 | 115109 | |
| 115086 | 115110 | /* If everything has worked, invoke fts3DisconnectMethod() to free the |
| 115087 | 115111 | ** memory associated with the Fts3Table structure and return SQLITE_OK. |
| 115088 | 115112 | ** Otherwise, return an SQLite error code. |
| 115089 | 115113 | */ |
| @@ -115141,27 +115165,31 @@ | ||
| 115141 | 115165 | ** %_stat tables required by FTS4. |
| 115142 | 115166 | */ |
| 115143 | 115167 | static int fts3CreateTables(Fts3Table *p){ |
| 115144 | 115168 | int rc = SQLITE_OK; /* Return code */ |
| 115145 | 115169 | int i; /* Iterator variable */ |
| 115146 | - char *zContentCols; /* Columns of %_content table */ | |
| 115147 | 115170 | sqlite3 *db = p->db; /* The database connection */ |
| 115148 | 115171 | |
| 115149 | - /* Create a list of user columns for the content table */ | |
| 115150 | - zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); | |
| 115151 | - for(i=0; zContentCols && i<p->nColumn; i++){ | |
| 115152 | - char *z = p->azColumn[i]; | |
| 115153 | - zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); | |
| 115154 | - } | |
| 115155 | - if( zContentCols==0 ) rc = SQLITE_NOMEM; | |
| 115156 | - | |
| 115157 | - /* Create the content table */ | |
| 115158 | - fts3DbExec(&rc, db, | |
| 115159 | - "CREATE TABLE %Q.'%q_content'(%s)", | |
| 115160 | - p->zDb, p->zName, zContentCols | |
| 115161 | - ); | |
| 115162 | - sqlite3_free(zContentCols); | |
| 115172 | + if( p->zContentTbl==0 ){ | |
| 115173 | + char *zContentCols; /* Columns of %_content table */ | |
| 115174 | + | |
| 115175 | + /* Create a list of user columns for the content table */ | |
| 115176 | + zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); | |
| 115177 | + for(i=0; zContentCols && i<p->nColumn; i++){ | |
| 115178 | + char *z = p->azColumn[i]; | |
| 115179 | + zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); | |
| 115180 | + } | |
| 115181 | + if( zContentCols==0 ) rc = SQLITE_NOMEM; | |
| 115182 | + | |
| 115183 | + /* Create the content table */ | |
| 115184 | + fts3DbExec(&rc, db, | |
| 115185 | + "CREATE TABLE %Q.'%q_content'(%s)", | |
| 115186 | + p->zDb, p->zName, zContentCols | |
| 115187 | + ); | |
| 115188 | + sqlite3_free(zContentCols); | |
| 115189 | + } | |
| 115190 | + | |
| 115163 | 115191 | /* Create other tables */ |
| 115164 | 115192 | fts3DbExec(&rc, db, |
| 115165 | 115193 | "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", |
| 115166 | 115194 | p->zDb, p->zName |
| 115167 | 115195 | ); |
| @@ -115308,12 +115336,12 @@ | ||
| 115308 | 115336 | } |
| 115309 | 115337 | return zRet; |
| 115310 | 115338 | } |
| 115311 | 115339 | |
| 115312 | 115340 | /* |
| 115313 | -** Return a list of comma separated SQL expressions that could be used | |
| 115314 | -** in a SELECT statement such as the following: | |
| 115341 | +** Return a list of comma separated SQL expressions and a FROM clause that | |
| 115342 | +** could be used in a SELECT statement such as the following: | |
| 115315 | 115343 | ** |
| 115316 | 115344 | ** SELECT <list of expressions> FROM %_content AS x ... |
| 115317 | 115345 | ** |
| 115318 | 115346 | ** to return the docid, followed by each column of text data in order |
| 115319 | 115347 | ** from left to write. If parameter zFunc is not NULL, then instead of |
| @@ -115320,11 +115348,11 @@ | ||
| 115320 | 115348 | ** being returned directly each column of text data is passed to an SQL |
| 115321 | 115349 | ** function named zFunc first. For example, if zFunc is "unzip" and the |
| 115322 | 115350 | ** table has the three user-defined columns "a", "b", and "c", the following |
| 115323 | 115351 | ** string is returned: |
| 115324 | 115352 | ** |
| 115325 | -** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')" | |
| 115353 | +** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" | |
| 115326 | 115354 | ** |
| 115327 | 115355 | ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It |
| 115328 | 115356 | ** is the responsibility of the caller to eventually free it. |
| 115329 | 115357 | ** |
| 115330 | 115358 | ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and |
| @@ -115336,20 +115364,32 @@ | ||
| 115336 | 115364 | char *zRet = 0; |
| 115337 | 115365 | char *zFree = 0; |
| 115338 | 115366 | char *zFunction; |
| 115339 | 115367 | int i; |
| 115340 | 115368 | |
| 115341 | - if( !zFunc ){ | |
| 115342 | - zFunction = ""; | |
| 115369 | + if( p->zContentTbl==0 ){ | |
| 115370 | + if( !zFunc ){ | |
| 115371 | + zFunction = ""; | |
| 115372 | + }else{ | |
| 115373 | + zFree = zFunction = fts3QuoteId(zFunc); | |
| 115374 | + } | |
| 115375 | + fts3Appendf(pRc, &zRet, "docid"); | |
| 115376 | + for(i=0; i<p->nColumn; i++){ | |
| 115377 | + fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); | |
| 115378 | + } | |
| 115379 | + sqlite3_free(zFree); | |
| 115343 | 115380 | }else{ |
| 115344 | - zFree = zFunction = fts3QuoteId(zFunc); | |
| 115381 | + fts3Appendf(pRc, &zRet, "rowid"); | |
| 115382 | + for(i=0; i<p->nColumn; i++){ | |
| 115383 | + fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); | |
| 115384 | + } | |
| 115345 | 115385 | } |
| 115346 | - fts3Appendf(pRc, &zRet, "docid"); | |
| 115347 | - for(i=0; i<p->nColumn; i++){ | |
| 115348 | - fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); | |
| 115349 | - } | |
| 115350 | - sqlite3_free(zFree); | |
| 115386 | + fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x", | |
| 115387 | + p->zDb, | |
| 115388 | + (p->zContentTbl ? p->zContentTbl : p->zName), | |
| 115389 | + (p->zContentTbl ? "" : "_content") | |
| 115390 | + ); | |
| 115351 | 115391 | return zRet; |
| 115352 | 115392 | } |
| 115353 | 115393 | |
| 115354 | 115394 | /* |
| 115355 | 115395 | ** Return a list of N comma separated question marks, where N is the number |
| @@ -115468,10 +115508,95 @@ | ||
| 115468 | 115508 | } |
| 115469 | 115509 | } |
| 115470 | 115510 | |
| 115471 | 115511 | return SQLITE_OK; |
| 115472 | 115512 | } |
| 115513 | + | |
| 115514 | +/* | |
| 115515 | +** This function is called when initializing an FTS4 table that uses the | |
| 115516 | +** content=xxx option. It determines the number of and names of the columns | |
| 115517 | +** of the new FTS4 table. | |
| 115518 | +** | |
| 115519 | +** The third argument passed to this function is the value passed to the | |
| 115520 | +** config=xxx option (i.e. "xxx"). This function queries the database for | |
| 115521 | +** a table of that name. If found, the output variables are populated | |
| 115522 | +** as follows: | |
| 115523 | +** | |
| 115524 | +** *pnCol: Set to the number of columns table xxx has, | |
| 115525 | +** | |
| 115526 | +** *pnStr: Set to the total amount of space required to store a copy | |
| 115527 | +** of each columns name, including the nul-terminator. | |
| 115528 | +** | |
| 115529 | +** *pazCol: Set to point to an array of *pnCol strings. Each string is | |
| 115530 | +** the name of the corresponding column in table xxx. The array | |
| 115531 | +** and its contents are allocated using a single allocation. It | |
| 115532 | +** is the responsibility of the caller to free this allocation | |
| 115533 | +** by eventually passing the *pazCol value to sqlite3_free(). | |
| 115534 | +** | |
| 115535 | +** If the table cannot be found, an error code is returned and the output | |
| 115536 | +** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is | |
| 115537 | +** returned (and the output variables are undefined). | |
| 115538 | +*/ | |
| 115539 | +static int fts3ContentColumns( | |
| 115540 | + sqlite3 *db, /* Database handle */ | |
| 115541 | + const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ | |
| 115542 | + const char *zTbl, /* Name of content table */ | |
| 115543 | + const char ***pazCol, /* OUT: Malloc'd array of column names */ | |
| 115544 | + int *pnCol, /* OUT: Size of array *pazCol */ | |
| 115545 | + int *pnStr /* OUT: Bytes of string content */ | |
| 115546 | +){ | |
| 115547 | + int rc = SQLITE_OK; /* Return code */ | |
| 115548 | + char *zSql; /* "SELECT *" statement on zTbl */ | |
| 115549 | + sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ | |
| 115550 | + | |
| 115551 | + zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); | |
| 115552 | + if( !zSql ){ | |
| 115553 | + rc = SQLITE_NOMEM; | |
| 115554 | + }else{ | |
| 115555 | + rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); | |
| 115556 | + } | |
| 115557 | + sqlite3_free(zSql); | |
| 115558 | + | |
| 115559 | + if( rc==SQLITE_OK ){ | |
| 115560 | + const char **azCol; /* Output array */ | |
| 115561 | + int nStr = 0; /* Size of all column names (incl. 0x00) */ | |
| 115562 | + int nCol; /* Number of table columns */ | |
| 115563 | + int i; /* Used to iterate through columns */ | |
| 115564 | + | |
| 115565 | + /* Loop through the returned columns. Set nStr to the number of bytes of | |
| 115566 | + ** space required to store a copy of each column name, including the | |
| 115567 | + ** nul-terminator byte. */ | |
| 115568 | + nCol = sqlite3_column_count(pStmt); | |
| 115569 | + for(i=0; i<nCol; i++){ | |
| 115570 | + const char *zCol = sqlite3_column_name(pStmt, i); | |
| 115571 | + nStr += strlen(zCol) + 1; | |
| 115572 | + } | |
| 115573 | + | |
| 115574 | + /* Allocate and populate the array to return. */ | |
| 115575 | + azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr); | |
| 115576 | + if( azCol==0 ){ | |
| 115577 | + rc = SQLITE_NOMEM; | |
| 115578 | + }else{ | |
| 115579 | + char *p = (char *)&azCol[nCol]; | |
| 115580 | + for(i=0; i<nCol; i++){ | |
| 115581 | + const char *zCol = sqlite3_column_name(pStmt, i); | |
| 115582 | + int n = strlen(zCol)+1; | |
| 115583 | + memcpy(p, zCol, n); | |
| 115584 | + azCol[i] = p; | |
| 115585 | + p += n; | |
| 115586 | + } | |
| 115587 | + } | |
| 115588 | + sqlite3_finalize(pStmt); | |
| 115589 | + | |
| 115590 | + /* Set the output variables. */ | |
| 115591 | + *pnCol = nCol; | |
| 115592 | + *pnStr = nStr; | |
| 115593 | + *pazCol = azCol; | |
| 115594 | + } | |
| 115595 | + | |
| 115596 | + return rc; | |
| 115597 | +} | |
| 115473 | 115598 | |
| 115474 | 115599 | /* |
| 115475 | 115600 | ** This function is the implementation of both the xConnect and xCreate |
| 115476 | 115601 | ** methods of the FTS3 virtual table. |
| 115477 | 115602 | ** |
| @@ -115513,10 +115638,11 @@ | ||
| 115513 | 115638 | int bNoDocsize = 0; /* True to omit %_docsize table */ |
| 115514 | 115639 | int bDescIdx = 0; /* True to store descending indexes */ |
| 115515 | 115640 | char *zPrefix = 0; /* Prefix parameter value (or NULL) */ |
| 115516 | 115641 | char *zCompress = 0; /* compress=? parameter (or NULL) */ |
| 115517 | 115642 | char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ |
| 115643 | + char *zContent = 0; /* content=? parameter (or NULL) */ | |
| 115518 | 115644 | |
| 115519 | 115645 | assert( strlen(argv[0])==4 ); |
| 115520 | 115646 | assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) |
| 115521 | 115647 | || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) |
| 115522 | 115648 | ); |
| @@ -115556,17 +115682,17 @@ | ||
| 115556 | 115682 | /* Check if it is an FTS4 special argument. */ |
| 115557 | 115683 | else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ |
| 115558 | 115684 | struct Fts4Option { |
| 115559 | 115685 | const char *zOpt; |
| 115560 | 115686 | int nOpt; |
| 115561 | - char **pzVar; | |
| 115562 | 115687 | } aFts4Opt[] = { |
| 115563 | - { "matchinfo", 9, 0 }, /* 0 -> MATCHINFO */ | |
| 115564 | - { "prefix", 6, 0 }, /* 1 -> PREFIX */ | |
| 115565 | - { "compress", 8, 0 }, /* 2 -> COMPRESS */ | |
| 115566 | - { "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */ | |
| 115567 | - { "order", 5, 0 } /* 4 -> ORDER */ | |
| 115688 | + { "matchinfo", 9 }, /* 0 -> MATCHINFO */ | |
| 115689 | + { "prefix", 6 }, /* 1 -> PREFIX */ | |
| 115690 | + { "compress", 8 }, /* 2 -> COMPRESS */ | |
| 115691 | + { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ | |
| 115692 | + { "order", 5 }, /* 4 -> ORDER */ | |
| 115693 | + { "content", 7 } /* 5 -> CONTENT */ | |
| 115568 | 115694 | }; |
| 115569 | 115695 | |
| 115570 | 115696 | int iOpt; |
| 115571 | 115697 | if( !zVal ){ |
| 115572 | 115698 | rc = SQLITE_NOMEM; |
| @@ -115608,17 +115734,24 @@ | ||
| 115608 | 115734 | zVal = 0; |
| 115609 | 115735 | break; |
| 115610 | 115736 | |
| 115611 | 115737 | case 4: /* ORDER */ |
| 115612 | 115738 | if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) |
| 115613 | - && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3)) | |
| 115739 | + && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) | |
| 115614 | 115740 | ){ |
| 115615 | 115741 | *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal); |
| 115616 | 115742 | rc = SQLITE_ERROR; |
| 115617 | 115743 | } |
| 115618 | 115744 | bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); |
| 115619 | 115745 | break; |
| 115746 | + | |
| 115747 | + default: /* CONTENT */ | |
| 115748 | + assert( iOpt==5 ); | |
| 115749 | + sqlite3_free(zUncompress); | |
| 115750 | + zContent = zVal; | |
| 115751 | + zVal = 0; | |
| 115752 | + break; | |
| 115620 | 115753 | } |
| 115621 | 115754 | } |
| 115622 | 115755 | sqlite3_free(zVal); |
| 115623 | 115756 | } |
| 115624 | 115757 | } |
| @@ -115627,10 +115760,30 @@ | ||
| 115627 | 115760 | else { |
| 115628 | 115761 | nString += (int)(strlen(z) + 1); |
| 115629 | 115762 | aCol[nCol++] = z; |
| 115630 | 115763 | } |
| 115631 | 115764 | } |
| 115765 | + | |
| 115766 | + /* If a content=xxx option was specified, the following: | |
| 115767 | + ** | |
| 115768 | + ** 1. Ignore any compress= and uncompress= options. | |
| 115769 | + ** | |
| 115770 | + ** 2. If no column names were specified as part of the CREATE VIRTUAL | |
| 115771 | + ** TABLE statement, use all columns from the content table. | |
| 115772 | + */ | |
| 115773 | + if( rc==SQLITE_OK && zContent ){ | |
| 115774 | + sqlite3_free(zCompress); | |
| 115775 | + sqlite3_free(zUncompress); | |
| 115776 | + zCompress = 0; | |
| 115777 | + zUncompress = 0; | |
| 115778 | + if( nCol==0 ){ | |
| 115779 | + sqlite3_free((void*)aCol); | |
| 115780 | + aCol = 0; | |
| 115781 | + rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); | |
| 115782 | + } | |
| 115783 | + assert( rc!=SQLITE_OK || nCol>0 ); | |
| 115784 | + } | |
| 115632 | 115785 | if( rc!=SQLITE_OK ) goto fts3_init_out; |
| 115633 | 115786 | |
| 115634 | 115787 | if( nCol==0 ){ |
| 115635 | 115788 | assert( nString==0 ); |
| 115636 | 115789 | aCol[0] = "content"; |
| @@ -115671,10 +115824,12 @@ | ||
| 115671 | 115824 | p->pTokenizer = pTokenizer; |
| 115672 | 115825 | p->nMaxPendingData = FTS3_MAX_PENDING_DATA; |
| 115673 | 115826 | p->bHasDocsize = (isFts4 && bNoDocsize==0); |
| 115674 | 115827 | p->bHasStat = isFts4; |
| 115675 | 115828 | p->bDescIdx = bDescIdx; |
| 115829 | + p->zContentTbl = zContent; | |
| 115830 | + zContent = 0; | |
| 115676 | 115831 | TESTONLY( p->inTransaction = -1 ); |
| 115677 | 115832 | TESTONLY( p->mxSavepoint = -1 ); |
| 115678 | 115833 | |
| 115679 | 115834 | p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; |
| 115680 | 115835 | memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); |
| @@ -115732,10 +115887,11 @@ | ||
| 115732 | 115887 | fts3_init_out: |
| 115733 | 115888 | sqlite3_free(zPrefix); |
| 115734 | 115889 | sqlite3_free(aIndex); |
| 115735 | 115890 | sqlite3_free(zCompress); |
| 115736 | 115891 | sqlite3_free(zUncompress); |
| 115892 | + sqlite3_free(zContent); | |
| 115737 | 115893 | sqlite3_free((void *)aCol); |
| 115738 | 115894 | if( rc!=SQLITE_OK ){ |
| 115739 | 115895 | if( p ){ |
| 115740 | 115896 | fts3DisconnectMethod((sqlite3_vtab *)p); |
| 115741 | 115897 | }else if( pTokenizer ){ |
| @@ -115882,40 +116038,69 @@ | ||
| 115882 | 116038 | sqlite3_free(pCsr->aMatchinfo); |
| 115883 | 116039 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| 115884 | 116040 | sqlite3_free(pCsr); |
| 115885 | 116041 | return SQLITE_OK; |
| 115886 | 116042 | } |
| 116043 | + | |
| 116044 | +/* | |
| 116045 | +** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then | |
| 116046 | +** compose and prepare an SQL statement of the form: | |
| 116047 | +** | |
| 116048 | +** "SELECT <columns> FROM %_content WHERE rowid = ?" | |
| 116049 | +** | |
| 116050 | +** (or the equivalent for a content=xxx table) and set pCsr->pStmt to | |
| 116051 | +** it. If an error occurs, return an SQLite error code. | |
| 116052 | +** | |
| 116053 | +** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK. | |
| 116054 | +*/ | |
| 116055 | +static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ | |
| 116056 | + int rc = SQLITE_OK; | |
| 116057 | + if( pCsr->pStmt==0 ){ | |
| 116058 | + Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; | |
| 116059 | + char *zSql; | |
| 116060 | + zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); | |
| 116061 | + if( !zSql ) return SQLITE_NOMEM; | |
| 116062 | + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); | |
| 116063 | + sqlite3_free(zSql); | |
| 116064 | + } | |
| 116065 | + *ppStmt = pCsr->pStmt; | |
| 116066 | + return rc; | |
| 116067 | +} | |
| 115887 | 116068 | |
| 115888 | 116069 | /* |
| 115889 | 116070 | ** Position the pCsr->pStmt statement so that it is on the row |
| 115890 | 116071 | ** of the %_content table that contains the last match. Return |
| 115891 | 116072 | ** SQLITE_OK on success. |
| 115892 | 116073 | */ |
| 115893 | 116074 | static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ |
| 116075 | + int rc = SQLITE_OK; | |
| 115894 | 116076 | if( pCsr->isRequireSeek ){ |
| 115895 | - sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); | |
| 115896 | - pCsr->isRequireSeek = 0; | |
| 115897 | - if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ | |
| 115898 | - return SQLITE_OK; | |
| 115899 | - }else{ | |
| 115900 | - int rc = sqlite3_reset(pCsr->pStmt); | |
| 115901 | - if( rc==SQLITE_OK ){ | |
| 115902 | - /* If no row was found and no error has occured, then the %_content | |
| 115903 | - ** table is missing a row that is present in the full-text index. | |
| 115904 | - ** The data structures are corrupt. | |
| 115905 | - */ | |
| 115906 | - rc = FTS_CORRUPT_VTAB; | |
| 115907 | - } | |
| 115908 | - pCsr->isEof = 1; | |
| 115909 | - if( pContext ){ | |
| 115910 | - sqlite3_result_error_code(pContext, rc); | |
| 115911 | - } | |
| 115912 | - return rc; | |
| 115913 | - } | |
| 115914 | - }else{ | |
| 115915 | - return SQLITE_OK; | |
| 115916 | - } | |
| 116077 | + sqlite3_stmt *pStmt = 0; | |
| 116078 | + | |
| 116079 | + rc = fts3CursorSeekStmt(pCsr, &pStmt); | |
| 116080 | + if( rc==SQLITE_OK ){ | |
| 116081 | + sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); | |
| 116082 | + pCsr->isRequireSeek = 0; | |
| 116083 | + if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ | |
| 116084 | + return SQLITE_OK; | |
| 116085 | + }else{ | |
| 116086 | + rc = sqlite3_reset(pCsr->pStmt); | |
| 116087 | + if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ | |
| 116088 | + /* If no row was found and no error has occured, then the %_content | |
| 116089 | + ** table is missing a row that is present in the full-text index. | |
| 116090 | + ** The data structures are corrupt. */ | |
| 116091 | + rc = FTS_CORRUPT_VTAB; | |
| 116092 | + pCsr->isEof = 1; | |
| 116093 | + } | |
| 116094 | + } | |
| 116095 | + } | |
| 116096 | + } | |
| 116097 | + | |
| 116098 | + if( rc!=SQLITE_OK && pContext ){ | |
| 116099 | + sqlite3_result_error_code(pContext, rc); | |
| 116100 | + } | |
| 116101 | + return rc; | |
| 115917 | 116102 | } |
| 115918 | 116103 | |
| 115919 | 116104 | /* |
| 115920 | 116105 | ** This function is used to process a single interior node when searching |
| 115921 | 116106 | ** a b-tree for a term or term prefix. The node data is passed to this |
| @@ -116351,20 +116536,20 @@ | ||
| 116351 | 116536 | int isSaveLeft, /* Save the left position */ |
| 116352 | 116537 | int isExact, /* If *pp1 is exactly nTokens before *pp2 */ |
| 116353 | 116538 | char **pp1, /* IN/OUT: Left input list */ |
| 116354 | 116539 | char **pp2 /* IN/OUT: Right input list */ |
| 116355 | 116540 | ){ |
| 116356 | - char *p = (pp ? *pp : 0); | |
| 116541 | + char *p = *pp; | |
| 116357 | 116542 | char *p1 = *pp1; |
| 116358 | 116543 | char *p2 = *pp2; |
| 116359 | 116544 | int iCol1 = 0; |
| 116360 | 116545 | int iCol2 = 0; |
| 116361 | 116546 | |
| 116362 | 116547 | /* Never set both isSaveLeft and isExact for the same invocation. */ |
| 116363 | 116548 | assert( isSaveLeft==0 || isExact==0 ); |
| 116364 | 116549 | |
| 116365 | - assert( *p1!=0 && *p2!=0 ); | |
| 116550 | + assert( p!=0 && *p1!=0 && *p2!=0 ); | |
| 116366 | 116551 | if( *p1==POS_COLUMN ){ |
| 116367 | 116552 | p1++; |
| 116368 | 116553 | p1 += sqlite3Fts3GetVarint32(p1, &iCol1); |
| 116369 | 116554 | } |
| 116370 | 116555 | if( *p2==POS_COLUMN ){ |
| @@ -116377,11 +116562,11 @@ | ||
| 116377 | 116562 | char *pSave = p; |
| 116378 | 116563 | sqlite3_int64 iPrev = 0; |
| 116379 | 116564 | sqlite3_int64 iPos1 = 0; |
| 116380 | 116565 | sqlite3_int64 iPos2 = 0; |
| 116381 | 116566 | |
| 116382 | - if( pp && iCol1 ){ | |
| 116567 | + if( iCol1 ){ | |
| 116383 | 116568 | *p++ = POS_COLUMN; |
| 116384 | 116569 | p += sqlite3Fts3PutVarint(p, iCol1); |
| 116385 | 116570 | } |
| 116386 | 116571 | |
| 116387 | 116572 | assert( *p1!=POS_END && *p1!=POS_COLUMN ); |
| @@ -116392,20 +116577,14 @@ | ||
| 116392 | 116577 | while( 1 ){ |
| 116393 | 116578 | if( iPos2==iPos1+nToken |
| 116394 | 116579 | || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) |
| 116395 | 116580 | ){ |
| 116396 | 116581 | sqlite3_int64 iSave; |
| 116397 | - if( !pp ){ | |
| 116398 | - fts3PoslistCopy(0, &p2); | |
| 116399 | - fts3PoslistCopy(0, &p1); | |
| 116400 | - *pp1 = p1; | |
| 116401 | - *pp2 = p2; | |
| 116402 | - return 1; | |
| 116403 | - } | |
| 116404 | 116582 | iSave = isSaveLeft ? iPos1 : iPos2; |
| 116405 | 116583 | fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; |
| 116406 | 116584 | pSave = 0; |
| 116585 | + assert( p ); | |
| 116407 | 116586 | } |
| 116408 | 116587 | if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ |
| 116409 | 116588 | if( (*p2&0xFE)==0 ) break; |
| 116410 | 116589 | fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; |
| 116411 | 116590 | }else{ |
| @@ -116450,11 +116629,11 @@ | ||
| 116450 | 116629 | |
| 116451 | 116630 | fts3PoslistCopy(0, &p2); |
| 116452 | 116631 | fts3PoslistCopy(0, &p1); |
| 116453 | 116632 | *pp1 = p1; |
| 116454 | 116633 | *pp2 = p2; |
| 116455 | - if( !pp || *pp==p ){ | |
| 116634 | + if( *pp==p ){ | |
| 116456 | 116635 | return 0; |
| 116457 | 116636 | } |
| 116458 | 116637 | *p++ = 0x00; |
| 116459 | 116638 | *pp = p; |
| 116460 | 116639 | return 1; |
| @@ -116752,10 +116931,60 @@ | ||
| 116752 | 116931 | } |
| 116753 | 116932 | } |
| 116754 | 116933 | |
| 116755 | 116934 | *pnRight = p - aOut; |
| 116756 | 116935 | } |
| 116936 | + | |
| 116937 | +/* | |
| 116938 | +** Argument pList points to a position list nList bytes in size. This | |
| 116939 | +** function checks to see if the position list contains any entries for | |
| 116940 | +** a token in position 0 (of any column). If so, it writes argument iDelta | |
| 116941 | +** to the output buffer pOut, followed by a position list consisting only | |
| 116942 | +** of the entries from pList at position 0, and terminated by an 0x00 byte. | |
| 116943 | +** The value returned is the number of bytes written to pOut (if any). | |
| 116944 | +*/ | |
| 116945 | +SQLITE_PRIVATE int sqlite3Fts3FirstFilter( | |
| 116946 | + sqlite3_int64 iDelta, /* Varint that may be written to pOut */ | |
| 116947 | + char *pList, /* Position list (no 0x00 term) */ | |
| 116948 | + int nList, /* Size of pList in bytes */ | |
| 116949 | + char *pOut /* Write output here */ | |
| 116950 | +){ | |
| 116951 | + int nOut = 0; | |
| 116952 | + int bWritten = 0; /* True once iDelta has been written */ | |
| 116953 | + char *p = pList; | |
| 116954 | + char *pEnd = &pList[nList]; | |
| 116955 | + | |
| 116956 | + if( *p!=0x01 ){ | |
| 116957 | + if( *p==0x02 ){ | |
| 116958 | + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); | |
| 116959 | + pOut[nOut++] = 0x02; | |
| 116960 | + bWritten = 1; | |
| 116961 | + } | |
| 116962 | + fts3ColumnlistCopy(0, &p); | |
| 116963 | + } | |
| 116964 | + | |
| 116965 | + while( p<pEnd && *p==0x01 ){ | |
| 116966 | + sqlite3_int64 iCol; | |
| 116967 | + p++; | |
| 116968 | + p += sqlite3Fts3GetVarint(p, &iCol); | |
| 116969 | + if( *p==0x02 ){ | |
| 116970 | + if( bWritten==0 ){ | |
| 116971 | + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); | |
| 116972 | + bWritten = 1; | |
| 116973 | + } | |
| 116974 | + pOut[nOut++] = 0x01; | |
| 116975 | + nOut += sqlite3Fts3PutVarint(&pOut[nOut], iCol); | |
| 116976 | + pOut[nOut++] = 0x02; | |
| 116977 | + } | |
| 116978 | + fts3ColumnlistCopy(0, &p); | |
| 116979 | + } | |
| 116980 | + if( bWritten ){ | |
| 116981 | + pOut[nOut++] = 0x00; | |
| 116982 | + } | |
| 116983 | + | |
| 116984 | + return nOut; | |
| 116985 | +} | |
| 116757 | 116986 | |
| 116758 | 116987 | |
| 116759 | 116988 | /* |
| 116760 | 116989 | ** Merge all doclists in the TermSelect.aaOutput[] array into a single |
| 116761 | 116990 | ** doclist stored in TermSelect.aaOutput[0]. If successful, delete all |
| @@ -117109,10 +117338,11 @@ | ||
| 117109 | 117338 | pSegcsr = pTok->pSegcsr; |
| 117110 | 117339 | memset(&tsc, 0, sizeof(TermSelect)); |
| 117111 | 117340 | |
| 117112 | 117341 | filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS |
| 117113 | 117342 | | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) |
| 117343 | + | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) | |
| 117114 | 117344 | | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); |
| 117115 | 117345 | filter.iCol = iColumn; |
| 117116 | 117346 | filter.zTerm = pTok->z; |
| 117117 | 117347 | filter.nTerm = pTok->n; |
| 117118 | 117348 | |
| @@ -117249,12 +117479,12 @@ | ||
| 117249 | 117479 | |
| 117250 | 117480 | if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 117251 | 117481 | return SQLITE_NOMEM; |
| 117252 | 117482 | } |
| 117253 | 117483 | |
| 117254 | - rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn, | |
| 117255 | - iCol, zQuery, -1, &pCsr->pExpr | |
| 117484 | + rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat, | |
| 117485 | + p->nColumn, iCol, zQuery, -1, &pCsr->pExpr | |
| 117256 | 117486 | ); |
| 117257 | 117487 | if( rc!=SQLITE_OK ){ |
| 117258 | 117488 | if( rc==SQLITE_ERROR ){ |
| 117259 | 117489 | static const char *zErr = "malformed MATCH expression: [%s]"; |
| 117260 | 117490 | p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery); |
| @@ -117277,26 +117507,27 @@ | ||
| 117277 | 117507 | ** statement loops through all rows of the %_content table. For a |
| 117278 | 117508 | ** full-text query or docid lookup, the statement retrieves a single |
| 117279 | 117509 | ** row by docid. |
| 117280 | 117510 | */ |
| 117281 | 117511 | if( idxNum==FTS3_FULLSCAN_SEARCH ){ |
| 117282 | - const char *zSort = (pCsr->bDesc ? "DESC" : "ASC"); | |
| 117283 | - const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s"; | |
| 117284 | - zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort); | |
| 117285 | - }else{ | |
| 117286 | - const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?"; | |
| 117287 | - zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName); | |
| 117288 | - } | |
| 117289 | - if( !zSql ) return SQLITE_NOMEM; | |
| 117290 | - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); | |
| 117291 | - sqlite3_free(zSql); | |
| 117292 | - if( rc!=SQLITE_OK ) return rc; | |
| 117293 | - | |
| 117294 | - if( idxNum==FTS3_DOCID_SEARCH ){ | |
| 117295 | - rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); | |
| 117296 | - if( rc!=SQLITE_OK ) return rc; | |
| 117297 | - } | |
| 117512 | + zSql = sqlite3_mprintf( | |
| 117513 | + "SELECT %s ORDER BY rowid %s", | |
| 117514 | + p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") | |
| 117515 | + ); | |
| 117516 | + if( zSql ){ | |
| 117517 | + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); | |
| 117518 | + sqlite3_free(zSql); | |
| 117519 | + }else{ | |
| 117520 | + rc = SQLITE_NOMEM; | |
| 117521 | + } | |
| 117522 | + }else if( idxNum==FTS3_DOCID_SEARCH ){ | |
| 117523 | + rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt); | |
| 117524 | + if( rc==SQLITE_OK ){ | |
| 117525 | + rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); | |
| 117526 | + } | |
| 117527 | + } | |
| 117528 | + if( rc!=SQLITE_OK ) return rc; | |
| 117298 | 117529 | |
| 117299 | 117530 | return fts3NextMethod(pCursor); |
| 117300 | 117531 | } |
| 117301 | 117532 | |
| 117302 | 117533 | /* |
| @@ -117345,11 +117576,11 @@ | ||
| 117345 | 117576 | ** Return a blob which is a pointer to the cursor. |
| 117346 | 117577 | */ |
| 117347 | 117578 | sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); |
| 117348 | 117579 | }else{ |
| 117349 | 117580 | rc = fts3CursorSeek(0, pCsr); |
| 117350 | - if( rc==SQLITE_OK ){ | |
| 117581 | + if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){ | |
| 117351 | 117582 | sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1)); |
| 117352 | 117583 | } |
| 117353 | 117584 | } |
| 117354 | 117585 | |
| 117355 | 117586 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| @@ -117638,19 +117869,26 @@ | ||
| 117638 | 117869 | ){ |
| 117639 | 117870 | Fts3Table *p = (Fts3Table *)pVtab; |
| 117640 | 117871 | sqlite3 *db = p->db; /* Database connection */ |
| 117641 | 117872 | int rc; /* Return Code */ |
| 117642 | 117873 | |
| 117874 | + /* As it happens, the pending terms table is always empty here. This is | |
| 117875 | + ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction | |
| 117876 | + ** always opens a savepoint transaction. And the xSavepoint() method | |
| 117877 | + ** flushes the pending terms table. But leave the (no-op) call to | |
| 117878 | + ** PendingTermsFlush() in in case that changes. | |
| 117879 | + */ | |
| 117880 | + assert( p->nPendingData==0 ); | |
| 117643 | 117881 | rc = sqlite3Fts3PendingTermsFlush(p); |
| 117644 | - if( rc!=SQLITE_OK ){ | |
| 117645 | - return rc; | |
| 117882 | + | |
| 117883 | + if( p->zContentTbl==0 ){ | |
| 117884 | + fts3DbExec(&rc, db, | |
| 117885 | + "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", | |
| 117886 | + p->zDb, p->zName, zName | |
| 117887 | + ); | |
| 117646 | 117888 | } |
| 117647 | 117889 | |
| 117648 | - fts3DbExec(&rc, db, | |
| 117649 | - "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", | |
| 117650 | - p->zDb, p->zName, zName | |
| 117651 | - ); | |
| 117652 | 117890 | if( p->bHasDocsize ){ |
| 117653 | 117891 | fts3DbExec(&rc, db, |
| 117654 | 117892 | "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", |
| 117655 | 117893 | p->zDb, p->zName, zName |
| 117656 | 117894 | ); |
| @@ -118005,25 +118243,24 @@ | ||
| 118005 | 118243 | ** |
| 118006 | 118244 | ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. |
| 118007 | 118245 | */ |
| 118008 | 118246 | static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ |
| 118009 | 118247 | int iToken; /* Used to iterate through phrase tokens */ |
| 118010 | - int rc = SQLITE_OK; /* Return code */ | |
| 118011 | 118248 | char *aPoslist = 0; /* Position list for deferred tokens */ |
| 118012 | 118249 | int nPoslist = 0; /* Number of bytes in aPoslist */ |
| 118013 | 118250 | int iPrev = -1; /* Token number of previous deferred token */ |
| 118014 | 118251 | |
| 118015 | 118252 | assert( pPhrase->doclist.bFreeList==0 ); |
| 118016 | 118253 | |
| 118017 | - for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){ | |
| 118254 | + for(iToken=0; iToken<pPhrase->nToken; iToken++){ | |
| 118018 | 118255 | Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; |
| 118019 | 118256 | Fts3DeferredToken *pDeferred = pToken->pDeferred; |
| 118020 | 118257 | |
| 118021 | 118258 | if( pDeferred ){ |
| 118022 | 118259 | char *pList; |
| 118023 | 118260 | int nList; |
| 118024 | - rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); | |
| 118261 | + int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); | |
| 118025 | 118262 | if( rc!=SQLITE_OK ) return rc; |
| 118026 | 118263 | |
| 118027 | 118264 | if( pList==0 ){ |
| 118028 | 118265 | sqlite3_free(aPoslist); |
| 118029 | 118266 | pPhrase->doclist.pList = 0; |
| @@ -118120,10 +118357,11 @@ | ||
| 118120 | 118357 | if( pCsr->bDesc==pTab->bDescIdx |
| 118121 | 118358 | && bOptOk==1 |
| 118122 | 118359 | && p->nToken==1 |
| 118123 | 118360 | && pFirst->pSegcsr |
| 118124 | 118361 | && pFirst->pSegcsr->bLookup |
| 118362 | + && pFirst->bFirst==0 | |
| 118125 | 118363 | ){ |
| 118126 | 118364 | /* Use the incremental approach. */ |
| 118127 | 118365 | int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); |
| 118128 | 118366 | rc = sqlite3Fts3MsrIncrStart( |
| 118129 | 118367 | pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n); |
| @@ -118349,11 +118587,11 @@ | ||
| 118349 | 118587 | Fts3Expr *pExpr, /* Expression to consider */ |
| 118350 | 118588 | Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ |
| 118351 | 118589 | Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ |
| 118352 | 118590 | int *pRc /* IN/OUT: Error code */ |
| 118353 | 118591 | ){ |
| 118354 | - if( *pRc==SQLITE_OK && pExpr ){ | |
| 118592 | + if( *pRc==SQLITE_OK ){ | |
| 118355 | 118593 | if( pExpr->eType==FTSQUERY_PHRASE ){ |
| 118356 | 118594 | Fts3Phrase *pPhrase = pExpr->pPhrase; |
| 118357 | 118595 | int i; |
| 118358 | 118596 | for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){ |
| 118359 | 118597 | Fts3TokenAndCost *pTC = (*ppTC)++; |
| @@ -118363,10 +118601,15 @@ | ||
| 118363 | 118601 | pTC->pToken = &pPhrase->aToken[i]; |
| 118364 | 118602 | pTC->iCol = pPhrase->iColumn; |
| 118365 | 118603 | *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); |
| 118366 | 118604 | } |
| 118367 | 118605 | }else if( pExpr->eType!=FTSQUERY_NOT ){ |
| 118606 | + assert( pExpr->eType==FTSQUERY_OR | |
| 118607 | + || pExpr->eType==FTSQUERY_AND | |
| 118608 | + || pExpr->eType==FTSQUERY_NEAR | |
| 118609 | + ); | |
| 118610 | + assert( pExpr->pLeft && pExpr->pRight ); | |
| 118368 | 118611 | if( pExpr->eType==FTSQUERY_OR ){ |
| 118369 | 118612 | pRoot = pExpr->pLeft; |
| 118370 | 118613 | **ppOr = pRoot; |
| 118371 | 118614 | (*ppOr)++; |
| 118372 | 118615 | } |
| @@ -118466,10 +118709,19 @@ | ||
| 118466 | 118709 | int nOvfl = 0; /* Total overflow pages used by doclists */ |
| 118467 | 118710 | int nToken = 0; /* Total number of tokens in cluster */ |
| 118468 | 118711 | |
| 118469 | 118712 | int nMinEst = 0; /* The minimum count for any phrase so far. */ |
| 118470 | 118713 | int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ |
| 118714 | + | |
| 118715 | + /* Tokens are never deferred for FTS tables created using the content=xxx | |
| 118716 | + ** option. The reason being that it is not guaranteed that the content | |
| 118717 | + ** table actually contains the same data as the index. To prevent this from | |
| 118718 | + ** causing any problems, the deferred token optimization is completely | |
| 118719 | + ** disabled for content=xxx tables. */ | |
| 118720 | + if( pTab->zContentTbl ){ | |
| 118721 | + return SQLITE_OK; | |
| 118722 | + } | |
| 118471 | 118723 | |
| 118472 | 118724 | /* Count the tokens in this AND/NEAR cluster. If none of the doclists |
| 118473 | 118725 | ** associated with the tokens spill onto overflow pages, or if there is |
| 118474 | 118726 | ** only 1 token, exit early. No tokens to defer in this case. */ |
| 118475 | 118727 | for(ii=0; ii<nTC; ii++){ |
| @@ -118529,11 +118781,15 @@ | ||
| 118529 | 118781 | Fts3PhraseToken *pToken = pTC->pToken; |
| 118530 | 118782 | rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); |
| 118531 | 118783 | fts3SegReaderCursorFree(pToken->pSegcsr); |
| 118532 | 118784 | pToken->pSegcsr = 0; |
| 118533 | 118785 | }else{ |
| 118534 | - nLoad4 = nLoad4*4; | |
| 118786 | + /* Set nLoad4 to the value of (4^nOther) for the next iteration of the | |
| 118787 | + ** for-loop. Except, limit the value to 2^24 to prevent it from | |
| 118788 | + ** overflowing the 32-bit integer it is stored in. */ | |
| 118789 | + if( ii<12 ) nLoad4 = nLoad4*4; | |
| 118790 | + | |
| 118535 | 118791 | if( ii==0 || pTC->pPhrase->nToken>1 ){ |
| 118536 | 118792 | /* Either this is the cheapest token in the entire query, or it is |
| 118537 | 118793 | ** part of a multi-token phrase. Either way, the entire doclist will |
| 118538 | 118794 | ** (eventually) be loaded into memory. It may as well be now. */ |
| 118539 | 118795 | Fts3PhraseToken *pToken = pTC->pToken; |
| @@ -119990,10 +120246,11 @@ | ||
| 119990 | 120246 | */ |
| 119991 | 120247 | typedef struct ParseContext ParseContext; |
| 119992 | 120248 | struct ParseContext { |
| 119993 | 120249 | sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ |
| 119994 | 120250 | const char **azCol; /* Array of column names for fts3 table */ |
| 120251 | + int bFts4; /* True to allow FTS4-only syntax */ | |
| 119995 | 120252 | int nCol; /* Number of entries in azCol[] */ |
| 119996 | 120253 | int iDefaultCol; /* Default column to query */ |
| 119997 | 120254 | int isNot; /* True if getNextNode() sees a unary - */ |
| 119998 | 120255 | sqlite3_context *pCtx; /* Write error message here */ |
| 119999 | 120256 | int nNest; /* Number of nested brackets */ |
| @@ -120077,13 +120334,25 @@ | ||
| 120077 | 120334 | |
| 120078 | 120335 | if( iEnd<n && z[iEnd]=='*' ){ |
| 120079 | 120336 | pRet->pPhrase->aToken[0].isPrefix = 1; |
| 120080 | 120337 | iEnd++; |
| 120081 | 120338 | } |
| 120082 | - if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){ | |
| 120083 | - pParse->isNot = 1; | |
| 120339 | + | |
| 120340 | + while( 1 ){ | |
| 120341 | + if( !sqlite3_fts3_enable_parentheses | |
| 120342 | + && iStart>0 && z[iStart-1]=='-' | |
| 120343 | + ){ | |
| 120344 | + pParse->isNot = 1; | |
| 120345 | + iStart--; | |
| 120346 | + }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ | |
| 120347 | + pRet->pPhrase->aToken[0].bFirst = 1; | |
| 120348 | + iStart--; | |
| 120349 | + }else{ | |
| 120350 | + break; | |
| 120351 | + } | |
| 120084 | 120352 | } |
| 120353 | + | |
| 120085 | 120354 | } |
| 120086 | 120355 | nConsumed = iEnd; |
| 120087 | 120356 | } |
| 120088 | 120357 | |
| 120089 | 120358 | pModule->xClose(pCursor); |
| @@ -120178,10 +120447,11 @@ | ||
| 120178 | 120447 | memcpy(&zTemp[nTemp], zByte, nByte); |
| 120179 | 120448 | nTemp += nByte; |
| 120180 | 120449 | |
| 120181 | 120450 | pToken->n = nByte; |
| 120182 | 120451 | pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*'); |
| 120452 | + pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^'); | |
| 120183 | 120453 | nToken = ii+1; |
| 120184 | 120454 | } |
| 120185 | 120455 | } |
| 120186 | 120456 | |
| 120187 | 120457 | pModule->xClose(pCursor); |
| @@ -120629,10 +120899,11 @@ | ||
| 120629 | 120899 | ** match any table column. |
| 120630 | 120900 | */ |
| 120631 | 120901 | SQLITE_PRIVATE int sqlite3Fts3ExprParse( |
| 120632 | 120902 | sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ |
| 120633 | 120903 | char **azCol, /* Array of column names for fts3 table */ |
| 120904 | + int bFts4, /* True to allow FTS4-only syntax */ | |
| 120634 | 120905 | int nCol, /* Number of entries in azCol[] */ |
| 120635 | 120906 | int iDefaultCol, /* Default column to query */ |
| 120636 | 120907 | const char *z, int n, /* Text of MATCH query */ |
| 120637 | 120908 | Fts3Expr **ppExpr /* OUT: Parsed query structure */ |
| 120638 | 120909 | ){ |
| @@ -120642,10 +120913,11 @@ | ||
| 120642 | 120913 | sParse.pTokenizer = pTokenizer; |
| 120643 | 120914 | sParse.azCol = (const char **)azCol; |
| 120644 | 120915 | sParse.nCol = nCol; |
| 120645 | 120916 | sParse.iDefaultCol = iDefaultCol; |
| 120646 | 120917 | sParse.nNest = 0; |
| 120918 | + sParse.bFts4 = bFts4; | |
| 120647 | 120919 | if( z==0 ){ |
| 120648 | 120920 | *ppExpr = 0; |
| 120649 | 120921 | return SQLITE_OK; |
| 120650 | 120922 | } |
| 120651 | 120923 | if( n<0 ){ |
| @@ -120831,11 +121103,11 @@ | ||
| 120831 | 121103 | for(ii=0; ii<nCol; ii++){ |
| 120832 | 121104 | azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); |
| 120833 | 121105 | } |
| 120834 | 121106 | |
| 120835 | 121107 | rc = sqlite3Fts3ExprParse( |
| 120836 | - pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr | |
| 121108 | + pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr | |
| 120837 | 121109 | ); |
| 120838 | 121110 | if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ |
| 120839 | 121111 | sqlite3_result_error(context, "Error parsing expression", -1); |
| 120840 | 121112 | }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ |
| 120841 | 121113 | sqlite3_result_error_nomem(context); |
| @@ -122878,11 +123150,11 @@ | ||
| 122878 | 123150 | /* 2 */ "DELETE FROM %Q.'%q_content'", |
| 122879 | 123151 | /* 3 */ "DELETE FROM %Q.'%q_segments'", |
| 122880 | 123152 | /* 4 */ "DELETE FROM %Q.'%q_segdir'", |
| 122881 | 123153 | /* 5 */ "DELETE FROM %Q.'%q_docsize'", |
| 122882 | 123154 | /* 6 */ "DELETE FROM %Q.'%q_stat'", |
| 122883 | -/* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?", | |
| 123155 | +/* 7 */ "SELECT %s WHERE rowid=?", | |
| 122884 | 123156 | /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", |
| 122885 | 123157 | /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", |
| 122886 | 123158 | /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", |
| 122887 | 123159 | /* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", |
| 122888 | 123160 | |
| @@ -122920,11 +123192,11 @@ | ||
| 122920 | 123192 | if( !pStmt ){ |
| 122921 | 123193 | char *zSql; |
| 122922 | 123194 | if( eStmt==SQL_CONTENT_INSERT ){ |
| 122923 | 123195 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); |
| 122924 | 123196 | }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ |
| 122925 | - zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName); | |
| 123197 | + zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); | |
| 122926 | 123198 | }else{ |
| 122927 | 123199 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); |
| 122928 | 123200 | } |
| 122929 | 123201 | if( !zSql ){ |
| 122930 | 123202 | rc = SQLITE_NOMEM; |
| @@ -123031,21 +123303,28 @@ | ||
| 123031 | 123303 | ** We try to avoid this because if FTS3 returns any error when committing |
| 123032 | 123304 | ** a transaction, the whole transaction will be rolled back. And this is |
| 123033 | 123305 | ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can |
| 123034 | 123306 | ** still happen if the user reads data directly from the %_segments or |
| 123035 | 123307 | ** %_segdir tables instead of going through FTS3 though. |
| 123308 | +** | |
| 123309 | +** This reasoning does not apply to a content=xxx table. | |
| 123036 | 123310 | */ |
| 123037 | 123311 | SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){ |
| 123038 | 123312 | int rc; /* Return code */ |
| 123039 | 123313 | sqlite3_stmt *pStmt; /* Statement used to obtain lock */ |
| 123040 | 123314 | |
| 123041 | - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); | |
| 123042 | - if( rc==SQLITE_OK ){ | |
| 123043 | - sqlite3_bind_null(pStmt, 1); | |
| 123044 | - sqlite3_step(pStmt); | |
| 123045 | - rc = sqlite3_reset(pStmt); | |
| 123315 | + if( p->zContentTbl==0 ){ | |
| 123316 | + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); | |
| 123317 | + if( rc==SQLITE_OK ){ | |
| 123318 | + sqlite3_bind_null(pStmt, 1); | |
| 123319 | + sqlite3_step(pStmt); | |
| 123320 | + rc = sqlite3_reset(pStmt); | |
| 123321 | + } | |
| 123322 | + }else{ | |
| 123323 | + rc = SQLITE_OK; | |
| 123046 | 123324 | } |
| 123325 | + | |
| 123047 | 123326 | return rc; |
| 123048 | 123327 | } |
| 123049 | 123328 | |
| 123050 | 123329 | /* |
| 123051 | 123330 | ** Set *ppStmt to a statement handle that may be used to iterate through |
| @@ -123401,10 +123680,22 @@ | ||
| 123401 | 123680 | sqlite3_value **apVal, /* Array of values to insert */ |
| 123402 | 123681 | sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ |
| 123403 | 123682 | ){ |
| 123404 | 123683 | int rc; /* Return code */ |
| 123405 | 123684 | sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ |
| 123685 | + | |
| 123686 | + if( p->zContentTbl ){ | |
| 123687 | + sqlite3_value *pRowid = apVal[p->nColumn+3]; | |
| 123688 | + if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ | |
| 123689 | + pRowid = apVal[1]; | |
| 123690 | + } | |
| 123691 | + if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ | |
| 123692 | + return SQLITE_CONSTRAINT; | |
| 123693 | + } | |
| 123694 | + *piDocid = sqlite3_value_int64(pRowid); | |
| 123695 | + return SQLITE_OK; | |
| 123696 | + } | |
| 123406 | 123697 | |
| 123407 | 123698 | /* Locate the statement handle used to insert data into the %_content |
| 123408 | 123699 | ** table. The SQL for this statement is: |
| 123409 | 123700 | ** |
| 123410 | 123701 | ** INSERT INTO %_content VALUES(?, ?, ?, ...) |
| @@ -123452,18 +123743,20 @@ | ||
| 123452 | 123743 | |
| 123453 | 123744 | /* |
| 123454 | 123745 | ** Remove all data from the FTS3 table. Clear the hash table containing |
| 123455 | 123746 | ** pending terms. |
| 123456 | 123747 | */ |
| 123457 | -static int fts3DeleteAll(Fts3Table *p){ | |
| 123748 | +static int fts3DeleteAll(Fts3Table *p, int bContent){ | |
| 123458 | 123749 | int rc = SQLITE_OK; /* Return code */ |
| 123459 | 123750 | |
| 123460 | 123751 | /* Discard the contents of the pending-terms hash table. */ |
| 123461 | 123752 | sqlite3Fts3PendingTermsClear(p); |
| 123462 | 123753 | |
| 123463 | - /* Delete everything from the %_content, %_segments and %_segdir tables. */ | |
| 123464 | - fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); | |
| 123754 | + /* Delete everything from the shadow tables. Except, leave %_content as | |
| 123755 | + ** is if bContent is false. */ | |
| 123756 | + assert( p->zContentTbl==0 || bContent==0 ); | |
| 123757 | + if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); | |
| 123465 | 123758 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); |
| 123466 | 123759 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); |
| 123467 | 123760 | if( p->bHasDocsize ){ |
| 123468 | 123761 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); |
| 123469 | 123762 | } |
| @@ -124747,16 +125040,22 @@ | ||
| 124747 | 125040 | ** error occurs, an SQLite error code is returned. |
| 124748 | 125041 | */ |
| 124749 | 125042 | static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ |
| 124750 | 125043 | sqlite3_stmt *pStmt; |
| 124751 | 125044 | int rc; |
| 124752 | - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); | |
| 124753 | - if( rc==SQLITE_OK ){ | |
| 124754 | - if( SQLITE_ROW==sqlite3_step(pStmt) ){ | |
| 124755 | - *pisEmpty = sqlite3_column_int(pStmt, 0); | |
| 125045 | + if( p->zContentTbl ){ | |
| 125046 | + /* If using the content=xxx option, assume the table is never empty */ | |
| 125047 | + *pisEmpty = 0; | |
| 125048 | + rc = SQLITE_OK; | |
| 125049 | + }else{ | |
| 125050 | + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); | |
| 125051 | + if( rc==SQLITE_OK ){ | |
| 125052 | + if( SQLITE_ROW==sqlite3_step(pStmt) ){ | |
| 125053 | + *pisEmpty = sqlite3_column_int(pStmt, 0); | |
| 125054 | + } | |
| 125055 | + rc = sqlite3_reset(pStmt); | |
| 124756 | 125056 | } |
| 124757 | - rc = sqlite3_reset(pStmt); | |
| 124758 | 125057 | } |
| 124759 | 125058 | return rc; |
| 124760 | 125059 | } |
| 124761 | 125060 | |
| 124762 | 125061 | /* |
| @@ -125104,10 +125403,11 @@ | ||
| 125104 | 125403 | int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); |
| 125105 | 125404 | int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); |
| 125106 | 125405 | int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); |
| 125107 | 125406 | int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); |
| 125108 | 125407 | int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); |
| 125408 | + int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); | |
| 125109 | 125409 | |
| 125110 | 125410 | Fts3SegReader **apSegment = pCsr->apSegment; |
| 125111 | 125411 | int nSegment = pCsr->nSegment; |
| 125112 | 125412 | Fts3SegFilter *pFilter = pCsr->pFilter; |
| 125113 | 125413 | int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( |
| @@ -125163,10 +125463,11 @@ | ||
| 125163 | 125463 | } |
| 125164 | 125464 | |
| 125165 | 125465 | assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); |
| 125166 | 125466 | if( nMerge==1 |
| 125167 | 125467 | && !isIgnoreEmpty |
| 125468 | + && !isFirst | |
| 125168 | 125469 | && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) |
| 125169 | 125470 | ){ |
| 125170 | 125471 | pCsr->nDoclist = apSegment[0]->nDoclist; |
| 125171 | 125472 | if( fts3SegReaderIsPending(apSegment[0]) ){ |
| 125172 | 125473 | rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); |
| @@ -125228,16 +125529,28 @@ | ||
| 125228 | 125529 | if( !aNew ){ |
| 125229 | 125530 | return SQLITE_NOMEM; |
| 125230 | 125531 | } |
| 125231 | 125532 | pCsr->aBuffer = aNew; |
| 125232 | 125533 | } |
| 125233 | - nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); | |
| 125234 | - iPrev = iDocid; | |
| 125235 | - if( isRequirePos ){ | |
| 125236 | - memcpy(&pCsr->aBuffer[nDoclist], pList, nList); | |
| 125237 | - nDoclist += nList; | |
| 125238 | - pCsr->aBuffer[nDoclist++] = '\0'; | |
| 125534 | + | |
| 125535 | + if( isFirst ){ | |
| 125536 | + char *a = &pCsr->aBuffer[nDoclist]; | |
| 125537 | + int nWrite; | |
| 125538 | + | |
| 125539 | + nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); | |
| 125540 | + if( nWrite ){ | |
| 125541 | + iPrev = iDocid; | |
| 125542 | + nDoclist += nWrite; | |
| 125543 | + } | |
| 125544 | + }else{ | |
| 125545 | + nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); | |
| 125546 | + iPrev = iDocid; | |
| 125547 | + if( isRequirePos ){ | |
| 125548 | + memcpy(&pCsr->aBuffer[nDoclist], pList, nList); | |
| 125549 | + nDoclist += nList; | |
| 125550 | + pCsr->aBuffer[nDoclist++] = '\0'; | |
| 125551 | + } | |
| 125239 | 125552 | } |
| 125240 | 125553 | } |
| 125241 | 125554 | |
| 125242 | 125555 | fts3SegReaderSort(apSegment, nMerge, j, xCmp); |
| 125243 | 125556 | } |
| @@ -125409,13 +125722,13 @@ | ||
| 125409 | 125722 | ** Insert the sizes (in tokens) for each column of the document |
| 125410 | 125723 | ** with docid equal to p->iPrevDocid. The sizes are encoded as |
| 125411 | 125724 | ** a blob of varints. |
| 125412 | 125725 | */ |
| 125413 | 125726 | static void fts3InsertDocsize( |
| 125414 | - int *pRC, /* Result code */ | |
| 125415 | - Fts3Table *p, /* Table into which to insert */ | |
| 125416 | - u32 *aSz /* Sizes of each column */ | |
| 125727 | + int *pRC, /* Result code */ | |
| 125728 | + Fts3Table *p, /* Table into which to insert */ | |
| 125729 | + u32 *aSz /* Sizes of each column, in tokens */ | |
| 125417 | 125730 | ){ |
| 125418 | 125731 | char *pBlob; /* The BLOB encoding of the document size */ |
| 125419 | 125732 | int nBlob; /* Number of bytes in the BLOB */ |
| 125420 | 125733 | sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ |
| 125421 | 125734 | int rc; /* Result code from subfunctions */ |
| @@ -125532,10 +125845,90 @@ | ||
| 125532 | 125845 | sqlite3Fts3SegmentsClose(p); |
| 125533 | 125846 | sqlite3Fts3PendingTermsClear(p); |
| 125534 | 125847 | |
| 125535 | 125848 | return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; |
| 125536 | 125849 | } |
| 125850 | + | |
| 125851 | +/* | |
| 125852 | +** This function is called when the user executes the following statement: | |
| 125853 | +** | |
| 125854 | +** INSERT INTO <tbl>(<tbl>) VALUES('rebuild'); | |
| 125855 | +** | |
| 125856 | +** The entire FTS index is discarded and rebuilt. If the table is one | |
| 125857 | +** created using the content=xxx option, then the new index is based on | |
| 125858 | +** the current contents of the xxx table. Otherwise, it is rebuilt based | |
| 125859 | +** on the contents of the %_content table. | |
| 125860 | +*/ | |
| 125861 | +static int fts3DoRebuild(Fts3Table *p){ | |
| 125862 | + int rc; /* Return Code */ | |
| 125863 | + | |
| 125864 | + rc = fts3DeleteAll(p, 0); | |
| 125865 | + if( rc==SQLITE_OK ){ | |
| 125866 | + u32 *aSz = 0; | |
| 125867 | + u32 *aSzIns = 0; | |
| 125868 | + u32 *aSzDel = 0; | |
| 125869 | + sqlite3_stmt *pStmt = 0; | |
| 125870 | + int nEntry = 0; | |
| 125871 | + | |
| 125872 | + /* Compose and prepare an SQL statement to loop through the content table */ | |
| 125873 | + char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); | |
| 125874 | + if( !zSql ){ | |
| 125875 | + rc = SQLITE_NOMEM; | |
| 125876 | + }else{ | |
| 125877 | + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); | |
| 125878 | + sqlite3_free(zSql); | |
| 125879 | + } | |
| 125880 | + | |
| 125881 | + if( rc==SQLITE_OK ){ | |
| 125882 | + int nByte = sizeof(u32) * (p->nColumn+1)*3; | |
| 125883 | + aSz = (u32 *)sqlite3_malloc(nByte); | |
| 125884 | + if( aSz==0 ){ | |
| 125885 | + rc = SQLITE_NOMEM; | |
| 125886 | + }else{ | |
| 125887 | + memset(aSz, 0, nByte); | |
| 125888 | + aSzIns = &aSz[p->nColumn+1]; | |
| 125889 | + aSzDel = &aSzIns[p->nColumn+1]; | |
| 125890 | + } | |
| 125891 | + } | |
| 125892 | + | |
| 125893 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ | |
| 125894 | + int iCol; | |
| 125895 | + rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0)); | |
| 125896 | + aSz[p->nColumn] = 0; | |
| 125897 | + for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){ | |
| 125898 | + const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); | |
| 125899 | + rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]); | |
| 125900 | + aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); | |
| 125901 | + } | |
| 125902 | + if( p->bHasDocsize ){ | |
| 125903 | + fts3InsertDocsize(&rc, p, aSz); | |
| 125904 | + } | |
| 125905 | + if( rc!=SQLITE_OK ){ | |
| 125906 | + sqlite3_finalize(pStmt); | |
| 125907 | + pStmt = 0; | |
| 125908 | + }else{ | |
| 125909 | + nEntry++; | |
| 125910 | + for(iCol=0; iCol<=p->nColumn; iCol++){ | |
| 125911 | + aSzIns[iCol] += aSz[iCol]; | |
| 125912 | + } | |
| 125913 | + } | |
| 125914 | + } | |
| 125915 | + if( p->bHasStat ){ | |
| 125916 | + fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); | |
| 125917 | + } | |
| 125918 | + sqlite3_free(aSz); | |
| 125919 | + | |
| 125920 | + if( pStmt ){ | |
| 125921 | + int rc2 = sqlite3_finalize(pStmt); | |
| 125922 | + if( rc==SQLITE_OK ){ | |
| 125923 | + rc = rc2; | |
| 125924 | + } | |
| 125925 | + } | |
| 125926 | + } | |
| 125927 | + | |
| 125928 | + return rc; | |
| 125929 | +} | |
| 125537 | 125930 | |
| 125538 | 125931 | /* |
| 125539 | 125932 | ** Handle a 'special' INSERT of the form: |
| 125540 | 125933 | ** |
| 125541 | 125934 | ** "INSERT INTO tbl(tbl) VALUES(<expr>)" |
| @@ -125550,10 +125943,12 @@ | ||
| 125550 | 125943 | |
| 125551 | 125944 | if( !zVal ){ |
| 125552 | 125945 | return SQLITE_NOMEM; |
| 125553 | 125946 | }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ |
| 125554 | 125947 | rc = fts3DoOptimize(p, 0); |
| 125948 | + }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ | |
| 125949 | + rc = fts3DoRebuild(p); | |
| 125555 | 125950 | #ifdef SQLITE_TEST |
| 125556 | 125951 | }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ |
| 125557 | 125952 | p->nNodeSize = atoi(&zVal[9]); |
| 125558 | 125953 | rc = SQLITE_OK; |
| 125559 | 125954 | }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ |
| @@ -125630,10 +126025,11 @@ | ||
| 125630 | 126025 | pTC->pTokenizer = pT; |
| 125631 | 126026 | rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); |
| 125632 | 126027 | for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ |
| 125633 | 126028 | Fts3PhraseToken *pPT = pDef->pToken; |
| 125634 | 126029 | if( (pDef->iCol>=p->nColumn || pDef->iCol==i) |
| 126030 | + && (pPT->bFirst==0 || iPos==0) | |
| 125635 | 126031 | && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken)) |
| 125636 | 126032 | && (0==memcmp(zToken, pPT->z, pPT->n)) |
| 125637 | 126033 | ){ |
| 125638 | 126034 | fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); |
| 125639 | 126035 | } |
| @@ -125721,18 +126117,22 @@ | ||
| 125721 | 126117 | if( rc==SQLITE_OK ){ |
| 125722 | 126118 | if( isEmpty ){ |
| 125723 | 126119 | /* Deleting this row means the whole table is empty. In this case |
| 125724 | 126120 | ** delete the contents of all three tables and throw away any |
| 125725 | 126121 | ** data in the pendingTerms hash table. */ |
| 125726 | - rc = fts3DeleteAll(p); | |
| 126122 | + rc = fts3DeleteAll(p, 1); | |
| 125727 | 126123 | *pnDoc = *pnDoc - 1; |
| 125728 | 126124 | }else{ |
| 125729 | 126125 | sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); |
| 125730 | 126126 | rc = fts3PendingTermsDocid(p, iRemove); |
| 125731 | 126127 | fts3DeleteTerms(&rc, p, pRowid, aSzDel); |
| 125732 | - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); | |
| 125733 | - if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; | |
| 126128 | + if( p->zContentTbl==0 ){ | |
| 126129 | + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); | |
| 126130 | + if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; | |
| 126131 | + }else{ | |
| 126132 | + *pnDoc = *pnDoc - 1; | |
| 126133 | + } | |
| 125734 | 126134 | if( p->bHasDocsize ){ |
| 125735 | 126135 | fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); |
| 125736 | 126136 | } |
| 125737 | 126137 | } |
| 125738 | 126138 | } |
| @@ -125788,11 +126188,11 @@ | ||
| 125788 | 126188 | ** should be deleted from the database before inserting the new row. Or, |
| 125789 | 126189 | ** if the on-conflict mode is other than REPLACE, then this method must |
| 125790 | 126190 | ** detect the conflict and return SQLITE_CONSTRAINT before beginning to |
| 125791 | 126191 | ** modify the database file. |
| 125792 | 126192 | */ |
| 125793 | - if( nArg>1 ){ | |
| 126193 | + if( nArg>1 && p->zContentTbl==0 ){ | |
| 125794 | 126194 | /* Find the value object that holds the new rowid value. */ |
| 125795 | 126195 | sqlite3_value *pNewRowid = apVal[3+p->nColumn]; |
| 125796 | 126196 | if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ |
| 125797 | 126197 | pNewRowid = apVal[1]; |
| 125798 | 126198 | } |
| @@ -125839,11 +126239,13 @@ | ||
| 125839 | 126239 | |
| 125840 | 126240 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 125841 | 126241 | if( nArg>1 && rc==SQLITE_OK ){ |
| 125842 | 126242 | if( bInsertDone==0 ){ |
| 125843 | 126243 | rc = fts3InsertData(p, apVal, pRowid); |
| 125844 | - if( rc==SQLITE_CONSTRAINT ) rc = FTS_CORRUPT_VTAB; | |
| 126244 | + if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ | |
| 126245 | + rc = FTS_CORRUPT_VTAB; | |
| 126246 | + } | |
| 125845 | 126247 | } |
| 125846 | 126248 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ |
| 125847 | 126249 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 125848 | 126250 | } |
| 125849 | 126251 | if( rc==SQLITE_OK ){ |
| @@ -126259,10 +126661,11 @@ | ||
| 126259 | 126661 | pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol); |
| 126260 | 126662 | if( pCsr ){ |
| 126261 | 126663 | int iFirst = 0; |
| 126262 | 126664 | pPhrase->pList = pCsr; |
| 126263 | 126665 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 126666 | + assert( iFirst>=0 ); | |
| 126264 | 126667 | pPhrase->pHead = pCsr; |
| 126265 | 126668 | pPhrase->pTail = pCsr; |
| 126266 | 126669 | pPhrase->iHead = iFirst; |
| 126267 | 126670 | pPhrase->iTail = iFirst; |
| 126268 | 126671 | }else{ |
| @@ -127300,11 +127703,11 @@ | ||
| 127300 | 127703 | } |
| 127301 | 127704 | } |
| 127302 | 127705 | |
| 127303 | 127706 | if( !pTerm ){ |
| 127304 | 127707 | /* All offsets for this column have been gathered. */ |
| 127305 | - break; | |
| 127708 | + rc = SQLITE_DONE; | |
| 127306 | 127709 | }else{ |
| 127307 | 127710 | assert( iCurrent<=iMinPos ); |
| 127308 | 127711 | if( 0==(0xFE&*pTerm->pList) ){ |
| 127309 | 127712 | pTerm->pList = 0; |
| 127310 | 127713 | }else{ |
| @@ -127317,11 +127720,11 @@ | ||
| 127317 | 127720 | char aBuffer[64]; |
| 127318 | 127721 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 127319 | 127722 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 127320 | 127723 | ); |
| 127321 | 127724 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 127322 | - }else if( rc==SQLITE_DONE ){ | |
| 127725 | + }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ | |
| 127323 | 127726 | rc = FTS_CORRUPT_VTAB; |
| 127324 | 127727 | } |
| 127325 | 127728 | } |
| 127326 | 127729 | } |
| 127327 | 127730 | if( rc==SQLITE_DONE ){ |
| 127328 | 127731 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -656,11 +656,11 @@ | |
| 656 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 657 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 658 | */ |
| 659 | #define SQLITE_VERSION "3.7.9" |
| 660 | #define SQLITE_VERSION_NUMBER 3007009 |
| 661 | #define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe" |
| 662 | |
| 663 | /* |
| 664 | ** CAPI3REF: Run-Time Library Version Numbers |
| 665 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 666 | ** |
| @@ -1951,12 +1951,12 @@ | |
| 1951 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1952 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1953 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1954 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1955 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1956 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1957 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1958 | ** |
| 1959 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1960 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1961 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1962 | ** alternative low-level mutex routines to be used in place |
| @@ -20969,11 +20969,11 @@ | |
| 20969 | }else if( *z=='+' ){ |
| 20970 | z+=incr; |
| 20971 | } |
| 20972 | /* copy digits to exponent */ |
| 20973 | while( z<zEnd && sqlite3Isdigit(*z) ){ |
| 20974 | e = e*10 + (*z - '0'); |
| 20975 | z+=incr; |
| 20976 | eValid = 1; |
| 20977 | } |
| 20978 | } |
| 20979 | |
| @@ -21020,10 +21020,16 @@ | |
| 21020 | result /= 1.0e+308; |
| 21021 | }else{ |
| 21022 | result = s * scale; |
| 21023 | result *= 1.0e+308; |
| 21024 | } |
| 21025 | }else{ |
| 21026 | /* 1.0e+22 is the largest power of 10 than can be |
| 21027 | ** represented exactly. */ |
| 21028 | while( e%22 ) { scale *= 1.0e+1; e -= 1; } |
| 21029 | while( e>0 ) { scale *= 1.0e+22; e -= 22; } |
| @@ -68962,11 +68968,11 @@ | |
| 68962 | |
| 68963 | /* Do not allow a transition to journal_mode=WAL for a database |
| 68964 | ** in temporary storage or if the VFS does not support shared memory |
| 68965 | */ |
| 68966 | if( u.ch.eNew==PAGER_JOURNALMODE_WAL |
| 68967 | && (u.ch.zFilename[0]==0 /* Temp file */ |
| 68968 | || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */ |
| 68969 | ){ |
| 68970 | u.ch.eNew = u.ch.eOld; |
| 68971 | } |
| 68972 | |
| @@ -69397,14 +69403,19 @@ | |
| 69397 | u.co.pName = &aMem[pOp->p1]; |
| 69398 | assert( u.co.pVtab->pModule->xRename ); |
| 69399 | assert( memIsValid(u.co.pName) ); |
| 69400 | REGISTER_TRACE(pOp->p1, u.co.pName); |
| 69401 | assert( u.co.pName->flags & MEM_Str ); |
| 69402 | rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z); |
| 69403 | importVtabErrMsg(p, u.co.pVtab); |
| 69404 | p->expired = 0; |
| 69405 | |
| 69406 | break; |
| 69407 | } |
| 69408 | #endif |
| 69409 | |
| 69410 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| @@ -71758,10 +71769,28 @@ | |
| 71758 | ExprSetProperty(pExpr, EP_Static); |
| 71759 | sqlite3ExprDelete(db, pExpr); |
| 71760 | memcpy(pExpr, pDup, sizeof(*pExpr)); |
| 71761 | sqlite3DbFree(db, pDup); |
| 71762 | } |
| 71763 | |
| 71764 | /* |
| 71765 | ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up |
| 71766 | ** that name in the set of source tables in pSrcList and make the pExpr |
| 71767 | ** expression node refer back to that source column. The following changes |
| @@ -71850,38 +71879,25 @@ | |
| 71850 | pSchema = pTab->pSchema; |
| 71851 | pMatch = pItem; |
| 71852 | } |
| 71853 | for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ |
| 71854 | if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ |
| 71855 | IdList *pUsing; |
| 71856 | cnt++; |
| 71857 | pExpr->iTable = pItem->iCursor; |
| 71858 | pExpr->pTab = pTab; |
| 71859 | pMatch = pItem; |
| 71860 | pSchema = pTab->pSchema; |
| 71861 | /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ |
| 71862 | pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; |
| 71863 | if( i<pSrcList->nSrc-1 ){ |
| 71864 | if( pItem[1].jointype & JT_NATURAL ){ |
| 71865 | /* If this match occurred in the left table of a natural join, |
| 71866 | ** then skip the right table to avoid a duplicate match */ |
| 71867 | pItem++; |
| 71868 | i++; |
| 71869 | }else if( (pUsing = pItem[1].pUsing)!=0 ){ |
| 71870 | /* If this match occurs on a column that is in the USING clause |
| 71871 | ** of a join, skip the search of the right table of the join |
| 71872 | ** to avoid a duplicate match there. */ |
| 71873 | int k; |
| 71874 | for(k=0; k<pUsing->nId; k++){ |
| 71875 | if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){ |
| 71876 | pItem++; |
| 71877 | i++; |
| 71878 | break; |
| 71879 | } |
| 71880 | } |
| 71881 | } |
| 71882 | } |
| 71883 | break; |
| 71884 | } |
| 71885 | } |
| 71886 | } |
| 71887 | } |
| @@ -102501,10 +102517,11 @@ | |
| 102501 | tempWC.pParse = pWC->pParse; |
| 102502 | tempWC.pMaskSet = pWC->pMaskSet; |
| 102503 | tempWC.pOuter = pWC; |
| 102504 | tempWC.op = TK_AND; |
| 102505 | tempWC.a = pOrTerm; |
| 102506 | tempWC.nTerm = 1; |
| 102507 | bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); |
| 102508 | }else{ |
| 102509 | continue; |
| 102510 | } |
| @@ -114528,10 +114545,11 @@ | |
| 114528 | const char *zDb; /* logical database name */ |
| 114529 | const char *zName; /* virtual table name */ |
| 114530 | int nColumn; /* number of named columns in virtual table */ |
| 114531 | char **azColumn; /* column names. malloced */ |
| 114532 | sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ |
| 114533 | |
| 114534 | /* Precompiled statements used by the implementation. Each of these |
| 114535 | ** statements is run and reset within a single virtual table API call. |
| 114536 | */ |
| 114537 | sqlite3_stmt *aStmt[27]; |
| @@ -114568,11 +114586,11 @@ | |
| 114568 | } *aIndex; |
| 114569 | int nMaxPendingData; /* Max pending data before flush to disk */ |
| 114570 | int nPendingData; /* Current bytes of pending data */ |
| 114571 | sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ |
| 114572 | |
| 114573 | #if defined(SQLITE_DEBUG) |
| 114574 | /* State variables used for validating that the transaction control |
| 114575 | ** methods of the virtual table are called at appropriate times. These |
| 114576 | ** values do not contribution to the FTS computation; they are used for |
| 114577 | ** verifying the SQLite core. |
| 114578 | */ |
| @@ -114653,10 +114671,11 @@ | |
| 114653 | */ |
| 114654 | struct Fts3PhraseToken { |
| 114655 | char *z; /* Text of the token */ |
| 114656 | int n; /* Number of bytes in buffer z */ |
| 114657 | int isPrefix; /* True if token ends with a "*" character */ |
| 114658 | |
| 114659 | /* Variables above this point are populated when the expression is |
| 114660 | ** parsed (by code in fts3_expr.c). Below this point the variables are |
| 114661 | ** used when evaluating the expression. */ |
| 114662 | Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ |
| @@ -114771,10 +114790,11 @@ | |
| 114771 | #define FTS3_SEGMENT_REQUIRE_POS 0x00000001 |
| 114772 | #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 |
| 114773 | #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 |
| 114774 | #define FTS3_SEGMENT_PREFIX 0x00000008 |
| 114775 | #define FTS3_SEGMENT_SCAN 0x00000010 |
| 114776 | |
| 114777 | /* Type passed as 4th argument to SegmentReaderIterate() */ |
| 114778 | struct Fts3SegFilter { |
| 114779 | const char *zTerm; |
| 114780 | int nTerm; |
| @@ -114810,12 +114830,12 @@ | |
| 114810 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 114811 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 114812 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 114813 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 114814 | SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); |
| 114815 | |
| 114816 | SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); |
| 114817 | |
| 114818 | /* fts3_tokenizer.c */ |
| 114819 | SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); |
| 114820 | SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); |
| 114821 | SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, |
| @@ -114830,11 +114850,11 @@ | |
| 114830 | ); |
| 114831 | SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); |
| 114832 | |
| 114833 | /* fts3_expr.c */ |
| 114834 | SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, |
| 114835 | char **, int, int, const char *, int, Fts3Expr ** |
| 114836 | ); |
| 114837 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 114838 | #ifdef SQLITE_TEST |
| 114839 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 114840 | SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); |
| @@ -115031,10 +115051,11 @@ | |
| 115031 | sqlite3_finalize(p->aStmt[i]); |
| 115032 | } |
| 115033 | sqlite3_free(p->zSegmentsTbl); |
| 115034 | sqlite3_free(p->zReadExprlist); |
| 115035 | sqlite3_free(p->zWriteExprlist); |
| 115036 | |
| 115037 | /* Invoke the tokenizer destructor to free the tokenizer. */ |
| 115038 | p->pTokenizer->pModule->xDestroy(p->pTokenizer); |
| 115039 | |
| 115040 | sqlite3_free(p); |
| @@ -115070,20 +115091,23 @@ | |
| 115070 | |
| 115071 | /* |
| 115072 | ** The xDestroy() virtual table method. |
| 115073 | */ |
| 115074 | static int fts3DestroyMethod(sqlite3_vtab *pVtab){ |
| 115075 | int rc = SQLITE_OK; /* Return code */ |
| 115076 | Fts3Table *p = (Fts3Table *)pVtab; |
| 115077 | sqlite3 *db = p->db; |
| 115078 | |
| 115079 | /* Drop the shadow tables */ |
| 115080 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName); |
| 115081 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName); |
| 115082 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName); |
| 115083 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName); |
| 115084 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName); |
| 115085 | |
| 115086 | /* If everything has worked, invoke fts3DisconnectMethod() to free the |
| 115087 | ** memory associated with the Fts3Table structure and return SQLITE_OK. |
| 115088 | ** Otherwise, return an SQLite error code. |
| 115089 | */ |
| @@ -115141,27 +115165,31 @@ | |
| 115141 | ** %_stat tables required by FTS4. |
| 115142 | */ |
| 115143 | static int fts3CreateTables(Fts3Table *p){ |
| 115144 | int rc = SQLITE_OK; /* Return code */ |
| 115145 | int i; /* Iterator variable */ |
| 115146 | char *zContentCols; /* Columns of %_content table */ |
| 115147 | sqlite3 *db = p->db; /* The database connection */ |
| 115148 | |
| 115149 | /* Create a list of user columns for the content table */ |
| 115150 | zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); |
| 115151 | for(i=0; zContentCols && i<p->nColumn; i++){ |
| 115152 | char *z = p->azColumn[i]; |
| 115153 | zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); |
| 115154 | } |
| 115155 | if( zContentCols==0 ) rc = SQLITE_NOMEM; |
| 115156 | |
| 115157 | /* Create the content table */ |
| 115158 | fts3DbExec(&rc, db, |
| 115159 | "CREATE TABLE %Q.'%q_content'(%s)", |
| 115160 | p->zDb, p->zName, zContentCols |
| 115161 | ); |
| 115162 | sqlite3_free(zContentCols); |
| 115163 | /* Create other tables */ |
| 115164 | fts3DbExec(&rc, db, |
| 115165 | "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", |
| 115166 | p->zDb, p->zName |
| 115167 | ); |
| @@ -115308,12 +115336,12 @@ | |
| 115308 | } |
| 115309 | return zRet; |
| 115310 | } |
| 115311 | |
| 115312 | /* |
| 115313 | ** Return a list of comma separated SQL expressions that could be used |
| 115314 | ** in a SELECT statement such as the following: |
| 115315 | ** |
| 115316 | ** SELECT <list of expressions> FROM %_content AS x ... |
| 115317 | ** |
| 115318 | ** to return the docid, followed by each column of text data in order |
| 115319 | ** from left to write. If parameter zFunc is not NULL, then instead of |
| @@ -115320,11 +115348,11 @@ | |
| 115320 | ** being returned directly each column of text data is passed to an SQL |
| 115321 | ** function named zFunc first. For example, if zFunc is "unzip" and the |
| 115322 | ** table has the three user-defined columns "a", "b", and "c", the following |
| 115323 | ** string is returned: |
| 115324 | ** |
| 115325 | ** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')" |
| 115326 | ** |
| 115327 | ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It |
| 115328 | ** is the responsibility of the caller to eventually free it. |
| 115329 | ** |
| 115330 | ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and |
| @@ -115336,20 +115364,32 @@ | |
| 115336 | char *zRet = 0; |
| 115337 | char *zFree = 0; |
| 115338 | char *zFunction; |
| 115339 | int i; |
| 115340 | |
| 115341 | if( !zFunc ){ |
| 115342 | zFunction = ""; |
| 115343 | }else{ |
| 115344 | zFree = zFunction = fts3QuoteId(zFunc); |
| 115345 | } |
| 115346 | fts3Appendf(pRc, &zRet, "docid"); |
| 115347 | for(i=0; i<p->nColumn; i++){ |
| 115348 | fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); |
| 115349 | } |
| 115350 | sqlite3_free(zFree); |
| 115351 | return zRet; |
| 115352 | } |
| 115353 | |
| 115354 | /* |
| 115355 | ** Return a list of N comma separated question marks, where N is the number |
| @@ -115468,10 +115508,95 @@ | |
| 115468 | } |
| 115469 | } |
| 115470 | |
| 115471 | return SQLITE_OK; |
| 115472 | } |
| 115473 | |
| 115474 | /* |
| 115475 | ** This function is the implementation of both the xConnect and xCreate |
| 115476 | ** methods of the FTS3 virtual table. |
| 115477 | ** |
| @@ -115513,10 +115638,11 @@ | |
| 115513 | int bNoDocsize = 0; /* True to omit %_docsize table */ |
| 115514 | int bDescIdx = 0; /* True to store descending indexes */ |
| 115515 | char *zPrefix = 0; /* Prefix parameter value (or NULL) */ |
| 115516 | char *zCompress = 0; /* compress=? parameter (or NULL) */ |
| 115517 | char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ |
| 115518 | |
| 115519 | assert( strlen(argv[0])==4 ); |
| 115520 | assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) |
| 115521 | || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) |
| 115522 | ); |
| @@ -115556,17 +115682,17 @@ | |
| 115556 | /* Check if it is an FTS4 special argument. */ |
| 115557 | else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ |
| 115558 | struct Fts4Option { |
| 115559 | const char *zOpt; |
| 115560 | int nOpt; |
| 115561 | char **pzVar; |
| 115562 | } aFts4Opt[] = { |
| 115563 | { "matchinfo", 9, 0 }, /* 0 -> MATCHINFO */ |
| 115564 | { "prefix", 6, 0 }, /* 1 -> PREFIX */ |
| 115565 | { "compress", 8, 0 }, /* 2 -> COMPRESS */ |
| 115566 | { "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */ |
| 115567 | { "order", 5, 0 } /* 4 -> ORDER */ |
| 115568 | }; |
| 115569 | |
| 115570 | int iOpt; |
| 115571 | if( !zVal ){ |
| 115572 | rc = SQLITE_NOMEM; |
| @@ -115608,17 +115734,24 @@ | |
| 115608 | zVal = 0; |
| 115609 | break; |
| 115610 | |
| 115611 | case 4: /* ORDER */ |
| 115612 | if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) |
| 115613 | && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3)) |
| 115614 | ){ |
| 115615 | *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal); |
| 115616 | rc = SQLITE_ERROR; |
| 115617 | } |
| 115618 | bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); |
| 115619 | break; |
| 115620 | } |
| 115621 | } |
| 115622 | sqlite3_free(zVal); |
| 115623 | } |
| 115624 | } |
| @@ -115627,10 +115760,30 @@ | |
| 115627 | else { |
| 115628 | nString += (int)(strlen(z) + 1); |
| 115629 | aCol[nCol++] = z; |
| 115630 | } |
| 115631 | } |
| 115632 | if( rc!=SQLITE_OK ) goto fts3_init_out; |
| 115633 | |
| 115634 | if( nCol==0 ){ |
| 115635 | assert( nString==0 ); |
| 115636 | aCol[0] = "content"; |
| @@ -115671,10 +115824,12 @@ | |
| 115671 | p->pTokenizer = pTokenizer; |
| 115672 | p->nMaxPendingData = FTS3_MAX_PENDING_DATA; |
| 115673 | p->bHasDocsize = (isFts4 && bNoDocsize==0); |
| 115674 | p->bHasStat = isFts4; |
| 115675 | p->bDescIdx = bDescIdx; |
| 115676 | TESTONLY( p->inTransaction = -1 ); |
| 115677 | TESTONLY( p->mxSavepoint = -1 ); |
| 115678 | |
| 115679 | p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; |
| 115680 | memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); |
| @@ -115732,10 +115887,11 @@ | |
| 115732 | fts3_init_out: |
| 115733 | sqlite3_free(zPrefix); |
| 115734 | sqlite3_free(aIndex); |
| 115735 | sqlite3_free(zCompress); |
| 115736 | sqlite3_free(zUncompress); |
| 115737 | sqlite3_free((void *)aCol); |
| 115738 | if( rc!=SQLITE_OK ){ |
| 115739 | if( p ){ |
| 115740 | fts3DisconnectMethod((sqlite3_vtab *)p); |
| 115741 | }else if( pTokenizer ){ |
| @@ -115882,40 +116038,69 @@ | |
| 115882 | sqlite3_free(pCsr->aMatchinfo); |
| 115883 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| 115884 | sqlite3_free(pCsr); |
| 115885 | return SQLITE_OK; |
| 115886 | } |
| 115887 | |
| 115888 | /* |
| 115889 | ** Position the pCsr->pStmt statement so that it is on the row |
| 115890 | ** of the %_content table that contains the last match. Return |
| 115891 | ** SQLITE_OK on success. |
| 115892 | */ |
| 115893 | static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ |
| 115894 | if( pCsr->isRequireSeek ){ |
| 115895 | sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); |
| 115896 | pCsr->isRequireSeek = 0; |
| 115897 | if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ |
| 115898 | return SQLITE_OK; |
| 115899 | }else{ |
| 115900 | int rc = sqlite3_reset(pCsr->pStmt); |
| 115901 | if( rc==SQLITE_OK ){ |
| 115902 | /* If no row was found and no error has occured, then the %_content |
| 115903 | ** table is missing a row that is present in the full-text index. |
| 115904 | ** The data structures are corrupt. |
| 115905 | */ |
| 115906 | rc = FTS_CORRUPT_VTAB; |
| 115907 | } |
| 115908 | pCsr->isEof = 1; |
| 115909 | if( pContext ){ |
| 115910 | sqlite3_result_error_code(pContext, rc); |
| 115911 | } |
| 115912 | return rc; |
| 115913 | } |
| 115914 | }else{ |
| 115915 | return SQLITE_OK; |
| 115916 | } |
| 115917 | } |
| 115918 | |
| 115919 | /* |
| 115920 | ** This function is used to process a single interior node when searching |
| 115921 | ** a b-tree for a term or term prefix. The node data is passed to this |
| @@ -116351,20 +116536,20 @@ | |
| 116351 | int isSaveLeft, /* Save the left position */ |
| 116352 | int isExact, /* If *pp1 is exactly nTokens before *pp2 */ |
| 116353 | char **pp1, /* IN/OUT: Left input list */ |
| 116354 | char **pp2 /* IN/OUT: Right input list */ |
| 116355 | ){ |
| 116356 | char *p = (pp ? *pp : 0); |
| 116357 | char *p1 = *pp1; |
| 116358 | char *p2 = *pp2; |
| 116359 | int iCol1 = 0; |
| 116360 | int iCol2 = 0; |
| 116361 | |
| 116362 | /* Never set both isSaveLeft and isExact for the same invocation. */ |
| 116363 | assert( isSaveLeft==0 || isExact==0 ); |
| 116364 | |
| 116365 | assert( *p1!=0 && *p2!=0 ); |
| 116366 | if( *p1==POS_COLUMN ){ |
| 116367 | p1++; |
| 116368 | p1 += sqlite3Fts3GetVarint32(p1, &iCol1); |
| 116369 | } |
| 116370 | if( *p2==POS_COLUMN ){ |
| @@ -116377,11 +116562,11 @@ | |
| 116377 | char *pSave = p; |
| 116378 | sqlite3_int64 iPrev = 0; |
| 116379 | sqlite3_int64 iPos1 = 0; |
| 116380 | sqlite3_int64 iPos2 = 0; |
| 116381 | |
| 116382 | if( pp && iCol1 ){ |
| 116383 | *p++ = POS_COLUMN; |
| 116384 | p += sqlite3Fts3PutVarint(p, iCol1); |
| 116385 | } |
| 116386 | |
| 116387 | assert( *p1!=POS_END && *p1!=POS_COLUMN ); |
| @@ -116392,20 +116577,14 @@ | |
| 116392 | while( 1 ){ |
| 116393 | if( iPos2==iPos1+nToken |
| 116394 | || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) |
| 116395 | ){ |
| 116396 | sqlite3_int64 iSave; |
| 116397 | if( !pp ){ |
| 116398 | fts3PoslistCopy(0, &p2); |
| 116399 | fts3PoslistCopy(0, &p1); |
| 116400 | *pp1 = p1; |
| 116401 | *pp2 = p2; |
| 116402 | return 1; |
| 116403 | } |
| 116404 | iSave = isSaveLeft ? iPos1 : iPos2; |
| 116405 | fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; |
| 116406 | pSave = 0; |
| 116407 | } |
| 116408 | if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ |
| 116409 | if( (*p2&0xFE)==0 ) break; |
| 116410 | fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; |
| 116411 | }else{ |
| @@ -116450,11 +116629,11 @@ | |
| 116450 | |
| 116451 | fts3PoslistCopy(0, &p2); |
| 116452 | fts3PoslistCopy(0, &p1); |
| 116453 | *pp1 = p1; |
| 116454 | *pp2 = p2; |
| 116455 | if( !pp || *pp==p ){ |
| 116456 | return 0; |
| 116457 | } |
| 116458 | *p++ = 0x00; |
| 116459 | *pp = p; |
| 116460 | return 1; |
| @@ -116752,10 +116931,60 @@ | |
| 116752 | } |
| 116753 | } |
| 116754 | |
| 116755 | *pnRight = p - aOut; |
| 116756 | } |
| 116757 | |
| 116758 | |
| 116759 | /* |
| 116760 | ** Merge all doclists in the TermSelect.aaOutput[] array into a single |
| 116761 | ** doclist stored in TermSelect.aaOutput[0]. If successful, delete all |
| @@ -117109,10 +117338,11 @@ | |
| 117109 | pSegcsr = pTok->pSegcsr; |
| 117110 | memset(&tsc, 0, sizeof(TermSelect)); |
| 117111 | |
| 117112 | filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS |
| 117113 | | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) |
| 117114 | | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); |
| 117115 | filter.iCol = iColumn; |
| 117116 | filter.zTerm = pTok->z; |
| 117117 | filter.nTerm = pTok->n; |
| 117118 | |
| @@ -117249,12 +117479,12 @@ | |
| 117249 | |
| 117250 | if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 117251 | return SQLITE_NOMEM; |
| 117252 | } |
| 117253 | |
| 117254 | rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn, |
| 117255 | iCol, zQuery, -1, &pCsr->pExpr |
| 117256 | ); |
| 117257 | if( rc!=SQLITE_OK ){ |
| 117258 | if( rc==SQLITE_ERROR ){ |
| 117259 | static const char *zErr = "malformed MATCH expression: [%s]"; |
| 117260 | p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery); |
| @@ -117277,26 +117507,27 @@ | |
| 117277 | ** statement loops through all rows of the %_content table. For a |
| 117278 | ** full-text query or docid lookup, the statement retrieves a single |
| 117279 | ** row by docid. |
| 117280 | */ |
| 117281 | if( idxNum==FTS3_FULLSCAN_SEARCH ){ |
| 117282 | const char *zSort = (pCsr->bDesc ? "DESC" : "ASC"); |
| 117283 | const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s"; |
| 117284 | zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort); |
| 117285 | }else{ |
| 117286 | const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?"; |
| 117287 | zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName); |
| 117288 | } |
| 117289 | if( !zSql ) return SQLITE_NOMEM; |
| 117290 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 117291 | sqlite3_free(zSql); |
| 117292 | if( rc!=SQLITE_OK ) return rc; |
| 117293 | |
| 117294 | if( idxNum==FTS3_DOCID_SEARCH ){ |
| 117295 | rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); |
| 117296 | if( rc!=SQLITE_OK ) return rc; |
| 117297 | } |
| 117298 | |
| 117299 | return fts3NextMethod(pCursor); |
| 117300 | } |
| 117301 | |
| 117302 | /* |
| @@ -117345,11 +117576,11 @@ | |
| 117345 | ** Return a blob which is a pointer to the cursor. |
| 117346 | */ |
| 117347 | sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); |
| 117348 | }else{ |
| 117349 | rc = fts3CursorSeek(0, pCsr); |
| 117350 | if( rc==SQLITE_OK ){ |
| 117351 | sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1)); |
| 117352 | } |
| 117353 | } |
| 117354 | |
| 117355 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| @@ -117638,19 +117869,26 @@ | |
| 117638 | ){ |
| 117639 | Fts3Table *p = (Fts3Table *)pVtab; |
| 117640 | sqlite3 *db = p->db; /* Database connection */ |
| 117641 | int rc; /* Return Code */ |
| 117642 | |
| 117643 | rc = sqlite3Fts3PendingTermsFlush(p); |
| 117644 | if( rc!=SQLITE_OK ){ |
| 117645 | return rc; |
| 117646 | } |
| 117647 | |
| 117648 | fts3DbExec(&rc, db, |
| 117649 | "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", |
| 117650 | p->zDb, p->zName, zName |
| 117651 | ); |
| 117652 | if( p->bHasDocsize ){ |
| 117653 | fts3DbExec(&rc, db, |
| 117654 | "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", |
| 117655 | p->zDb, p->zName, zName |
| 117656 | ); |
| @@ -118005,25 +118243,24 @@ | |
| 118005 | ** |
| 118006 | ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. |
| 118007 | */ |
| 118008 | static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ |
| 118009 | int iToken; /* Used to iterate through phrase tokens */ |
| 118010 | int rc = SQLITE_OK; /* Return code */ |
| 118011 | char *aPoslist = 0; /* Position list for deferred tokens */ |
| 118012 | int nPoslist = 0; /* Number of bytes in aPoslist */ |
| 118013 | int iPrev = -1; /* Token number of previous deferred token */ |
| 118014 | |
| 118015 | assert( pPhrase->doclist.bFreeList==0 ); |
| 118016 | |
| 118017 | for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){ |
| 118018 | Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; |
| 118019 | Fts3DeferredToken *pDeferred = pToken->pDeferred; |
| 118020 | |
| 118021 | if( pDeferred ){ |
| 118022 | char *pList; |
| 118023 | int nList; |
| 118024 | rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); |
| 118025 | if( rc!=SQLITE_OK ) return rc; |
| 118026 | |
| 118027 | if( pList==0 ){ |
| 118028 | sqlite3_free(aPoslist); |
| 118029 | pPhrase->doclist.pList = 0; |
| @@ -118120,10 +118357,11 @@ | |
| 118120 | if( pCsr->bDesc==pTab->bDescIdx |
| 118121 | && bOptOk==1 |
| 118122 | && p->nToken==1 |
| 118123 | && pFirst->pSegcsr |
| 118124 | && pFirst->pSegcsr->bLookup |
| 118125 | ){ |
| 118126 | /* Use the incremental approach. */ |
| 118127 | int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); |
| 118128 | rc = sqlite3Fts3MsrIncrStart( |
| 118129 | pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n); |
| @@ -118349,11 +118587,11 @@ | |
| 118349 | Fts3Expr *pExpr, /* Expression to consider */ |
| 118350 | Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ |
| 118351 | Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ |
| 118352 | int *pRc /* IN/OUT: Error code */ |
| 118353 | ){ |
| 118354 | if( *pRc==SQLITE_OK && pExpr ){ |
| 118355 | if( pExpr->eType==FTSQUERY_PHRASE ){ |
| 118356 | Fts3Phrase *pPhrase = pExpr->pPhrase; |
| 118357 | int i; |
| 118358 | for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){ |
| 118359 | Fts3TokenAndCost *pTC = (*ppTC)++; |
| @@ -118363,10 +118601,15 @@ | |
| 118363 | pTC->pToken = &pPhrase->aToken[i]; |
| 118364 | pTC->iCol = pPhrase->iColumn; |
| 118365 | *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); |
| 118366 | } |
| 118367 | }else if( pExpr->eType!=FTSQUERY_NOT ){ |
| 118368 | if( pExpr->eType==FTSQUERY_OR ){ |
| 118369 | pRoot = pExpr->pLeft; |
| 118370 | **ppOr = pRoot; |
| 118371 | (*ppOr)++; |
| 118372 | } |
| @@ -118466,10 +118709,19 @@ | |
| 118466 | int nOvfl = 0; /* Total overflow pages used by doclists */ |
| 118467 | int nToken = 0; /* Total number of tokens in cluster */ |
| 118468 | |
| 118469 | int nMinEst = 0; /* The minimum count for any phrase so far. */ |
| 118470 | int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ |
| 118471 | |
| 118472 | /* Count the tokens in this AND/NEAR cluster. If none of the doclists |
| 118473 | ** associated with the tokens spill onto overflow pages, or if there is |
| 118474 | ** only 1 token, exit early. No tokens to defer in this case. */ |
| 118475 | for(ii=0; ii<nTC; ii++){ |
| @@ -118529,11 +118781,15 @@ | |
| 118529 | Fts3PhraseToken *pToken = pTC->pToken; |
| 118530 | rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); |
| 118531 | fts3SegReaderCursorFree(pToken->pSegcsr); |
| 118532 | pToken->pSegcsr = 0; |
| 118533 | }else{ |
| 118534 | nLoad4 = nLoad4*4; |
| 118535 | if( ii==0 || pTC->pPhrase->nToken>1 ){ |
| 118536 | /* Either this is the cheapest token in the entire query, or it is |
| 118537 | ** part of a multi-token phrase. Either way, the entire doclist will |
| 118538 | ** (eventually) be loaded into memory. It may as well be now. */ |
| 118539 | Fts3PhraseToken *pToken = pTC->pToken; |
| @@ -119990,10 +120246,11 @@ | |
| 119990 | */ |
| 119991 | typedef struct ParseContext ParseContext; |
| 119992 | struct ParseContext { |
| 119993 | sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ |
| 119994 | const char **azCol; /* Array of column names for fts3 table */ |
| 119995 | int nCol; /* Number of entries in azCol[] */ |
| 119996 | int iDefaultCol; /* Default column to query */ |
| 119997 | int isNot; /* True if getNextNode() sees a unary - */ |
| 119998 | sqlite3_context *pCtx; /* Write error message here */ |
| 119999 | int nNest; /* Number of nested brackets */ |
| @@ -120077,13 +120334,25 @@ | |
| 120077 | |
| 120078 | if( iEnd<n && z[iEnd]=='*' ){ |
| 120079 | pRet->pPhrase->aToken[0].isPrefix = 1; |
| 120080 | iEnd++; |
| 120081 | } |
| 120082 | if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){ |
| 120083 | pParse->isNot = 1; |
| 120084 | } |
| 120085 | } |
| 120086 | nConsumed = iEnd; |
| 120087 | } |
| 120088 | |
| 120089 | pModule->xClose(pCursor); |
| @@ -120178,10 +120447,11 @@ | |
| 120178 | memcpy(&zTemp[nTemp], zByte, nByte); |
| 120179 | nTemp += nByte; |
| 120180 | |
| 120181 | pToken->n = nByte; |
| 120182 | pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*'); |
| 120183 | nToken = ii+1; |
| 120184 | } |
| 120185 | } |
| 120186 | |
| 120187 | pModule->xClose(pCursor); |
| @@ -120629,10 +120899,11 @@ | |
| 120629 | ** match any table column. |
| 120630 | */ |
| 120631 | SQLITE_PRIVATE int sqlite3Fts3ExprParse( |
| 120632 | sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ |
| 120633 | char **azCol, /* Array of column names for fts3 table */ |
| 120634 | int nCol, /* Number of entries in azCol[] */ |
| 120635 | int iDefaultCol, /* Default column to query */ |
| 120636 | const char *z, int n, /* Text of MATCH query */ |
| 120637 | Fts3Expr **ppExpr /* OUT: Parsed query structure */ |
| 120638 | ){ |
| @@ -120642,10 +120913,11 @@ | |
| 120642 | sParse.pTokenizer = pTokenizer; |
| 120643 | sParse.azCol = (const char **)azCol; |
| 120644 | sParse.nCol = nCol; |
| 120645 | sParse.iDefaultCol = iDefaultCol; |
| 120646 | sParse.nNest = 0; |
| 120647 | if( z==0 ){ |
| 120648 | *ppExpr = 0; |
| 120649 | return SQLITE_OK; |
| 120650 | } |
| 120651 | if( n<0 ){ |
| @@ -120831,11 +121103,11 @@ | |
| 120831 | for(ii=0; ii<nCol; ii++){ |
| 120832 | azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); |
| 120833 | } |
| 120834 | |
| 120835 | rc = sqlite3Fts3ExprParse( |
| 120836 | pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr |
| 120837 | ); |
| 120838 | if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ |
| 120839 | sqlite3_result_error(context, "Error parsing expression", -1); |
| 120840 | }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ |
| 120841 | sqlite3_result_error_nomem(context); |
| @@ -122878,11 +123150,11 @@ | |
| 122878 | /* 2 */ "DELETE FROM %Q.'%q_content'", |
| 122879 | /* 3 */ "DELETE FROM %Q.'%q_segments'", |
| 122880 | /* 4 */ "DELETE FROM %Q.'%q_segdir'", |
| 122881 | /* 5 */ "DELETE FROM %Q.'%q_docsize'", |
| 122882 | /* 6 */ "DELETE FROM %Q.'%q_stat'", |
| 122883 | /* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?", |
| 122884 | /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", |
| 122885 | /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", |
| 122886 | /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", |
| 122887 | /* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", |
| 122888 | |
| @@ -122920,11 +123192,11 @@ | |
| 122920 | if( !pStmt ){ |
| 122921 | char *zSql; |
| 122922 | if( eStmt==SQL_CONTENT_INSERT ){ |
| 122923 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); |
| 122924 | }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ |
| 122925 | zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName); |
| 122926 | }else{ |
| 122927 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); |
| 122928 | } |
| 122929 | if( !zSql ){ |
| 122930 | rc = SQLITE_NOMEM; |
| @@ -123031,21 +123303,28 @@ | |
| 123031 | ** We try to avoid this because if FTS3 returns any error when committing |
| 123032 | ** a transaction, the whole transaction will be rolled back. And this is |
| 123033 | ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can |
| 123034 | ** still happen if the user reads data directly from the %_segments or |
| 123035 | ** %_segdir tables instead of going through FTS3 though. |
| 123036 | */ |
| 123037 | SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){ |
| 123038 | int rc; /* Return code */ |
| 123039 | sqlite3_stmt *pStmt; /* Statement used to obtain lock */ |
| 123040 | |
| 123041 | rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); |
| 123042 | if( rc==SQLITE_OK ){ |
| 123043 | sqlite3_bind_null(pStmt, 1); |
| 123044 | sqlite3_step(pStmt); |
| 123045 | rc = sqlite3_reset(pStmt); |
| 123046 | } |
| 123047 | return rc; |
| 123048 | } |
| 123049 | |
| 123050 | /* |
| 123051 | ** Set *ppStmt to a statement handle that may be used to iterate through |
| @@ -123401,10 +123680,22 @@ | |
| 123401 | sqlite3_value **apVal, /* Array of values to insert */ |
| 123402 | sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ |
| 123403 | ){ |
| 123404 | int rc; /* Return code */ |
| 123405 | sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ |
| 123406 | |
| 123407 | /* Locate the statement handle used to insert data into the %_content |
| 123408 | ** table. The SQL for this statement is: |
| 123409 | ** |
| 123410 | ** INSERT INTO %_content VALUES(?, ?, ?, ...) |
| @@ -123452,18 +123743,20 @@ | |
| 123452 | |
| 123453 | /* |
| 123454 | ** Remove all data from the FTS3 table. Clear the hash table containing |
| 123455 | ** pending terms. |
| 123456 | */ |
| 123457 | static int fts3DeleteAll(Fts3Table *p){ |
| 123458 | int rc = SQLITE_OK; /* Return code */ |
| 123459 | |
| 123460 | /* Discard the contents of the pending-terms hash table. */ |
| 123461 | sqlite3Fts3PendingTermsClear(p); |
| 123462 | |
| 123463 | /* Delete everything from the %_content, %_segments and %_segdir tables. */ |
| 123464 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); |
| 123465 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); |
| 123466 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); |
| 123467 | if( p->bHasDocsize ){ |
| 123468 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); |
| 123469 | } |
| @@ -124747,16 +125040,22 @@ | |
| 124747 | ** error occurs, an SQLite error code is returned. |
| 124748 | */ |
| 124749 | static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ |
| 124750 | sqlite3_stmt *pStmt; |
| 124751 | int rc; |
| 124752 | rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); |
| 124753 | if( rc==SQLITE_OK ){ |
| 124754 | if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 124755 | *pisEmpty = sqlite3_column_int(pStmt, 0); |
| 124756 | } |
| 124757 | rc = sqlite3_reset(pStmt); |
| 124758 | } |
| 124759 | return rc; |
| 124760 | } |
| 124761 | |
| 124762 | /* |
| @@ -125104,10 +125403,11 @@ | |
| 125104 | int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); |
| 125105 | int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); |
| 125106 | int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); |
| 125107 | int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); |
| 125108 | int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); |
| 125109 | |
| 125110 | Fts3SegReader **apSegment = pCsr->apSegment; |
| 125111 | int nSegment = pCsr->nSegment; |
| 125112 | Fts3SegFilter *pFilter = pCsr->pFilter; |
| 125113 | int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( |
| @@ -125163,10 +125463,11 @@ | |
| 125163 | } |
| 125164 | |
| 125165 | assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); |
| 125166 | if( nMerge==1 |
| 125167 | && !isIgnoreEmpty |
| 125168 | && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) |
| 125169 | ){ |
| 125170 | pCsr->nDoclist = apSegment[0]->nDoclist; |
| 125171 | if( fts3SegReaderIsPending(apSegment[0]) ){ |
| 125172 | rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); |
| @@ -125228,16 +125529,28 @@ | |
| 125228 | if( !aNew ){ |
| 125229 | return SQLITE_NOMEM; |
| 125230 | } |
| 125231 | pCsr->aBuffer = aNew; |
| 125232 | } |
| 125233 | nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); |
| 125234 | iPrev = iDocid; |
| 125235 | if( isRequirePos ){ |
| 125236 | memcpy(&pCsr->aBuffer[nDoclist], pList, nList); |
| 125237 | nDoclist += nList; |
| 125238 | pCsr->aBuffer[nDoclist++] = '\0'; |
| 125239 | } |
| 125240 | } |
| 125241 | |
| 125242 | fts3SegReaderSort(apSegment, nMerge, j, xCmp); |
| 125243 | } |
| @@ -125409,13 +125722,13 @@ | |
| 125409 | ** Insert the sizes (in tokens) for each column of the document |
| 125410 | ** with docid equal to p->iPrevDocid. The sizes are encoded as |
| 125411 | ** a blob of varints. |
| 125412 | */ |
| 125413 | static void fts3InsertDocsize( |
| 125414 | int *pRC, /* Result code */ |
| 125415 | Fts3Table *p, /* Table into which to insert */ |
| 125416 | u32 *aSz /* Sizes of each column */ |
| 125417 | ){ |
| 125418 | char *pBlob; /* The BLOB encoding of the document size */ |
| 125419 | int nBlob; /* Number of bytes in the BLOB */ |
| 125420 | sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ |
| 125421 | int rc; /* Result code from subfunctions */ |
| @@ -125532,10 +125845,90 @@ | |
| 125532 | sqlite3Fts3SegmentsClose(p); |
| 125533 | sqlite3Fts3PendingTermsClear(p); |
| 125534 | |
| 125535 | return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; |
| 125536 | } |
| 125537 | |
| 125538 | /* |
| 125539 | ** Handle a 'special' INSERT of the form: |
| 125540 | ** |
| 125541 | ** "INSERT INTO tbl(tbl) VALUES(<expr>)" |
| @@ -125550,10 +125943,12 @@ | |
| 125550 | |
| 125551 | if( !zVal ){ |
| 125552 | return SQLITE_NOMEM; |
| 125553 | }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ |
| 125554 | rc = fts3DoOptimize(p, 0); |
| 125555 | #ifdef SQLITE_TEST |
| 125556 | }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ |
| 125557 | p->nNodeSize = atoi(&zVal[9]); |
| 125558 | rc = SQLITE_OK; |
| 125559 | }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ |
| @@ -125630,10 +126025,11 @@ | |
| 125630 | pTC->pTokenizer = pT; |
| 125631 | rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); |
| 125632 | for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ |
| 125633 | Fts3PhraseToken *pPT = pDef->pToken; |
| 125634 | if( (pDef->iCol>=p->nColumn || pDef->iCol==i) |
| 125635 | && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken)) |
| 125636 | && (0==memcmp(zToken, pPT->z, pPT->n)) |
| 125637 | ){ |
| 125638 | fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); |
| 125639 | } |
| @@ -125721,18 +126117,22 @@ | |
| 125721 | if( rc==SQLITE_OK ){ |
| 125722 | if( isEmpty ){ |
| 125723 | /* Deleting this row means the whole table is empty. In this case |
| 125724 | ** delete the contents of all three tables and throw away any |
| 125725 | ** data in the pendingTerms hash table. */ |
| 125726 | rc = fts3DeleteAll(p); |
| 125727 | *pnDoc = *pnDoc - 1; |
| 125728 | }else{ |
| 125729 | sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); |
| 125730 | rc = fts3PendingTermsDocid(p, iRemove); |
| 125731 | fts3DeleteTerms(&rc, p, pRowid, aSzDel); |
| 125732 | fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); |
| 125733 | if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; |
| 125734 | if( p->bHasDocsize ){ |
| 125735 | fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); |
| 125736 | } |
| 125737 | } |
| 125738 | } |
| @@ -125788,11 +126188,11 @@ | |
| 125788 | ** should be deleted from the database before inserting the new row. Or, |
| 125789 | ** if the on-conflict mode is other than REPLACE, then this method must |
| 125790 | ** detect the conflict and return SQLITE_CONSTRAINT before beginning to |
| 125791 | ** modify the database file. |
| 125792 | */ |
| 125793 | if( nArg>1 ){ |
| 125794 | /* Find the value object that holds the new rowid value. */ |
| 125795 | sqlite3_value *pNewRowid = apVal[3+p->nColumn]; |
| 125796 | if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ |
| 125797 | pNewRowid = apVal[1]; |
| 125798 | } |
| @@ -125839,11 +126239,13 @@ | |
| 125839 | |
| 125840 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 125841 | if( nArg>1 && rc==SQLITE_OK ){ |
| 125842 | if( bInsertDone==0 ){ |
| 125843 | rc = fts3InsertData(p, apVal, pRowid); |
| 125844 | if( rc==SQLITE_CONSTRAINT ) rc = FTS_CORRUPT_VTAB; |
| 125845 | } |
| 125846 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ |
| 125847 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 125848 | } |
| 125849 | if( rc==SQLITE_OK ){ |
| @@ -126259,10 +126661,11 @@ | |
| 126259 | pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol); |
| 126260 | if( pCsr ){ |
| 126261 | int iFirst = 0; |
| 126262 | pPhrase->pList = pCsr; |
| 126263 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 126264 | pPhrase->pHead = pCsr; |
| 126265 | pPhrase->pTail = pCsr; |
| 126266 | pPhrase->iHead = iFirst; |
| 126267 | pPhrase->iTail = iFirst; |
| 126268 | }else{ |
| @@ -127300,11 +127703,11 @@ | |
| 127300 | } |
| 127301 | } |
| 127302 | |
| 127303 | if( !pTerm ){ |
| 127304 | /* All offsets for this column have been gathered. */ |
| 127305 | break; |
| 127306 | }else{ |
| 127307 | assert( iCurrent<=iMinPos ); |
| 127308 | if( 0==(0xFE&*pTerm->pList) ){ |
| 127309 | pTerm->pList = 0; |
| 127310 | }else{ |
| @@ -127317,11 +127720,11 @@ | |
| 127317 | char aBuffer[64]; |
| 127318 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 127319 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 127320 | ); |
| 127321 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 127322 | }else if( rc==SQLITE_DONE ){ |
| 127323 | rc = FTS_CORRUPT_VTAB; |
| 127324 | } |
| 127325 | } |
| 127326 | } |
| 127327 | if( rc==SQLITE_DONE ){ |
| 127328 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -656,11 +656,11 @@ | |
| 656 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 657 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 658 | */ |
| 659 | #define SQLITE_VERSION "3.7.9" |
| 660 | #define SQLITE_VERSION_NUMBER 3007009 |
| 661 | #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486" |
| 662 | |
| 663 | /* |
| 664 | ** CAPI3REF: Run-Time Library Version Numbers |
| 665 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 666 | ** |
| @@ -1951,12 +1951,12 @@ | |
| 1951 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1952 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1953 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1954 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1955 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1956 | ** The minimum allocation size is capped at 2**12. Reasonable values |
| 1957 | ** for the minimum allocation size are 2**5 through 2**8.</dd> |
| 1958 | ** |
| 1959 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1960 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1961 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1962 | ** alternative low-level mutex routines to be used in place |
| @@ -20969,11 +20969,11 @@ | |
| 20969 | }else if( *z=='+' ){ |
| 20970 | z+=incr; |
| 20971 | } |
| 20972 | /* copy digits to exponent */ |
| 20973 | while( z<zEnd && sqlite3Isdigit(*z) ){ |
| 20974 | e = e<10000 ? (e*10 + (*z - '0')) : 10000; |
| 20975 | z+=incr; |
| 20976 | eValid = 1; |
| 20977 | } |
| 20978 | } |
| 20979 | |
| @@ -21020,10 +21020,16 @@ | |
| 21020 | result /= 1.0e+308; |
| 21021 | }else{ |
| 21022 | result = s * scale; |
| 21023 | result *= 1.0e+308; |
| 21024 | } |
| 21025 | }else if( e>=342 ){ |
| 21026 | if( esign<0 ){ |
| 21027 | result = 0.0*s; |
| 21028 | }else{ |
| 21029 | result = 1e308*1e308*s; /* Infinity */ |
| 21030 | } |
| 21031 | }else{ |
| 21032 | /* 1.0e+22 is the largest power of 10 than can be |
| 21033 | ** represented exactly. */ |
| 21034 | while( e%22 ) { scale *= 1.0e+1; e -= 1; } |
| 21035 | while( e>0 ) { scale *= 1.0e+22; e -= 22; } |
| @@ -68962,11 +68968,11 @@ | |
| 68968 | |
| 68969 | /* Do not allow a transition to journal_mode=WAL for a database |
| 68970 | ** in temporary storage or if the VFS does not support shared memory |
| 68971 | */ |
| 68972 | if( u.ch.eNew==PAGER_JOURNALMODE_WAL |
| 68973 | && (sqlite3Strlen30(u.ch.zFilename)==0 /* Temp file */ |
| 68974 | || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */ |
| 68975 | ){ |
| 68976 | u.ch.eNew = u.ch.eOld; |
| 68977 | } |
| 68978 | |
| @@ -69397,14 +69403,19 @@ | |
| 69403 | u.co.pName = &aMem[pOp->p1]; |
| 69404 | assert( u.co.pVtab->pModule->xRename ); |
| 69405 | assert( memIsValid(u.co.pName) ); |
| 69406 | REGISTER_TRACE(pOp->p1, u.co.pName); |
| 69407 | assert( u.co.pName->flags & MEM_Str ); |
| 69408 | testcase( u.co.pName->enc==SQLITE_UTF8 ); |
| 69409 | testcase( u.co.pName->enc==SQLITE_UTF16BE ); |
| 69410 | testcase( u.co.pName->enc==SQLITE_UTF16LE ); |
| 69411 | rc = sqlite3VdbeChangeEncoding(u.co.pName, SQLITE_UTF8); |
| 69412 | if( rc==SQLITE_OK ){ |
| 69413 | rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z); |
| 69414 | importVtabErrMsg(p, u.co.pVtab); |
| 69415 | p->expired = 0; |
| 69416 | } |
| 69417 | break; |
| 69418 | } |
| 69419 | #endif |
| 69420 | |
| 69421 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| @@ -71758,10 +71769,28 @@ | |
| 71769 | ExprSetProperty(pExpr, EP_Static); |
| 71770 | sqlite3ExprDelete(db, pExpr); |
| 71771 | memcpy(pExpr, pDup, sizeof(*pExpr)); |
| 71772 | sqlite3DbFree(db, pDup); |
| 71773 | } |
| 71774 | |
| 71775 | |
| 71776 | /* |
| 71777 | ** Return TRUE if the name zCol occurs anywhere in the USING clause. |
| 71778 | ** |
| 71779 | ** Return FALSE if the USING clause is NULL or if it does not contain |
| 71780 | ** zCol. |
| 71781 | */ |
| 71782 | static int nameInUsingClause(IdList *pUsing, const char *zCol){ |
| 71783 | if( pUsing ){ |
| 71784 | int k; |
| 71785 | for(k=0; k<pUsing->nId; k++){ |
| 71786 | if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; |
| 71787 | } |
| 71788 | } |
| 71789 | return 0; |
| 71790 | } |
| 71791 | |
| 71792 | |
| 71793 | /* |
| 71794 | ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up |
| 71795 | ** that name in the set of source tables in pSrcList and make the pExpr |
| 71796 | ** expression node refer back to that source column. The following changes |
| @@ -71850,38 +71879,25 @@ | |
| 71879 | pSchema = pTab->pSchema; |
| 71880 | pMatch = pItem; |
| 71881 | } |
| 71882 | for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ |
| 71883 | if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ |
| 71884 | /* If there has been exactly one prior match and this match |
| 71885 | ** is for the right-hand table of a NATURAL JOIN or is in a |
| 71886 | ** USING clause, then skip this match. |
| 71887 | */ |
| 71888 | if( cnt==1 ){ |
| 71889 | if( pItem->jointype & JT_NATURAL ) continue; |
| 71890 | if( nameInUsingClause(pItem->pUsing, zCol) ) continue; |
| 71891 | } |
| 71892 | cnt++; |
| 71893 | pExpr->iTable = pItem->iCursor; |
| 71894 | pExpr->pTab = pTab; |
| 71895 | pMatch = pItem; |
| 71896 | pSchema = pTab->pSchema; |
| 71897 | /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ |
| 71898 | pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; |
| 71899 | break; |
| 71900 | } |
| 71901 | } |
| 71902 | } |
| 71903 | } |
| @@ -102501,10 +102517,11 @@ | |
| 102517 | tempWC.pParse = pWC->pParse; |
| 102518 | tempWC.pMaskSet = pWC->pMaskSet; |
| 102519 | tempWC.pOuter = pWC; |
| 102520 | tempWC.op = TK_AND; |
| 102521 | tempWC.a = pOrTerm; |
| 102522 | tempWC.wctrlFlags = 0; |
| 102523 | tempWC.nTerm = 1; |
| 102524 | bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); |
| 102525 | }else{ |
| 102526 | continue; |
| 102527 | } |
| @@ -114528,10 +114545,11 @@ | |
| 114545 | const char *zDb; /* logical database name */ |
| 114546 | const char *zName; /* virtual table name */ |
| 114547 | int nColumn; /* number of named columns in virtual table */ |
| 114548 | char **azColumn; /* column names. malloced */ |
| 114549 | sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ |
| 114550 | char *zContentTbl; /* content=xxx option, or NULL */ |
| 114551 | |
| 114552 | /* Precompiled statements used by the implementation. Each of these |
| 114553 | ** statements is run and reset within a single virtual table API call. |
| 114554 | */ |
| 114555 | sqlite3_stmt *aStmt[27]; |
| @@ -114568,11 +114586,11 @@ | |
| 114586 | } *aIndex; |
| 114587 | int nMaxPendingData; /* Max pending data before flush to disk */ |
| 114588 | int nPendingData; /* Current bytes of pending data */ |
| 114589 | sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */ |
| 114590 | |
| 114591 | #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) |
| 114592 | /* State variables used for validating that the transaction control |
| 114593 | ** methods of the virtual table are called at appropriate times. These |
| 114594 | ** values do not contribution to the FTS computation; they are used for |
| 114595 | ** verifying the SQLite core. |
| 114596 | */ |
| @@ -114653,10 +114671,11 @@ | |
| 114671 | */ |
| 114672 | struct Fts3PhraseToken { |
| 114673 | char *z; /* Text of the token */ |
| 114674 | int n; /* Number of bytes in buffer z */ |
| 114675 | int isPrefix; /* True if token ends with a "*" character */ |
| 114676 | int bFirst; /* True if token must appear at position 0 */ |
| 114677 | |
| 114678 | /* Variables above this point are populated when the expression is |
| 114679 | ** parsed (by code in fts3_expr.c). Below this point the variables are |
| 114680 | ** used when evaluating the expression. */ |
| 114681 | Fts3DeferredToken *pDeferred; /* Deferred token object for this token */ |
| @@ -114771,10 +114790,11 @@ | |
| 114790 | #define FTS3_SEGMENT_REQUIRE_POS 0x00000001 |
| 114791 | #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002 |
| 114792 | #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004 |
| 114793 | #define FTS3_SEGMENT_PREFIX 0x00000008 |
| 114794 | #define FTS3_SEGMENT_SCAN 0x00000010 |
| 114795 | #define FTS3_SEGMENT_FIRST 0x00000020 |
| 114796 | |
| 114797 | /* Type passed as 4th argument to SegmentReaderIterate() */ |
| 114798 | struct Fts3SegFilter { |
| 114799 | const char *zTerm; |
| 114800 | int nTerm; |
| @@ -114810,12 +114830,12 @@ | |
| 114830 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 114831 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 114832 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 114833 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 114834 | SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*); |
| 114835 | SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *); |
| 114836 | SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *); |
| 114837 | |
| 114838 | /* fts3_tokenizer.c */ |
| 114839 | SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *); |
| 114840 | SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *); |
| 114841 | SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *, |
| @@ -114830,11 +114850,11 @@ | |
| 114850 | ); |
| 114851 | SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *); |
| 114852 | |
| 114853 | /* fts3_expr.c */ |
| 114854 | SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, |
| 114855 | char **, int, int, int, const char *, int, Fts3Expr ** |
| 114856 | ); |
| 114857 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 114858 | #ifdef SQLITE_TEST |
| 114859 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 114860 | SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); |
| @@ -115031,10 +115051,11 @@ | |
| 115051 | sqlite3_finalize(p->aStmt[i]); |
| 115052 | } |
| 115053 | sqlite3_free(p->zSegmentsTbl); |
| 115054 | sqlite3_free(p->zReadExprlist); |
| 115055 | sqlite3_free(p->zWriteExprlist); |
| 115056 | sqlite3_free(p->zContentTbl); |
| 115057 | |
| 115058 | /* Invoke the tokenizer destructor to free the tokenizer. */ |
| 115059 | p->pTokenizer->pModule->xDestroy(p->pTokenizer); |
| 115060 | |
| 115061 | sqlite3_free(p); |
| @@ -115070,20 +115091,23 @@ | |
| 115091 | |
| 115092 | /* |
| 115093 | ** The xDestroy() virtual table method. |
| 115094 | */ |
| 115095 | static int fts3DestroyMethod(sqlite3_vtab *pVtab){ |
| 115096 | Fts3Table *p = (Fts3Table *)pVtab; |
| 115097 | int rc = SQLITE_OK; /* Return code */ |
| 115098 | const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */ |
| 115099 | sqlite3 *db = p->db; /* Database handle */ |
| 115100 | |
| 115101 | /* Drop the shadow tables */ |
| 115102 | if( p->zContentTbl==0 ){ |
| 115103 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName); |
| 115104 | } |
| 115105 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName); |
| 115106 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName); |
| 115107 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName); |
| 115108 | fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName); |
| 115109 | |
| 115110 | /* If everything has worked, invoke fts3DisconnectMethod() to free the |
| 115111 | ** memory associated with the Fts3Table structure and return SQLITE_OK. |
| 115112 | ** Otherwise, return an SQLite error code. |
| 115113 | */ |
| @@ -115141,27 +115165,31 @@ | |
| 115165 | ** %_stat tables required by FTS4. |
| 115166 | */ |
| 115167 | static int fts3CreateTables(Fts3Table *p){ |
| 115168 | int rc = SQLITE_OK; /* Return code */ |
| 115169 | int i; /* Iterator variable */ |
| 115170 | sqlite3 *db = p->db; /* The database connection */ |
| 115171 | |
| 115172 | if( p->zContentTbl==0 ){ |
| 115173 | char *zContentCols; /* Columns of %_content table */ |
| 115174 | |
| 115175 | /* Create a list of user columns for the content table */ |
| 115176 | zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY"); |
| 115177 | for(i=0; zContentCols && i<p->nColumn; i++){ |
| 115178 | char *z = p->azColumn[i]; |
| 115179 | zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z); |
| 115180 | } |
| 115181 | if( zContentCols==0 ) rc = SQLITE_NOMEM; |
| 115182 | |
| 115183 | /* Create the content table */ |
| 115184 | fts3DbExec(&rc, db, |
| 115185 | "CREATE TABLE %Q.'%q_content'(%s)", |
| 115186 | p->zDb, p->zName, zContentCols |
| 115187 | ); |
| 115188 | sqlite3_free(zContentCols); |
| 115189 | } |
| 115190 | |
| 115191 | /* Create other tables */ |
| 115192 | fts3DbExec(&rc, db, |
| 115193 | "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);", |
| 115194 | p->zDb, p->zName |
| 115195 | ); |
| @@ -115308,12 +115336,12 @@ | |
| 115336 | } |
| 115337 | return zRet; |
| 115338 | } |
| 115339 | |
| 115340 | /* |
| 115341 | ** Return a list of comma separated SQL expressions and a FROM clause that |
| 115342 | ** could be used in a SELECT statement such as the following: |
| 115343 | ** |
| 115344 | ** SELECT <list of expressions> FROM %_content AS x ... |
| 115345 | ** |
| 115346 | ** to return the docid, followed by each column of text data in order |
| 115347 | ** from left to write. If parameter zFunc is not NULL, then instead of |
| @@ -115320,11 +115348,11 @@ | |
| 115348 | ** being returned directly each column of text data is passed to an SQL |
| 115349 | ** function named zFunc first. For example, if zFunc is "unzip" and the |
| 115350 | ** table has the three user-defined columns "a", "b", and "c", the following |
| 115351 | ** string is returned: |
| 115352 | ** |
| 115353 | ** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x" |
| 115354 | ** |
| 115355 | ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It |
| 115356 | ** is the responsibility of the caller to eventually free it. |
| 115357 | ** |
| 115358 | ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and |
| @@ -115336,20 +115364,32 @@ | |
| 115364 | char *zRet = 0; |
| 115365 | char *zFree = 0; |
| 115366 | char *zFunction; |
| 115367 | int i; |
| 115368 | |
| 115369 | if( p->zContentTbl==0 ){ |
| 115370 | if( !zFunc ){ |
| 115371 | zFunction = ""; |
| 115372 | }else{ |
| 115373 | zFree = zFunction = fts3QuoteId(zFunc); |
| 115374 | } |
| 115375 | fts3Appendf(pRc, &zRet, "docid"); |
| 115376 | for(i=0; i<p->nColumn; i++){ |
| 115377 | fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]); |
| 115378 | } |
| 115379 | sqlite3_free(zFree); |
| 115380 | }else{ |
| 115381 | fts3Appendf(pRc, &zRet, "rowid"); |
| 115382 | for(i=0; i<p->nColumn; i++){ |
| 115383 | fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]); |
| 115384 | } |
| 115385 | } |
| 115386 | fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x", |
| 115387 | p->zDb, |
| 115388 | (p->zContentTbl ? p->zContentTbl : p->zName), |
| 115389 | (p->zContentTbl ? "" : "_content") |
| 115390 | ); |
| 115391 | return zRet; |
| 115392 | } |
| 115393 | |
| 115394 | /* |
| 115395 | ** Return a list of N comma separated question marks, where N is the number |
| @@ -115468,10 +115508,95 @@ | |
| 115508 | } |
| 115509 | } |
| 115510 | |
| 115511 | return SQLITE_OK; |
| 115512 | } |
| 115513 | |
| 115514 | /* |
| 115515 | ** This function is called when initializing an FTS4 table that uses the |
| 115516 | ** content=xxx option. It determines the number of and names of the columns |
| 115517 | ** of the new FTS4 table. |
| 115518 | ** |
| 115519 | ** The third argument passed to this function is the value passed to the |
| 115520 | ** config=xxx option (i.e. "xxx"). This function queries the database for |
| 115521 | ** a table of that name. If found, the output variables are populated |
| 115522 | ** as follows: |
| 115523 | ** |
| 115524 | ** *pnCol: Set to the number of columns table xxx has, |
| 115525 | ** |
| 115526 | ** *pnStr: Set to the total amount of space required to store a copy |
| 115527 | ** of each columns name, including the nul-terminator. |
| 115528 | ** |
| 115529 | ** *pazCol: Set to point to an array of *pnCol strings. Each string is |
| 115530 | ** the name of the corresponding column in table xxx. The array |
| 115531 | ** and its contents are allocated using a single allocation. It |
| 115532 | ** is the responsibility of the caller to free this allocation |
| 115533 | ** by eventually passing the *pazCol value to sqlite3_free(). |
| 115534 | ** |
| 115535 | ** If the table cannot be found, an error code is returned and the output |
| 115536 | ** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is |
| 115537 | ** returned (and the output variables are undefined). |
| 115538 | */ |
| 115539 | static int fts3ContentColumns( |
| 115540 | sqlite3 *db, /* Database handle */ |
| 115541 | const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */ |
| 115542 | const char *zTbl, /* Name of content table */ |
| 115543 | const char ***pazCol, /* OUT: Malloc'd array of column names */ |
| 115544 | int *pnCol, /* OUT: Size of array *pazCol */ |
| 115545 | int *pnStr /* OUT: Bytes of string content */ |
| 115546 | ){ |
| 115547 | int rc = SQLITE_OK; /* Return code */ |
| 115548 | char *zSql; /* "SELECT *" statement on zTbl */ |
| 115549 | sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */ |
| 115550 | |
| 115551 | zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl); |
| 115552 | if( !zSql ){ |
| 115553 | rc = SQLITE_NOMEM; |
| 115554 | }else{ |
| 115555 | rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); |
| 115556 | } |
| 115557 | sqlite3_free(zSql); |
| 115558 | |
| 115559 | if( rc==SQLITE_OK ){ |
| 115560 | const char **azCol; /* Output array */ |
| 115561 | int nStr = 0; /* Size of all column names (incl. 0x00) */ |
| 115562 | int nCol; /* Number of table columns */ |
| 115563 | int i; /* Used to iterate through columns */ |
| 115564 | |
| 115565 | /* Loop through the returned columns. Set nStr to the number of bytes of |
| 115566 | ** space required to store a copy of each column name, including the |
| 115567 | ** nul-terminator byte. */ |
| 115568 | nCol = sqlite3_column_count(pStmt); |
| 115569 | for(i=0; i<nCol; i++){ |
| 115570 | const char *zCol = sqlite3_column_name(pStmt, i); |
| 115571 | nStr += strlen(zCol) + 1; |
| 115572 | } |
| 115573 | |
| 115574 | /* Allocate and populate the array to return. */ |
| 115575 | azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr); |
| 115576 | if( azCol==0 ){ |
| 115577 | rc = SQLITE_NOMEM; |
| 115578 | }else{ |
| 115579 | char *p = (char *)&azCol[nCol]; |
| 115580 | for(i=0; i<nCol; i++){ |
| 115581 | const char *zCol = sqlite3_column_name(pStmt, i); |
| 115582 | int n = strlen(zCol)+1; |
| 115583 | memcpy(p, zCol, n); |
| 115584 | azCol[i] = p; |
| 115585 | p += n; |
| 115586 | } |
| 115587 | } |
| 115588 | sqlite3_finalize(pStmt); |
| 115589 | |
| 115590 | /* Set the output variables. */ |
| 115591 | *pnCol = nCol; |
| 115592 | *pnStr = nStr; |
| 115593 | *pazCol = azCol; |
| 115594 | } |
| 115595 | |
| 115596 | return rc; |
| 115597 | } |
| 115598 | |
| 115599 | /* |
| 115600 | ** This function is the implementation of both the xConnect and xCreate |
| 115601 | ** methods of the FTS3 virtual table. |
| 115602 | ** |
| @@ -115513,10 +115638,11 @@ | |
| 115638 | int bNoDocsize = 0; /* True to omit %_docsize table */ |
| 115639 | int bDescIdx = 0; /* True to store descending indexes */ |
| 115640 | char *zPrefix = 0; /* Prefix parameter value (or NULL) */ |
| 115641 | char *zCompress = 0; /* compress=? parameter (or NULL) */ |
| 115642 | char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ |
| 115643 | char *zContent = 0; /* content=? parameter (or NULL) */ |
| 115644 | |
| 115645 | assert( strlen(argv[0])==4 ); |
| 115646 | assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) |
| 115647 | || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4) |
| 115648 | ); |
| @@ -115556,17 +115682,17 @@ | |
| 115682 | /* Check if it is an FTS4 special argument. */ |
| 115683 | else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){ |
| 115684 | struct Fts4Option { |
| 115685 | const char *zOpt; |
| 115686 | int nOpt; |
| 115687 | } aFts4Opt[] = { |
| 115688 | { "matchinfo", 9 }, /* 0 -> MATCHINFO */ |
| 115689 | { "prefix", 6 }, /* 1 -> PREFIX */ |
| 115690 | { "compress", 8 }, /* 2 -> COMPRESS */ |
| 115691 | { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ |
| 115692 | { "order", 5 }, /* 4 -> ORDER */ |
| 115693 | { "content", 7 } /* 5 -> CONTENT */ |
| 115694 | }; |
| 115695 | |
| 115696 | int iOpt; |
| 115697 | if( !zVal ){ |
| 115698 | rc = SQLITE_NOMEM; |
| @@ -115608,17 +115734,24 @@ | |
| 115734 | zVal = 0; |
| 115735 | break; |
| 115736 | |
| 115737 | case 4: /* ORDER */ |
| 115738 | if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) |
| 115739 | && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4)) |
| 115740 | ){ |
| 115741 | *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal); |
| 115742 | rc = SQLITE_ERROR; |
| 115743 | } |
| 115744 | bDescIdx = (zVal[0]=='d' || zVal[0]=='D'); |
| 115745 | break; |
| 115746 | |
| 115747 | default: /* CONTENT */ |
| 115748 | assert( iOpt==5 ); |
| 115749 | sqlite3_free(zUncompress); |
| 115750 | zContent = zVal; |
| 115751 | zVal = 0; |
| 115752 | break; |
| 115753 | } |
| 115754 | } |
| 115755 | sqlite3_free(zVal); |
| 115756 | } |
| 115757 | } |
| @@ -115627,10 +115760,30 @@ | |
| 115760 | else { |
| 115761 | nString += (int)(strlen(z) + 1); |
| 115762 | aCol[nCol++] = z; |
| 115763 | } |
| 115764 | } |
| 115765 | |
| 115766 | /* If a content=xxx option was specified, the following: |
| 115767 | ** |
| 115768 | ** 1. Ignore any compress= and uncompress= options. |
| 115769 | ** |
| 115770 | ** 2. If no column names were specified as part of the CREATE VIRTUAL |
| 115771 | ** TABLE statement, use all columns from the content table. |
| 115772 | */ |
| 115773 | if( rc==SQLITE_OK && zContent ){ |
| 115774 | sqlite3_free(zCompress); |
| 115775 | sqlite3_free(zUncompress); |
| 115776 | zCompress = 0; |
| 115777 | zUncompress = 0; |
| 115778 | if( nCol==0 ){ |
| 115779 | sqlite3_free((void*)aCol); |
| 115780 | aCol = 0; |
| 115781 | rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString); |
| 115782 | } |
| 115783 | assert( rc!=SQLITE_OK || nCol>0 ); |
| 115784 | } |
| 115785 | if( rc!=SQLITE_OK ) goto fts3_init_out; |
| 115786 | |
| 115787 | if( nCol==0 ){ |
| 115788 | assert( nString==0 ); |
| 115789 | aCol[0] = "content"; |
| @@ -115671,10 +115824,12 @@ | |
| 115824 | p->pTokenizer = pTokenizer; |
| 115825 | p->nMaxPendingData = FTS3_MAX_PENDING_DATA; |
| 115826 | p->bHasDocsize = (isFts4 && bNoDocsize==0); |
| 115827 | p->bHasStat = isFts4; |
| 115828 | p->bDescIdx = bDescIdx; |
| 115829 | p->zContentTbl = zContent; |
| 115830 | zContent = 0; |
| 115831 | TESTONLY( p->inTransaction = -1 ); |
| 115832 | TESTONLY( p->mxSavepoint = -1 ); |
| 115833 | |
| 115834 | p->aIndex = (struct Fts3Index *)&p->azColumn[nCol]; |
| 115835 | memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex); |
| @@ -115732,10 +115887,11 @@ | |
| 115887 | fts3_init_out: |
| 115888 | sqlite3_free(zPrefix); |
| 115889 | sqlite3_free(aIndex); |
| 115890 | sqlite3_free(zCompress); |
| 115891 | sqlite3_free(zUncompress); |
| 115892 | sqlite3_free(zContent); |
| 115893 | sqlite3_free((void *)aCol); |
| 115894 | if( rc!=SQLITE_OK ){ |
| 115895 | if( p ){ |
| 115896 | fts3DisconnectMethod((sqlite3_vtab *)p); |
| 115897 | }else if( pTokenizer ){ |
| @@ -115882,40 +116038,69 @@ | |
| 116038 | sqlite3_free(pCsr->aMatchinfo); |
| 116039 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| 116040 | sqlite3_free(pCsr); |
| 116041 | return SQLITE_OK; |
| 116042 | } |
| 116043 | |
| 116044 | /* |
| 116045 | ** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then |
| 116046 | ** compose and prepare an SQL statement of the form: |
| 116047 | ** |
| 116048 | ** "SELECT <columns> FROM %_content WHERE rowid = ?" |
| 116049 | ** |
| 116050 | ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to |
| 116051 | ** it. If an error occurs, return an SQLite error code. |
| 116052 | ** |
| 116053 | ** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK. |
| 116054 | */ |
| 116055 | static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){ |
| 116056 | int rc = SQLITE_OK; |
| 116057 | if( pCsr->pStmt==0 ){ |
| 116058 | Fts3Table *p = (Fts3Table *)pCsr->base.pVtab; |
| 116059 | char *zSql; |
| 116060 | zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); |
| 116061 | if( !zSql ) return SQLITE_NOMEM; |
| 116062 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 116063 | sqlite3_free(zSql); |
| 116064 | } |
| 116065 | *ppStmt = pCsr->pStmt; |
| 116066 | return rc; |
| 116067 | } |
| 116068 | |
| 116069 | /* |
| 116070 | ** Position the pCsr->pStmt statement so that it is on the row |
| 116071 | ** of the %_content table that contains the last match. Return |
| 116072 | ** SQLITE_OK on success. |
| 116073 | */ |
| 116074 | static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){ |
| 116075 | int rc = SQLITE_OK; |
| 116076 | if( pCsr->isRequireSeek ){ |
| 116077 | sqlite3_stmt *pStmt = 0; |
| 116078 | |
| 116079 | rc = fts3CursorSeekStmt(pCsr, &pStmt); |
| 116080 | if( rc==SQLITE_OK ){ |
| 116081 | sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId); |
| 116082 | pCsr->isRequireSeek = 0; |
| 116083 | if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){ |
| 116084 | return SQLITE_OK; |
| 116085 | }else{ |
| 116086 | rc = sqlite3_reset(pCsr->pStmt); |
| 116087 | if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){ |
| 116088 | /* If no row was found and no error has occured, then the %_content |
| 116089 | ** table is missing a row that is present in the full-text index. |
| 116090 | ** The data structures are corrupt. */ |
| 116091 | rc = FTS_CORRUPT_VTAB; |
| 116092 | pCsr->isEof = 1; |
| 116093 | } |
| 116094 | } |
| 116095 | } |
| 116096 | } |
| 116097 | |
| 116098 | if( rc!=SQLITE_OK && pContext ){ |
| 116099 | sqlite3_result_error_code(pContext, rc); |
| 116100 | } |
| 116101 | return rc; |
| 116102 | } |
| 116103 | |
| 116104 | /* |
| 116105 | ** This function is used to process a single interior node when searching |
| 116106 | ** a b-tree for a term or term prefix. The node data is passed to this |
| @@ -116351,20 +116536,20 @@ | |
| 116536 | int isSaveLeft, /* Save the left position */ |
| 116537 | int isExact, /* If *pp1 is exactly nTokens before *pp2 */ |
| 116538 | char **pp1, /* IN/OUT: Left input list */ |
| 116539 | char **pp2 /* IN/OUT: Right input list */ |
| 116540 | ){ |
| 116541 | char *p = *pp; |
| 116542 | char *p1 = *pp1; |
| 116543 | char *p2 = *pp2; |
| 116544 | int iCol1 = 0; |
| 116545 | int iCol2 = 0; |
| 116546 | |
| 116547 | /* Never set both isSaveLeft and isExact for the same invocation. */ |
| 116548 | assert( isSaveLeft==0 || isExact==0 ); |
| 116549 | |
| 116550 | assert( p!=0 && *p1!=0 && *p2!=0 ); |
| 116551 | if( *p1==POS_COLUMN ){ |
| 116552 | p1++; |
| 116553 | p1 += sqlite3Fts3GetVarint32(p1, &iCol1); |
| 116554 | } |
| 116555 | if( *p2==POS_COLUMN ){ |
| @@ -116377,11 +116562,11 @@ | |
| 116562 | char *pSave = p; |
| 116563 | sqlite3_int64 iPrev = 0; |
| 116564 | sqlite3_int64 iPos1 = 0; |
| 116565 | sqlite3_int64 iPos2 = 0; |
| 116566 | |
| 116567 | if( iCol1 ){ |
| 116568 | *p++ = POS_COLUMN; |
| 116569 | p += sqlite3Fts3PutVarint(p, iCol1); |
| 116570 | } |
| 116571 | |
| 116572 | assert( *p1!=POS_END && *p1!=POS_COLUMN ); |
| @@ -116392,20 +116577,14 @@ | |
| 116577 | while( 1 ){ |
| 116578 | if( iPos2==iPos1+nToken |
| 116579 | || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken) |
| 116580 | ){ |
| 116581 | sqlite3_int64 iSave; |
| 116582 | iSave = isSaveLeft ? iPos1 : iPos2; |
| 116583 | fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2; |
| 116584 | pSave = 0; |
| 116585 | assert( p ); |
| 116586 | } |
| 116587 | if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){ |
| 116588 | if( (*p2&0xFE)==0 ) break; |
| 116589 | fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2; |
| 116590 | }else{ |
| @@ -116450,11 +116629,11 @@ | |
| 116629 | |
| 116630 | fts3PoslistCopy(0, &p2); |
| 116631 | fts3PoslistCopy(0, &p1); |
| 116632 | *pp1 = p1; |
| 116633 | *pp2 = p2; |
| 116634 | if( *pp==p ){ |
| 116635 | return 0; |
| 116636 | } |
| 116637 | *p++ = 0x00; |
| 116638 | *pp = p; |
| 116639 | return 1; |
| @@ -116752,10 +116931,60 @@ | |
| 116931 | } |
| 116932 | } |
| 116933 | |
| 116934 | *pnRight = p - aOut; |
| 116935 | } |
| 116936 | |
| 116937 | /* |
| 116938 | ** Argument pList points to a position list nList bytes in size. This |
| 116939 | ** function checks to see if the position list contains any entries for |
| 116940 | ** a token in position 0 (of any column). If so, it writes argument iDelta |
| 116941 | ** to the output buffer pOut, followed by a position list consisting only |
| 116942 | ** of the entries from pList at position 0, and terminated by an 0x00 byte. |
| 116943 | ** The value returned is the number of bytes written to pOut (if any). |
| 116944 | */ |
| 116945 | SQLITE_PRIVATE int sqlite3Fts3FirstFilter( |
| 116946 | sqlite3_int64 iDelta, /* Varint that may be written to pOut */ |
| 116947 | char *pList, /* Position list (no 0x00 term) */ |
| 116948 | int nList, /* Size of pList in bytes */ |
| 116949 | char *pOut /* Write output here */ |
| 116950 | ){ |
| 116951 | int nOut = 0; |
| 116952 | int bWritten = 0; /* True once iDelta has been written */ |
| 116953 | char *p = pList; |
| 116954 | char *pEnd = &pList[nList]; |
| 116955 | |
| 116956 | if( *p!=0x01 ){ |
| 116957 | if( *p==0x02 ){ |
| 116958 | nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); |
| 116959 | pOut[nOut++] = 0x02; |
| 116960 | bWritten = 1; |
| 116961 | } |
| 116962 | fts3ColumnlistCopy(0, &p); |
| 116963 | } |
| 116964 | |
| 116965 | while( p<pEnd && *p==0x01 ){ |
| 116966 | sqlite3_int64 iCol; |
| 116967 | p++; |
| 116968 | p += sqlite3Fts3GetVarint(p, &iCol); |
| 116969 | if( *p==0x02 ){ |
| 116970 | if( bWritten==0 ){ |
| 116971 | nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta); |
| 116972 | bWritten = 1; |
| 116973 | } |
| 116974 | pOut[nOut++] = 0x01; |
| 116975 | nOut += sqlite3Fts3PutVarint(&pOut[nOut], iCol); |
| 116976 | pOut[nOut++] = 0x02; |
| 116977 | } |
| 116978 | fts3ColumnlistCopy(0, &p); |
| 116979 | } |
| 116980 | if( bWritten ){ |
| 116981 | pOut[nOut++] = 0x00; |
| 116982 | } |
| 116983 | |
| 116984 | return nOut; |
| 116985 | } |
| 116986 | |
| 116987 | |
| 116988 | /* |
| 116989 | ** Merge all doclists in the TermSelect.aaOutput[] array into a single |
| 116990 | ** doclist stored in TermSelect.aaOutput[0]. If successful, delete all |
| @@ -117109,10 +117338,11 @@ | |
| 117338 | pSegcsr = pTok->pSegcsr; |
| 117339 | memset(&tsc, 0, sizeof(TermSelect)); |
| 117340 | |
| 117341 | filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS |
| 117342 | | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0) |
| 117343 | | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0) |
| 117344 | | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0); |
| 117345 | filter.iCol = iColumn; |
| 117346 | filter.zTerm = pTok->z; |
| 117347 | filter.nTerm = pTok->n; |
| 117348 | |
| @@ -117249,12 +117479,12 @@ | |
| 117479 | |
| 117480 | if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 117481 | return SQLITE_NOMEM; |
| 117482 | } |
| 117483 | |
| 117484 | rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat, |
| 117485 | p->nColumn, iCol, zQuery, -1, &pCsr->pExpr |
| 117486 | ); |
| 117487 | if( rc!=SQLITE_OK ){ |
| 117488 | if( rc==SQLITE_ERROR ){ |
| 117489 | static const char *zErr = "malformed MATCH expression: [%s]"; |
| 117490 | p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery); |
| @@ -117277,26 +117507,27 @@ | |
| 117507 | ** statement loops through all rows of the %_content table. For a |
| 117508 | ** full-text query or docid lookup, the statement retrieves a single |
| 117509 | ** row by docid. |
| 117510 | */ |
| 117511 | if( idxNum==FTS3_FULLSCAN_SEARCH ){ |
| 117512 | zSql = sqlite3_mprintf( |
| 117513 | "SELECT %s ORDER BY rowid %s", |
| 117514 | p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC") |
| 117515 | ); |
| 117516 | if( zSql ){ |
| 117517 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 117518 | sqlite3_free(zSql); |
| 117519 | }else{ |
| 117520 | rc = SQLITE_NOMEM; |
| 117521 | } |
| 117522 | }else if( idxNum==FTS3_DOCID_SEARCH ){ |
| 117523 | rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt); |
| 117524 | if( rc==SQLITE_OK ){ |
| 117525 | rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); |
| 117526 | } |
| 117527 | } |
| 117528 | if( rc!=SQLITE_OK ) return rc; |
| 117529 | |
| 117530 | return fts3NextMethod(pCursor); |
| 117531 | } |
| 117532 | |
| 117533 | /* |
| @@ -117345,11 +117576,11 @@ | |
| 117576 | ** Return a blob which is a pointer to the cursor. |
| 117577 | */ |
| 117578 | sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT); |
| 117579 | }else{ |
| 117580 | rc = fts3CursorSeek(0, pCsr); |
| 117581 | if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){ |
| 117582 | sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1)); |
| 117583 | } |
| 117584 | } |
| 117585 | |
| 117586 | assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 ); |
| @@ -117638,19 +117869,26 @@ | |
| 117869 | ){ |
| 117870 | Fts3Table *p = (Fts3Table *)pVtab; |
| 117871 | sqlite3 *db = p->db; /* Database connection */ |
| 117872 | int rc; /* Return Code */ |
| 117873 | |
| 117874 | /* As it happens, the pending terms table is always empty here. This is |
| 117875 | ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction |
| 117876 | ** always opens a savepoint transaction. And the xSavepoint() method |
| 117877 | ** flushes the pending terms table. But leave the (no-op) call to |
| 117878 | ** PendingTermsFlush() in in case that changes. |
| 117879 | */ |
| 117880 | assert( p->nPendingData==0 ); |
| 117881 | rc = sqlite3Fts3PendingTermsFlush(p); |
| 117882 | |
| 117883 | if( p->zContentTbl==0 ){ |
| 117884 | fts3DbExec(&rc, db, |
| 117885 | "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';", |
| 117886 | p->zDb, p->zName, zName |
| 117887 | ); |
| 117888 | } |
| 117889 | |
| 117890 | if( p->bHasDocsize ){ |
| 117891 | fts3DbExec(&rc, db, |
| 117892 | "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';", |
| 117893 | p->zDb, p->zName, zName |
| 117894 | ); |
| @@ -118005,25 +118243,24 @@ | |
| 118243 | ** |
| 118244 | ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. |
| 118245 | */ |
| 118246 | static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ |
| 118247 | int iToken; /* Used to iterate through phrase tokens */ |
| 118248 | char *aPoslist = 0; /* Position list for deferred tokens */ |
| 118249 | int nPoslist = 0; /* Number of bytes in aPoslist */ |
| 118250 | int iPrev = -1; /* Token number of previous deferred token */ |
| 118251 | |
| 118252 | assert( pPhrase->doclist.bFreeList==0 ); |
| 118253 | |
| 118254 | for(iToken=0; iToken<pPhrase->nToken; iToken++){ |
| 118255 | Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; |
| 118256 | Fts3DeferredToken *pDeferred = pToken->pDeferred; |
| 118257 | |
| 118258 | if( pDeferred ){ |
| 118259 | char *pList; |
| 118260 | int nList; |
| 118261 | int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); |
| 118262 | if( rc!=SQLITE_OK ) return rc; |
| 118263 | |
| 118264 | if( pList==0 ){ |
| 118265 | sqlite3_free(aPoslist); |
| 118266 | pPhrase->doclist.pList = 0; |
| @@ -118120,10 +118357,11 @@ | |
| 118357 | if( pCsr->bDesc==pTab->bDescIdx |
| 118358 | && bOptOk==1 |
| 118359 | && p->nToken==1 |
| 118360 | && pFirst->pSegcsr |
| 118361 | && pFirst->pSegcsr->bLookup |
| 118362 | && pFirst->bFirst==0 |
| 118363 | ){ |
| 118364 | /* Use the incremental approach. */ |
| 118365 | int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn); |
| 118366 | rc = sqlite3Fts3MsrIncrStart( |
| 118367 | pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n); |
| @@ -118349,11 +118587,11 @@ | |
| 118587 | Fts3Expr *pExpr, /* Expression to consider */ |
| 118588 | Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */ |
| 118589 | Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */ |
| 118590 | int *pRc /* IN/OUT: Error code */ |
| 118591 | ){ |
| 118592 | if( *pRc==SQLITE_OK ){ |
| 118593 | if( pExpr->eType==FTSQUERY_PHRASE ){ |
| 118594 | Fts3Phrase *pPhrase = pExpr->pPhrase; |
| 118595 | int i; |
| 118596 | for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){ |
| 118597 | Fts3TokenAndCost *pTC = (*ppTC)++; |
| @@ -118363,10 +118601,15 @@ | |
| 118601 | pTC->pToken = &pPhrase->aToken[i]; |
| 118602 | pTC->iCol = pPhrase->iColumn; |
| 118603 | *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl); |
| 118604 | } |
| 118605 | }else if( pExpr->eType!=FTSQUERY_NOT ){ |
| 118606 | assert( pExpr->eType==FTSQUERY_OR |
| 118607 | || pExpr->eType==FTSQUERY_AND |
| 118608 | || pExpr->eType==FTSQUERY_NEAR |
| 118609 | ); |
| 118610 | assert( pExpr->pLeft && pExpr->pRight ); |
| 118611 | if( pExpr->eType==FTSQUERY_OR ){ |
| 118612 | pRoot = pExpr->pLeft; |
| 118613 | **ppOr = pRoot; |
| 118614 | (*ppOr)++; |
| 118615 | } |
| @@ -118466,10 +118709,19 @@ | |
| 118709 | int nOvfl = 0; /* Total overflow pages used by doclists */ |
| 118710 | int nToken = 0; /* Total number of tokens in cluster */ |
| 118711 | |
| 118712 | int nMinEst = 0; /* The minimum count for any phrase so far. */ |
| 118713 | int nLoad4 = 1; /* (Phrases that will be loaded)^4. */ |
| 118714 | |
| 118715 | /* Tokens are never deferred for FTS tables created using the content=xxx |
| 118716 | ** option. The reason being that it is not guaranteed that the content |
| 118717 | ** table actually contains the same data as the index. To prevent this from |
| 118718 | ** causing any problems, the deferred token optimization is completely |
| 118719 | ** disabled for content=xxx tables. */ |
| 118720 | if( pTab->zContentTbl ){ |
| 118721 | return SQLITE_OK; |
| 118722 | } |
| 118723 | |
| 118724 | /* Count the tokens in this AND/NEAR cluster. If none of the doclists |
| 118725 | ** associated with the tokens spill onto overflow pages, or if there is |
| 118726 | ** only 1 token, exit early. No tokens to defer in this case. */ |
| 118727 | for(ii=0; ii<nTC; ii++){ |
| @@ -118529,11 +118781,15 @@ | |
| 118781 | Fts3PhraseToken *pToken = pTC->pToken; |
| 118782 | rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol); |
| 118783 | fts3SegReaderCursorFree(pToken->pSegcsr); |
| 118784 | pToken->pSegcsr = 0; |
| 118785 | }else{ |
| 118786 | /* Set nLoad4 to the value of (4^nOther) for the next iteration of the |
| 118787 | ** for-loop. Except, limit the value to 2^24 to prevent it from |
| 118788 | ** overflowing the 32-bit integer it is stored in. */ |
| 118789 | if( ii<12 ) nLoad4 = nLoad4*4; |
| 118790 | |
| 118791 | if( ii==0 || pTC->pPhrase->nToken>1 ){ |
| 118792 | /* Either this is the cheapest token in the entire query, or it is |
| 118793 | ** part of a multi-token phrase. Either way, the entire doclist will |
| 118794 | ** (eventually) be loaded into memory. It may as well be now. */ |
| 118795 | Fts3PhraseToken *pToken = pTC->pToken; |
| @@ -119990,10 +120246,11 @@ | |
| 120246 | */ |
| 120247 | typedef struct ParseContext ParseContext; |
| 120248 | struct ParseContext { |
| 120249 | sqlite3_tokenizer *pTokenizer; /* Tokenizer module */ |
| 120250 | const char **azCol; /* Array of column names for fts3 table */ |
| 120251 | int bFts4; /* True to allow FTS4-only syntax */ |
| 120252 | int nCol; /* Number of entries in azCol[] */ |
| 120253 | int iDefaultCol; /* Default column to query */ |
| 120254 | int isNot; /* True if getNextNode() sees a unary - */ |
| 120255 | sqlite3_context *pCtx; /* Write error message here */ |
| 120256 | int nNest; /* Number of nested brackets */ |
| @@ -120077,13 +120334,25 @@ | |
| 120334 | |
| 120335 | if( iEnd<n && z[iEnd]=='*' ){ |
| 120336 | pRet->pPhrase->aToken[0].isPrefix = 1; |
| 120337 | iEnd++; |
| 120338 | } |
| 120339 | |
| 120340 | while( 1 ){ |
| 120341 | if( !sqlite3_fts3_enable_parentheses |
| 120342 | && iStart>0 && z[iStart-1]=='-' |
| 120343 | ){ |
| 120344 | pParse->isNot = 1; |
| 120345 | iStart--; |
| 120346 | }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){ |
| 120347 | pRet->pPhrase->aToken[0].bFirst = 1; |
| 120348 | iStart--; |
| 120349 | }else{ |
| 120350 | break; |
| 120351 | } |
| 120352 | } |
| 120353 | |
| 120354 | } |
| 120355 | nConsumed = iEnd; |
| 120356 | } |
| 120357 | |
| 120358 | pModule->xClose(pCursor); |
| @@ -120178,10 +120447,11 @@ | |
| 120447 | memcpy(&zTemp[nTemp], zByte, nByte); |
| 120448 | nTemp += nByte; |
| 120449 | |
| 120450 | pToken->n = nByte; |
| 120451 | pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*'); |
| 120452 | pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^'); |
| 120453 | nToken = ii+1; |
| 120454 | } |
| 120455 | } |
| 120456 | |
| 120457 | pModule->xClose(pCursor); |
| @@ -120629,10 +120899,11 @@ | |
| 120899 | ** match any table column. |
| 120900 | */ |
| 120901 | SQLITE_PRIVATE int sqlite3Fts3ExprParse( |
| 120902 | sqlite3_tokenizer *pTokenizer, /* Tokenizer module */ |
| 120903 | char **azCol, /* Array of column names for fts3 table */ |
| 120904 | int bFts4, /* True to allow FTS4-only syntax */ |
| 120905 | int nCol, /* Number of entries in azCol[] */ |
| 120906 | int iDefaultCol, /* Default column to query */ |
| 120907 | const char *z, int n, /* Text of MATCH query */ |
| 120908 | Fts3Expr **ppExpr /* OUT: Parsed query structure */ |
| 120909 | ){ |
| @@ -120642,10 +120913,11 @@ | |
| 120913 | sParse.pTokenizer = pTokenizer; |
| 120914 | sParse.azCol = (const char **)azCol; |
| 120915 | sParse.nCol = nCol; |
| 120916 | sParse.iDefaultCol = iDefaultCol; |
| 120917 | sParse.nNest = 0; |
| 120918 | sParse.bFts4 = bFts4; |
| 120919 | if( z==0 ){ |
| 120920 | *ppExpr = 0; |
| 120921 | return SQLITE_OK; |
| 120922 | } |
| 120923 | if( n<0 ){ |
| @@ -120831,11 +121103,11 @@ | |
| 121103 | for(ii=0; ii<nCol; ii++){ |
| 121104 | azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]); |
| 121105 | } |
| 121106 | |
| 121107 | rc = sqlite3Fts3ExprParse( |
| 121108 | pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr |
| 121109 | ); |
| 121110 | if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ |
| 121111 | sqlite3_result_error(context, "Error parsing expression", -1); |
| 121112 | }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){ |
| 121113 | sqlite3_result_error_nomem(context); |
| @@ -122878,11 +123150,11 @@ | |
| 123150 | /* 2 */ "DELETE FROM %Q.'%q_content'", |
| 123151 | /* 3 */ "DELETE FROM %Q.'%q_segments'", |
| 123152 | /* 4 */ "DELETE FROM %Q.'%q_segdir'", |
| 123153 | /* 5 */ "DELETE FROM %Q.'%q_docsize'", |
| 123154 | /* 6 */ "DELETE FROM %Q.'%q_stat'", |
| 123155 | /* 7 */ "SELECT %s WHERE rowid=?", |
| 123156 | /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1", |
| 123157 | /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)", |
| 123158 | /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)", |
| 123159 | /* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)", |
| 123160 | |
| @@ -122920,11 +123192,11 @@ | |
| 123192 | if( !pStmt ){ |
| 123193 | char *zSql; |
| 123194 | if( eStmt==SQL_CONTENT_INSERT ){ |
| 123195 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); |
| 123196 | }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ |
| 123197 | zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); |
| 123198 | }else{ |
| 123199 | zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); |
| 123200 | } |
| 123201 | if( !zSql ){ |
| 123202 | rc = SQLITE_NOMEM; |
| @@ -123031,21 +123303,28 @@ | |
| 123303 | ** We try to avoid this because if FTS3 returns any error when committing |
| 123304 | ** a transaction, the whole transaction will be rolled back. And this is |
| 123305 | ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can |
| 123306 | ** still happen if the user reads data directly from the %_segments or |
| 123307 | ** %_segdir tables instead of going through FTS3 though. |
| 123308 | ** |
| 123309 | ** This reasoning does not apply to a content=xxx table. |
| 123310 | */ |
| 123311 | SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){ |
| 123312 | int rc; /* Return code */ |
| 123313 | sqlite3_stmt *pStmt; /* Statement used to obtain lock */ |
| 123314 | |
| 123315 | if( p->zContentTbl==0 ){ |
| 123316 | rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0); |
| 123317 | if( rc==SQLITE_OK ){ |
| 123318 | sqlite3_bind_null(pStmt, 1); |
| 123319 | sqlite3_step(pStmt); |
| 123320 | rc = sqlite3_reset(pStmt); |
| 123321 | } |
| 123322 | }else{ |
| 123323 | rc = SQLITE_OK; |
| 123324 | } |
| 123325 | |
| 123326 | return rc; |
| 123327 | } |
| 123328 | |
| 123329 | /* |
| 123330 | ** Set *ppStmt to a statement handle that may be used to iterate through |
| @@ -123401,10 +123680,22 @@ | |
| 123680 | sqlite3_value **apVal, /* Array of values to insert */ |
| 123681 | sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ |
| 123682 | ){ |
| 123683 | int rc; /* Return code */ |
| 123684 | sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ |
| 123685 | |
| 123686 | if( p->zContentTbl ){ |
| 123687 | sqlite3_value *pRowid = apVal[p->nColumn+3]; |
| 123688 | if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ |
| 123689 | pRowid = apVal[1]; |
| 123690 | } |
| 123691 | if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ |
| 123692 | return SQLITE_CONSTRAINT; |
| 123693 | } |
| 123694 | *piDocid = sqlite3_value_int64(pRowid); |
| 123695 | return SQLITE_OK; |
| 123696 | } |
| 123697 | |
| 123698 | /* Locate the statement handle used to insert data into the %_content |
| 123699 | ** table. The SQL for this statement is: |
| 123700 | ** |
| 123701 | ** INSERT INTO %_content VALUES(?, ?, ?, ...) |
| @@ -123452,18 +123743,20 @@ | |
| 123743 | |
| 123744 | /* |
| 123745 | ** Remove all data from the FTS3 table. Clear the hash table containing |
| 123746 | ** pending terms. |
| 123747 | */ |
| 123748 | static int fts3DeleteAll(Fts3Table *p, int bContent){ |
| 123749 | int rc = SQLITE_OK; /* Return code */ |
| 123750 | |
| 123751 | /* Discard the contents of the pending-terms hash table. */ |
| 123752 | sqlite3Fts3PendingTermsClear(p); |
| 123753 | |
| 123754 | /* Delete everything from the shadow tables. Except, leave %_content as |
| 123755 | ** is if bContent is false. */ |
| 123756 | assert( p->zContentTbl==0 || bContent==0 ); |
| 123757 | if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0); |
| 123758 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0); |
| 123759 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0); |
| 123760 | if( p->bHasDocsize ){ |
| 123761 | fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0); |
| 123762 | } |
| @@ -124747,16 +125040,22 @@ | |
| 125040 | ** error occurs, an SQLite error code is returned. |
| 125041 | */ |
| 125042 | static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ |
| 125043 | sqlite3_stmt *pStmt; |
| 125044 | int rc; |
| 125045 | if( p->zContentTbl ){ |
| 125046 | /* If using the content=xxx option, assume the table is never empty */ |
| 125047 | *pisEmpty = 0; |
| 125048 | rc = SQLITE_OK; |
| 125049 | }else{ |
| 125050 | rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); |
| 125051 | if( rc==SQLITE_OK ){ |
| 125052 | if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 125053 | *pisEmpty = sqlite3_column_int(pStmt, 0); |
| 125054 | } |
| 125055 | rc = sqlite3_reset(pStmt); |
| 125056 | } |
| 125057 | } |
| 125058 | return rc; |
| 125059 | } |
| 125060 | |
| 125061 | /* |
| @@ -125104,10 +125403,11 @@ | |
| 125403 | int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY); |
| 125404 | int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS); |
| 125405 | int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER); |
| 125406 | int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX); |
| 125407 | int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN); |
| 125408 | int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST); |
| 125409 | |
| 125410 | Fts3SegReader **apSegment = pCsr->apSegment; |
| 125411 | int nSegment = pCsr->nSegment; |
| 125412 | Fts3SegFilter *pFilter = pCsr->pFilter; |
| 125413 | int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = ( |
| @@ -125163,10 +125463,11 @@ | |
| 125463 | } |
| 125464 | |
| 125465 | assert( isIgnoreEmpty || (isRequirePos && !isColFilter) ); |
| 125466 | if( nMerge==1 |
| 125467 | && !isIgnoreEmpty |
| 125468 | && !isFirst |
| 125469 | && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) |
| 125470 | ){ |
| 125471 | pCsr->nDoclist = apSegment[0]->nDoclist; |
| 125472 | if( fts3SegReaderIsPending(apSegment[0]) ){ |
| 125473 | rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); |
| @@ -125228,16 +125529,28 @@ | |
| 125529 | if( !aNew ){ |
| 125530 | return SQLITE_NOMEM; |
| 125531 | } |
| 125532 | pCsr->aBuffer = aNew; |
| 125533 | } |
| 125534 | |
| 125535 | if( isFirst ){ |
| 125536 | char *a = &pCsr->aBuffer[nDoclist]; |
| 125537 | int nWrite; |
| 125538 | |
| 125539 | nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); |
| 125540 | if( nWrite ){ |
| 125541 | iPrev = iDocid; |
| 125542 | nDoclist += nWrite; |
| 125543 | } |
| 125544 | }else{ |
| 125545 | nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta); |
| 125546 | iPrev = iDocid; |
| 125547 | if( isRequirePos ){ |
| 125548 | memcpy(&pCsr->aBuffer[nDoclist], pList, nList); |
| 125549 | nDoclist += nList; |
| 125550 | pCsr->aBuffer[nDoclist++] = '\0'; |
| 125551 | } |
| 125552 | } |
| 125553 | } |
| 125554 | |
| 125555 | fts3SegReaderSort(apSegment, nMerge, j, xCmp); |
| 125556 | } |
| @@ -125409,13 +125722,13 @@ | |
| 125722 | ** Insert the sizes (in tokens) for each column of the document |
| 125723 | ** with docid equal to p->iPrevDocid. The sizes are encoded as |
| 125724 | ** a blob of varints. |
| 125725 | */ |
| 125726 | static void fts3InsertDocsize( |
| 125727 | int *pRC, /* Result code */ |
| 125728 | Fts3Table *p, /* Table into which to insert */ |
| 125729 | u32 *aSz /* Sizes of each column, in tokens */ |
| 125730 | ){ |
| 125731 | char *pBlob; /* The BLOB encoding of the document size */ |
| 125732 | int nBlob; /* Number of bytes in the BLOB */ |
| 125733 | sqlite3_stmt *pStmt; /* Statement used to insert the encoding */ |
| 125734 | int rc; /* Result code from subfunctions */ |
| @@ -125532,10 +125845,90 @@ | |
| 125845 | sqlite3Fts3SegmentsClose(p); |
| 125846 | sqlite3Fts3PendingTermsClear(p); |
| 125847 | |
| 125848 | return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc; |
| 125849 | } |
| 125850 | |
| 125851 | /* |
| 125852 | ** This function is called when the user executes the following statement: |
| 125853 | ** |
| 125854 | ** INSERT INTO <tbl>(<tbl>) VALUES('rebuild'); |
| 125855 | ** |
| 125856 | ** The entire FTS index is discarded and rebuilt. If the table is one |
| 125857 | ** created using the content=xxx option, then the new index is based on |
| 125858 | ** the current contents of the xxx table. Otherwise, it is rebuilt based |
| 125859 | ** on the contents of the %_content table. |
| 125860 | */ |
| 125861 | static int fts3DoRebuild(Fts3Table *p){ |
| 125862 | int rc; /* Return Code */ |
| 125863 | |
| 125864 | rc = fts3DeleteAll(p, 0); |
| 125865 | if( rc==SQLITE_OK ){ |
| 125866 | u32 *aSz = 0; |
| 125867 | u32 *aSzIns = 0; |
| 125868 | u32 *aSzDel = 0; |
| 125869 | sqlite3_stmt *pStmt = 0; |
| 125870 | int nEntry = 0; |
| 125871 | |
| 125872 | /* Compose and prepare an SQL statement to loop through the content table */ |
| 125873 | char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist); |
| 125874 | if( !zSql ){ |
| 125875 | rc = SQLITE_NOMEM; |
| 125876 | }else{ |
| 125877 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); |
| 125878 | sqlite3_free(zSql); |
| 125879 | } |
| 125880 | |
| 125881 | if( rc==SQLITE_OK ){ |
| 125882 | int nByte = sizeof(u32) * (p->nColumn+1)*3; |
| 125883 | aSz = (u32 *)sqlite3_malloc(nByte); |
| 125884 | if( aSz==0 ){ |
| 125885 | rc = SQLITE_NOMEM; |
| 125886 | }else{ |
| 125887 | memset(aSz, 0, nByte); |
| 125888 | aSzIns = &aSz[p->nColumn+1]; |
| 125889 | aSzDel = &aSzIns[p->nColumn+1]; |
| 125890 | } |
| 125891 | } |
| 125892 | |
| 125893 | while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 125894 | int iCol; |
| 125895 | rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0)); |
| 125896 | aSz[p->nColumn] = 0; |
| 125897 | for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){ |
| 125898 | const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1); |
| 125899 | rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]); |
| 125900 | aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1); |
| 125901 | } |
| 125902 | if( p->bHasDocsize ){ |
| 125903 | fts3InsertDocsize(&rc, p, aSz); |
| 125904 | } |
| 125905 | if( rc!=SQLITE_OK ){ |
| 125906 | sqlite3_finalize(pStmt); |
| 125907 | pStmt = 0; |
| 125908 | }else{ |
| 125909 | nEntry++; |
| 125910 | for(iCol=0; iCol<=p->nColumn; iCol++){ |
| 125911 | aSzIns[iCol] += aSz[iCol]; |
| 125912 | } |
| 125913 | } |
| 125914 | } |
| 125915 | if( p->bHasStat ){ |
| 125916 | fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry); |
| 125917 | } |
| 125918 | sqlite3_free(aSz); |
| 125919 | |
| 125920 | if( pStmt ){ |
| 125921 | int rc2 = sqlite3_finalize(pStmt); |
| 125922 | if( rc==SQLITE_OK ){ |
| 125923 | rc = rc2; |
| 125924 | } |
| 125925 | } |
| 125926 | } |
| 125927 | |
| 125928 | return rc; |
| 125929 | } |
| 125930 | |
| 125931 | /* |
| 125932 | ** Handle a 'special' INSERT of the form: |
| 125933 | ** |
| 125934 | ** "INSERT INTO tbl(tbl) VALUES(<expr>)" |
| @@ -125550,10 +125943,12 @@ | |
| 125943 | |
| 125944 | if( !zVal ){ |
| 125945 | return SQLITE_NOMEM; |
| 125946 | }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){ |
| 125947 | rc = fts3DoOptimize(p, 0); |
| 125948 | }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){ |
| 125949 | rc = fts3DoRebuild(p); |
| 125950 | #ifdef SQLITE_TEST |
| 125951 | }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){ |
| 125952 | p->nNodeSize = atoi(&zVal[9]); |
| 125953 | rc = SQLITE_OK; |
| 125954 | }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ |
| @@ -125630,10 +126025,11 @@ | |
| 126025 | pTC->pTokenizer = pT; |
| 126026 | rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos); |
| 126027 | for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){ |
| 126028 | Fts3PhraseToken *pPT = pDef->pToken; |
| 126029 | if( (pDef->iCol>=p->nColumn || pDef->iCol==i) |
| 126030 | && (pPT->bFirst==0 || iPos==0) |
| 126031 | && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken)) |
| 126032 | && (0==memcmp(zToken, pPT->z, pPT->n)) |
| 126033 | ){ |
| 126034 | fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc); |
| 126035 | } |
| @@ -125721,18 +126117,22 @@ | |
| 126117 | if( rc==SQLITE_OK ){ |
| 126118 | if( isEmpty ){ |
| 126119 | /* Deleting this row means the whole table is empty. In this case |
| 126120 | ** delete the contents of all three tables and throw away any |
| 126121 | ** data in the pendingTerms hash table. */ |
| 126122 | rc = fts3DeleteAll(p, 1); |
| 126123 | *pnDoc = *pnDoc - 1; |
| 126124 | }else{ |
| 126125 | sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); |
| 126126 | rc = fts3PendingTermsDocid(p, iRemove); |
| 126127 | fts3DeleteTerms(&rc, p, pRowid, aSzDel); |
| 126128 | if( p->zContentTbl==0 ){ |
| 126129 | fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); |
| 126130 | if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; |
| 126131 | }else{ |
| 126132 | *pnDoc = *pnDoc - 1; |
| 126133 | } |
| 126134 | if( p->bHasDocsize ){ |
| 126135 | fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); |
| 126136 | } |
| 126137 | } |
| 126138 | } |
| @@ -125788,11 +126188,11 @@ | |
| 126188 | ** should be deleted from the database before inserting the new row. Or, |
| 126189 | ** if the on-conflict mode is other than REPLACE, then this method must |
| 126190 | ** detect the conflict and return SQLITE_CONSTRAINT before beginning to |
| 126191 | ** modify the database file. |
| 126192 | */ |
| 126193 | if( nArg>1 && p->zContentTbl==0 ){ |
| 126194 | /* Find the value object that holds the new rowid value. */ |
| 126195 | sqlite3_value *pNewRowid = apVal[3+p->nColumn]; |
| 126196 | if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ |
| 126197 | pNewRowid = apVal[1]; |
| 126198 | } |
| @@ -125839,11 +126239,13 @@ | |
| 126239 | |
| 126240 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 126241 | if( nArg>1 && rc==SQLITE_OK ){ |
| 126242 | if( bInsertDone==0 ){ |
| 126243 | rc = fts3InsertData(p, apVal, pRowid); |
| 126244 | if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ |
| 126245 | rc = FTS_CORRUPT_VTAB; |
| 126246 | } |
| 126247 | } |
| 126248 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){ |
| 126249 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 126250 | } |
| 126251 | if( rc==SQLITE_OK ){ |
| @@ -126259,10 +126661,11 @@ | |
| 126661 | pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol); |
| 126662 | if( pCsr ){ |
| 126663 | int iFirst = 0; |
| 126664 | pPhrase->pList = pCsr; |
| 126665 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 126666 | assert( iFirst>=0 ); |
| 126667 | pPhrase->pHead = pCsr; |
| 126668 | pPhrase->pTail = pCsr; |
| 126669 | pPhrase->iHead = iFirst; |
| 126670 | pPhrase->iTail = iFirst; |
| 126671 | }else{ |
| @@ -127300,11 +127703,11 @@ | |
| 127703 | } |
| 127704 | } |
| 127705 | |
| 127706 | if( !pTerm ){ |
| 127707 | /* All offsets for this column have been gathered. */ |
| 127708 | rc = SQLITE_DONE; |
| 127709 | }else{ |
| 127710 | assert( iCurrent<=iMinPos ); |
| 127711 | if( 0==(0xFE&*pTerm->pList) ){ |
| 127712 | pTerm->pList = 0; |
| 127713 | }else{ |
| @@ -127317,11 +127720,11 @@ | |
| 127720 | char aBuffer[64]; |
| 127721 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 127722 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 127723 | ); |
| 127724 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 127725 | }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){ |
| 127726 | rc = FTS_CORRUPT_VTAB; |
| 127727 | } |
| 127728 | } |
| 127729 | } |
| 127730 | if( rc==SQLITE_DONE ){ |
| 127731 |
+3
-3
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -107,11 +107,11 @@ | ||
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | 110 | #define SQLITE_VERSION "3.7.9" |
| 111 | 111 | #define SQLITE_VERSION_NUMBER 3007009 |
| 112 | -#define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe" | |
| 112 | +#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| @@ -1402,12 +1402,12 @@ | ||
| 1402 | 1402 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1403 | 1403 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1404 | 1404 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1405 | 1405 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1406 | 1406 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1407 | -** The minimum allocation size is capped at 2^12. Reasonable values | |
| 1408 | -** for the minimum allocation size are 2^5 through 2^8.</dd> | |
| 1407 | +** The minimum allocation size is capped at 2**12. Reasonable values | |
| 1408 | +** for the minimum allocation size are 2**5 through 2**8.</dd> | |
| 1409 | 1409 | ** |
| 1410 | 1410 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1411 | 1411 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1412 | 1412 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1413 | 1413 | ** alternative low-level mutex routines to be used in place |
| 1414 | 1414 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.9" |
| 111 | #define SQLITE_VERSION_NUMBER 3007009 |
| 112 | #define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -1402,12 +1402,12 @@ | |
| 1402 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1403 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1404 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1405 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1406 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1407 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1408 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1409 | ** |
| 1410 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1411 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1412 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1413 | ** alternative low-level mutex routines to be used in place |
| 1414 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.9" |
| 111 | #define SQLITE_VERSION_NUMBER 3007009 |
| 112 | #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -1402,12 +1402,12 @@ | |
| 1402 | ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or |
| 1403 | ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory |
| 1404 | ** allocator is engaged to handle all of SQLites memory allocation needs. |
| 1405 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1406 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1407 | ** The minimum allocation size is capped at 2**12. Reasonable values |
| 1408 | ** for the minimum allocation size are 2**5 through 2**8.</dd> |
| 1409 | ** |
| 1410 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1411 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1412 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1413 | ** alternative low-level mutex routines to be used in place |
| 1414 |