/ Check-in [5fcd840c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Update this branch with latest changes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | schemalint
Files: files | file ages | folders
SHA3-256: 5fcd840cf9b6a5c3ee4ef1e8f92f6c30f96a7899a3d774ee9be8a816916f2c3b
User & Date: dan 2017-04-13 16:19:40
Context
2017-04-14
19:41
Modify the code in ext/expert/ to use the vtab interface instead of sqlite3_whereinfo_hook(). Remove sqlite3_whereinfo_hook(). check-in: 3bb65850 user: dan tags: schemalint
2017-04-13
16:19
Update this branch with latest changes from trunk. check-in: 5fcd840c user: dan tags: schemalint
15:51
Reinstate the SQLITE_API qualifier on the sqlite3_delete_database() method in test_delete.c. Accidentally removed by the previous commit. check-in: 59c70108 user: dan tags: trunk
2017-04-11
19:00
Update this branch with latest trunk changes. check-in: 0f66a093 user: dan tags: schemalint
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts5/fts5Int.h.

   650    650     const char *p;                  /* Token text (not NULL terminated) */
   651    651     int n;                          /* Size of buffer p in bytes */
   652    652   };
   653    653   
   654    654   /* Parse a MATCH expression. */
   655    655   int sqlite3Fts5ExprNew(
   656    656     Fts5Config *pConfig, 
          657  +  int iCol,                       /* Column on LHS of MATCH operator */
   657    658     const char *zExpr,
   658    659     Fts5Expr **ppNew, 
   659    660     char **pzErr
   660    661   );
   661    662   
   662    663   /*
   663    664   ** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
................................................................................
   734    735   );
   735    736   
   736    737   void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*);
   737    738   void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
   738    739   void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
   739    740   
   740    741   void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
   741         -void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
          742  +void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
   742    743   Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
   743    744   void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
   744    745   void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
   745    746   
   746    747   /*
   747    748   ** End of interface to code in fts5_expr.c.
   748    749   **************************************************************************/

Changes to ext/fts5/fts5_expr.c.

   209    209   }
   210    210   
   211    211   static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
   212    212   static void fts5ParseFree(void *p){ sqlite3_free(p); }
   213    213   
   214    214   int sqlite3Fts5ExprNew(
   215    215     Fts5Config *pConfig,            /* FTS5 Configuration */
          216  +  int iCol,
   216    217     const char *zExpr,              /* Expression text */
   217    218     Fts5Expr **ppNew, 
   218    219     char **pzErr
   219    220   ){
   220    221     Fts5Parse sParse;
   221    222     Fts5Token token;
   222    223     const char *z = zExpr;
................................................................................
   232    233     sParse.pConfig = pConfig;
   233    234   
   234    235     do {
   235    236       t = fts5ExprGetToken(&sParse, &z, &token);
   236    237       sqlite3Fts5Parser(pEngine, t, token, &sParse);
   237    238     }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
   238    239     sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
          240  +
          241  +  /* If the LHS of the MATCH expression was a user column, apply the
          242  +  ** implicit column-filter.  */
          243  +  if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
          244  +    int n = sizeof(Fts5Colset);
          245  +    Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
          246  +    if( pColset ){
          247  +      pColset->nCol = 1;
          248  +      pColset->aiCol[0] = iCol;
          249  +      sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
          250  +    }
          251  +  }
   239    252   
   240    253     assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
   241    254     if( sParse.rc==SQLITE_OK ){
   242    255       *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
   243    256       if( pNew==0 ){
   244    257         sParse.rc = SQLITE_NOMEM;
   245    258         sqlite3Fts5ParseNodeFree(sParse.pExpr);
................................................................................
  1882   1895       assert( pParse->rc!=SQLITE_OK );
  1883   1896       sqlite3_free(pColset);
  1884   1897     }
  1885   1898   
  1886   1899     return pRet;
  1887   1900   }
  1888   1901   
         1902  +/*
         1903  +** If argument pOrig is NULL, or if (*pRc) is set to anything other than
         1904  +** SQLITE_OK when this function is called, NULL is returned. 
         1905  +**
         1906  +** Otherwise, a copy of (*pOrig) is made into memory obtained from
         1907  +** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
         1908  +** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
         1909  +*/
         1910  +static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
         1911  +  Fts5Colset *pRet;
         1912  +  if( pOrig ){
         1913  +    int nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
         1914  +    pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
         1915  +    if( pRet ){ 
         1916  +      memcpy(pRet, pOrig, nByte);
         1917  +    }
         1918  +  }else{
         1919  +    pRet = 0;
         1920  +  }
         1921  +  return pRet;
         1922  +}
         1923  +
         1924  +/*
         1925  +** Remove from colset pColset any columns that are not also in colset pMerge.
         1926  +*/
         1927  +static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
         1928  +  int iIn = 0;          /* Next input in pColset */
         1929  +  int iMerge = 0;       /* Next input in pMerge */
         1930  +  int iOut = 0;         /* Next output slot in pColset */
         1931  +
         1932  +  while( iIn<pColset->nCol && iMerge<pMerge->nCol ){
         1933  +    int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
         1934  +    if( iDiff==0 ){
         1935  +      pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
         1936  +      iMerge++;
         1937  +      iIn++;
         1938  +    }else if( iDiff>0 ){
         1939  +      iMerge++;
         1940  +    }else{
         1941  +      iIn++;
         1942  +    }
         1943  +  }
         1944  +  pColset->nCol = iOut;
         1945  +}
         1946  +
         1947  +/*
         1948  +** Recursively apply colset pColset to expression node pNode and all of
         1949  +** its decendents. If (*ppFree) is not NULL, it contains a spare copy
         1950  +** of pColset. This function may use the spare copy and set (*ppFree) to
         1951  +** zero, or it may create copies of pColset using fts5CloneColset().
         1952  +*/
         1953  +static void fts5ParseSetColset(
         1954  +  Fts5Parse *pParse, 
         1955  +  Fts5ExprNode *pNode, 
         1956  +  Fts5Colset *pColset,
         1957  +  Fts5Colset **ppFree
         1958  +){
         1959  +  if( pParse->rc==SQLITE_OK ){
         1960  +    assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING 
         1961  +         || pNode->eType==FTS5_AND  || pNode->eType==FTS5_OR
         1962  +         || pNode->eType==FTS5_NOT  || pNode->eType==FTS5_EOF
         1963  +    );
         1964  +    if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
         1965  +      Fts5ExprNearset *pNear = pNode->pNear;
         1966  +      if( pNear->pColset ){
         1967  +        fts5MergeColset(pNear->pColset, pColset);
         1968  +        if( pNear->pColset->nCol==0 ){
         1969  +          pNode->eType = FTS5_EOF;
         1970  +          pNode->xNext = 0;
         1971  +        }
         1972  +      }else if( *ppFree ){
         1973  +        pNear->pColset = pColset;
         1974  +        *ppFree = 0;
         1975  +      }else{
         1976  +        pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
         1977  +      }
         1978  +    }else{
         1979  +      int i;
         1980  +      assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
         1981  +      for(i=0; i<pNode->nChild; i++){
         1982  +        fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
         1983  +      }
         1984  +    }
         1985  +  }
         1986  +}
         1987  +
         1988  +/*
         1989  +** Apply colset pColset to expression node pExpr and all of its descendents.
         1990  +*/
  1889   1991   void sqlite3Fts5ParseSetColset(
  1890   1992     Fts5Parse *pParse, 
  1891         -  Fts5ExprNearset *pNear, 
         1993  +  Fts5ExprNode *pExpr, 
  1892   1994     Fts5Colset *pColset 
  1893   1995   ){
         1996  +  Fts5Colset *pFree = pColset;
  1894   1997     if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
  1895   1998       pParse->rc = SQLITE_ERROR;
  1896   1999       pParse->zErr = sqlite3_mprintf(
  1897   2000         "fts5: column queries are not supported (detail=none)"
  1898   2001       );
  1899         -    sqlite3_free(pColset);
  1900         -    return;
  1901         -  }
  1902         -
  1903         -  if( pNear ){
  1904         -    pNear->pColset = pColset;
  1905   2002     }else{
  1906         -    sqlite3_free(pColset);
         2003  +    fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
  1907   2004     }
         2005  +  sqlite3_free(pFree);
  1908   2006   }
  1909   2007   
  1910   2008   static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
  1911   2009     switch( pNode->eType ){
  1912   2010       case FTS5_STRING: {
  1913   2011         Fts5ExprNearset *pNear = pNode->pNear;
  1914   2012         if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 
................................................................................
  2354   2452       azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
  2355   2453     }
  2356   2454   
  2357   2455     zExpr = (const char*)sqlite3_value_text(apVal[0]);
  2358   2456   
  2359   2457     rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
  2360   2458     if( rc==SQLITE_OK ){
  2361         -    rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
         2459  +    rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
  2362   2460     }
  2363   2461     if( rc==SQLITE_OK ){
  2364   2462       char *zText;
  2365   2463       if( pExpr->pRoot->xNext==0 ){
  2366   2464         zText = sqlite3_mprintf("");
  2367   2465       }else if( bTcl ){
  2368   2466         zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot);

Changes to ext/fts5/fts5_index.c.

  3154   3154     while( p<pEnd && *p!=0x01 ){
  3155   3155       while( *p++ & 0x80 );
  3156   3156     }
  3157   3157   
  3158   3158     return p - (*pa);
  3159   3159   }
  3160   3160   
  3161         -static int fts5IndexExtractColset (
         3161  +static void fts5IndexExtractColset(
         3162  +  int *pRc,
  3162   3163     Fts5Colset *pColset,            /* Colset to filter on */
  3163   3164     const u8 *pPos, int nPos,       /* Position list */
  3164   3165     Fts5Buffer *pBuf                /* Output buffer */
  3165   3166   ){
  3166         -  int rc = SQLITE_OK;
  3167         -  int i;
  3168         -
  3169         -  fts5BufferZero(pBuf);
  3170         -  for(i=0; i<pColset->nCol; i++){
  3171         -    const u8 *pSub = pPos;
  3172         -    int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
  3173         -    if( nSub ){
  3174         -      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
         3167  +  if( *pRc==SQLITE_OK ){
         3168  +    int i;
         3169  +    fts5BufferZero(pBuf);
         3170  +    for(i=0; i<pColset->nCol; i++){
         3171  +      const u8 *pSub = pPos;
         3172  +      int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
         3173  +      if( nSub ){
         3174  +        fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
         3175  +      }
  3175   3176       }
  3176   3177     }
  3177         -  return rc;
  3178   3178   }
  3179   3179   
  3180   3180   /*
  3181   3181   ** xSetOutputs callback used by detail=none tables.
  3182   3182   */
  3183   3183   static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){
  3184   3184     assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE );
................................................................................
  3294   3294       /* All data is stored on the current page. Populate the output 
  3295   3295       ** variables to point into the body of the page object. */
  3296   3296       const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
  3297   3297       if( pColset->nCol==1 ){
  3298   3298         pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
  3299   3299         pIter->base.pData = a;
  3300   3300       }else{
         3301  +      int *pRc = &pIter->pIndex->rc;
  3301   3302         fts5BufferZero(&pIter->poslist);
  3302         -      fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist);
         3303  +      fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
  3303   3304         pIter->base.pData = pIter->poslist.p;
  3304   3305         pIter->base.nData = pIter->poslist.n;
  3305   3306       }
  3306   3307     }else{
  3307   3308       /* The data is distributed over two or more pages. Copy it into the
  3308   3309       ** Fts5Iter.poslist buffer and then set the output pointer to point
  3309   3310       ** to this buffer.  */

Changes to ext/fts5/fts5_main.c.

   502    502   **       * An == rowid constraint:       cost=10.0
   503    503   **
   504    504   ** Costs are not modified by the ORDER BY clause.
   505    505   */
   506    506   static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
   507    507     Fts5Table *pTab = (Fts5Table*)pVTab;
   508    508     Fts5Config *pConfig = pTab->pConfig;
          509  +  const int nCol = pConfig->nCol;
   509    510     int idxFlags = 0;               /* Parameter passed through to xFilter() */
   510    511     int bHasMatch;
   511    512     int iNext;
   512    513     int i;
   513    514   
   514    515     struct Constraint {
   515    516       int op;                       /* Mask against sqlite3_index_constraint.op */
................................................................................
   527    528                                       FTS5_BI_ROWID_LE, 0, 0, -1},
   528    529       {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, 
   529    530                                       FTS5_BI_ROWID_GE, 0, 0, -1},
   530    531     };
   531    532   
   532    533     int aColMap[3];
   533    534     aColMap[0] = -1;
   534         -  aColMap[1] = pConfig->nCol;
   535         -  aColMap[2] = pConfig->nCol+1;
          535  +  aColMap[1] = nCol;
          536  +  aColMap[2] = nCol+1;
   536    537   
   537    538     /* Set idxFlags flags for all WHERE clause terms that will be used. */
   538    539     for(i=0; i<pInfo->nConstraint; i++){
   539    540       struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
   540         -    int j;
   541         -    for(j=0; j<ArraySize(aConstraint); j++){
   542         -      struct Constraint *pC = &aConstraint[j];
   543         -      if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
   544         -        if( p->usable ){
          541  +    int iCol = p->iColumn;
          542  +
          543  +    if( (p->op==SQLITE_INDEX_CONSTRAINT_MATCH && iCol>=0 && iCol<=nCol)
          544  +     || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol)
          545  +    ){
          546  +      /* A MATCH operator or equivalent */
          547  +      if( p->usable ){
          548  +        idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16);
          549  +        aConstraint[0].iConsIndex = i;
          550  +      }else{
          551  +        /* As there exists an unusable MATCH constraint this is an 
          552  +        ** unusable plan. Set a prohibitively high cost. */
          553  +        pInfo->estimatedCost = 1e50;
          554  +        return SQLITE_OK;
          555  +      }
          556  +    }else{
          557  +      int j;
          558  +      for(j=1; j<ArraySize(aConstraint); j++){
          559  +        struct Constraint *pC = &aConstraint[j];
          560  +        if( iCol==aColMap[pC->iCol] && p->op & pC->op && p->usable ){
   545    561             pC->iConsIndex = i;
   546    562             idxFlags |= pC->fts5op;
   547         -        }else if( j==0 ){
   548         -          /* As there exists an unusable MATCH constraint this is an 
   549         -          ** unusable plan. Set a prohibitively high cost. */
   550         -          pInfo->estimatedCost = 1e50;
   551         -          return SQLITE_OK;
   552    563           }
   553    564         }
   554    565       }
   555    566     }
   556    567   
   557    568     /* Set idxFlags flags for the ORDER BY clause */
   558    569     if( pInfo->nOrderBy==1 ){
................................................................................
  1119   1130     int bDesc;                      /* True if ORDER BY [rank|rowid] DESC */
  1120   1131     int bOrderByRank;               /* True if ORDER BY rank */
  1121   1132     sqlite3_value *pMatch = 0;      /* <tbl> MATCH ? expression (or NULL) */
  1122   1133     sqlite3_value *pRank = 0;       /* rank MATCH ? expression (or NULL) */
  1123   1134     sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
  1124   1135     sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
  1125   1136     sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
         1137  +  int iCol;                       /* Column on LHS of MATCH operator */
  1126   1138     char **pzErrmsg = pConfig->pzErrmsg;
  1127   1139   
  1128   1140     UNUSED_PARAM(zUnused);
  1129   1141     UNUSED_PARAM(nVal);
  1130   1142   
  1131   1143     if( pCsr->ePlan ){
  1132   1144       fts5FreeCursorComponents(pCsr);
................................................................................
  1149   1161     ** order as the corresponding entries in the struct at the top of
  1150   1162     ** fts5BestIndexMethod().  */
  1151   1163     if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
  1152   1164     if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
  1153   1165     if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
  1154   1166     if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
  1155   1167     if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
         1168  +  iCol = (idxNum>>16);
         1169  +  assert( iCol>=0 && iCol<=pConfig->nCol );
  1156   1170     assert( iVal==nVal );
  1157   1171     bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
  1158   1172     pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
  1159   1173   
  1160   1174     /* Set the cursor upper and lower rowid limits. Only some strategies 
  1161   1175     ** actually use them. This is ok, as the xBestIndex() method leaves the
  1162   1176     ** sqlite3_index_constraint.omit flag clear for range constraints
................................................................................
  1195   1209         if( zExpr[0]=='*' ){
  1196   1210           /* The user has issued a query of the form "MATCH '*...'". This
  1197   1211           ** indicates that the MATCH expression is not a full text query,
  1198   1212           ** but a request for an internal parameter.  */
  1199   1213           rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
  1200   1214         }else{
  1201   1215           char **pzErr = &pTab->base.zErrMsg;
  1202         -        rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
         1216  +        rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr);
  1203   1217           if( rc==SQLITE_OK ){
  1204   1218             if( bOrderByRank ){
  1205   1219               pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
  1206   1220               rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
  1207   1221             }else{
  1208   1222               pCsr->ePlan = FTS5_PLAN_MATCH;
  1209   1223               rc = fts5CursorFirst(pTab, pCsr, bDesc);

Changes to ext/fts5/fts5parse.y.

    85     85   %type cnearset    {Fts5ExprNode*}
    86     86   %type expr        {Fts5ExprNode*}
    87     87   %type exprlist    {Fts5ExprNode*}
    88     88   %destructor cnearset { sqlite3Fts5ParseNodeFree($$); }
    89     89   %destructor expr     { sqlite3Fts5ParseNodeFree($$); }
    90     90   %destructor exprlist { sqlite3Fts5ParseNodeFree($$); }
    91     91   
    92         -expr(A) ::= expr(X) AND expr(Y). {
    93         -  A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
    94         -}
    95         -expr(A) ::= expr(X) OR expr(Y). {
    96         -  A = sqlite3Fts5ParseNode(pParse, FTS5_OR, X, Y, 0);
    97         -}
    98         -expr(A) ::= expr(X) NOT expr(Y). {
    99         -  A = sqlite3Fts5ParseNode(pParse, FTS5_NOT, X, Y, 0);
   100         -}
   101         -
   102         -expr(A) ::= LP expr(X) RP. {A = X;}
   103         -expr(A) ::= exprlist(X).   {A = X;}
   104         -
   105         -exprlist(A) ::= cnearset(X). {A = X;}
   106         -exprlist(A) ::= exprlist(X) cnearset(Y). {
   107         -  A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
   108         -}
   109         -
   110         -cnearset(A) ::= nearset(X). { 
   111         -  A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X); 
   112         -}
   113         -cnearset(A) ::= colset(X) COLON nearset(Y). { 
   114         -  sqlite3Fts5ParseSetColset(pParse, Y, X);
   115         -  A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y); 
   116         -}
   117         -
   118     92   %type colset {Fts5Colset*}
   119     93   %destructor colset { sqlite3_free($$); }
   120     94   %type colsetlist {Fts5Colset*}
   121     95   %destructor colsetlist { sqlite3_free($$); }
   122     96   
   123     97   colset(A) ::= MINUS LCP colsetlist(X) RCP. { 
   124     98       A = sqlite3Fts5ParseColsetInvert(pParse, X);
................................................................................
   133    107   }
   134    108   
   135    109   colsetlist(A) ::= colsetlist(Y) STRING(X). { 
   136    110     A = sqlite3Fts5ParseColset(pParse, Y, &X); }
   137    111   colsetlist(A) ::= STRING(X). { 
   138    112     A = sqlite3Fts5ParseColset(pParse, 0, &X); 
   139    113   }
          114  +
          115  +expr(A) ::= expr(X) AND expr(Y). {
          116  +  A = sqlite3Fts5ParseNode(pParse, FTS5_AND, X, Y, 0);
          117  +}
          118  +expr(A) ::= expr(X) OR expr(Y). {
          119  +  A = sqlite3Fts5ParseNode(pParse, FTS5_OR, X, Y, 0);
          120  +}
          121  +expr(A) ::= expr(X) NOT expr(Y). {
          122  +  A = sqlite3Fts5ParseNode(pParse, FTS5_NOT, X, Y, 0);
          123  +}
          124  +
          125  +expr(A) ::= colset(X) COLON LP expr(Y) RP. {
          126  +  sqlite3Fts5ParseSetColset(pParse, Y, X);
          127  +  A = Y;
          128  +}
          129  +expr(A) ::= LP expr(X) RP. {A = X;}
          130  +expr(A) ::= exprlist(X).   {A = X;}
          131  +
          132  +exprlist(A) ::= cnearset(X). {A = X;}
          133  +exprlist(A) ::= exprlist(X) cnearset(Y). {
          134  +  A = sqlite3Fts5ParseImplicitAnd(pParse, X, Y);
          135  +}
          136  +
          137  +cnearset(A) ::= nearset(X). { 
          138  +  A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, X); 
          139  +}
          140  +cnearset(A) ::= colset(X) COLON nearset(Y). { 
          141  +  A = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, Y); 
          142  +  sqlite3Fts5ParseSetColset(pParse, A, X);
          143  +}
          144  +
   140    145   
   141    146   %type nearset     {Fts5ExprNearset*}
   142    147   %type nearphrases {Fts5ExprNearset*}
   143    148   %destructor nearset { sqlite3Fts5ParseNearsetFree($$); }
   144    149   %destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); }
   145    150   
   146    151   nearset(A) ::= phrase(X). { A = sqlite3Fts5ParseNearset(pParse, 0, X); }

Changes to ext/fts5/test/fts5colset.test.

    40     40       5 " - {d d c} : a" {1 2}
    41     41       6 "- {d c b a} : a" {}
    42     42       7 "-{\"a\"} : b" {1 2 3}
    43     43       8 "- c : a" {1 2 4}
    44     44       9 "-c : a"  {1 2 4}
    45     45       10 "-\"c\" : a"  {1 2 4}
    46     46     } {
    47         -  breakpoint
    48     47       do_execsql_test 1.$tn {
    49     48         SELECT rowid FROM t1($q)
    50     49       } $res
    51     50     }
    52     51   
           52  +  foreach {tn q res} {
           53  +    0 {{a} : (a AND ":")}     {}
           54  +    1 "{a b c} : (a AND d)"   {2 3}
           55  +    2 "{a b c} : (a AND b:d)" {3}
           56  +    3 "{a b c} : (a AND d:d)" {}
           57  +    4 "{b} : ( {b a} : ( {c b a} : ( {d b c a} : ( d OR c ) ) ) )" {3 4}
           58  +    5 "{a} : ( {b a} : ( {c b a} : ( {d b c a} : ( d OR c ) ) ) )" {2 3}
           59  +    6 "{a} : ( {b a} : ( {c b} : ( {d b c a} : ( d OR c ) ) ) )" {}
           60  +    7 "{a b c} : (b:a AND c:b)" {2}
           61  +  } {
           62  +    do_execsql_test 2.$tn {
           63  +      SELECT rowid FROM t1($q)
           64  +    } $res
           65  +  }
           66  +
           67  +  foreach {tn w res} {
           68  +    0 "a MATCH 'a'" {1}
           69  +    1 "b MATCH 'a'" {2}
           70  +    2 "b MATCH '{a b c} : a'" {2}
           71  +    3 "b MATCH 'a OR b'"      {1 2}
           72  +    4 "b MATCH 'a OR a:b'"    {2}
           73  +    5 "b MATCH 'a OR b:b'"    {1 2}
           74  +  } {
           75  +    do_execsql_test 3.$tn "
           76  +      SELECT rowid FROM t1 WHERE $w
           77  +    " $res
           78  +  }
    53     79   
           80  +  do_catchsql_test 4.1 {
           81  +    SELECT * FROM t1 WHERE rowid MATCH 'a'
           82  +  } {1 {unable to use function MATCH in the requested context}}
    54     83   }
    55     84   
    56     85   
    57     86   finish_test
    58     87   
    59     88   

Changes to ext/fts5/test/fts5faultB.test.

   102    102   do_faultsim_test 3.3 -faults oom* -body {
   103    103     execsql {
   104    104       SELECT rowid FROM x1('c') WHERE rowid>1;
   105    105     }
   106    106   } -test {
   107    107     faultsim_test_result {0 {2 3}}
   108    108   }
          109  +
          110  +#-------------------------------------------------------------------------
          111  +# Test OOM injection with nested colsets.
          112  +#
          113  +reset_db
          114  +do_execsql_test 4.0 {
          115  +  CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, d);
          116  +  INSERT INTO t1 VALUES('a', 'b', 'c', 'd');  -- 1
          117  +  INSERT INTO t1 VALUES('d', 'a', 'b', 'c');  -- 2
          118  +  INSERT INTO t1 VALUES('c', 'd', 'a', 'b');  -- 3
          119  +  INSERT INTO t1 VALUES('b', 'c', 'd', 'a');  -- 4
          120  +}
          121  +do_faultsim_test 4.1 -faults oom* -body {
          122  +  execsql { SELECT rowid FROM t1('{a b c} : (b:a AND c:b)'); }
          123  +} -test {
          124  +  faultsim_test_result {0 2}
          125  +}
          126  +
          127  +do_faultsim_test 4.2 -faults oom* -body {
          128  +  execsql { SELECT rowid FROM t1('{a b c} : (a AND d)') }
          129  +} -test {
          130  +  faultsim_test_result {0 {2 3}}
          131  +}
          132  +
   109    133   
   110    134   finish_test
   111    135   

Changes to ext/fts5/test/fts5plan.test.

    26     26     CREATE VIRTUAL TABLE f1 USING fts5(ff);
    27     27   }
    28     28   
    29     29   do_eqp_test 1.1 {
    30     30     SELECT * FROM t1, f1 WHERE f1 MATCH t1.x
    31     31   } {
    32     32     0 0 0 {SCAN TABLE t1} 
    33         -  0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
           33  +  0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
    34     34   }
    35     35   
    36     36   do_eqp_test 1.2 {
    37     37     SELECT * FROM t1, f1 WHERE f1 > t1.x
    38     38   } {
    39     39     0 0 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:}
    40     40     0 1 0 {SCAN TABLE t1} 
    41     41   }
    42     42   
    43     43   do_eqp_test 1.3 {
    44     44     SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff
    45     45   } {
    46         -  0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 1:}
           46  +  0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:}
    47     47     0 0 0 {USE TEMP B-TREE FOR ORDER BY}
    48     48   }
    49     49   
    50     50   do_eqp_test 1.4 {
    51     51     SELECT * FROM f1 ORDER BY rank
    52     52   } {
    53     53     0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:}

Changes to ext/misc/dbdump.c.

   320    320     z = sqlite3_vmprintf(zFormat, ap);
   321    321     va_end(ap);
   322    322     p->xCallback(z, p->pArg);
   323    323     sqlite3_free(z);
   324    324   }
   325    325   
   326    326   /*
   327         -** Output the given string as a quoted string using SQL quoting conventions.
          327  +** Find a string that is not found anywhere in z[].  Return a pointer
          328  +** to that string.
   328    329   **
   329         -** The "\n" and "\r" characters are converted to char(10) and char(13)
   330         -** to prevent them from being transformed by end-of-line translators.
          330  +** Try to use zA and zB first.  If both of those are already found in z[]
          331  +** then make up some string and store it in the buffer zBuf.
          332  +*/
          333  +static const char *unused_string(
          334  +  const char *z,                    /* Result must not appear anywhere in z */
          335  +  const char *zA, const char *zB,   /* Try these first */
          336  +  char *zBuf                        /* Space to store a generated string */
          337  +){
          338  +  unsigned i = 0;
          339  +  if( strstr(z, zA)==0 ) return zA;
          340  +  if( strstr(z, zB)==0 ) return zB;
          341  +  do{
          342  +    sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
          343  +  }while( strstr(z,zBuf)!=0 );
          344  +  return zBuf;
          345  +}
          346  +
          347  +/*
          348  +** Output the given string as a quoted string using SQL quoting conventions.
          349  +** Additionallly , escape the "\n" and "\r" characters so that they do not
          350  +** get corrupted by end-of-line translation facilities in some operating
          351  +** systems.
   331    352   */
   332         -static void output_quoted_string(DState *p, const unsigned char *z){
          353  +static void output_quoted_escaped_string(DState *p, const char *z){
   333    354     int i;
   334    355     char c;
   335         -  int inQuote = 0;
   336         -  int bStarted = 0;
   337         -
   338    356     for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
   339    357     if( c==0 ){
   340         -    output_formatted(p, "'%s'", z);
   341         -    return;
   342         -  }
   343         -  while( *z ){
   344         -    for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
   345         -    if( c=='\'' ) i++;
   346         -    if( i ){
   347         -      if( !inQuote ){
   348         -        if( bStarted ) p->xCallback("||", p->pArg);
          358  +    output_formatted(p,"'%s'",z);
          359  +  }else{
          360  +    const char *zNL = 0;
          361  +    const char *zCR = 0;
          362  +    int nNL = 0;
          363  +    int nCR = 0;
          364  +    char zBuf1[20], zBuf2[20];
          365  +    for(i=0; z[i]; i++){
          366  +      if( z[i]=='\n' ) nNL++;
          367  +      if( z[i]=='\r' ) nCR++;
          368  +    }
          369  +    if( nNL ){
          370  +      p->xCallback("replace(", p->pArg);
          371  +      zNL = unused_string(z, "\\n", "\\012", zBuf1);
          372  +    }
          373  +    if( nCR ){
          374  +      p->xCallback("replace(", p->pArg);
          375  +      zCR = unused_string(z, "\\r", "\\015", zBuf2);
          376  +    }
          377  +    p->xCallback("'", p->pArg);
          378  +    while( *z ){
          379  +      for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
          380  +      if( c=='\'' ) i++;
          381  +      if( i ){
          382  +        output_formatted(p, "%.*s", i, z);
          383  +        z += i;
          384  +      }
          385  +      if( c=='\'' ){
   349    386           p->xCallback("'", p->pArg);
   350         -        inQuote = 1;
          387  +        continue;
          388  +      }
          389  +      if( c==0 ){
          390  +        break;
          391  +      }
          392  +      z++;
          393  +      if( c=='\n' ){
          394  +        p->xCallback(zNL, p->pArg);
          395  +        continue;
   351    396         }
   352         -      output_formatted(p, "%.*s", i, z);
   353         -      z += i;
   354         -      bStarted = 1;
          397  +      p->xCallback(zCR, p->pArg);
   355    398       }
   356         -    if( c=='\'' ){
   357         -      p->xCallback("'", p->pArg);
   358         -      continue;
          399  +    p->xCallback("'", p->pArg);
          400  +    if( nCR ){
          401  +      output_formatted(p, ",'%s',char(13))", zCR);
   359    402       }
   360         -    if( inQuote ){
   361         -      p->xCallback("'", p->pArg);
   362         -      inQuote = 0;
          403  +    if( nNL ){
          404  +      output_formatted(p, ",'%s',char(10))", zNL);
   363    405       }
   364         -    if( c==0 ){
   365         -      break;
   366         -    }
   367         -    for(i=0; (c = z[i])=='\r' || c=='\n'; i++){
   368         -      if( bStarted ) p->xCallback("||", p->pArg);
   369         -      output_formatted(p, "char(%d)", c);
   370         -      bStarted = 1;
   371         -    }
   372         -    z += i;
   373    406     }
   374         -  if( inQuote ) p->xCallback("'", p->pArg);
   375    407   }
   376    408   
   377    409   /*
   378    410   ** This is an sqlite3_exec callback routine used for dumping the database.
   379    411   ** Each row received by this callback consists of a table name,
   380    412   ** the table type ("index" or "table") and SQL to create the table.
   381    413   ** This routine should print text sufficient to recreate the table.
................................................................................
   491    523                 break;
   492    524               }
   493    525               case SQLITE_NULL: {
   494    526                 p->xCallback("NULL", p->pArg);
   495    527                 break;
   496    528               }
   497    529               case SQLITE_TEXT: {
   498         -              output_quoted_string(p, sqlite3_column_text(pStmt,i));
          530  +              output_quoted_escaped_string(p, 
          531  +                   (const char*)sqlite3_column_text(pStmt,i));
   499    532                 break;
   500    533               }
   501    534               case SQLITE_BLOB: {
   502    535                 int nByte = sqlite3_column_bytes(pStmt,i);
   503    536                 unsigned char *a = (unsigned char*)sqlite3_column_blob(pStmt,i);
   504    537                 int j;
   505    538                 p->xCallback("x'", p->pArg);

Changes to ext/misc/json1.c.

    86     86   #define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
    87     87   
    88     88   #ifndef SQLITE_AMALGAMATION
    89     89     /* Unsigned integer types.  These are already defined in the sqliteInt.h,
    90     90     ** but the definitions need to be repeated for separate compilation. */
    91     91     typedef sqlite3_uint64 u64;
    92     92     typedef unsigned int u32;
           93  +  typedef unsigned short int u16;
    93     94     typedef unsigned char u8;
    94     95   #endif
    95     96   
    96     97   /* Objects */
    97     98   typedef struct JsonString JsonString;
    98     99   typedef struct JsonNode JsonNode;
    99    100   typedef struct JsonParse JsonParse;
................................................................................
   165    166     u32 nNode;         /* Number of slots of aNode[] used */
   166    167     u32 nAlloc;        /* Number of slots of aNode[] allocated */
   167    168     JsonNode *aNode;   /* Array of nodes containing the parse */
   168    169     const char *zJson; /* Original JSON string */
   169    170     u32 *aUp;          /* Index of parent of each node */
   170    171     u8 oom;            /* Set to true if out of memory */
   171    172     u8 nErr;           /* Number of errors seen */
          173  +  u16 iDepth;        /* Nesting depth */
   172    174   };
   173    175   
          176  +/*
          177  +** Maximum nesting depth of JSON for this implementation.
          178  +**
          179  +** This limit is needed to avoid a stack overflow in the recursive
          180  +** descent parser.  A depth of 2000 is far deeper than any sane JSON
          181  +** should go.
          182  +*/
          183  +#define JSON_MAX_DEPTH  2000
          184  +
   174    185   /**************************************************************************
   175    186   ** Utility routines for dealing with JsonString objects
   176    187   **************************************************************************/
   177    188   
   178    189   /* Set the JsonString object to an empty string
   179    190   */
   180    191   static void jsonZero(JsonString *p){
................................................................................
   731    742     while( safe_isspace(z[i]) ){ i++; }
   732    743     if( (c = z[i])=='{' ){
   733    744       /* Parse object */
   734    745       iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
   735    746       if( iThis<0 ) return -1;
   736    747       for(j=i+1;;j++){
   737    748         while( safe_isspace(z[j]) ){ j++; }
          749  +      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
   738    750         x = jsonParseValue(pParse, j);
   739    751         if( x<0 ){
          752  +        pParse->iDepth--;
   740    753           if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
   741    754           return -1;
   742    755         }
   743    756         if( pParse->oom ) return -1;
   744    757         pNode = &pParse->aNode[pParse->nNode-1];
   745    758         if( pNode->eType!=JSON_STRING ) return -1;
   746    759         pNode->jnFlags |= JNODE_LABEL;
   747    760         j = x;
   748    761         while( safe_isspace(z[j]) ){ j++; }
   749    762         if( z[j]!=':' ) return -1;
   750    763         j++;
   751    764         x = jsonParseValue(pParse, j);
          765  +      pParse->iDepth--;
   752    766         if( x<0 ) return -1;
   753    767         j = x;
   754    768         while( safe_isspace(z[j]) ){ j++; }
   755    769         c = z[j];
   756    770         if( c==',' ) continue;
   757    771         if( c!='}' ) return -1;
   758    772         break;
................................................................................
   761    775       return j+1;
   762    776     }else if( c=='[' ){
   763    777       /* Parse array */
   764    778       iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
   765    779       if( iThis<0 ) return -1;
   766    780       for(j=i+1;;j++){
   767    781         while( safe_isspace(z[j]) ){ j++; }
          782  +      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
   768    783         x = jsonParseValue(pParse, j);
          784  +      pParse->iDepth--;
   769    785         if( x<0 ){
   770    786           if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
   771    787           return -1;
   772    788         }
   773    789         j = x;
   774    790         while( safe_isspace(z[j]) ){ j++; }
   775    791         c = z[j];
................................................................................
   781    797       return j+1;
   782    798     }else if( c=='"' ){
   783    799       /* Parse string */
   784    800       u8 jnFlags = 0;
   785    801       j = i+1;
   786    802       for(;;){
   787    803         c = z[j];
   788         -      if( c<=0x1f ) return -1;  /* Control characters not allowed in strings */
          804  +      if( (c & ~0x1f)==0 ){
          805  +        /* Control characters are not allowed in strings */
          806  +        return -1;
          807  +      }
   789    808         if( c=='\\' ){
   790    809           c = z[++j];
   791    810           if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
   792    811              || c=='n' || c=='r' || c=='t'
   793    812              || (c=='u' && jsonIs4Hex(z+j+1)) ){
   794    813             jnFlags = JNODE_ESCAPE;
   795    814           }else{
................................................................................
   881    900     int i;
   882    901     memset(pParse, 0, sizeof(*pParse));
   883    902     if( zJson==0 ) return 1;
   884    903     pParse->zJson = zJson;
   885    904     i = jsonParseValue(pParse, 0);
   886    905     if( pParse->oom ) i = -1;
   887    906     if( i>0 ){
          907  +    assert( pParse->iDepth==0 );
   888    908       while( safe_isspace(zJson[i]) ) i++;
   889    909       if( zJson[i] ) i = -1;
   890    910     }
   891    911     if( i<=0 ){
   892    912       if( pCtx!=0 ){
   893    913         if( pParse->oom ){
   894    914           sqlite3_result_error_nomem(pCtx);

Changes to src/fkey.c.

  1083   1083   ** to an array of size N, where N is the number of columns in table pTab.
  1084   1084   ** If the i'th column is not modified by the UPDATE, then the corresponding 
  1085   1085   ** entry in the aChange[] array is set to -1. If the column is modified,
  1086   1086   ** the value is 0 or greater. Parameter chngRowid is set to true if the
  1087   1087   ** UPDATE statement modifies the rowid fields of the table.
  1088   1088   **
  1089   1089   ** If any foreign key processing will be required, this function returns
  1090         -** true. If there is no foreign key related processing, this function 
  1091         -** returns false.
         1090  +** non-zero. If there is no foreign key related processing, this function 
         1091  +** returns zero.
         1092  +**
         1093  +** For an UPDATE, this function returns 2 if:
         1094  +**
         1095  +**   * There are any FKs for which pTab is the child and the parent table, or
         1096  +**   * the UPDATE modifies one or more parent keys for which the action is
         1097  +**     not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
         1098  +**
         1099  +** Or, assuming some other foreign key processing is required, 1.
  1092   1100   */
  1093   1101   int sqlite3FkRequired(
  1094   1102     Parse *pParse,                  /* Parse context */
  1095   1103     Table *pTab,                    /* Table being modified */
  1096   1104     int *aChange,                   /* Non-NULL for UPDATE operations */
  1097   1105     int chngRowid                   /* True for UPDATE that affects rowid */
  1098   1106   ){
         1107  +  int eRet = 0;
  1099   1108     if( pParse->db->flags&SQLITE_ForeignKeys ){
  1100   1109       if( !aChange ){
  1101   1110         /* A DELETE operation. Foreign key processing is required if the 
  1102   1111         ** table in question is either the child or parent table for any 
  1103   1112         ** foreign key constraint.  */
  1104         -      return (sqlite3FkReferences(pTab) || pTab->pFKey);
         1113  +      eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
  1105   1114       }else{
  1106   1115         /* This is an UPDATE. Foreign key processing is only required if the
  1107   1116         ** operation modifies one or more child or parent key columns. */
  1108   1117         FKey *p;
  1109   1118   
  1110   1119         /* Check if any child key columns are being modified. */
  1111   1120         for(p=pTab->pFKey; p; p=p->pNextFrom){
  1112         -        if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
         1121  +        if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
         1122  +        if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
         1123  +          eRet = 1;
         1124  +        }
  1113   1125         }
  1114   1126   
  1115   1127         /* Check if any parent key columns are being modified. */
  1116   1128         for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
  1117         -        if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
         1129  +        if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
         1130  +          if( p->aAction[1]!=OE_None ) return 2;
         1131  +          eRet = 1;
         1132  +        }
  1118   1133         }
  1119   1134       }
  1120   1135     }
  1121         -  return 0;
         1136  +  return eRet;
  1122   1137   }
  1123   1138   
  1124   1139   /*
  1125   1140   ** This function is called when an UPDATE or DELETE operation is being 
  1126   1141   ** compiled on table pTab, which is the parent table of foreign-key pFKey.
  1127   1142   ** If the current operation is an UPDATE, then the pChanges parameter is
  1128   1143   ** passed a pointer to the list of columns being modified. If it is a

Changes to src/test_delete.c.

    15     15   **   * The journal file.
    16     16   **   * The wal file.
    17     17   **   * The SQLITE_ENABLE_8_3_NAMES version of the db, journal or wal files.
    18     18   **   * Files created by the test_multiplex.c module to extend any of the 
    19     19   **     above.
    20     20   */
    21     21   
    22         -#if SQLITE_OS_WIN
    23         -#  include <io.h>
    24         -#  define F_OK 0
    25         -#else
           22  +#ifndef SQLITE_OS_WIN
    26     23   #  include <unistd.h>
           24  +#  include <errno.h>
    27     25   #endif
    28     26   #include <string.h>
    29         -#include <errno.h>
           27  +#include <assert.h>
    30     28   #include "sqlite3.h"
    31     29   
    32     30   /* The following #defines are copied from test_multiplex.c */
    33     31   #ifndef MX_CHUNK_NUMBER 
    34     32   # define MX_CHUNK_NUMBER 299
    35     33   #endif
    36     34   #ifndef SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET
................................................................................
    53     51   }
    54     52   
    55     53   /*
    56     54   ** zFile is a filename. Assuming no error occurs, if this file exists, 
    57     55   ** set *pbExists to true and unlink it. Or, if the file does not exist,
    58     56   ** set *pbExists to false before returning.
    59     57   **
    60         -** If an error occurs, the value of errno is returned. Or, if no error
    61         -** occurs, zero is returned.
           58  +** If an error occurs, non-zero is returned. Or, if no error occurs, zero.
    62     59   */
    63         -static int sqlite3DeleteUnlinkIfExists(const char *zFile, int *pbExists){
    64         -  int rc;
           60  +static int sqlite3DeleteUnlinkIfExists(
           61  +  sqlite3_vfs *pVfs,
           62  +  const char *zFile, 
           63  +  int *pbExists
           64  +){
           65  +  int rc = SQLITE_ERROR;
           66  +#if SQLITE_OS_WIN
           67  +  if( pVfs ){
           68  +    if( pbExists ) *pbExists = 1;
           69  +    rc = pVfs->xDelete(pVfs, zFile, 0);
           70  +    if( rc==SQLITE_IOERR_DELETE_NOENT ){
           71  +      if( pbExists ) *pbExists = 0;
           72  +      rc = SQLITE_OK;
           73  +    }
           74  +  }
           75  +#else
           76  +  assert( pVfs==0 );
    65     77     rc = access(zFile, F_OK);
    66     78     if( rc ){
    67     79       if( errno==ENOENT ){ 
    68     80         if( pbExists ) *pbExists = 0;
    69         -      return 0; 
           81  +      rc = SQLITE_OK; 
    70     82       }
    71         -    return errno;
           83  +  }else{
           84  +    if( pbExists ) *pbExists = 1;
           85  +    rc = unlink(zFile);
    72     86     }
    73         -  if( pbExists ) *pbExists = 1;
    74         -  rc = unlink(zFile);
    75         -  if( rc ) return errno;
    76         -  return 0;
           87  +#endif
           88  +  return rc;
    77     89   }
    78     90   
    79     91   /*
    80     92   ** Delete the database file identified by the string argument passed to this
    81     93   ** function. The string must contain a filename, not an SQLite URI.
    82     94   */
    83     95   SQLITE_API int sqlite3_delete_database(
................................................................................
    98    110       { "%s%03d",         0,   0 },
    99    111       { "%s-journal%03d", 0,   0 },
   100    112       { "%s-wal%03d",     0,   0 },
   101    113       { "%s%03d",         0,   1 },
   102    114       { "%s-journal%03d", SQLITE_MULTIPLEX_JOURNAL_8_3_OFFSET, 1 },
   103    115       { "%s-wal%03d",     SQLITE_MULTIPLEX_WAL_8_3_OFFSET, 1 },
   104    116     };
          117  +
          118  +#ifdef SQLITE_OS_WIN
          119  +  sqlite3_vfs *pVfs = sqlite3_vfs_find("win32");
          120  +#else
          121  +  sqlite3_vfs *pVfs = 0;
          122  +#endif
   105    123   
   106    124     /* Allocate a buffer large enough for any of the files that need to be
   107    125     ** deleted.  */
   108    126     nBuf = (int)strlen(zFile) + 100;
   109    127     zBuf = (char*)sqlite3_malloc(nBuf);
   110    128     if( zBuf==0 ) return SQLITE_NOMEM;
   111    129   
   112    130     /* Delete both the regular and 8.3 filenames versions of the database,
   113    131     ** journal, wal and shm files.  */
   114    132     for(i=0; rc==0 && i<sizeof(azFmt)/sizeof(azFmt[0]); i++){
   115    133       sqlite3_snprintf(nBuf, zBuf, azFmt[i], zFile);
   116         -    rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
          134  +    rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
   117    135       if( rc==0 && i!=0 ){
   118    136         sqlite3Delete83Name(zBuf);
   119         -      rc = sqlite3DeleteUnlinkIfExists(zBuf, 0);
          137  +      rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, 0);
   120    138       }
   121    139     }
   122    140   
   123    141     /* Delete any multiplexor files */
   124    142     for(i=0; rc==0 && i<sizeof(aMFile)/sizeof(aMFile[0]); i++){
   125    143       struct MFile *p = &aMFile[i];
   126    144       int iChunk;
   127    145       for(iChunk=1; iChunk<=MX_CHUNK_NUMBER; iChunk++){
   128    146         int bExists;
   129    147         sqlite3_snprintf(nBuf, zBuf, p->zFmt, zFile, iChunk+p->iOffset);
   130    148         if( p->b83 ) sqlite3Delete83Name(zBuf);
   131         -      rc = sqlite3DeleteUnlinkIfExists(zBuf, &bExists);
          149  +      rc = sqlite3DeleteUnlinkIfExists(pVfs, zBuf, &bExists);
   132    150         if( bExists==0 || rc!=0 ) break;
   133    151       }
   134    152     }
   135    153   
   136    154     sqlite3_free(zBuf);
   137    155     return (rc ? SQLITE_ERROR : SQLITE_OK);
   138    156   }

Changes to src/update.c.

   281    281     ** being updated.  Fill in aRegIdx[] with a register number that will hold
   282    282     ** the key for accessing each index.
   283    283     **
   284    284     ** FIXME:  Be smarter about omitting indexes that use expressions.
   285    285     */
   286    286     for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
   287    287       int reg;
   288         -    if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
          288  +    if( chngKey || hasFK>1 || pIdx->pPartIdxWhere || pIdx==pPk ){
   289    289         reg = ++pParse->nMem;
   290    290         pParse->nMem += pIdx->nColumn;
   291    291       }else{
   292    292         reg = 0;
   293    293         for(i=0; i<pIdx->nKeyCol; i++){
   294    294           i16 iIdxCol = pIdx->aiColumn[i];
   295    295           if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
................................................................................
   636    636       ** pre-update hook. If the caller invokes preupdate_new(), the returned
   637    637       ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
   638    638       ** is the column index supplied by the user.
   639    639       */
   640    640       assert( regNew==regNewRowid+1 );
   641    641   #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
   642    642       sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
   643         -        OPFLAG_ISUPDATE | ((hasFK || chngKey) ? 0 : OPFLAG_ISNOOP),
          643  +        OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
   644    644           regNewRowid
   645    645       );
   646    646       if( eOnePass==ONEPASS_MULTI ){
   647    647         assert( hasFK==0 && chngKey==0 );
   648    648         sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
   649    649       }
   650    650       if( !pParse->nested ){
   651    651         sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
   652    652       }
   653    653   #else
   654         -    if( hasFK || chngKey ){
          654  +    if( hasFK>1 || chngKey ){
   655    655         sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
   656    656       }
   657    657   #endif
   658    658       if( bReplace || chngKey ){
   659    659         sqlite3VdbeJumpHere(v, addr1);
   660    660       }
   661    661   

Changes to test/json101.test.

   351    351     INSERT INTO t8(a) VALUES('abc' || char(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35) || 'xyz');
   352    352     UPDATE t8 SET b=json_array(a);
   353    353     SELECT b FROM t8;
   354    354   } {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}}
   355    355   do_execsql_test json-8.2 {
   356    356     SELECT a=json_extract(b,'$[0]') FROM t8;
   357    357   } {1}
          358  +
          359  +# 2017-04-12.  Regression reported on the mailing list by Rolf Ade
          360  +#
          361  +do_execsql_test json-8.3 {
          362  +  SELECT json_valid(char(0x22,0xe4,0x22));
          363  +} {1}
          364  +do_execsql_test json-8.4 {
          365  +  SELECT unicode(json_extract(char(0x22,228,0x22),'$'));
          366  +} {228}
   358    367   
   359    368   # The json_quote() function transforms an SQL value into a JSON value.
   360    369   # String values are quoted and interior quotes are escaped.  NULL values
   361    370   # are rendered as the unquoted string "null".
   362    371   #
   363    372   do_execsql_test json-9.1 {
   364    373     SELECT json_quote('abc"xyz');
................................................................................
   684    693   do_execsql_test json-10.94 {
   685    694     SELECT json_valid('" \} "');
   686    695   } {0}
   687    696   do_execsql_test json-10.95 {
   688    697     SELECT json_valid('" \~ "');
   689    698   } {0}
   690    699   
          700  +#--------------------------------------------------------------------------
          701  +# 2017-04-11.  https://www.sqlite.org/src/info/981329adeef51011
          702  +# Stack overflow on deeply nested JSON.
          703  +#
          704  +# The following tests confirm that deeply nested JSON is considered invalid.
          705  +#
          706  +do_execsql_test json-11.0 {
          707  +  /* Shallow enough to be parsed */
          708  +  SELECT json_valid(printf('%.2000c0%.2000c','[',']'));
          709  +} {1}
          710  +do_execsql_test json-11.1 {
          711  +  /* Too deep by one */
          712  +  SELECT json_valid(printf('%.2001c0%.2001c','[',']'));
          713  +} {0}
          714  +do_execsql_test json-11.2 {
          715  +  /* Shallow enough to be parsed { */
          716  +  SELECT json_valid(replace(printf('%.2000c0%.2000c','[','}'),'[','{"a":'));
          717  +  /* } */
          718  +} {1}
          719  +do_execsql_test json-11.3 {
          720  +  /* Too deep by one { */
          721  +  SELECT json_valid(replace(printf('%.2001c0%.2001c','[','}'),'[','{"a":'));
          722  +  /* } */
          723  +} {0}
   691    724   
   692    725   finish_test