/ Check-in [b9fad449]
Login

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

Overview
Comment:Merge trunk changes into the apple-osx branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1:b9fad4490c437a2c49cf86cc1c068433d6d2866b
User & Date: drh 2014-05-29 20:36:56
Context
2014-06-05
12:53
Merge in the 3.8.5 release changes and the FTS integrity-check fix. check-in: 2dbdfa51 user: drh tags: apple-osx
2014-05-29
20:36
Merge trunk changes into the apple-osx branch. check-in: b9fad449 user: drh tags: apple-osx
20:17
Fix to the EXPLAIN indentation logic in the command-line shell. check-in: 8f916ed1 user: drh tags: trunk
2014-05-26
20:08
Merge recent trunk changes into the apple-osx branch. check-in: 54b5fa77 user: drh tags: apple-osx
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

  1372   1372     }
  1373   1373   
  1374   1374     /* Fill in the abNotindexed array */
  1375   1375     for(iCol=0; iCol<nCol; iCol++){
  1376   1376       int n = (int)strlen(p->azColumn[iCol]);
  1377   1377       for(i=0; i<nNotindexed; i++){
  1378   1378         char *zNot = azNotindexed[i];
  1379         -      if( zNot && strlen(zNot)==n 
         1379  +      if( zNot && n==(int)strlen(zNot)
  1380   1380          && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n) 
  1381   1381         ){
  1382   1382           p->abNotindexed[iCol] = 1;
  1383   1383           sqlite3_free(zNot);
  1384   1384           azNotindexed[i] = 0;
  1385   1385         }
  1386   1386       }

Changes to ext/fts3/fts3_expr.c.

   498    498         pParse->nNest++;
   499    499         rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
   500    500         if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; }
   501    501         *pnConsumed = (int)(zInput - z) + 1 + nConsumed;
   502    502         return rc;
   503    503       }else if( *zInput==')' ){
   504    504         pParse->nNest--;
   505         -      *pnConsumed = (zInput - z) + 1;
          505  +      *pnConsumed = (int)((zInput - z) + 1);
   506    506         *ppExpr = 0;
   507    507         return SQLITE_DONE;
   508    508       }
   509    509     }
   510    510   
   511    511     /* If control flows to this point, this must be a regular token, or 
   512    512     ** the end of the input. Read a regular token using the sqlite3_tokenizer

Changes to ext/fts3/fts3_write.c.

  3061   3061       ** segments in this index on levels greater than iAbsLevel. If there is
  3062   3062       ** at least one such segment, and it is possible to determine that all 
  3063   3063       ** such segments are smaller than nLimit bytes in size, they will be 
  3064   3064       ** promoted to level iAbsLevel.  */
  3065   3065       sqlite3_bind_int64(pRange, 1, iAbsLevel+1);
  3066   3066       sqlite3_bind_int64(pRange, 2, iLast);
  3067   3067       while( SQLITE_ROW==sqlite3_step(pRange) ){
  3068         -      i64 nSize, dummy;
         3068  +      i64 nSize = 0, dummy;
  3069   3069         fts3ReadEndBlockField(pRange, 2, &dummy, &nSize);
  3070   3070         if( nSize<=0 || nSize>nLimit ){
  3071   3071           /* If nSize==0, then the %_segdir.end_block field does not not 
  3072   3072           ** contain a size value. This happens if it was written by an
  3073   3073           ** old version of FTS. In this case it is not possible to determine
  3074   3074           ** the size of the segment, and so segment promotion does not
  3075   3075           ** take place.  */
................................................................................
  4866   4866       memset(pWriter, 0, nAlloc);
  4867   4867       pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
  4868   4868   
  4869   4869       if( rc==SQLITE_OK ){
  4870   4870         rc = fts3IncrmergeOutputIdx(p, iAbsLevel, &iIdx);
  4871   4871         assert( bUseHint==1 || bUseHint==0 );
  4872   4872         if( iIdx==0 || (bUseHint && iIdx==1) ){
  4873         -        int bIgnore;
         4873  +        int bIgnore = 0;
  4874   4874           rc = fts3SegmentIsMaxLevel(p, iAbsLevel+1, &bIgnore);
  4875   4875           if( bIgnore ){
  4876   4876             pFilter->flags |= FTS3_SEGMENT_IGNORE_EMPTY;
  4877   4877           }
  4878   4878         }
  4879   4879       }
  4880   4880   

Changes to src/analyze.c.

   998    998       if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
   999    999       VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName));
  1000   1000       nCol = pIdx->nKeyCol;
  1001   1001       aGotoChng = sqlite3DbMallocRaw(db, sizeof(int)*(nCol+1));
  1002   1002       if( aGotoChng==0 ) continue;
  1003   1003   
  1004   1004       /* Populate the register containing the index name. */
  1005         -    if( pIdx->autoIndex==2 && !HasRowid(pTab) ){
         1005  +    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
  1006   1006         zIdxName = pTab->zName;
  1007   1007       }else{
  1008   1008         zIdxName = pIdx->zName;
  1009   1009       }
  1010   1010       sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0);
  1011   1011   
  1012   1012       /*

Changes to src/btree.c.

  4241   4241   ){
  4242   4242     assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
  4243   4243     assert( pCur->eState==CURSOR_VALID );
  4244   4244     assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
  4245   4245     assert( cursorHoldsMutex(pCur) );
  4246   4246     assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
  4247   4247     assert( pCur->info.nSize>0 );
  4248         -#if 0
  4249         -  if( pCur->info.nSize==0 ){
  4250         -    btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
  4251         -                   &pCur->info);
  4252         -  }
  4253         -#endif
  4254   4248     *pAmt = pCur->info.nLocal;
  4255   4249     return (void*)(pCur->info.pCell + pCur->info.nHeader);
  4256   4250   }
  4257   4251   
  4258   4252   
  4259   4253   /*
  4260   4254   ** For the entry that cursor pCur is point to, return as

Changes to src/build.c.

   753    753   }
   754    754   
   755    755   /*
   756    756   ** Return the PRIMARY KEY index of a table
   757    757   */
   758    758   Index *sqlite3PrimaryKeyIndex(Table *pTab){
   759    759     Index *p;
   760         -  for(p=pTab->pIndex; p && p->autoIndex!=2; p=p->pNext){}
          760  +  for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){}
   761    761     return p;
   762    762   }
   763    763   
   764    764   /*
   765    765   ** Return the column of index pIdx that corresponds to table
   766    766   ** column iCol.  Return -1 if not found.
   767    767   */
................................................................................
  1282   1282     }else{
  1283   1283       Vdbe *v = pParse->pVdbe;
  1284   1284       Index *p;
  1285   1285       if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop);
  1286   1286       p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
  1287   1287                              0, sortOrder, 0);
  1288   1288       if( p ){
  1289         -      p->autoIndex = 2;
         1289  +      p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
  1290   1290         if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK);
  1291   1291       }
  1292   1292       pList = 0;
  1293   1293     }
  1294   1294   
  1295   1295   primary_key_exit:
  1296   1296     sqlite3ExprListDelete(pParse->db, pList);
................................................................................
  1657   1657       if( pList==0 ) return;
  1658   1658       pList->a[0].zName = sqlite3DbStrDup(pParse->db,
  1659   1659                                           pTab->aCol[pTab->iPKey].zName);
  1660   1660       pList->a[0].sortOrder = pParse->iPkSortOrder;
  1661   1661       assert( pParse->pNewTable==pTab );
  1662   1662       pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
  1663   1663       if( pPk==0 ) return;
  1664         -    pPk->autoIndex = 2;
         1664  +    pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
  1665   1665       pTab->iPKey = -1;
  1666   1666     }else{
  1667   1667       pPk = sqlite3PrimaryKeyIndex(pTab);
  1668   1668     }
  1669   1669     pPk->isCovering = 1;
  1670   1670     assert( pPk!=0 );
  1671   1671     nPk = pPk->nKeyCol;
................................................................................
  1680   1680     pPk->tnum = pTab->tnum;
  1681   1681   
  1682   1682     /* Update the in-memory representation of all UNIQUE indices by converting
  1683   1683     ** the final rowid column into one or more columns of the PRIMARY KEY.
  1684   1684     */
  1685   1685     for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
  1686   1686       int n;
  1687         -    if( pIdx->autoIndex==2 ) continue;
         1687  +    if( IsPrimaryKeyIndex(pIdx) ) continue;
  1688   1688       for(i=n=0; i<nPk; i++){
  1689   1689         if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
  1690   1690       }
  1691   1691       if( n==0 ){
  1692   1692         /* This index is a superset of the primary key */
  1693   1693         pIdx->nColumn = pIdx->nKeyCol;
  1694   1694         continue;
................................................................................
  2760   2760   **
  2761   2761   ** pList is a list of columns to be indexed.  pList will be NULL if this
  2762   2762   ** is a primary key or unique-constraint on the most recent column added
  2763   2763   ** to the table currently under construction.  
  2764   2764   **
  2765   2765   ** If the index is created successfully, return a pointer to the new Index
  2766   2766   ** structure. This is used by sqlite3AddPrimaryKey() to mark the index
  2767         -** as the tables primary key (Index.autoIndex==2).
         2767  +** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
  2768   2768   */
  2769   2769   Index *sqlite3CreateIndex(
  2770   2770     Parse *pParse,     /* All information about this parse */
  2771   2771     Token *pName1,     /* First part of index name. May be NULL */
  2772   2772     Token *pName2,     /* Second part of index name. May be NULL */
  2773   2773     SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */
  2774   2774     ExprList *pList,   /* A list of columns to be indexed */
................................................................................
  2975   2975     assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
  2976   2976     pIndex->zName = zExtra;
  2977   2977     zExtra += nName + 1;
  2978   2978     memcpy(pIndex->zName, zName, nName+1);
  2979   2979     pIndex->pTable = pTab;
  2980   2980     pIndex->onError = (u8)onError;
  2981   2981     pIndex->uniqNotNull = onError!=OE_None;
  2982         -  pIndex->autoIndex = (u8)(pName==0);
         2982  +  pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
  2983   2983     pIndex->pSchema = db->aDb[iDb].pSchema;
  2984   2984     pIndex->nKeyCol = pList->nExpr;
  2985   2985     if( pPIWhere ){
  2986   2986       sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0);
  2987   2987       pIndex->pPartIdxWhere = pPIWhere;
  2988   2988       pPIWhere = 0;
  2989   2989     }
................................................................................
  3087   3087       ** the constraint occur in different orders, then the constraints are
  3088   3088       ** considered distinct and both result in separate indices.
  3089   3089       */
  3090   3090       Index *pIdx;
  3091   3091       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
  3092   3092         int k;
  3093   3093         assert( pIdx->onError!=OE_None );
  3094         -      assert( pIdx->autoIndex );
         3094  +      assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
  3095   3095         assert( pIndex->onError!=OE_None );
  3096   3096   
  3097   3097         if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
  3098   3098         for(k=0; k<pIdx->nKeyCol; k++){
  3099   3099           const char *z1;
  3100   3100           const char *z2;
  3101   3101           if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
................................................................................
  3310   3310         sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
  3311   3311       }else{
  3312   3312         sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
  3313   3313       }
  3314   3314       pParse->checkSchema = 1;
  3315   3315       goto exit_drop_index;
  3316   3316     }
  3317         -  if( pIndex->autoIndex ){
         3317  +  if( pIndex->idxType!=SQLITE_IDXTYPE_APPDEF ){
  3318   3318       sqlite3ErrorMsg(pParse, "index associated with UNIQUE "
  3319   3319         "or PRIMARY KEY constraint cannot be dropped", 0);
  3320   3320       goto exit_drop_index;
  3321   3321     }
  3322   3322     iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
  3323   3323   #ifndef SQLITE_OMIT_AUTHORIZATION
  3324   3324     {
................................................................................
  3969   3969       if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
  3970   3970       sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
  3971   3971       sqlite3StrAccumAppend(&errMsg, ".", 1);
  3972   3972       sqlite3StrAccumAppendAll(&errMsg, zCol);
  3973   3973     }
  3974   3974     zErr = sqlite3StrAccumFinish(&errMsg);
  3975   3975     sqlite3HaltConstraint(pParse, 
  3976         -    (pIdx->autoIndex==2)?SQLITE_CONSTRAINT_PRIMARYKEY:SQLITE_CONSTRAINT_UNIQUE,
         3976  +    IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY 
         3977  +                            : SQLITE_CONSTRAINT_UNIQUE,
  3977   3978       onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
  3978   3979   }
  3979   3980   
  3980   3981   
  3981   3982   /*
  3982   3983   ** Code an OP_Halt due to non-unique rowid.
  3983   3984   */

Changes to src/fkey.c.

   229    229         /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
   230    230         ** of columns. If each indexed column corresponds to a foreign key
   231    231         ** column of pFKey, then this index is a winner.  */
   232    232   
   233    233         if( zKey==0 ){
   234    234           /* If zKey is NULL, then this foreign key is implicitly mapped to 
   235    235           ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be 
   236         -        ** identified by the test (Index.autoIndex==2).  */
   237         -        if( pIdx->autoIndex==2 ){
          236  +        ** identified by the test.  */
          237  +        if( IsPrimaryKeyIndex(pIdx) ){
   238    238             if( aiCol ){
   239    239               int i;
   240    240               for(i=0; i<nCol; i++) aiCol[i] = pFKey->aCol[i].iFrom;
   241    241             }
   242    242             break;
   243    243           }
   244    244         }else{

Changes to src/insert.c.

  1459   1459             ** different from the old.
  1460   1460             **
  1461   1461             ** For a UNIQUE index, only conflict if the PRIMARY KEY values
  1462   1462             ** of the matched index row are different from the original PRIMARY
  1463   1463             ** KEY values of this row before the update.  */
  1464   1464             int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
  1465   1465             int op = OP_Ne;
  1466         -          int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
         1466  +          int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
  1467   1467     
  1468   1468             for(i=0; i<pPk->nKeyCol; i++){
  1469   1469               char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
  1470   1470               x = pPk->aiColumn[i];
  1471   1471               if( i==(pPk->nKeyCol-1) ){
  1472   1472                 addrJump = addrUniqueOk;
  1473   1473                 op = OP_Eq;
................................................................................
  1560   1560       if( pIdx->pPartIdxWhere ){
  1561   1561         sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
  1562   1562         VdbeCoverage(v);
  1563   1563       }
  1564   1564       sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
  1565   1565       pik_flags = 0;
  1566   1566       if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
  1567         -    if( pIdx->autoIndex==2 && !HasRowid(pTab) ){
         1567  +    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
  1568   1568         assert( pParse->nested==0 );
  1569   1569         pik_flags |= OPFLAG_NCHANGE;
  1570   1570       }
  1571   1571       if( pik_flags )  sqlite3VdbeChangeP5(v, pik_flags);
  1572   1572     }
  1573   1573     if( !HasRowid(pTab) ) return;
  1574   1574     regData = regNewData + 1;
................................................................................
  1646   1646     }else{
  1647   1647       sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
  1648   1648     }
  1649   1649     if( piIdxCur ) *piIdxCur = iBase;
  1650   1650     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
  1651   1651       int iIdxCur = iBase++;
  1652   1652       assert( pIdx->pSchema==pTab->pSchema );
  1653         -    if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){
         1653  +    if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) && piDataCur ){
  1654   1654         *piDataCur = iIdxCur;
  1655   1655       }
  1656   1656       if( aToOpen==0 || aToOpen[i+1] ){
  1657   1657         sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
  1658   1658         sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  1659   1659         VdbeComment((v, "%s", pIdx->zName));
  1660   1660       }

Changes to src/os_win.c.

  2821   2821                         SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
  2822   2822     }
  2823   2823   #endif
  2824   2824     if( res == 0 ){
  2825   2825       pFile->lastErrno = osGetLastError();
  2826   2826       /* No need to log a failure to lock */
  2827   2827     }
  2828         -  OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
         2828  +  OSTRACE(("READ-LOCK file=%p, result=%d\n", pFile->h, res));
  2829   2829     return res;
  2830   2830   }
  2831   2831   
  2832   2832   /*
  2833   2833   ** Undo a readlock
  2834   2834   */
  2835   2835   static int winUnlockReadLock(winFile *pFile){
................................................................................
  2845   2845     }
  2846   2846   #endif
  2847   2847     if( res==0 && ((lastErrno = osGetLastError())!=ERROR_NOT_LOCKED) ){
  2848   2848       pFile->lastErrno = lastErrno;
  2849   2849       winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
  2850   2850                   "winUnlockReadLock", pFile->zPath);
  2851   2851     }
  2852         -  OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
         2852  +  OSTRACE(("READ-UNLOCK file=%p, result=%d\n", pFile->h, res));
  2853   2853     return res;
  2854   2854   }
  2855   2855   
  2856   2856   /*
  2857   2857   ** Lock the file with the lock specified by parameter locktype - one
  2858   2858   ** of the following:
  2859   2859   **
................................................................................
  2920   2920                                            PENDING_BYTE, 0, 1, 0))==0 ){
  2921   2921         /* Try 3 times to get the pending lock.  This is needed to work
  2922   2922         ** around problems caused by indexing and/or anti-virus software on
  2923   2923         ** Windows systems.
  2924   2924         ** If you are using this code as a model for alternative VFSes, do not
  2925   2925         ** copy this retry logic.  It is a hack intended for Windows only.
  2926   2926         */
  2927         -      OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
  2928         -               pFile->h, cnt, sqlite3ErrName(res)));
         2927  +      OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
         2928  +               pFile->h, cnt, res));
  2929   2929         if( cnt ) sqlite3_win32_sleep(1);
  2930   2930       }
  2931   2931       gotPendingLock = res;
  2932   2932       if( !res ){
  2933   2933         lastErrno = osGetLastError();
  2934   2934       }
  2935   2935     }
................................................................................
  3006   3006   
  3007   3007   /*
  3008   3008   ** This routine checks if there is a RESERVED lock held on the specified
  3009   3009   ** file by this or any other process. If such a lock is held, return
  3010   3010   ** non-zero, otherwise zero.
  3011   3011   */
  3012   3012   static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
  3013         -  int rc;
         3013  +  int res;
  3014   3014     winFile *pFile = (winFile*)id;
  3015   3015   
  3016   3016     SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
  3017   3017     OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
  3018   3018   
  3019   3019     assert( id!=0 );
  3020   3020     if( pFile->locktype>=RESERVED_LOCK ){
  3021         -    rc = 1;
  3022         -    OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
         3021  +    res = 1;
         3022  +    OSTRACE(("TEST-WR-LOCK file=%p, result=%d (local)\n", pFile->h, res));
  3023   3023     }else{
  3024         -    rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
  3025         -    if( rc ){
         3024  +    res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
         3025  +    if( res ){
  3026   3026         winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
  3027   3027       }
  3028         -    rc = !rc;
  3029         -    OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
         3028  +    res = !res;
         3029  +    OSTRACE(("TEST-WR-LOCK file=%p, result=%d (remote)\n", pFile->h, res));
  3030   3030     }
  3031         -  *pResOut = rc;
         3031  +  *pResOut = res;
  3032   3032     OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
  3033   3033              pFile->h, pResOut, *pResOut));
  3034   3034     return SQLITE_OK;
  3035   3035   }
  3036   3036   
  3037   3037   /*
  3038   3038   ** Lower the locking level on file descriptor id to locktype.  locktype

Changes to src/select.c.

  4494   4494   #ifndef SQLITE_OMIT_EXPLAIN
  4495   4495   static void explainSimpleCount(
  4496   4496     Parse *pParse,                  /* Parse context */
  4497   4497     Table *pTab,                    /* Table being queried */
  4498   4498     Index *pIdx                     /* Index used to optimize scan, or NULL */
  4499   4499   ){
  4500   4500     if( pParse->explain==2 ){
  4501         -    int bCover = (pIdx!=0 && (HasRowid(pTab) || pIdx->autoIndex!=2));
         4501  +    int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
  4502   4502       char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s",
  4503   4503           pTab->zName,
  4504   4504           bCover ? " USING COVERING INDEX " : "",
  4505   4505           bCover ? pIdx->zName : ""
  4506   4506       );
  4507   4507       sqlite3VdbeAddOp4(
  4508   4508           pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC

Changes to src/shell.c.

   442    442   ** An pointer to an instance of this structure is passed from
   443    443   ** the main program to the callback.  This is used to communicate
   444    444   ** state and mode information.
   445    445   */
   446    446   struct callback_data {
   447    447     sqlite3 *db;           /* The database */
   448    448     int echoOn;            /* True to echo input commands */
   449         -  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL statement */
          449  +  int autoEQP;           /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
   450    450     int statsOn;           /* True to display memory stats before each finalize */
          451  +  int outCount;          /* Revert to stdout when reaching zero */
   451    452     int cnt;               /* Number of records displayed so far */
   452    453     FILE *out;             /* Write results here */
   453    454     FILE *traceOut;        /* Output for sqlite3_trace() */
   454    455     int nErr;              /* Number of errors seen */
   455    456     int mode;              /* An output mode setting */
   456    457     int writableSchema;    /* True if PRAGMA writable_schema=ON */
   457    458     int showHeader;        /* True to show column names in List or Column mode */
................................................................................
   874    875         for(i=0; i<nArg; i++){
   875    876           char *zSep = i>0 ? ",": "";
   876    877           if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
   877    878             fprintf(p->out,"%sNULL",zSep);
   878    879           }else if( aiType && aiType[i]==SQLITE_TEXT ){
   879    880             if( zSep[0] ) fprintf(p->out,"%s",zSep);
   880    881             output_quoted_string(p->out, azArg[i]);
   881         -        }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
          882  +        }else if( aiType && (aiType[i]==SQLITE_INTEGER
          883  +                             || aiType[i]==SQLITE_FLOAT) ){
   882    884             fprintf(p->out,"%s%s",zSep, azArg[i]);
   883    885           }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
   884    886             const void *pBlob = sqlite3_column_blob(p->pStmt, i);
   885    887             int nBlob = sqlite3_column_bytes(p->pStmt, i);
   886    888             if( zSep[0] ) fprintf(p->out,"%s",zSep);
   887    889             output_hex_blob(p->out, pBlob, nBlob);
   888    890           }else if( isNumber(azArg[i], 0) ){
................................................................................
  1194   1196     const char *z;                  /* Used to check if this is an EXPLAIN */
  1195   1197     int *abYield = 0;               /* True if op is an OP_Yield */
  1196   1198     int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
  1197   1199     int iOp;                        /* Index of operation in p->aiIndent[] */
  1198   1200   
  1199   1201     const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
  1200   1202                              "NextIfOpen", "PrevIfOpen", 0 };
  1201         -  const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
         1203  +  const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 };
  1202   1204     const char *azGoto[] = { "Goto", 0 };
  1203   1205   
  1204   1206     /* Try to figure out if this is really an EXPLAIN statement. If this
  1205   1207     ** cannot be verified, return early.  */
  1206   1208     zSql = sqlite3_sql(pSql);
  1207   1209     if( zSql==0 ) return;
  1208   1210     for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
................................................................................
  1566   1568   }
  1567   1569   
  1568   1570   /*
  1569   1571   ** Text of a help message
  1570   1572   */
  1571   1573   static char zHelp[] =
  1572   1574     ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
  1573         -  ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"
         1575  +  ".bail on|off           Stop after hitting an error.  Default OFF\n"
  1574   1576     ".clone NEWDB           Clone data into NEWDB from the existing database\n"
  1575   1577     ".databases             List names and files of attached databases\n"
  1576   1578     ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
  1577   1579     "                         If TABLE specified, only dump tables matching\n"
  1578   1580     "                         LIKE pattern TABLE.\n"
  1579         -  ".echo ON|OFF           Turn command echo on or off\n"
         1581  +  ".echo on|off           Turn command echo on or off\n"
  1580   1582     ".exit                  Exit this program\n"
  1581         -  ".explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.\n"
         1583  +  ".explain ?on|off?      Turn output mode suitable for EXPLAIN on or off.\n"
  1582   1584     "                         With no args, it turns EXPLAIN on.\n"
  1583         -  ".header(s) ON|OFF      Turn display of headers on or off\n"
         1585  +  ".headers on|off        Turn display of headers on or off\n"
  1584   1586     ".help                  Show this message\n"
  1585   1587     ".import FILE TABLE     Import data from FILE into TABLE\n"
  1586   1588     ".indices ?TABLE?       Show names of all indices\n"
  1587   1589     "                         If TABLE specified, only show indices for tables\n"
  1588   1590     "                         matching LIKE pattern TABLE.\n"
  1589   1591   #ifdef SQLITE_ENABLE_IOTRACE
  1590   1592     ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
................................................................................
  1599   1601     "                         html     HTML <table> code\n"
  1600   1602     "                         insert   SQL insert statements for TABLE\n"
  1601   1603     "                         line     One value per line\n"
  1602   1604     "                         list     Values delimited by .separator string\n"
  1603   1605     "                         tabs     Tab-separated values\n"
  1604   1606     "                         tcl      TCL list elements\n"
  1605   1607     ".nullvalue STRING      Use STRING in place of NULL values\n"
         1608  +  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
  1606   1609     ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
  1607         -  ".output FILENAME       Send output to FILENAME\n"
  1608         -  ".output stdout         Send output to the screen\n"
         1610  +  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
  1609   1611     ".print STRING...       Print literal STRING\n"
  1610   1612     ".prompt MAIN CONTINUE  Replace the standard prompts\n"
  1611   1613     ".quit                  Exit this program\n"
  1612   1614     ".read FILENAME         Execute SQL in FILENAME\n"
  1613   1615     ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  1614   1616     ".save FILE             Write in-memory database into FILE\n"
  1615   1617     ".schema ?TABLE?        Show the CREATE statements\n"
  1616   1618     "                         If TABLE specified, only show tables matching\n"
  1617   1619     "                         LIKE pattern TABLE.\n"
  1618   1620     ".separator STRING      Change separator used by output mode and .import\n"
         1621  +  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
  1619   1622     ".show                  Show the current values for various settings\n"
  1620         -  ".stats ON|OFF          Turn stats on or off\n"
         1623  +  ".stats on|off          Turn stats on or off\n"
         1624  +  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
  1621   1625     ".tables ?TABLE?        List names of tables\n"
  1622   1626     "                         If TABLE specified, only list tables matching\n"
  1623   1627     "                         LIKE pattern TABLE.\n"
  1624   1628     ".timeout MS            Try opening locked tables for MS milliseconds\n"
         1629  +  ".timer on|off          Turn SQL timer on or off\n"
  1625   1630     ".trace FILE|off        Output each SQL statement as it is run\n"
  1626   1631     ".vfsname ?AUX?         Print the name of the VFS stack\n"
  1627   1632     ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
  1628         -;
  1629         -
  1630         -static char zTimerHelp[] =
  1631         -  ".timer ON|OFF          Turn the CPU timer measurement on or off\n"
         1633  +  "                         Negative values right-justify\n"
  1632   1634   ;
  1633   1635   
  1634   1636   /* Forward reference */
  1635   1637   static int process_input(struct callback_data *p, FILE *in);
  1636   1638   
  1637   1639   /*
  1638   1640   ** Make sure the database is open.  If it is not, then open it.  If
................................................................................
  1668   1670   **    \"    -> "
  1669   1671   **    \NNN  -> ascii character NNN in octal
  1670   1672   **    \\    -> backslash
  1671   1673   */
  1672   1674   static void resolve_backslashes(char *z){
  1673   1675     int i, j;
  1674   1676     char c;
         1677  +  while( *z && *z!='\\' ) z++;
  1675   1678     for(i=j=0; (c = z[i])!=0; i++, j++){
  1676   1679       if( c=='\\' ){
  1677   1680         c = z[++i];
  1678   1681         if( c=='n' ){
  1679   1682           c = '\n';
  1680   1683         }else if( c=='t' ){
  1681   1684           c = '\t';
................................................................................
  1693   1696               c = (c<<3) + z[i] - '0';
  1694   1697             }
  1695   1698           }
  1696   1699         }
  1697   1700       }
  1698   1701       z[j] = c;
  1699   1702     }
  1700         -  z[j] = 0;
         1703  +  if( j<i ) z[j] = 0;
  1701   1704   }
  1702   1705   
  1703   1706   /*
  1704   1707   ** Return the value of a hexadecimal digit.  Return -1 if the input
  1705   1708   ** is not a hex digit.
  1706   1709   */
  1707   1710   static int hexDigitValue(char c){
................................................................................
  2136   2139       tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
  2137   2140       tryToCloneSchema(p, newDb, "type!='table'", 0);
  2138   2141       sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
  2139   2142       sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  2140   2143     }
  2141   2144     sqlite3_close(newDb);
  2142   2145   }
         2146  +
         2147  +/*
         2148  +** Change the output file back to stdout
         2149  +*/
         2150  +static void output_reset(struct callback_data *p){
         2151  +  if( p->outfile[0]=='|' ){
         2152  +    pclose(p->out);
         2153  +  }else{
         2154  +    output_file_close(p->out);
         2155  +  }
         2156  +  p->outfile[0] = 0;
         2157  +  p->out = stdout;
         2158  +}
  2143   2159   
  2144   2160   /*
  2145   2161   ** If an input line begins with "." then invoke this routine to
  2146   2162   ** process that line.
  2147   2163   **
  2148   2164   ** Return 1 on error, 2 to exit, and 0 otherwise.
  2149   2165   */
................................................................................
  2235   2251       }else{
  2236   2252         fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
  2237   2253         rc = 1;
  2238   2254       }
  2239   2255       sqlite3_close(pDest);
  2240   2256     }else
  2241   2257   
  2242         -  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
  2243         -    bail_on_error = booleanValue(azArg[1]);
         2258  +  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
         2259  +    if( nArg==2 ){
         2260  +      bail_on_error = booleanValue(azArg[1]);
         2261  +    }else{
         2262  +      fprintf(stderr, "Usage: .bail on|off\n");
         2263  +      rc = 1;
         2264  +    }
  2244   2265     }else
  2245   2266   
  2246   2267     /* The undocumented ".breakpoint" command causes a call to the no-op
  2247   2268     ** routine named test_breakpoint().
  2248   2269     */
  2249   2270     if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
  2250   2271       test_breakpoint();
  2251   2272     }else
  2252   2273   
  2253         -  if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
  2254         -    tryToClone(p, azArg[1]);
         2274  +  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
         2275  +    if( nArg==2 ){
         2276  +      tryToClone(p, azArg[1]);
         2277  +    }else{
         2278  +      fprintf(stderr, "Usage: .clone FILENAME\n");
         2279  +      rc = 1;
         2280  +    }
  2255   2281     }else
  2256   2282   
  2257         -  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
         2283  +  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
  2258   2284       struct callback_data data;
  2259   2285       char *zErrMsg = 0;
  2260   2286       open_db(p, 0);
  2261   2287       memcpy(&data, p, sizeof(data));
  2262   2288       data.showHeader = 1;
  2263   2289       data.mode = MODE_Column;
  2264   2290       data.colWidth[0] = 3;
................................................................................
  2269   2295       if( zErrMsg ){
  2270   2296         fprintf(stderr,"Error: %s\n", zErrMsg);
  2271   2297         sqlite3_free(zErrMsg);
  2272   2298         rc = 1;
  2273   2299       }
  2274   2300     }else
  2275   2301   
  2276         -  if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
         2302  +  if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
  2277   2303       open_db(p, 0);
  2278   2304       /* When playing back a "dump", the content might appear in an order
  2279   2305       ** which causes immediate foreign key constraints to be violated.
  2280   2306       ** So disable foreign-key constraint enforcement to prevent problems. */
         2307  +    if( nArg!=1 && nArg!=2 ){
         2308  +      fprintf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
         2309  +      rc = 1;
         2310  +      goto meta_command_exit;
         2311  +    }
  2281   2312       fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
  2282   2313       fprintf(p->out, "BEGIN TRANSACTION;\n");
  2283   2314       p->writableSchema = 0;
  2284   2315       sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
  2285   2316       p->nErr = 0;
  2286   2317       if( nArg==1 ){
  2287   2318         run_schema_dump_query(p, 
................................................................................
  2318   2349         p->writableSchema = 0;
  2319   2350       }
  2320   2351       sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  2321   2352       sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
  2322   2353       fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
  2323   2354     }else
  2324   2355   
  2325         -  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
  2326         -    p->echoOn = booleanValue(azArg[1]);
         2356  +  if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
         2357  +    if( nArg==2 ){
         2358  +      p->echoOn = booleanValue(azArg[1]);
         2359  +    }else{
         2360  +      fprintf(stderr, "Usage: .echo on|off\n");
         2361  +      rc = 1;
         2362  +    }
  2327   2363     }else
  2328   2364   
  2329         -  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 && nArg>1 && nArg<3 ){
  2330         -    p->autoEQP = booleanValue(azArg[1]);
         2365  +  if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
         2366  +    if( nArg==2 ){
         2367  +      p->autoEQP = booleanValue(azArg[1]);
         2368  +    }else{
         2369  +      fprintf(stderr, "Usage: .eqp on|off\n");
         2370  +      rc = 1;
         2371  +    }   
  2331   2372     }else
  2332   2373   
  2333   2374     if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
  2334   2375       if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
  2335   2376       rc = 2;
  2336   2377     }else
  2337   2378   
  2338         -  if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
         2379  +  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
  2339   2380       int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
  2340   2381       if(val == 1) {
  2341   2382         if(!p->explainPrev.valid) {
  2342   2383           p->explainPrev.valid = 1;
  2343   2384           p->explainPrev.mode = p->mode;
  2344   2385           p->explainPrev.showHeader = p->showHeader;
  2345   2386           memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
................................................................................
  2366   2407         p->explainPrev.valid = 0;
  2367   2408         p->mode = p->explainPrev.mode;
  2368   2409         p->showHeader = p->explainPrev.showHeader;
  2369   2410         memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
  2370   2411       }
  2371   2412     }else
  2372   2413   
  2373         -  if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
  2374         -                 strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
  2375         -    p->showHeader = booleanValue(azArg[1]);
         2414  +  if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
         2415  +    if( nArg==2 ){
         2416  +      p->showHeader = booleanValue(azArg[1]);
         2417  +    }else{
         2418  +      fprintf(stderr, "Usage: .headers on|off\n");
         2419  +      rc = 1;
         2420  +    }
  2376   2421     }else
  2377   2422   
  2378   2423     if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
  2379         -    fprintf(stderr,"%s",zHelp);
  2380         -    if( HAS_TIMER ){
  2381         -      fprintf(stderr,"%s",zTimerHelp);
  2382         -    }
         2424  +    fprintf(p->out, "%s", zHelp);
  2383   2425     }else
  2384   2426   
  2385         -  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
         2427  +  if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
  2386   2428       char *zTable = azArg[2];    /* Insert data into this table */
  2387   2429       char *zFile = azArg[1];     /* Name of file to extra content from */
  2388   2430       sqlite3_stmt *pStmt = NULL; /* A statement */
  2389   2431       int nCol;                   /* Number of columns in the table */
  2390   2432       int nByte;                  /* Number of bytes in an SQL string */
  2391   2433       int i, j;                   /* Loop counters */
  2392   2434       int needCommit;             /* True to COMMIT or ROLLBACK at end */
  2393   2435       int nSep;                   /* Number of bytes in p->separator[] */
  2394   2436       char *zSql;                 /* An SQL statement */
  2395   2437       CSVReader sCsv;             /* Reader context */
  2396   2438       int (*xCloser)(FILE*);      /* Procedure to close th3 connection */
  2397   2439   
         2440  +    if( nArg!=3 ){
         2441  +      fprintf(stderr, "Usage: .import FILE TABLE\n");
         2442  +      goto meta_command_exit;
         2443  +    }
  2398   2444       seenInterrupt = 0;
  2399   2445       memset(&sCsv, 0, sizeof(sCsv));
  2400   2446       open_db(p, 0);
  2401   2447       nSep = strlen30(p->separator);
  2402   2448       if( nSep==0 ){
  2403   2449         fprintf(stderr, "Error: non-null separator required for import\n");
  2404   2450         return 1;
................................................................................
  2529   2575   
  2530   2576       xCloser(sCsv.in);
  2531   2577       sqlite3_free(sCsv.z);
  2532   2578       sqlite3_finalize(pStmt);
  2533   2579       if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
  2534   2580     }else
  2535   2581   
  2536         -  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
         2582  +  if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
  2537   2583       struct callback_data data;
  2538   2584       char *zErrMsg = 0;
  2539   2585       open_db(p, 0);
  2540   2586       memcpy(&data, p, sizeof(data));
  2541   2587       data.showHeader = 0;
  2542   2588       data.mode = MODE_List;
  2543   2589       if( nArg==1 ){
................................................................................
  2546   2592           "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
  2547   2593           "UNION ALL "
  2548   2594           "SELECT name FROM sqlite_temp_master "
  2549   2595           "WHERE type='index' "
  2550   2596           "ORDER BY 1",
  2551   2597           callback, &data, &zErrMsg
  2552   2598         );
  2553         -    }else{
         2599  +    }else if( nArg==2 ){
  2554   2600         zShellStatic = azArg[1];
  2555   2601         rc = sqlite3_exec(p->db,
  2556   2602           "SELECT name FROM sqlite_master "
  2557   2603           "WHERE type='index' AND tbl_name LIKE shellstatic() "
  2558   2604           "UNION ALL "
  2559   2605           "SELECT name FROM sqlite_temp_master "
  2560   2606           "WHERE type='index' AND tbl_name LIKE shellstatic() "
  2561   2607           "ORDER BY 1",
  2562   2608           callback, &data, &zErrMsg
  2563   2609         );
  2564   2610         zShellStatic = 0;
         2611  +    }else{
         2612  +      fprintf(stderr, "Usage: .indices ?LIKE-PATTERN?\n");
         2613  +      rc = 1;
         2614  +      goto meta_command_exit;
  2565   2615       }
  2566   2616       if( zErrMsg ){
  2567   2617         fprintf(stderr,"Error: %s\n", zErrMsg);
  2568   2618         sqlite3_free(zErrMsg);
  2569   2619         rc = 1;
  2570   2620       }else if( rc != SQLITE_OK ){
  2571   2621         fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
................................................................................
  2593   2643           sqlite3IoTrace = iotracePrintf;
  2594   2644         }
  2595   2645       }
  2596   2646     }else
  2597   2647   #endif
  2598   2648   
  2599   2649   #ifndef SQLITE_OMIT_LOAD_EXTENSION
  2600         -  if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
         2650  +  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
  2601   2651       const char *zFile, *zProc;
  2602   2652       char *zErrMsg = 0;
         2653  +    if( nArg<2 ){
         2654  +      fprintf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
         2655  +      rc = 1;
         2656  +      goto meta_command_exit;
         2657  +    }
  2603   2658       zFile = azArg[1];
  2604   2659       zProc = nArg>=3 ? azArg[2] : 0;
  2605   2660       open_db(p, 0);
  2606   2661       rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
  2607   2662       if( rc!=SQLITE_OK ){
  2608   2663         fprintf(stderr, "Error: %s\n", zErrMsg);
  2609   2664         sqlite3_free(zErrMsg);
  2610   2665         rc = 1;
  2611   2666       }
  2612   2667     }else
  2613   2668   #endif
  2614   2669   
  2615         -  if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
  2616         -    const char *zFile = azArg[1];
  2617         -    output_file_close(p->pLog);
  2618         -    p->pLog = output_file_open(zFile);
         2670  +  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
         2671  +    if( nArg!=2 ){
         2672  +      fprintf(stderr, "Usage: .log FILENAME\n");
         2673  +      rc = 1;
         2674  +    }else{
         2675  +      const char *zFile = azArg[1];
         2676  +      output_file_close(p->pLog);
         2677  +      p->pLog = output_file_open(zFile);
         2678  +    }
  2619   2679     }else
  2620   2680   
  2621         -  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
  2622         -    int n2 = strlen30(azArg[1]);
  2623         -    if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
  2624         -        ||
  2625         -        (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
         2681  +  if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
         2682  +    const char *zMode = nArg>=2 ? azArg[1] : "";
         2683  +    int n2 = (int)strlen(zMode);
         2684  +    int c2 = zMode[0];
         2685  +    if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
  2626   2686         p->mode = MODE_Line;
  2627         -    }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
  2628         -              ||
  2629         -              (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
         2687  +    }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
  2630   2688         p->mode = MODE_Column;
  2631         -    }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
         2689  +    }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
  2632   2690         p->mode = MODE_List;
  2633         -    }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
         2691  +    }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
  2634   2692         p->mode = MODE_Html;
  2635         -    }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
         2693  +    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
  2636   2694         p->mode = MODE_Tcl;
  2637   2695         sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
  2638         -    }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
         2696  +    }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
  2639   2697         p->mode = MODE_Csv;
  2640   2698         sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
  2641         -    }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
         2699  +    }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
  2642   2700         p->mode = MODE_List;
  2643   2701         sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
  2644         -    }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
         2702  +    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
  2645   2703         p->mode = MODE_Insert;
  2646         -      set_table_name(p, "table");
         2704  +      set_table_name(p, nArg>=3 ? azArg[2] : "table");
  2647   2705       }else {
  2648   2706         fprintf(stderr,"Error: mode should be one of: "
  2649   2707            "column csv html insert line list tabs tcl\n");
  2650   2708         rc = 1;
  2651   2709       }
  2652   2710     }else
  2653   2711   
  2654         -  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
  2655         -    int n2 = strlen30(azArg[1]);
  2656         -    if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
  2657         -      p->mode = MODE_Insert;
  2658         -      set_table_name(p, azArg[2]);
  2659         -    }else {
  2660         -      fprintf(stderr, "Error: invalid arguments: "
  2661         -        " \"%s\". Enter \".help\" for help\n", azArg[2]);
         2712  +  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
         2713  +    if( nArg==2 ){
         2714  +      sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
         2715  +                       "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
         2716  +    }else{
         2717  +      fprintf(stderr, "Usage: .nullvalue STRING\n");
  2662   2718         rc = 1;
  2663   2719       }
  2664   2720     }else
  2665   2721   
  2666         -  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
  2667         -    sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
  2668         -                     "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
  2669         -  }else
  2670         -
  2671   2722     if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
  2672   2723       sqlite3 *savedDb = p->db;
  2673   2724       const char *zSavedFilename = p->zDbFilename;
  2674   2725       char *zNewFilename = 0;
  2675   2726       p->db = 0;
  2676   2727       if( nArg>=2 ){
  2677   2728         p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
................................................................................
  2684   2735       }else{
  2685   2736         sqlite3_free(zNewFilename);
  2686   2737         p->db = savedDb;
  2687   2738         p->zDbFilename = zSavedFilename;
  2688   2739       }
  2689   2740     }else
  2690   2741   
  2691         -  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
  2692         -    if( p->outfile[0]=='|' ){
  2693         -      pclose(p->out);
         2742  +  if( c=='o'
         2743  +   && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
         2744  +  ){
         2745  +    const char *zFile = nArg>=2 ? azArg[1] : "stdout";
         2746  +    if( nArg>2 ){
         2747  +      fprintf(stderr, "Usage: .%s FILE\n", azArg[0]);
         2748  +      rc = 1;
         2749  +      goto meta_command_exit;
         2750  +    }
         2751  +    if( n>1 && strncmp(azArg[0], "once", n)==0 ){
         2752  +      if( nArg<2 ){
         2753  +        fprintf(stderr, "Usage: .once FILE\n");
         2754  +        rc = 1;
         2755  +        goto meta_command_exit;
         2756  +      }
         2757  +      p->outCount = 2;
  2694   2758       }else{
  2695         -      output_file_close(p->out);
         2759  +      p->outCount = 0;
  2696   2760       }
  2697         -    p->outfile[0] = 0;
  2698         -    if( azArg[1][0]=='|' ){
  2699         -      p->out = popen(&azArg[1][1], "w");
         2761  +    output_reset(p);
         2762  +    if( zFile[0]=='|' ){
         2763  +      p->out = popen(zFile + 1, "w");
  2700   2764         if( p->out==0 ){
  2701         -        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", &azArg[1][1]);
         2765  +        fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
  2702   2766           p->out = stdout;
  2703   2767           rc = 1;
  2704   2768         }else{
  2705         -        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
         2769  +        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
  2706   2770         }
  2707   2771       }else{
  2708         -      p->out = output_file_open(azArg[1]);
         2772  +      p->out = output_file_open(zFile);
  2709   2773         if( p->out==0 ){
  2710         -        if( strcmp(azArg[1],"off")!=0 ){
  2711         -          fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
         2774  +        if( strcmp(zFile,"off")!=0 ){
         2775  +          fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
  2712   2776           }
  2713   2777           p->out = stdout;
  2714   2778           rc = 1;
  2715   2779         } else {
  2716         -        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
         2780  +        sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
  2717   2781         }
  2718   2782       }
  2719   2783     }else
  2720   2784   
  2721   2785     if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
  2722   2786       int i;
  2723   2787       for(i=1; i<nArg; i++){
  2724   2788         if( i>1 ) fprintf(p->out, " ");
  2725   2789         fprintf(p->out, "%s", azArg[i]);
  2726   2790       }
  2727   2791       fprintf(p->out, "\n");
  2728   2792     }else
  2729   2793   
  2730         -  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
         2794  +  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
  2731   2795       if( nArg >= 2) {
  2732   2796         strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
  2733   2797       }
  2734   2798       if( nArg >= 3) {
  2735   2799         strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
  2736   2800       }
  2737   2801     }else
  2738   2802   
  2739         -  if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
         2803  +  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
  2740   2804       rc = 2;
  2741   2805     }else
  2742   2806   
  2743         -  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
  2744         -    FILE *alt = fopen(azArg[1], "rb");
         2807  +  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
         2808  +    FILE *alt;
         2809  +    if( nArg!=2 ){
         2810  +      fprintf(stderr, "Usage: .read FILE\n");
         2811  +      rc = 1;
         2812  +      goto meta_command_exit;
         2813  +    }
         2814  +    alt = fopen(azArg[1], "rb");
  2745   2815       if( alt==0 ){
  2746   2816         fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
  2747   2817         rc = 1;
  2748   2818       }else{
  2749   2819         rc = process_input(p, alt);
  2750   2820         fclose(alt);
  2751   2821       }
  2752   2822     }else
  2753   2823   
  2754         -  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
         2824  +  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
  2755   2825       const char *zSrcFile;
  2756   2826       const char *zDb;
  2757   2827       sqlite3 *pSrc;
  2758   2828       sqlite3_backup *pBackup;
  2759   2829       int nTimeout = 0;
  2760   2830   
  2761   2831       if( nArg==2 ){
  2762   2832         zSrcFile = azArg[1];
  2763   2833         zDb = "main";
  2764         -    }else{
         2834  +    }else if( nArg==3 ){
  2765   2835         zSrcFile = azArg[2];
  2766   2836         zDb = azArg[1];
         2837  +    }else{
         2838  +      fprintf(stderr, "Usage: .restore ?DB? FILE\n");
         2839  +      rc = 1;
         2840  +      goto meta_command_exit;
  2767   2841       }
  2768   2842       rc = sqlite3_open(zSrcFile, &pSrc);
  2769   2843       if( rc!=SQLITE_OK ){
  2770   2844         fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
  2771   2845         sqlite3_close(pSrc);
  2772   2846         return 1;
  2773   2847       }
................................................................................
  2794   2868       }else{
  2795   2869         fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
  2796   2870         rc = 1;
  2797   2871       }
  2798   2872       sqlite3_close(pSrc);
  2799   2873     }else
  2800   2874   
  2801         -  if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
         2875  +  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
  2802   2876       struct callback_data data;
  2803   2877       char *zErrMsg = 0;
  2804   2878       open_db(p, 0);
  2805   2879       memcpy(&data, p, sizeof(data));
  2806   2880       data.showHeader = 0;
  2807   2881       data.mode = MODE_Semi;
  2808         -    if( nArg>1 ){
         2882  +    if( nArg==2 ){
  2809   2883         int i;
  2810   2884         for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
  2811   2885         if( strcmp(azArg[1],"sqlite_master")==0 ){
  2812   2886           char *new_argv[2], *new_colv[2];
  2813   2887           new_argv[0] = "CREATE TABLE sqlite_master (\n"
  2814   2888                         "  type text,\n"
  2815   2889                         "  name text,\n"
................................................................................
  2845   2919             "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
  2846   2920             "WHERE lower(tbl_name) LIKE shellstatic()"
  2847   2921             "  AND type!='meta' AND sql NOTNULL "
  2848   2922             "ORDER BY rowid",
  2849   2923             callback, &data, &zErrMsg);
  2850   2924           zShellStatic = 0;
  2851   2925         }
  2852         -    }else{
         2926  +    }else if( nArg==1 ){
  2853   2927         rc = sqlite3_exec(p->db,
  2854   2928            "SELECT sql FROM "
  2855   2929            "  (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
  2856   2930            "     FROM sqlite_master UNION ALL"
  2857   2931            "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
  2858   2932            "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
  2859   2933            "ORDER BY rowid",
  2860   2934            callback, &data, &zErrMsg
  2861   2935         );
         2936  +    }else{
         2937  +      fprintf(stderr, "Usage: .schema ?LIKE-PATTERN?\n");
         2938  +      rc = 1;
         2939  +      goto meta_command_exit;
  2862   2940       }
  2863   2941       if( zErrMsg ){
  2864   2942         fprintf(stderr,"Error: %s\n", zErrMsg);
  2865   2943         sqlite3_free(zErrMsg);
  2866   2944         rc = 1;
  2867   2945       }else if( rc != SQLITE_OK ){
  2868   2946         fprintf(stderr,"Error: querying schema information\n");
................................................................................
  2884   2962         }
  2885   2963       }
  2886   2964       if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
  2887   2965         int i; sqlite3_int64 v;
  2888   2966         for(i=1; i<nArg; i++){
  2889   2967           char zBuf[200];
  2890   2968           v = integerValue(azArg[i]);
  2891         -        sqlite3_snprintf(sizeof(zBuf), zBuf, "%s: %lld 0x%llx\n", azArg[i], v, v);
         2969  +        sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v);
  2892   2970           fprintf(p->out, "%s", zBuf);
  2893   2971         }
  2894   2972       }
  2895   2973     }else
  2896   2974   #endif
  2897   2975   
  2898         -  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
  2899         -    sqlite3_snprintf(sizeof(p->separator), p->separator,
  2900         -                     "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
         2976  +  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
         2977  +    if( nArg==2 ){
         2978  +      sqlite3_snprintf(sizeof(p->separator), p->separator,
         2979  +                       "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
         2980  +    }else{
         2981  +      fprintf(stderr, "Usage: .separator STRING\n");
         2982  +      rc = 1;
         2983  +    }
         2984  +  }else
         2985  +
         2986  +  if( c=='s'
         2987  +   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
         2988  +  ){
         2989  +    char *zCmd;
         2990  +    int i;
         2991  +    if( nArg<2 ){
         2992  +      fprintf(stderr, "Usage: .system COMMAND\n");
         2993  +      rc = 1;
         2994  +      goto meta_command_exit;
         2995  +    }
         2996  +    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
         2997  +    for(i=2; i<nArg; i++){
         2998  +      zCmd = sqlite3_mprintf(strchr(azArg[i],' ')==0?"%z %s":"%z \"%s\"",
         2999  +                             zCmd, azArg[i]);
         3000  +    }
         3001  +    system(zCmd);
         3002  +    sqlite3_free(zCmd);
  2901   3003     }else
  2902   3004   
  2903         -  if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
         3005  +  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
  2904   3006       int i;
         3007  +    if( nArg!=1 ){
         3008  +      fprintf(stderr, "Usage: .show\n");
         3009  +      rc = 1;
         3010  +      goto meta_command_exit;
         3011  +    }
  2905   3012       fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
  2906   3013       fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
  2907   3014       fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
  2908   3015       fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
  2909   3016       fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
  2910   3017       fprintf(p->out,"%9.9s: ", "nullvalue");
  2911   3018         output_c_string(p->out, p->nullvalue);
................................................................................
  2919   3026       fprintf(p->out,"%9.9s: ","width");
  2920   3027       for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
  2921   3028         fprintf(p->out,"%d ",p->colWidth[i]);
  2922   3029       }
  2923   3030       fprintf(p->out,"\n");
  2924   3031     }else
  2925   3032   
  2926         -  if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
  2927         -    p->statsOn = booleanValue(azArg[1]);
         3033  +  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
         3034  +    if( nArg==2 ){
         3035  +      p->statsOn = booleanValue(azArg[1]);
         3036  +    }else{
         3037  +      fprintf(stderr, "Usage: .stats on|off\n");
         3038  +      rc = 1;
         3039  +    }
  2928   3040     }else
  2929   3041   
  2930         -  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
         3042  +  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
  2931   3043       sqlite3_stmt *pStmt;
  2932   3044       char **azResult;
  2933   3045       int nRow, nAlloc;
  2934   3046       char *zSql = 0;
  2935   3047       int ii;
  2936   3048       open_db(p, 0);
  2937   3049       rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
................................................................................
  3129   3241             fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
  3130   3242                     azArg[1]);
  3131   3243             break;
  3132   3244         }
  3133   3245       }
  3134   3246     }else
  3135   3247   
  3136         -  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
         3248  +  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
  3137   3249       open_db(p, 0);
  3138         -    sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
         3250  +    sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0);
  3139   3251     }else
  3140   3252       
  3141         -  if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
  3142         -   && nArg==2
  3143         -  ){
  3144         -    enableTimer = booleanValue(azArg[1]);
         3253  +  if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){
         3254  +    if( nArg==2 ){
         3255  +      enableTimer = booleanValue(azArg[1]);
         3256  +      if( enableTimer && !HAS_TIMER ){
         3257  +        fprintf(stderr, "Error: timer not available on this system.\n");
         3258  +        enableTimer = 0;
         3259  +      }
         3260  +    }else{
         3261  +      fprintf(stderr, "Usage: .timer on|off\n");
         3262  +      rc = 1;
         3263  +    }
  3145   3264     }else
  3146   3265     
  3147         -  if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
         3266  +  if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
  3148   3267       open_db(p, 0);
  3149   3268       output_file_close(p->traceOut);
         3269  +    if( nArg!=2 ){
         3270  +      fprintf(stderr, "Usage: .trace FILE|off\n");
         3271  +      rc = 1;
         3272  +      goto meta_command_exit;
         3273  +    }
  3150   3274       p->traceOut = output_file_open(azArg[1]);
  3151   3275   #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
  3152   3276       if( p->traceOut==0 ){
  3153   3277         sqlite3_trace(p->db, 0, 0);
  3154   3278       }else{
  3155   3279         sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
  3156   3280       }
................................................................................
  3173   3297         }
  3174   3298       }
  3175   3299     }else
  3176   3300   
  3177   3301   #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
  3178   3302     if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
  3179   3303       extern int sqlite3WhereTrace;
  3180         -    sqlite3WhereTrace = booleanValue(azArg[1]);
         3304  +    sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
  3181   3305     }else
  3182   3306   #endif
  3183   3307   
  3184         -  if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
         3308  +  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
  3185   3309       int j;
  3186   3310       assert( nArg<=ArraySize(azArg) );
  3187   3311       for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
  3188   3312         p->colWidth[j-1] = (int)integerValue(azArg[j]);
  3189   3313       }
  3190   3314     }else
  3191   3315   
  3192   3316     {
  3193   3317       fprintf(stderr, "Error: unknown command or invalid arguments: "
  3194   3318         " \"%s\". Enter \".help\" for help\n", azArg[0]);
  3195   3319       rc = 1;
  3196   3320     }
  3197   3321   
         3322  +meta_command_exit:
         3323  +  if( p->outCount ){
         3324  +    p->outCount--;
         3325  +    if( p->outCount==0 ) output_reset(p);
         3326  +  }
  3198   3327     return rc;
  3199   3328   }
  3200   3329   
  3201   3330   /*
  3202   3331   ** Return TRUE if a semicolon occurs anywhere in the first N characters
  3203   3332   ** of string z[].
  3204   3333   */
................................................................................
  3358   3487             zErrMsg = 0;
  3359   3488           }else{
  3360   3489             fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
  3361   3490           }
  3362   3491           errCnt++;
  3363   3492         }
  3364   3493         nSql = 0;
         3494  +      if( p->outCount ){
         3495  +        output_reset(p);
         3496  +        p->outCount = 0;
         3497  +      }
  3365   3498       }else if( nSql && _all_whitespace(zSql) ){
  3366   3499         if( p->echoOn ) printf("%s\n", zSql);
  3367   3500         nSql = 0;
  3368   3501       }
  3369   3502     }
  3370   3503     if( nSql ){
  3371   3504       if( !_all_whitespace(zSql) ){

Changes to src/sqliteInt.h.

  1700   1700     Expr *pPartIdxWhere;     /* WHERE clause for partial indices */
  1701   1701     KeyInfo *pKeyInfo;       /* A KeyInfo object suitable for this index */
  1702   1702     int tnum;                /* DB Page containing root of this index */
  1703   1703     LogEst szIdxRow;         /* Estimated average row size in bytes */
  1704   1704     u16 nKeyCol;             /* Number of columns forming the key */
  1705   1705     u16 nColumn;             /* Number of columns stored in the index */
  1706   1706     u8 onError;              /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
  1707         -  unsigned autoIndex:2;    /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
         1707  +  unsigned idxType:2;      /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
  1708   1708     unsigned bUnordered:1;   /* Use this index for == or IN queries only */
  1709   1709     unsigned uniqNotNull:1;  /* True if UNIQUE and NOT NULL for all columns */
  1710   1710     unsigned isResized:1;    /* True if resizeIndexObject() has been called */
  1711   1711     unsigned isCovering:1;   /* True if this is a covering index */
  1712   1712   #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
  1713   1713     int nSample;             /* Number of elements in aSample[] */
  1714   1714     int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
  1715   1715     tRowcnt *aAvgEq;         /* Average nEq values for keys not in aSample */
  1716   1716     IndexSample *aSample;    /* Samples of the left-most key */
  1717   1717   #endif
  1718   1718   };
  1719   1719   
         1720  +/*
         1721  +** Allowed values for Index.idxType
         1722  +*/
         1723  +#define SQLITE_IDXTYPE_APPDEF      0   /* Created using CREATE INDEX */
         1724  +#define SQLITE_IDXTYPE_UNIQUE      1   /* Implements a UNIQUE constraint */
         1725  +#define SQLITE_IDXTYPE_PRIMARYKEY  2   /* Is the PRIMARY KEY for the table */
         1726  +
         1727  +/* Return true if index X is a PRIMARY KEY index */
         1728  +#define IsPrimaryKeyIndex(X)  ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
         1729  +
  1720   1730   /*
  1721   1731   ** Each sample stored in the sqlite_stat3 table is represented in memory 
  1722   1732   ** using a structure of this type.  See documentation at the top of the
  1723   1733   ** analyze.c source file for additional information.
  1724   1734   */
  1725   1735   struct IndexSample {
  1726   1736     void *p;          /* Pointer to sampled record */

Changes to src/update.c.

   183    183     ** need to occur right after the database cursor.  So go ahead and
   184    184     ** allocate enough space, just in case.
   185    185     */
   186    186     pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++;
   187    187     iIdxCur = iDataCur+1;
   188    188     pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
   189    189     for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
   190         -    if( pIdx->autoIndex==2 && pPk!=0 ){
          190  +    if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){
   191    191         iDataCur = pParse->nTab;
   192    192         pTabList->a[0].iCursor = iDataCur;
   193    193       }
   194    194       pParse->nTab++;
   195    195     }
   196    196   
   197    197     /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].  

Changes to src/vdbe.c.

  6277   6277       sqlite3DbFree(db, z);
  6278   6278     }
  6279   6279   #ifdef SQLITE_USE_FCNTL_TRACE
  6280   6280     zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
  6281   6281     if( zTrace ){
  6282   6282       int i;
  6283   6283       for(i=0; i<db->nDb; i++){
  6284         -      if( MASKBIT(i) & p->btreeMask)==0 ) continue;
         6284  +      if( (MASKBIT(i) & p->btreeMask)==0 ) continue;
  6285   6285         sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
  6286   6286       }
  6287   6287     }
  6288   6288   #endif /* SQLITE_USE_FCNTL_TRACE */
  6289   6289   #ifdef SQLITE_DEBUG
  6290   6290     if( (db->flags & SQLITE_SqlTrace)!=0
  6291   6291      && (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0

Changes to src/vdbesort.c.

   346    346         int nRead = nBuf - iBuf;
   347    347         if( (iStart + nRead) > pSorter->iWriteOff ){
   348    348           nRead = (int)(pSorter->iWriteOff - iStart);
   349    349         }
   350    350         rc = sqlite3OsRead(
   351    351             pSorter->pTemp1, &pIter->aBuffer[iBuf], nRead, iStart
   352    352         );
   353         -      assert( rc!=SQLITE_IOERR_SHORT_READ );
   354    353       }
   355    354   
   356    355       if( rc==SQLITE_OK ){
   357    356         u64 nByte;                       /* Size of PMA in bytes */
   358    357         pIter->iEof = pSorter->iWriteOff;
   359    358         rc = vdbeSorterIterVarint(db, pIter, &nByte);
   360    359         pIter->iEof = pIter->iReadOff + nByte;

Changes to src/where.c.

  2718   2718       if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0
  2719   2719        && ALWAYS(pLoop->u.btree.pIndex!=0)
  2720   2720       ){
  2721   2721         const char *zFmt;
  2722   2722         Index *pIdx = pLoop->u.btree.pIndex;
  2723   2723         char *zWhere = explainIndexRange(db, pLoop, pItem->pTab);
  2724   2724         assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) );
  2725         -      if( !HasRowid(pItem->pTab) && pIdx->autoIndex==2 ){
         2725  +      if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){
  2726   2726           zFmt = zWhere ? "%s USING PRIMARY KEY%.0s%s" : "%s%.0s%s";
  2727   2727         }else if( flags & WHERE_AUTO_INDEX ){
  2728   2728           zFmt = "%s USING AUTOMATIC COVERING INDEX%.0s%s";
  2729   2729         }else if( flags & WHERE_IDX_ONLY ){
  2730   2730           zFmt = "%s USING COVERING INDEX %s%s";
  2731   2731         }else{
  2732   2732           zFmt = "%s USING INDEX %s%s";
................................................................................
  3219   3219       if( omitTable ){
  3220   3220         /* pIdx is a covering index.  No need to access the main table. */
  3221   3221       }else if( HasRowid(pIdx->pTable) ){
  3222   3222         iRowidReg = ++pParse->nMem;
  3223   3223         sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
  3224   3224         sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
  3225   3225         sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg);  /* Deferred seek */
  3226         -    }else{
         3226  +    }else if( iCur!=iIdxCur ){
  3227   3227         Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
  3228   3228         iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
  3229   3229         for(j=0; j<pPk->nKeyCol; j++){
  3230   3230           k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
  3231   3231           sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
  3232   3232         }
  3233   3233         sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
................................................................................
  3289   3289       **
  3290   3290       **       A: <loop body>                 # Return data, whatever.
  3291   3291       **
  3292   3292       **          Return     2                # Jump back to the Gosub
  3293   3293       **
  3294   3294       **       B: <after the loop>
  3295   3295       **
         3296  +    ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then
         3297  +    ** use an ephermeral index instead of a RowSet to record the primary
         3298  +    ** keys of the rows we have already seen.
         3299  +    **
  3296   3300       */
  3297   3301       WhereClause *pOrWc;    /* The OR-clause broken out into subterms */
  3298   3302       SrcList *pOrTab;       /* Shortened table list or OR-clause generation */
  3299   3303       Index *pCov = 0;             /* Potential covering index (or NULL) */
  3300   3304       int iCovCur = pParse->nTab++;  /* Cursor used for index scans (if any) */
  3301   3305   
  3302   3306       int regReturn = ++pParse->nMem;           /* Register used with OP_Gosub */
................................................................................
  3303   3307       int regRowset = 0;                        /* Register for RowSet object */
  3304   3308       int regRowid = 0;                         /* Register holding rowid */
  3305   3309       int iLoopBody = sqlite3VdbeMakeLabel(v);  /* Start of loop body */
  3306   3310       int iRetInit;                             /* Address of regReturn init */
  3307   3311       int untestedTerms = 0;             /* Some terms not completely tested */
  3308   3312       int ii;                            /* Loop counter */
  3309   3313       Expr *pAndExpr = 0;                /* An ".. AND (...)" expression */
         3314  +    Table *pTab = pTabItem->pTab;
  3310   3315      
  3311   3316       pTerm = pLoop->aLTerm[0];
  3312   3317       assert( pTerm!=0 );
  3313   3318       assert( pTerm->eOperator & WO_OR );
  3314   3319       assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
  3315   3320       pOrWc = &pTerm->u.pOrInfo->wc;
  3316   3321       pLevel->op = OP_Return;
................................................................................
  3335   3340           memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
  3336   3341         }
  3337   3342       }else{
  3338   3343         pOrTab = pWInfo->pTabList;
  3339   3344       }
  3340   3345   
  3341   3346       /* Initialize the rowset register to contain NULL. An SQL NULL is 
  3342         -    ** equivalent to an empty rowset.
         3347  +    ** equivalent to an empty rowset.  Or, create an ephermeral index
         3348  +    ** capable of holding primary keys in the case of a WITHOUT ROWID.
  3343   3349       **
  3344   3350       ** Also initialize regReturn to contain the address of the instruction 
  3345   3351       ** immediately following the OP_Return at the bottom of the loop. This
  3346   3352       ** is required in a few obscure LEFT JOIN cases where control jumps
  3347   3353       ** over the top of the loop into the body of it. In this case the 
  3348   3354       ** correct response for the end-of-loop code (the OP_Return) is to 
  3349   3355       ** fall through to the next instruction, just as an OP_Next does if
  3350   3356       ** called on an uninitialized cursor.
  3351   3357       */
  3352   3358       if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
  3353         -      regRowset = ++pParse->nMem;
         3359  +      if( HasRowid(pTab) ){
         3360  +        regRowset = ++pParse->nMem;
         3361  +        sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
         3362  +      }else{
         3363  +        Index *pPk = sqlite3PrimaryKeyIndex(pTab);
         3364  +        regRowset = pParse->nTab++;
         3365  +        sqlite3VdbeAddOp2(v, OP_OpenEphemeral, regRowset, pPk->nKeyCol);
         3366  +        sqlite3VdbeSetP4KeyInfo(pParse, pPk);
         3367  +      }
  3354   3368         regRowid = ++pParse->nMem;
  3355         -      sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
  3356   3369       }
  3357   3370       iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
  3358   3371   
  3359   3372       /* If the original WHERE clause is z of the form:  (x1 OR x2 OR ...) AND y
  3360   3373       ** Then for every term xN, evaluate as the subexpression: xN AND z
  3361   3374       ** That way, terms in y that are factored into the disjunction will
  3362   3375       ** be picked up by the recursive calls to sqlite3WhereBegin() below.
................................................................................
  3384   3397           pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
  3385   3398         }
  3386   3399         if( pAndExpr ){
  3387   3400           pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
  3388   3401         }
  3389   3402       }
  3390   3403   
         3404  +    /* Run a separate WHERE clause for each term of the OR clause.  After
         3405  +    ** eliminating duplicates from other WHERE clauses, the action for each
         3406  +    ** sub-WHERE clause is to to invoke the main loop body as a subroutine.
         3407  +    */
  3391   3408       for(ii=0; ii<pOrWc->nTerm; ii++){
  3392   3409         WhereTerm *pOrTerm = &pOrWc->a[ii];
  3393   3410         if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
  3394         -        WhereInfo *pSubWInfo;          /* Info for single OR-term scan */
  3395         -        Expr *pOrExpr = pOrTerm->pExpr;
         3411  +        WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
         3412  +        Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
         3413  +        int j1 = 0;                     /* Address of jump operation */
  3396   3414           if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
  3397   3415             pAndExpr->pLeft = pOrExpr;
  3398   3416             pOrExpr = pAndExpr;
  3399   3417           }
  3400   3418           /* Loop through table entries that match term pOrTerm. */
  3401   3419           pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
  3402   3420                           WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
................................................................................
  3403   3421                           WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
  3404   3422           assert( pSubWInfo || pParse->nErr || db->mallocFailed );
  3405   3423           if( pSubWInfo ){
  3406   3424             WhereLoop *pSubLoop;
  3407   3425             explainOneScan(
  3408   3426                 pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
  3409   3427             );
         3428  +          /* This is the sub-WHERE clause body.  First skip over
         3429  +          ** duplicate rows from prior sub-WHERE clauses, and record the
         3430  +          ** rowid (or PRIMARY KEY) for the current row so that the same
         3431  +          ** row will be skipped in subsequent sub-WHERE clauses.
         3432  +          */
  3410   3433             if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
  3411         -            int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
  3412   3434               int r;
  3413         -            r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur, 
  3414         -                                         regRowid, 0);
  3415         -            sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
  3416         -                                 sqlite3VdbeCurrentAddr(v)+2, r, iSet);
  3417         -            VdbeCoverage(v);
         3435  +            int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
         3436  +            if( HasRowid(pTab) ){
         3437  +              r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
         3438  +              j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet);
         3439  +              VdbeCoverage(v);
         3440  +            }else{
         3441  +              Index *pPk = sqlite3PrimaryKeyIndex(pTab);
         3442  +              int nPk = pPk->nKeyCol;
         3443  +              int iPk;
         3444  +
         3445  +              /* Read the PK into an array of temp registers. */
         3446  +              r = sqlite3GetTempRange(pParse, nPk);
         3447  +              for(iPk=0; iPk<nPk; iPk++){
         3448  +                int iCol = pPk->aiColumn[iPk];
         3449  +                sqlite3ExprCodeGetColumn(pParse, pTab, iCol, iCur, r+iPk, 0);
         3450  +              }
         3451  +
         3452  +              /* Check if the temp table already contains this key. If so,
         3453  +              ** the row has already been included in the result set and
         3454  +              ** can be ignored (by jumping past the Gosub below). Otherwise,
         3455  +              ** insert the key into the temp table and proceed with processing
         3456  +              ** the row.
         3457  +              **
         3458  +              ** Use some of the same optimizations as OP_RowSetTest: If iSet
         3459  +              ** is zero, assume that the key cannot already be present in
         3460  +              ** the temp table. And if iSet is -1, assume that there is no 
         3461  +              ** need to insert the key into the temp table, as it will never 
         3462  +              ** be tested for.  */ 
         3463  +              if( iSet ){
         3464  +                j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
         3465  +                VdbeCoverage(v);
         3466  +              }
         3467  +              if( iSet>=0 ){
         3468  +                sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
         3469  +                sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
         3470  +                if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
         3471  +              }
         3472  +
         3473  +              /* Release the array of temp registers */
         3474  +              sqlite3ReleaseTempRange(pParse, r, nPk);
         3475  +            }
  3418   3476             }
         3477  +
         3478  +          /* Invoke the main loop body as a subroutine */
  3419   3479             sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
         3480  +
         3481  +          /* Jump here (skipping the main loop body subroutine) if the
         3482  +          ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */
         3483  +          if( j1 ) sqlite3VdbeJumpHere(v, j1);
  3420   3484   
  3421   3485             /* The pSubWInfo->untestedTerms flag means that this OR term
  3422   3486             ** contained one or more AND term from a notReady table.  The
  3423   3487             ** terms from the notReady table could not be tested and will
  3424   3488             ** need to be tested later.
  3425   3489             */
  3426   3490             if( pSubWInfo->untestedTerms ) untestedTerms = 1;
................................................................................
  3437   3501             ** pCov to NULL to indicate that no candidate covering index will 
  3438   3502             ** be available.
  3439   3503             */
  3440   3504             pSubLoop = pSubWInfo->a[0].pWLoop;
  3441   3505             assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
  3442   3506             if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0
  3443   3507              && (ii==0 || pSubLoop->u.btree.pIndex==pCov)
         3508  +           && (HasRowid(pTab) || !IsPrimaryKeyIndex(pSubLoop->u.btree.pIndex))
  3444   3509             ){
  3445   3510               assert( pSubWInfo->a[0].iIdxCur==iCovCur );
  3446   3511               pCov = pSubLoop->u.btree.pIndex;
  3447   3512             }else{
  3448   3513               pCov = 0;
  3449   3514             }
  3450   3515   
................................................................................
  4762   4827     
  4763   4828     pWC = pBuilder->pWC;
  4764   4829     if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
  4765   4830     pWCEnd = pWC->a + pWC->nTerm;
  4766   4831     pNew = pBuilder->pNew;
  4767   4832     memset(&sSum, 0, sizeof(sSum));
  4768   4833     pItem = pWInfo->pTabList->a + pNew->iTab;
  4769         -  if( !HasRowid(pItem->pTab) ) return SQLITE_OK;
  4770   4834     iCur = pItem->iCursor;
  4771   4835   
  4772   4836     for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
  4773   4837       if( (pTerm->eOperator & WO_OR)!=0
  4774   4838        && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 
  4775   4839       ){
  4776   4840         WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
................................................................................
  6011   6075       }
  6012   6076       if( pLoop->wsFlags & WHERE_INDEXED ){
  6013   6077         Index *pIx = pLoop->u.btree.pIndex;
  6014   6078         int iIndexCur;
  6015   6079         int op = OP_OpenRead;
  6016   6080         /* iIdxCur is always set if to a positive value if ONEPASS is possible */
  6017   6081         assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
  6018         -      if( pWInfo->okOnePass ){
         6082  +      if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
         6083  +       && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0
         6084  +      ){
         6085  +        /* This is one term of an OR-optimization using the PRIMARY KEY of a
         6086  +        ** WITHOUT ROWID table.  No need for a separate index */
         6087  +        iIndexCur = pLevel->iTabCur;
         6088  +        op = 0;
         6089  +      }else if( pWInfo->okOnePass ){
  6019   6090           Index *pJ = pTabItem->pTab->pIndex;
  6020   6091           iIndexCur = iIdxCur;
  6021   6092           assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
  6022   6093           while( ALWAYS(pJ) && pJ!=pIx ){
  6023   6094             iIndexCur++;
  6024   6095             pJ = pJ->pNext;
  6025   6096           }
................................................................................
  6029   6100           iIndexCur = iIdxCur;
  6030   6101         }else{
  6031   6102           iIndexCur = pParse->nTab++;
  6032   6103         }
  6033   6104         pLevel->iIdxCur = iIndexCur;
  6034   6105         assert( pIx->pSchema==pTab->pSchema );
  6035   6106         assert( iIndexCur>=0 );
  6036         -      sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
  6037         -      sqlite3VdbeSetP4KeyInfo(pParse, pIx);
  6038         -      VdbeComment((v, "%s", pIx->zName));
         6107  +      if( op ){
         6108  +        sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
         6109  +        sqlite3VdbeSetP4KeyInfo(pParse, pIx);
         6110  +        VdbeComment((v, "%s", pIx->zName));
         6111  +      }
  6039   6112       }
  6040   6113       if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
  6041   6114       notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor);
  6042   6115     }
  6043   6116     pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
  6044   6117     if( db->mallocFailed ) goto whereBeginError;
  6045   6118   

Changes to test/fts4noti.test.

   205    205   } {}
   206    206   do_execsql_test 6.2.4 {
   207    207     SELECT * FROM t1 WHERE t1 MATCH '6021';
   208    208   } { Restaurant 6021 }
   209    209   do_execsql_test 6.2.5 {
   210    210     SELECT * FROM t1 WHERE t1 MATCH '60*';
   211    211   } { Restaurant 6021 }
          212  +
          213  +do_execsql_test 6.3.1 {
          214  +  DROP TABLE t1;
          215  +  CREATE VIRTUAL TABLE t1 USING fts4(abc, ab, a, notindexed=abc);
          216  +  CREATE VIRTUAL TABLE t2 USING fts4(a, ab, abc, notindexed=abc);
          217  +
          218  +  INSERT INTO t1 VALUES('no', 'yes', 'yep');
          219  +  INSERT INTO t2 VALUES('yep', 'yes', 'no');
          220  +
          221  +  SELECT count(*) FROM t1 WHERE t1 MATCH 'no';
          222  +  SELECT count(*) FROM t1 WHERE t1 MATCH 'yes';
          223  +  SELECT count(*) FROM t1 WHERE t1 MATCH 'yep';
          224  +
          225  +  SELECT count(*) FROM t2 WHERE t2 MATCH 'no';
          226  +  SELECT count(*) FROM t2 WHERE t2 MATCH 'yes';
          227  +  SELECT count(*) FROM t2 WHERE t2 MATCH 'yep';
          228  +} {0 1 1 0 1 1}
   212    229   
   213    230   finish_test
   214    231   
   215    232   
   216    233   

Changes to test/shell1.test.

   264    264     # too many arguments
   265    265     catchcmd "test.db" ".backup FOO BAR BAD"
   266    266   } {1 {too many arguments to .backup}}
   267    267   
   268    268   # .bail ON|OFF           Stop after hitting an error.  Default OFF
   269    269   do_test shell1-3.2.1 {
   270    270     catchcmd "test.db" ".bail"
   271         -} {1 {Error: unknown command or invalid arguments:  "bail". Enter ".help" for help}}
          271  +} {1 {Usage: .bail on|off}}
   272    272   do_test shell1-3.2.2 {
   273    273     catchcmd "test.db" ".bail ON"
   274    274   } {0 {}}
   275    275   do_test shell1-3.2.3 {
   276    276     catchcmd "test.db" ".bail OFF"
   277    277   } {0 {}}
   278    278   do_test shell1-3.2.4 {
   279    279     # too many arguments
   280    280     catchcmd "test.db" ".bail OFF BAD"
   281         -} {1 {Error: unknown command or invalid arguments:  "bail". Enter ".help" for help}}
          281  +} {1 {Usage: .bail on|off}}
   282    282   
   283    283   # .databases             List names and files of attached databases
   284    284   do_test shell1-3.3.1 {
   285    285     catchcmd "-csv test.db" ".databases"
   286    286   } "/0 +.*main +[string map {/ .} [string range [get_pwd] 0 10]].*/"
   287    287   do_test shell1-3.3.2 {
   288         -  # too many arguments
          288  +  # extra arguments ignored
   289    289     catchcmd "test.db" ".databases BAD"
   290         -} {1 {Error: unknown command or invalid arguments:  "databases". Enter ".help" for help}}
          290  +} "/0 +.*main +[string map {/ .} [string range [get_pwd] 0 10]].*/"
   291    291   
   292    292   # .dump ?TABLE? ...      Dump the database in an SQL text format
   293    293   #                          If TABLE specified, only dump tables matching
   294    294   #                          LIKE pattern TABLE.
   295    295   do_test shell1-3.4.1 {
   296    296     set res [catchcmd "test.db" ".dump"]
   297    297     list [regexp {BEGIN TRANSACTION;} $res] \
................................................................................
   301    301     set res [catchcmd "test.db" ".dump FOO"]
   302    302     list [regexp {BEGIN TRANSACTION;} $res] \
   303    303          [regexp {COMMIT;} $res]
   304    304   } {1 1}
   305    305   do_test shell1-3.4.3 {
   306    306     # too many arguments
   307    307     catchcmd "test.db" ".dump FOO BAD"
   308         -} {1 {Error: unknown command or invalid arguments:  "dump". Enter ".help" for help}}
          308  +} {1 {Usage: .dump ?LIKE-PATTERN?}}
   309    309   
   310    310   # .echo ON|OFF           Turn command echo on or off
   311    311   do_test shell1-3.5.1 {
   312    312     catchcmd "test.db" ".echo"
   313         -} {1 {Error: unknown command or invalid arguments:  "echo". Enter ".help" for help}}
          313  +} {1 {Usage: .echo on|off}}
   314    314   do_test shell1-3.5.2 {
   315    315     catchcmd "test.db" ".echo ON"
   316    316   } {0 {}}
   317    317   do_test shell1-3.5.3 {
   318    318     catchcmd "test.db" ".echo OFF"
   319    319   } {0 {}}
   320    320   do_test shell1-3.5.4 {
   321    321     # too many arguments
   322    322     catchcmd "test.db" ".echo OFF BAD"
   323         -} {1 {Error: unknown command or invalid arguments:  "echo". Enter ".help" for help}}
          323  +} {1 {Usage: .echo on|off}}
   324    324   
   325    325   # .exit                  Exit this program
   326    326   do_test shell1-3.6.1 {
   327    327     catchcmd "test.db" ".exit"
   328    328   } {0 {}}
   329    329   
   330    330   # .explain ON|OFF        Turn output mode suitable for EXPLAIN on or off.
................................................................................
   335    335   do_test shell1-3.7.2 {
   336    336     catchcmd "test.db" ".explain ON"
   337    337   } {0 {}}
   338    338   do_test shell1-3.7.3 {
   339    339     catchcmd "test.db" ".explain OFF"
   340    340   } {0 {}}
   341    341   do_test shell1-3.7.4 {
   342         -  # too many arguments
          342  +  # extra arguments ignored
   343    343     catchcmd "test.db" ".explain OFF BAD"
   344         -} {1 {Error: unknown command or invalid arguments:  "explain". Enter ".help" for help}}
          344  +} {0 {}}
   345    345   
   346    346   
   347    347   # .header(s) ON|OFF      Turn display of headers on or off
   348    348   do_test shell1-3.9.1 {
   349    349     catchcmd "test.db" ".header"
   350         -} {1 {Error: unknown command or invalid arguments:  "header". Enter ".help" for help}}
          350  +} {1 {Usage: .headers on|off}}
   351    351   do_test shell1-3.9.2 {
   352    352     catchcmd "test.db" ".header ON"
   353    353   } {0 {}}
   354    354   do_test shell1-3.9.3 {
   355    355     catchcmd "test.db" ".header OFF"
   356    356   } {0 {}}
   357    357   do_test shell1-3.9.4 {
   358    358     # too many arguments
   359    359     catchcmd "test.db" ".header OFF BAD"
   360         -} {1 {Error: unknown command or invalid arguments:  "header". Enter ".help" for help}}
          360  +} {1 {Usage: .headers on|off}}
   361    361   
   362    362   do_test shell1-3.9.5 {
   363    363     catchcmd "test.db" ".headers"
   364         -} {1 {Error: unknown command or invalid arguments:  "headers". Enter ".help" for help}}
          364  +} {1 {Usage: .headers on|off}}
   365    365   do_test shell1-3.9.6 {
   366    366     catchcmd "test.db" ".headers ON"
   367    367   } {0 {}}
   368    368   do_test shell1-3.9.7 {
   369    369     catchcmd "test.db" ".headers OFF"
   370    370   } {0 {}}
   371    371   do_test shell1-3.9.8 {
   372    372     # too many arguments
   373    373     catchcmd "test.db" ".headers OFF BAD"
   374         -} {1 {Error: unknown command or invalid arguments:  "headers". Enter ".help" for help}}
          374  +} {1 {Usage: .headers on|off}}
   375    375   
   376    376   # .help                  Show this message
   377    377   do_test shell1-3.10.1 {
   378    378     set res [catchcmd "test.db" ".help"]
   379    379     # look for a few of the possible help commands
   380    380     list [regexp {.help} $res] \
   381    381          [regexp {.quit} $res] \
................................................................................
   389    389          [regexp {.quit} $res] \
   390    390          [regexp {.show} $res]
   391    391   } {1 1 1}
   392    392   
   393    393   # .import FILE TABLE     Import data from FILE into TABLE
   394    394   do_test shell1-3.11.1 {
   395    395     catchcmd "test.db" ".import"
   396         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
          396  +} {1 {Usage: .import FILE TABLE}}
   397    397   do_test shell1-3.11.2 {
   398    398     catchcmd "test.db" ".import FOO"
   399         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
          399  +} {1 {Usage: .import FILE TABLE}}
   400    400   #do_test shell1-3.11.2 {
   401    401   #  catchcmd "test.db" ".import FOO BAR"
   402    402   #} {1 {Error: no such table: BAR}}
   403    403   do_test shell1-3.11.3 {
   404    404     # too many arguments
   405    405     catchcmd "test.db" ".import FOO BAR BAD"
   406         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
          406  +} {1 {Usage: .import FILE TABLE}}
   407    407   
   408    408   # .indices ?TABLE?       Show names of all indices
   409    409   #                          If TABLE specified, only show indices for tables
   410    410   #                          matching LIKE pattern TABLE.
   411    411   do_test shell1-3.12.1 {
   412    412     catchcmd "test.db" ".indices"
   413    413   } {0 {}}
   414    414   do_test shell1-3.12.2 {
   415    415     catchcmd "test.db" ".indices FOO"
   416    416   } {0 {}}
   417    417   do_test shell1-3.12.3 {
   418    418     # too many arguments
   419    419     catchcmd "test.db" ".indices FOO BAD"
   420         -} {1 {Error: unknown command or invalid arguments:  "indices". Enter ".help" for help}}
          420  +} {1 {Usage: .indices ?LIKE-PATTERN?}}
   421    421   
   422    422   # .mode MODE ?TABLE?     Set output mode where MODE is one of:
   423    423   #                          csv      Comma-separated values
   424    424   #                          column   Left-aligned columns.  (See .width)
   425    425   #                          html     HTML <table> code
   426    426   #                          insert   SQL insert statements for TABLE
   427    427   #                          line     One value per line
   428    428   #                          list     Values delimited by .separator string
   429    429   #                          tabs     Tab-separated values
   430    430   #                          tcl      TCL list elements
   431    431   do_test shell1-3.13.1 {
   432    432     catchcmd "test.db" ".mode"
   433         -} {1 {Error: unknown command or invalid arguments:  "mode". Enter ".help" for help}}
          433  +} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}}
   434    434   do_test shell1-3.13.2 {
   435    435     catchcmd "test.db" ".mode FOO"
   436    436   } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}}
   437    437   do_test shell1-3.13.3 {
   438    438     catchcmd "test.db" ".mode csv"
   439    439   } {0 {}}
   440    440   do_test shell1-3.13.4 {
................................................................................
   455    455   do_test shell1-3.13.9 {
   456    456     catchcmd "test.db" ".mode tabs"
   457    457   } {0 {}}
   458    458   do_test shell1-3.13.10 {
   459    459     catchcmd "test.db" ".mode tcl"
   460    460   } {0 {}}
   461    461   do_test shell1-3.13.11 {
   462         -  # too many arguments
          462  +  # extra arguments ignored
   463    463     catchcmd "test.db" ".mode tcl BAD"
   464         -} {1 {Error: invalid arguments:  "BAD". Enter ".help" for help}}
          464  +} {0 {}}
   465    465   
   466    466   # don't allow partial mode type matches
   467    467   do_test shell1-3.13.12 {
   468    468     catchcmd "test.db" ".mode l"
   469    469   } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}}
   470    470   do_test shell1-3.13.13 {
   471    471     catchcmd "test.db" ".mode li"
   472    472   } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}}
   473    473   do_test shell1-3.13.14 {
   474    474     catchcmd "test.db" ".mode lin"
   475         -} {1 {Error: mode should be one of: column csv html insert line list tabs tcl}}
          475  +} {0 {}}
   476    476   
   477    477   # .nullvalue STRING      Print STRING in place of NULL values
   478    478   do_test shell1-3.14.1 {
   479    479     catchcmd "test.db" ".nullvalue"
   480         -} {1 {Error: unknown command or invalid arguments:  "nullvalue". Enter ".help" for help}}
          480  +} {1 {Usage: .nullvalue STRING}}
   481    481   do_test shell1-3.14.2 {
   482    482     catchcmd "test.db" ".nullvalue FOO"
   483    483   } {0 {}}
   484    484   do_test shell1-3.14.3 {
   485    485     # too many arguments
   486    486     catchcmd "test.db" ".nullvalue FOO BAD"
   487         -} {1 {Error: unknown command or invalid arguments:  "nullvalue". Enter ".help" for help}}
          487  +} {1 {Usage: .nullvalue STRING}}
   488    488   
   489    489   # .output FILENAME       Send output to FILENAME
   490    490   do_test shell1-3.15.1 {
   491    491     catchcmd "test.db" ".output"
   492         -} {1 {Error: unknown command or invalid arguments:  "output". Enter ".help" for help}}
          492  +} {0 {}}
   493    493   do_test shell1-3.15.2 {
   494    494     catchcmd "test.db" ".output FOO"
   495    495   } {0 {}}
   496    496   do_test shell1-3.15.3 {
   497    497     # too many arguments
   498    498     catchcmd "test.db" ".output FOO BAD"
   499         -} {1 {Error: unknown command or invalid arguments:  "output". Enter ".help" for help}}
          499  +} {1 {Usage: .output FILE}}
   500    500   
   501    501   # .output stdout         Send output to the screen
   502    502   do_test shell1-3.16.1 {
   503    503     catchcmd "test.db" ".output stdout"
   504    504   } {0 {}}
   505    505   do_test shell1-3.16.2 {
   506    506     # too many arguments
   507    507     catchcmd "test.db" ".output stdout BAD"
   508         -} {1 {Error: unknown command or invalid arguments:  "output". Enter ".help" for help}}
          508  +} {1 {Usage: .output FILE}}
   509    509   
   510    510   # .prompt MAIN CONTINUE  Replace the standard prompts
   511    511   do_test shell1-3.17.1 {
   512    512     catchcmd "test.db" ".prompt"
   513         -} {1 {Error: unknown command or invalid arguments:  "prompt". Enter ".help" for help}}
          513  +} {0 {}}
   514    514   do_test shell1-3.17.2 {
   515    515     catchcmd "test.db" ".prompt FOO"
   516    516   } {0 {}}
   517    517   do_test shell1-3.17.3 {
   518    518     catchcmd "test.db" ".prompt FOO BAR"
   519    519   } {0 {}}
   520    520   do_test shell1-3.17.4 {
   521    521     # too many arguments
   522    522     catchcmd "test.db" ".prompt FOO BAR BAD"
   523         -} {1 {Error: unknown command or invalid arguments:  "prompt". Enter ".help" for help}}
          523  +} {0 {}}
   524    524   
   525    525   # .quit                  Exit this program
   526    526   do_test shell1-3.18.1 {
   527    527     catchcmd "test.db" ".quit"
   528    528   } {0 {}}
   529    529   do_test shell1-3.18.2 {
   530    530     # too many arguments
   531    531     catchcmd "test.db" ".quit BAD"
   532         -} {1 {Error: unknown command or invalid arguments:  "quit". Enter ".help" for help}}
          532  +} {0 {}}
   533    533   
   534    534   # .read FILENAME         Execute SQL in FILENAME
   535    535   do_test shell1-3.19.1 {
   536    536     catchcmd "test.db" ".read"
   537         -} {1 {Error: unknown command or invalid arguments:  "read". Enter ".help" for help}}
          537  +} {1 {Usage: .read FILE}}
   538    538   do_test shell1-3.19.2 {
   539    539     forcedelete FOO
   540    540     catchcmd "test.db" ".read FOO"
   541    541   } {1 {Error: cannot open "FOO"}}
   542    542   do_test shell1-3.19.3 {
   543    543     # too many arguments
   544    544     catchcmd "test.db" ".read FOO BAD"
   545         -} {1 {Error: unknown command or invalid arguments:  "read". Enter ".help" for help}}
          545  +} {1 {Usage: .read FILE}}
   546    546   
   547    547   # .restore ?DB? FILE     Restore content of DB (default "main") from FILE
   548    548   do_test shell1-3.20.1 {
   549    549     catchcmd "test.db" ".restore"
   550         -} {1 {Error: unknown command or invalid arguments:  "restore". Enter ".help" for help}}
          550  +} {1 {Usage: .restore ?DB? FILE}}
   551    551   do_test shell1-3.20.2 {
   552    552     catchcmd "test.db" ".restore FOO"
   553    553   } {0 {}}
   554    554   do_test shell1-3.20.3 {
   555    555     catchcmd "test.db" ".restore FOO BAR"
   556    556   } {1 {Error: unknown database FOO}}
   557    557   do_test shell1-3.20.4 {
   558    558     # too many arguments
   559    559     catchcmd "test.db" ".restore FOO BAR BAD"
   560         -} {1 {Error: unknown command or invalid arguments:  "restore". Enter ".help" for help}}
          560  +} {1 {Usage: .restore ?DB? FILE}}
   561    561   
   562    562   # .schema ?TABLE?        Show the CREATE statements
   563    563   #                          If TABLE specified, only show tables matching
   564    564   #                          LIKE pattern TABLE.
   565    565   do_test shell1-3.21.1 {
   566    566     catchcmd "test.db" ".schema"
   567    567   } {0 {}}
   568    568   do_test shell1-3.21.2 {
   569    569     catchcmd "test.db" ".schema FOO"
   570    570   } {0 {}}
   571    571   do_test shell1-3.21.3 {
   572    572     # too many arguments
   573    573     catchcmd "test.db" ".schema FOO BAD"
   574         -} {1 {Error: unknown command or invalid arguments:  "schema". Enter ".help" for help}}
          574  +} {1 {Usage: .schema ?LIKE-PATTERN?}}
   575    575   
   576    576   do_test shell1-3.21.4 {
   577    577     catchcmd "test.db" {
   578    578        CREATE TABLE t1(x);
   579    579        CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
   580    580        CREATE VIEW v1 AS SELECT y+1 FROM v2;
   581    581     }
................................................................................
   584    584   CREATE VIEW v2 AS SELECT x+1 AS y FROM t1;
   585    585   CREATE VIEW v1 AS SELECT y+1 FROM v2;}}
   586    586   db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;}
   587    587   
   588    588   # .separator STRING      Change separator used by output mode and .import
   589    589   do_test shell1-3.22.1 {
   590    590     catchcmd "test.db" ".separator"
   591         -} {1 {Error: unknown command or invalid arguments:  "separator". Enter ".help" for help}}
          591  +} {1 {Usage: .separator STRING}}
   592    592   do_test shell1-3.22.2 {
   593    593     catchcmd "test.db" ".separator FOO"
   594    594   } {0 {}}
   595    595   do_test shell1-3.22.3 {
   596    596     # too many arguments
   597    597     catchcmd "test.db" ".separator FOO BAD"
   598         -} {1 {Error: unknown command or invalid arguments:  "separator". Enter ".help" for help}}
          598  +} {1 {Usage: .separator STRING}}
   599    599   
   600    600   # .show                  Show the current values for various settings
   601    601   do_test shell1-3.23.1 {
   602    602     set res [catchcmd "test.db" ".show"]
   603    603     list [regexp {echo:} $res] \
   604    604          [regexp {explain:} $res] \
   605    605          [regexp {headers:} $res] \
................................................................................
   609    609          [regexp {separator:} $res] \
   610    610          [regexp {stats:} $res] \
   611    611          [regexp {width:} $res]
   612    612   } {1 1 1 1 1 1 1 1 1}
   613    613   do_test shell1-3.23.2 {
   614    614     # too many arguments
   615    615     catchcmd "test.db" ".show BAD"
   616         -} {1 {Error: unknown command or invalid arguments:  "show". Enter ".help" for help}}
          616  +} {1 {Usage: .show}}
   617    617   
   618    618   # .stats ON|OFF          Turn stats on or off
   619    619   do_test shell1-3.23b.1 {
   620    620     catchcmd "test.db" ".stats"
   621         -} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
          621  +} {1 {Usage: .stats on|off}}
   622    622   do_test shell1-3.23b.2 {
   623    623     catchcmd "test.db" ".stats ON"
   624    624   } {0 {}}
   625    625   do_test shell1-3.23b.3 {
   626    626     catchcmd "test.db" ".stats OFF"
   627    627   } {0 {}}
   628    628   do_test shell1-3.23b.4 {
   629    629     # too many arguments
   630    630     catchcmd "test.db" ".stats OFF BAD"
   631         -} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
          631  +} {1 {Usage: .stats on|off}}
   632    632   
   633    633   # .tables ?TABLE?        List names of tables
   634    634   #                          If TABLE specified, only list tables matching
   635    635   #                          LIKE pattern TABLE.
   636    636   do_test shell1-3.24.1 {
   637    637     catchcmd "test.db" ".tables"
   638    638   } {0 {}}
   639    639   do_test shell1-3.24.2 {
   640    640     catchcmd "test.db" ".tables FOO"
   641    641   } {0 {}}
   642    642   do_test shell1-3.24.3 {
   643    643     # too many arguments
   644    644     catchcmd "test.db" ".tables FOO BAD"
   645         -} {1 {Error: unknown command or invalid arguments:  "tables". Enter ".help" for help}}
          645  +} {0 {}}
   646    646   
   647    647   # .timeout MS            Try opening locked tables for MS milliseconds
   648    648   do_test shell1-3.25.1 {
   649    649     catchcmd "test.db" ".timeout"
   650         -} {1 {Error: unknown command or invalid arguments:  "timeout". Enter ".help" for help}}
          650  +} {0 {}}
   651    651   do_test shell1-3.25.2 {
   652    652     catchcmd "test.db" ".timeout zzz"
   653    653     # this should be treated the same as a '0' timeout
   654    654   } {0 {}}
   655    655   do_test shell1-3.25.3 {
   656    656     catchcmd "test.db" ".timeout 1"
   657    657   } {0 {}}
   658    658   do_test shell1-3.25.4 {
   659    659     # too many arguments
   660    660     catchcmd "test.db" ".timeout 1 BAD"
   661         -} {1 {Error: unknown command or invalid arguments:  "timeout". Enter ".help" for help}}
          661  +} {0 {}}
   662    662   
   663    663   # .width NUM NUM ...     Set column widths for "column" mode
   664    664   do_test shell1-3.26.1 {
   665    665     catchcmd "test.db" ".width"
   666         -} {1 {Error: unknown command or invalid arguments:  "width". Enter ".help" for help}}
          666  +} {0 {}}
   667    667   do_test shell1-3.26.2 {
   668    668     catchcmd "test.db" ".width xxx"
   669    669     # this should be treated the same as a '0' width for col 1
   670    670   } {0 {}}
   671    671   do_test shell1-3.26.3 {
   672    672     catchcmd "test.db" ".width xxx yyy"
   673    673     # this should be treated the same as a '0' width for col 1 and 2
................................................................................
   685    685     # this should be treated the same as a '1' width for col 1 and 2
   686    686   } {0 {   abcdefg  123456    }}
   687    687   
   688    688   
   689    689   # .timer ON|OFF          Turn the CPU timer measurement on or off
   690    690   do_test shell1-3.27.1 {
   691    691     catchcmd "test.db" ".timer"
   692         -} {1 {Error: unknown command or invalid arguments:  "timer". Enter ".help" for help}}
          692  +} {1 {Usage: .timer on|off}}
   693    693   do_test shell1-3.27.2 {
   694    694     catchcmd "test.db" ".timer ON"
   695    695   } {0 {}}
   696    696   do_test shell1-3.27.3 {
   697    697     catchcmd "test.db" ".timer OFF"
   698    698   } {0 {}}
   699    699   do_test shell1-3.27.4 {
   700    700     # too many arguments
   701    701     catchcmd "test.db" ".timer OFF BAD"
   702         -} {1 {Error: unknown command or invalid arguments:  "timer". Enter ".help" for help}}
          702  +} {1 {Usage: .timer on|off}}
   703    703   
   704    704   do_test shell1-3-28.1 {
   705    705     catchcmd test.db \
   706    706        ".log stdout\nSELECT coalesce(sqlite_log(123,'hello'),'456');"
   707    707   } "0 {(123) hello\n456}"
   708    708   
   709    709   do_test shell1-3-29.1 {

Changes to test/shell4.test.

    59     59     set res [catchcmd "-stats test.db" ".show"]
    60     60     list [regexp {stats: off} $res]
    61     61   } {0}
    62     62   
    63     63   # .stats ON|OFF          Turn stats on or off
    64     64   do_test shell4-1.3.1 {
    65     65     catchcmd "test.db" ".stats"
    66         -} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
           66  +} {1 {Usage: .stats on|off}}
    67     67   do_test shell4-1.3.2 {
    68     68     catchcmd "test.db" ".stats ON"
    69     69   } {0 {}}
    70     70   do_test shell4-1.3.3 {
    71     71     catchcmd "test.db" ".stats OFF"
    72     72   } {0 {}}
    73     73   do_test shell4-1.3.4 {
    74     74     # too many arguments
    75     75     catchcmd "test.db" ".stats OFF BAD"
    76         -} {1 {Error: unknown command or invalid arguments:  "stats". Enter ".help" for help}}
           76  +} {1 {Usage: .stats on|off}}
    77     77   
    78     78   # NB. whitespace is important
    79     79   do_test shell4-1.4.1 {
    80     80     set res [catchcmd "test.db" {.show}]
    81     81     list [regexp {stats: off} $res]
    82     82   } {1}
    83     83   

Changes to test/shell5.test.

    36     36   #----------------------------------------------------------------------------
    37     37   # Test cases shell5-1.*: Basic handling of the .import and .separator commands.
    38     38   #
    39     39   
    40     40   # .import FILE TABLE     Import data from FILE into TABLE
    41     41   do_test shell5-1.1.1 {
    42     42     catchcmd "test.db" ".import"
    43         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
           43  +} {1 {Usage: .import FILE TABLE}}
    44     44   do_test shell5-1.1.2 {
    45     45     catchcmd "test.db" ".import FOO"
    46         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
           46  +} {1 {Usage: .import FILE TABLE}}
    47     47   #do_test shell5-1.1.2 {
    48     48   #  catchcmd "test.db" ".import FOO BAR"
    49     49   #} {1 {Error: no such table: BAR}}
    50     50   do_test shell5-1.1.3 {
    51     51     # too many arguments
    52     52     catchcmd "test.db" ".import FOO BAR BAD"
    53         -} {1 {Error: unknown command or invalid arguments:  "import". Enter ".help" for help}}
           53  +} {1 {Usage: .import FILE TABLE}}
    54     54   
    55     55   # .separator STRING      Change separator used by output mode and .import
    56         -do_test shell1-1.2.1 {
           56  +do_test shell5-1.2.1 {
    57     57     catchcmd "test.db" ".separator"
    58         -} {1 {Error: unknown command or invalid arguments:  "separator". Enter ".help" for help}}
    59         -do_test shell1-1.2.2 {
           58  +} {1 {Usage: .separator STRING}}
           59  +do_test shell5-1.2.2 {
    60     60     catchcmd "test.db" ".separator FOO"
    61     61   } {0 {}}
    62         -do_test shell1-1.2.3 {
           62  +do_test shell5-1.2.3 {
    63     63     # too many arguments
    64     64     catchcmd "test.db" ".separator FOO BAD"
    65         -} {1 {Error: unknown command or invalid arguments:  "separator". Enter ".help" for help}}
           65  +} {1 {Usage: .separator STRING}}
    66     66   
    67     67   # separator should default to "|"
    68     68   do_test shell5-1.3.1 {
    69     69     set res [catchcmd "test.db" ".show"]
    70     70     list [regexp {separator: \"\|\"} $res]
    71     71   } {1}
    72     72   

Added test/whereI.test.

            1  +# 2014-03-31
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# The focus of this file is testing the OR optimization on WITHOUT ROWID 
           12  +# tables.
           13  +#
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +set ::testprefix whereI
           18  +
           19  +do_execsql_test 1.0 {
           20  +  CREATE TABLE t1(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID;
           21  +  INSERT INTO t1 VALUES(1, 'a', 'z');
           22  +  INSERT INTO t1 VALUES(2, 'b', 'y');
           23  +  INSERT INTO t1 VALUES(3, 'c', 'x');
           24  +  INSERT INTO t1 VALUES(4, 'd', 'w');
           25  +  CREATE INDEX i1 ON t1(b);
           26  +  CREATE INDEX i2 ON t1(c);
           27  +}
           28  +
           29  +do_eqp_test 1.1 {
           30  +  SELECT a FROM t1 WHERE b='b' OR c='x'
           31  +} {
           32  +  0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b=?)} 
           33  +  0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}
           34  +}
           35  +
           36  +do_execsql_test 1.2 {
           37  +  SELECT a FROM t1 WHERE b='b' OR c='x'
           38  +} {2 3}
           39  +
           40  +do_execsql_test 1.3 {
           41  +  SELECT a FROM t1 WHERE b='a' OR c='z'
           42  +} {1}
           43  +
           44  +#----------------------------------------------------------------------
           45  +# Try that again, this time with non integer PRIMARY KEY values.
           46  +#
           47  +do_execsql_test 2.0 {
           48  +  CREATE TABLE t2(a, b, c, PRIMARY KEY(a)) WITHOUT ROWID;
           49  +  INSERT INTO t2 VALUES('i', 'a', 'z');
           50  +  INSERT INTO t2 VALUES('ii', 'b', 'y');
           51  +  INSERT INTO t2 VALUES('iii', 'c', 'x');
           52  +  INSERT INTO t2 VALUES('iv', 'd', 'w');
           53  +  CREATE INDEX i3 ON t2(b);
           54  +  CREATE INDEX i4 ON t2(c);
           55  +}
           56  +
           57  +do_eqp_test 2.1 {
           58  +  SELECT a FROM t2 WHERE b='b' OR c='x'
           59  +} {
           60  +  0 0 0 {SEARCH TABLE t2 USING INDEX i3 (b=?)} 
           61  +  0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)}
           62  +}
           63  +
           64  +do_execsql_test 2.2 {
           65  +  SELECT a FROM t2 WHERE b='b' OR c='x'
           66  +} {ii iii}
           67  +
           68  +do_execsql_test 2.3 {
           69  +  SELECT a FROM t2 WHERE b='a' OR c='z'
           70  +} {i}
           71  +
           72  +#----------------------------------------------------------------------
           73  +# On a table with a multi-column PK.
           74  +#
           75  +do_execsql_test 3.0 {
           76  +  CREATE TABLE t3(a, b, c, d, PRIMARY KEY(c, b)) WITHOUT ROWID;
           77  +
           78  +  INSERT INTO t3 VALUES('f', 1, 1, 'o');
           79  +  INSERT INTO t3 VALUES('o', 2, 1, 't');
           80  +  INSERT INTO t3 VALUES('t', 1, 2, 't');
           81  +  INSERT INTO t3 VALUES('t', 2, 2, 'f');
           82  +
           83  +  CREATE INDEX t3i1 ON t3(d);
           84  +  CREATE INDEX t3i2 ON t3(a);
           85  +
           86  +  SELECT c||'.'||b FROM t3 WHERE a='t' OR d='t'
           87  +} {
           88  +  2.1 2.2 1.2
           89  +}
           90  +
           91  +finish_test
           92  +

Changes to tool/warnings.sh.

     1      1   #/bin/sh
     2      2   #
     3      3   # Run this script in a directory with a working makefile to check for 
     4      4   # compiler warnings in SQLite.
     5      5   #
     6      6   rm -f sqlite3.c
     7         -make sqlite3.c-debug
            7  +make sqlite3.c
     8      8   echo '********** No optimizations.  Includes FTS4 and RTREE *********'
     9      9   gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
    10     10         -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
    11     11         sqlite3.c
    12     12   echo '********** No optimizations. ENABLE_STAT4. THREADSAFE=0 *******'
    13     13   gcc -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
    14     14         -ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \
    15     15         sqlite3.c
    16     16   echo '********** Optimized -O3.  Includes FTS4 and RTREE ************'
    17     17   gcc -O3 -c -Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long -std=c89 \
    18     18         -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE \
    19     19         sqlite3.c