|
|
@@ -400,7 +400,7 @@ extern "C" {
|
|
|
*/
|
|
|
#define SQLITE_VERSION "3.19.0"
|
|
|
#define SQLITE_VERSION_NUMBER 3019000
|
|
|
-#define SQLITE_SOURCE_ID "2017-04-12 17:50:12 c847543f8bb1376fef52bca72b4191162a32eb7e6c5f0cd1aa0ab116b3183396"
|
|
|
+#define SQLITE_SOURCE_ID "2017-04-15 11:53:47 89f9e4363aa19f306e55f749c442eae2f8994f6a47c65e645a79b308b450d5e5"
|
|
|
|
|
|
/*
|
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
|
@@ -26590,7 +26590,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
|
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
|
|
const char *zBinOp = 0; /* Binary operator */
|
|
|
const char *zUniOp = 0; /* Unary operator */
|
|
|
- char zFlgs[30];
|
|
|
+ char zFlgs[60];
|
|
|
pView = sqlite3TreeViewPush(pView, moreToFollow);
|
|
|
if( pExpr==0 ){
|
|
|
sqlite3TreeViewLine(pView, "nil");
|
|
|
@@ -26598,7 +26598,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
|
return;
|
|
|
}
|
|
|
if( pExpr->flags ){
|
|
|
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
|
|
+ if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
|
|
+ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d",
|
|
|
+ pExpr->flags, pExpr->iRightJoinTable);
|
|
|
+ }else{
|
|
|
+ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
|
|
|
+ }
|
|
|
}else{
|
|
|
zFlgs[0] = 0;
|
|
|
}
|
|
|
@@ -92520,7 +92525,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
|
|
|
z = pExpr->u.zToken;
|
|
|
assert( z!=0 );
|
|
|
assert( z[0]!=0 );
|
|
|
- assert( n==sqlite3Strlen30(z) );
|
|
|
+ assert( n==(u32)sqlite3Strlen30(z) );
|
|
|
if( z[1]==0 ){
|
|
|
/* Wildcard of the form "?". Assign the next variable number */
|
|
|
assert( z[0]=='?' );
|
|
|
@@ -118924,7 +118929,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
|
|
pColExpr = pColExpr->pRight;
|
|
|
assert( pColExpr!=0 );
|
|
|
}
|
|
|
- if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
|
|
|
+ if( pColExpr->op==TK_COLUMN && pColExpr->pTab!=0 ){
|
|
|
/* For columns use the column name name */
|
|
|
int iCol = pColExpr->iColumn;
|
|
|
pTab = pColExpr->pTab;
|
|
|
@@ -120378,9 +120383,22 @@ static int multiSelectOrderBy(
|
|
|
#endif
|
|
|
|
|
|
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
|
+
|
|
|
+/* An instance of the SubstContext object describes an substitution edit
|
|
|
+** to be performed on a parse tree.
|
|
|
+**
|
|
|
+** All references to columns in table iTable are to be replaced by corresponding
|
|
|
+** expressions in pEList.
|
|
|
+*/
|
|
|
+typedef struct SubstContext {
|
|
|
+ Parse *pParse; /* The parsing context */
|
|
|
+ int iTable; /* Replace references to this table */
|
|
|
+ ExprList *pEList; /* Replacement expressions */
|
|
|
+} SubstContext;
|
|
|
+
|
|
|
/* Forward Declarations */
|
|
|
-static void substExprList(Parse*, ExprList*, int, ExprList*);
|
|
|
-static void substSelect(Parse*, Select *, int, ExprList*, int);
|
|
|
+static void substExprList(SubstContext*, ExprList*);
|
|
|
+static void substSelect(SubstContext*, Select*, int);
|
|
|
|
|
|
/*
|
|
|
** Scan through the expression pExpr. Replace every reference to
|
|
|
@@ -120396,24 +120414,22 @@ static void substSelect(Parse*, Select *, int, ExprList*, int);
|
|
|
** of the subquery rather the result set of the subquery.
|
|
|
*/
|
|
|
static Expr *substExpr(
|
|
|
- Parse *pParse, /* Report errors here */
|
|
|
- Expr *pExpr, /* Expr in which substitution occurs */
|
|
|
- int iTable, /* Table to be substituted */
|
|
|
- ExprList *pEList /* Substitute expressions */
|
|
|
+ SubstContext *pSubst, /* Description of the substitution */
|
|
|
+ Expr *pExpr /* Expr in which substitution occurs */
|
|
|
){
|
|
|
- sqlite3 *db = pParse->db;
|
|
|
if( pExpr==0 ) return 0;
|
|
|
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
|
|
|
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
|
|
|
if( pExpr->iColumn<0 ){
|
|
|
pExpr->op = TK_NULL;
|
|
|
}else{
|
|
|
Expr *pNew;
|
|
|
- Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
|
|
|
- assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
|
|
+ Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
|
|
|
+ assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
|
|
|
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
|
|
if( sqlite3ExprIsVector(pCopy) ){
|
|
|
- sqlite3VectorErrorMsg(pParse, pCopy);
|
|
|
+ sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
|
|
|
}else{
|
|
|
+ sqlite3 *db = pSubst->pParse->db;
|
|
|
pNew = sqlite3ExprDup(db, pCopy, 0);
|
|
|
if( pNew && (pExpr->flags & EP_FromJoin) ){
|
|
|
pNew->iRightJoinTable = pExpr->iRightJoinTable;
|
|
|
@@ -120424,51 +120440,47 @@ static Expr *substExpr(
|
|
|
}
|
|
|
}
|
|
|
}else{
|
|
|
- pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
|
|
|
- pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
|
|
|
+ pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
|
|
|
+ pExpr->pRight = substExpr(pSubst, pExpr->pRight);
|
|
|
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
|
- substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
|
|
|
+ substSelect(pSubst, pExpr->x.pSelect, 1);
|
|
|
}else{
|
|
|
- substExprList(pParse, pExpr->x.pList, iTable, pEList);
|
|
|
+ substExprList(pSubst, pExpr->x.pList);
|
|
|
}
|
|
|
}
|
|
|
return pExpr;
|
|
|
}
|
|
|
static void substExprList(
|
|
|
- Parse *pParse, /* Report errors here */
|
|
|
- ExprList *pList, /* List to scan and in which to make substitutes */
|
|
|
- int iTable, /* Table to be substituted */
|
|
|
- ExprList *pEList /* Substitute values */
|
|
|
+ SubstContext *pSubst, /* Description of the substitution */
|
|
|
+ ExprList *pList /* List to scan and in which to make substitutes */
|
|
|
){
|
|
|
int i;
|
|
|
if( pList==0 ) return;
|
|
|
for(i=0; i<pList->nExpr; i++){
|
|
|
- pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
|
|
|
+ pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
|
|
|
}
|
|
|
}
|
|
|
static void substSelect(
|
|
|
- Parse *pParse, /* Report errors here */
|
|
|
- Select *p, /* SELECT statement in which to make substitutions */
|
|
|
- int iTable, /* Table to be replaced */
|
|
|
- ExprList *pEList, /* Substitute values */
|
|
|
- int doPrior /* Do substitutes on p->pPrior too */
|
|
|
+ SubstContext *pSubst, /* Description of the substitution */
|
|
|
+ Select *p, /* SELECT statement in which to make substitutions */
|
|
|
+ int doPrior /* Do substitutes on p->pPrior too */
|
|
|
){
|
|
|
SrcList *pSrc;
|
|
|
struct SrcList_item *pItem;
|
|
|
int i;
|
|
|
if( !p ) return;
|
|
|
do{
|
|
|
- substExprList(pParse, p->pEList, iTable, pEList);
|
|
|
- substExprList(pParse, p->pGroupBy, iTable, pEList);
|
|
|
- substExprList(pParse, p->pOrderBy, iTable, pEList);
|
|
|
- p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
|
|
|
- p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
|
|
|
+ substExprList(pSubst, p->pEList);
|
|
|
+ substExprList(pSubst, p->pGroupBy);
|
|
|
+ substExprList(pSubst, p->pOrderBy);
|
|
|
+ p->pHaving = substExpr(pSubst, p->pHaving);
|
|
|
+ p->pWhere = substExpr(pSubst, p->pWhere);
|
|
|
pSrc = p->pSrc;
|
|
|
assert( pSrc!=0 );
|
|
|
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
|
|
- substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
|
|
|
+ substSelect(pSubst, pItem->pSelect, 1);
|
|
|
if( pItem->fg.isTabFunc ){
|
|
|
- substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
|
|
|
+ substExprList(pSubst, pItem->u1.pFuncArg);
|
|
|
}
|
|
|
}
|
|
|
}while( doPrior && (p = p->pPrior)!=0 );
|
|
|
@@ -120995,7 +121007,11 @@ static int flattenSubquery(
|
|
|
pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
|
|
|
}
|
|
|
if( db->mallocFailed==0 ){
|
|
|
- substSelect(pParse, pParent, iParent, pSub->pEList, 0);
|
|
|
+ SubstContext x;
|
|
|
+ x.pParse = pParse;
|
|
|
+ x.iTable = iParent;
|
|
|
+ x.pEList = pSub->pEList;
|
|
|
+ substSelect(&x, pParent, 0);
|
|
|
}
|
|
|
|
|
|
/* The flattened query is distinct if either the inner or the
|
|
|
@@ -121098,8 +121114,12 @@ static int pushDownWhereTerms(
|
|
|
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
|
|
nChng++;
|
|
|
while( pSubq ){
|
|
|
+ SubstContext x;
|
|
|
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
|
|
- pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
|
|
|
+ x.pParse = pParse;
|
|
|
+ x.iTable = iCursor;
|
|
|
+ x.pEList = pSubq->pEList;
|
|
|
+ pNew = substExpr(&x, pNew);
|
|
|
pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
|
|
|
pSubq = pSubq->pPrior;
|
|
|
}
|
|
|
@@ -126918,6 +126938,7 @@ struct WhereLoop {
|
|
|
u16 nEq; /* Number of equality constraints */
|
|
|
u16 nBtm; /* Size of BTM vector */
|
|
|
u16 nTop; /* Size of TOP vector */
|
|
|
+ u16 nIdxCol; /* Index column used for ORDER BY */
|
|
|
Index *pIndex; /* Index used, or NULL */
|
|
|
} btree;
|
|
|
struct { /* Information for virtual tables */
|
|
|
@@ -134353,7 +134374,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
-** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
|
|
|
+** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
|
|
|
** parameters) to see if it outputs rows in the requested ORDER BY
|
|
|
** (or GROUP BY) without requiring a separate sort operation. Return N:
|
|
|
**
|
|
|
@@ -134448,6 +134469,8 @@ static i8 wherePathSatisfiesOrderBy(
|
|
|
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
|
|
|
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
|
|
|
break;
|
|
|
+ }else{
|
|
|
+ pLoop->u.btree.nIdxCol = 0;
|
|
|
}
|
|
|
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
|
|
|
|
|
@@ -134593,6 +134616,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
|
if( !pColl ) pColl = db->pDfltColl;
|
|
|
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
|
|
|
}
|
|
|
+ pLoop->u.btree.nIdxCol = j+1;
|
|
|
isMatch = 1;
|
|
|
break;
|
|
|
}
|
|
|
@@ -135674,6 +135698,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
|
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
|
|
|
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
|
|
|
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
|
|
|
+ && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
|
|
|
){
|
|
|
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
|
|
|
}
|
|
|
@@ -135762,14 +135787,43 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
|
int addr;
|
|
|
pLevel = &pWInfo->a[i];
|
|
|
pLoop = pLevel->pWLoop;
|
|
|
- sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
|
if( pLevel->op!=OP_Noop ){
|
|
|
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
|
+ int addrSeek = 0;
|
|
|
+ Index *pIdx;
|
|
|
+ int n;
|
|
|
+ if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
|
|
|
+ && (pLoop->wsFlags & WHERE_INDEXED)!=0
|
|
|
+ && (pIdx = pLoop->u.btree.pIndex)->hasStat1
|
|
|
+ && (n = pLoop->u.btree.nIdxCol)>0
|
|
|
+ && pIdx->aiRowLogEst[n]>=36
|
|
|
+ ){
|
|
|
+ int r1 = pParse->nMem+1;
|
|
|
+ int j, op;
|
|
|
+ for(j=0; j<n; j++){
|
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j);
|
|
|
+ }
|
|
|
+ pParse->nMem += n+1;
|
|
|
+ op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
|
|
|
+ addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
|
|
|
+ VdbeCoverageIf(v, op==OP_SeekLT);
|
|
|
+ VdbeCoverageIf(v, op==OP_SeekGT);
|
|
|
+ sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
|
|
|
+ }
|
|
|
+#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
|
|
|
+ /* The common case: Advance to the next row */
|
|
|
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
|
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
|
|
sqlite3VdbeChangeP5(v, pLevel->p5);
|
|
|
VdbeCoverage(v);
|
|
|
VdbeCoverageIf(v, pLevel->op==OP_Next);
|
|
|
VdbeCoverageIf(v, pLevel->op==OP_Prev);
|
|
|
VdbeCoverageIf(v, pLevel->op==OP_VNext);
|
|
|
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
|
+ if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
|
|
|
+#endif
|
|
|
+ }else{
|
|
|
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
|
}
|
|
|
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
|
|
struct InLoop *pIn;
|
|
|
@@ -182740,7 +182794,10 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
|
j = i+1;
|
|
|
for(;;){
|
|
|
c = z[j];
|
|
|
- if( c<=0x1f ) return -1; /* Control characters not allowed in strings */
|
|
|
+ if( (c & ~0x1f)==0 ){
|
|
|
+ /* Control characters are not allowed in strings */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
if( c=='\\' ){
|
|
|
c = z[++j];
|
|
|
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|
|
|
@@ -183341,7 +183398,7 @@ static void jsonExtractFunc(
|
|
|
*/
|
|
|
static JsonNode *jsonMergePatch(
|
|
|
JsonParse *pParse, /* The JSON parser that contains the TARGET */
|
|
|
- int iTarget, /* Node of the TARGET in pParse */
|
|
|
+ u32 iTarget, /* Node of the TARGET in pParse */
|
|
|
JsonNode *pPatch /* The PATCH */
|
|
|
){
|
|
|
u32 i, j;
|
|
|
@@ -185558,6 +185615,7 @@ struct Fts5Token {
|
|
|
/* Parse a MATCH expression. */
|
|
|
static int sqlite3Fts5ExprNew(
|
|
|
Fts5Config *pConfig,
|
|
|
+ int iCol, /* Column on LHS of MATCH operator */
|
|
|
const char *zExpr,
|
|
|
Fts5Expr **ppNew,
|
|
|
char **pzErr
|
|
|
@@ -189275,6 +189333,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
|
|
|
|
|
static int sqlite3Fts5ExprNew(
|
|
|
Fts5Config *pConfig, /* FTS5 Configuration */
|
|
|
+ int iCol,
|
|
|
const char *zExpr, /* Expression text */
|
|
|
Fts5Expr **ppNew,
|
|
|
char **pzErr
|
|
|
@@ -189299,6 +189358,18 @@ static int sqlite3Fts5ExprNew(
|
|
|
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
|
|
|
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
|
|
|
|
|
|
+ /* If the LHS of the MATCH expression was a user column, apply the
|
|
|
+ ** implicit column-filter. */
|
|
|
+ if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
|
|
|
+ int n = sizeof(Fts5Colset);
|
|
|
+ Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
|
|
|
+ if( pColset ){
|
|
|
+ pColset->nCol = 1;
|
|
|
+ pColset->aiCol[0] = iCol;
|
|
|
+ sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
|
|
|
if( sParse.rc==SQLITE_OK ){
|
|
|
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
|
|
|
@@ -191505,7 +191576,7 @@ static void fts5ExprFunction(
|
|
|
|
|
|
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
|
|
if( rc==SQLITE_OK ){
|
|
|
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
|
|
|
+ rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
|
|
|
}
|
|
|
if( rc==SQLITE_OK ){
|
|
|
char *zText;
|
|
|
@@ -199398,6 +199469,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
|
|
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
|
Fts5Table *pTab = (Fts5Table*)pVTab;
|
|
|
Fts5Config *pConfig = pTab->pConfig;
|
|
|
+ const int nCol = pConfig->nCol;
|
|
|
int idxFlags = 0; /* Parameter passed through to xFilter() */
|
|
|
int bHasMatch;
|
|
|
int iNext;
|
|
|
@@ -199423,24 +199495,34 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
|
|
|
|
int aColMap[3];
|
|
|
aColMap[0] = -1;
|
|
|
- aColMap[1] = pConfig->nCol;
|
|
|
- aColMap[2] = pConfig->nCol+1;
|
|
|
+ aColMap[1] = nCol;
|
|
|
+ aColMap[2] = nCol+1;
|
|
|
|
|
|
/* Set idxFlags flags for all WHERE clause terms that will be used. */
|
|
|
for(i=0; i<pInfo->nConstraint; i++){
|
|
|
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
|
|
|
- int j;
|
|
|
- for(j=0; j<ArraySize(aConstraint); j++){
|
|
|
- struct Constraint *pC = &aConstraint[j];
|
|
|
- if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
|
|
|
- if( p->usable ){
|
|
|
+ int iCol = p->iColumn;
|
|
|
+
|
|
|
+ if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
|
|
|
+ || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
|
|
|
+ ){
|
|
|
+ /* A MATCH operator or equivalent */
|
|
|
+ if( p->usable ){
|
|
|
+ idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
|
|
|
+ aConstraint[0].iConsIndex = i;
|
|
|
+ }else{
|
|
|
+ /* As there exists an unusable MATCH constraint this is an
|
|
|
+ ** unusable plan. Set a prohibitively high cost. */
|
|
|
+ pInfo->estimatedCost = 1e50;
|
|
|
+ return SQLITE_OK;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ int j;
|
|
|
+ for(j=1; j<ArraySize(aConstraint); j++){
|
|
|
+ struct Constraint *pC = &aConstraint[j];
|
|
|
+ if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
|
|
|
pC->iConsIndex = i;
|
|
|
idxFlags |= pC->fts5op;
|
|
|
- }else if( j==0 ){
|
|
|
- /* As there exists an unusable MATCH constraint this is an
|
|
|
- ** unusable plan. Set a prohibitively high cost. */
|
|
|
- pInfo->estimatedCost = 1e50;
|
|
|
- return SQLITE_OK;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -200015,6 +200097,7 @@ static int fts5FilterMethod(
|
|
|
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
|
|
|
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
|
|
|
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
|
|
|
+ int iCol; /* Column on LHS of MATCH operator */
|
|
|
char **pzErrmsg = pConfig->pzErrmsg;
|
|
|
|
|
|
UNUSED_PARAM(zUnused);
|
|
|
@@ -200045,6 +200128,8 @@ static int fts5FilterMethod(
|
|
|
if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
|
|
|
if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
|
|
|
if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
|
|
|
+ iCol = (idxNum>>16);
|
|
|
+ assert( iCol>=0 && iCol<=pConfig->nCol );
|
|
|
assert( iVal==nVal );
|
|
|
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
|
|
|
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
|
|
|
@@ -200091,7 +200176,7 @@ static int fts5FilterMethod(
|
|
|
rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
|
|
|
}else{
|
|
|
char **pzErr = &pTab->base.zErrMsg;
|
|
|
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
|
|
|
+ rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
|
|
|
if( rc==SQLITE_OK ){
|
|
|
if( bOrderByRank ){
|
|
|
pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
|
|
|
@@ -201508,7 +201593,7 @@ static void fts5SourceIdFunc(
|
|
|
){
|
|
|
assert( nArg==0 );
|
|
|
UNUSED_PARAM2(nArg, apUnused);
|
|
|
- sqlite3_result_text(pCtx, "fts5: 2017-04-12 17:50:12 c847543f8bb1376fef52bca72b4191162a32eb7e6c5f0cd1aa0ab116b3183396", -1, SQLITE_TRANSIENT);
|
|
|
+ sqlite3_result_text(pCtx, "fts5: 2017-04-14 19:46:12 d78355c85f49e139f1ac1a660563865350f0e442652b7bc50b684398f81cc602", -1, SQLITE_TRANSIENT);
|
|
|
}
|
|
|
|
|
|
static int fts5Init(sqlite3 *db){
|