/ Check-in [4ced2394]
Login

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

Overview
Comment:Add the SQLITE_OMIT_MERGE_SORT pre-processor directive. To omit the code in vdbesort.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: 4ced2394b10d0a4f86422ff893bcdf3cf32591e3
User & Date: dan 2011-08-12 15:02:00
Context
2011-08-12
16:11
Remove an unused parameter from a function in vdbesort.c. Fix some comments and other details in the same file. check-in: 1a8498d8 user: dan tags: experimental
15:02
Add the SQLITE_OMIT_MERGE_SORT pre-processor directive. To omit the code in vdbesort.c. check-in: 4ced2394 user: dan tags: experimental
11:59
Add tests to improve coverage of vdbesort.c. check-in: 87a15917 user: dan tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

  2304   2304   ** the index already exists and must be cleared before being refilled and
  2305   2305   ** the root page number of the index is taken from pIndex->tnum.
  2306   2306   */
  2307   2307   static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
  2308   2308     Table *pTab = pIndex->pTable;  /* The table that is indexed */
  2309   2309     int iTab = pParse->nTab++;     /* Btree cursor used for pTab */
  2310   2310     int iIdx = pParse->nTab++;     /* Btree cursor used for pIndex */
  2311         -  int iSorter = pParse->nTab++;  /* Btree cursor used for sorting */
         2311  +  int iSorter = iTab;            /* Cursor opened by OpenSorter (if in use) */
  2312   2312     int addr1;                     /* Address of top of loop */
  2313   2313     int tnum;                      /* Root page of index */
  2314   2314     Vdbe *v;                       /* Generate code into this virtual machine */
  2315   2315     KeyInfo *pKey;                 /* KeyInfo for index */
  2316   2316     int regIdxKey;                 /* Registers containing the index key */
  2317   2317     int regRecord;                 /* Register holding assemblied index record */
  2318   2318     sqlite3 *db = pParse->db;      /* The database connection */
  2319   2319     int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
         2320  +
         2321  +  /* Set bUseSorter to use OP_OpenSorter, or clear it to insert directly 
         2322  +  ** into the index. The sorter is used unless either OMIT_MERGE_SORT is
         2323  +  ** defined or the system is configured to store temp files in-memory. */
         2324  +#ifdef SQLITE_OMIT_MERGE_SORT
         2325  +  static const int bUseSorter = 0;
         2326  +#else
         2327  +  const int bUseSorter = !sqlite3TempInMemory(pParse->db);
         2328  +#endif
  2320   2329   
  2321   2330   #ifndef SQLITE_OMIT_AUTHORIZATION
  2322   2331     if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
  2323   2332         db->aDb[iDb].zName ) ){
  2324   2333       return;
  2325   2334     }
  2326   2335   #endif
................................................................................
  2339   2348     pKey = sqlite3IndexKeyinfo(pParse, pIndex);
  2340   2349     sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, 
  2341   2350                       (char *)pKey, P4_KEYINFO_HANDOFF);
  2342   2351     if( memRootPage>=0 ){
  2343   2352       sqlite3VdbeChangeP5(v, 1);
  2344   2353     }
  2345   2354   
  2346         -  /* Open the sorter cursor. */
  2347         -  sqlite3VdbeAddOp4(v, OP_OpenSorter, iSorter, 0, 0, (char*)pKey, P4_KEYINFO);
         2355  +  /* Open the sorter cursor if we are to use one. */
         2356  +  if( bUseSorter ){
         2357  +    iSorter = pParse->nTab++;
         2358  +    sqlite3VdbeAddOp4(v, OP_OpenSorter, iSorter, 0, 0, (char*)pKey, P4_KEYINFO);
         2359  +  }
  2348   2360   
  2349   2361     /* Open the table. Loop through all rows of the table, inserting index
  2350   2362     ** records into the sorter. */
  2351   2363     sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
  2352   2364     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
  2353   2365     regRecord = sqlite3GetTempReg(pParse);
  2354   2366     regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
  2355         -  sqlite3VdbeAddOp2(v, OP_IdxInsert, iSorter, regRecord);
  2356         -  sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
  2357         -  sqlite3VdbeJumpHere(v, addr1);
  2358   2367   
  2359         -  /* Rewind the sorter. Loop through index records in sorted order. */
  2360         -  addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSorter, 0);
  2361         -  sqlite3VdbeAddOp2(v, OP_RowKey, iSorter, regRecord);
         2368  +  if( bUseSorter ){
         2369  +    sqlite3VdbeAddOp2(v, OP_IdxInsert, iSorter, regRecord);
         2370  +    sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
         2371  +    sqlite3VdbeJumpHere(v, addr1);
         2372  +    addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSorter, 0);
         2373  +    sqlite3VdbeAddOp2(v, OP_RowKey, iSorter, regRecord);
         2374  +  }
  2362   2375   
  2363   2376     if( pIndex->onError!=OE_None ){
  2364   2377       const int regRowid = regIdxKey + pIndex->nColumn;
  2365   2378       const int j2 = sqlite3VdbeCurrentAddr(v) + 2;
  2366   2379       void * const pRegKey = SQLITE_INT_TO_PTR(regIdxKey);
  2367   2380   
  2368   2381       /* The registers accessed by the OP_IsUnique opcode were allocated
................................................................................
  2374   2387       ** we can be sure that no other temp registers have been allocated
  2375   2388       ** since sqlite3ReleaseTempRange() was called, it is safe to do so.
  2376   2389       */
  2377   2390       sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
  2378   2391       sqlite3HaltConstraint(
  2379   2392           pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
  2380   2393     }
  2381         -  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1);
         2394  +  sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, bUseSorter);
  2382   2395     sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
  2383   2396     sqlite3ReleaseTempReg(pParse, regRecord);
  2384   2397     sqlite3VdbeAddOp2(v, OP_Next, iSorter, addr1+1);
  2385   2398     sqlite3VdbeJumpHere(v, addr1);
  2386   2399   
  2387   2400     sqlite3VdbeAddOp1(v, OP_Close, iTab);
  2388         -  sqlite3VdbeAddOp1(v, OP_Close, iSorter);
  2389   2401     sqlite3VdbeAddOp1(v, OP_Close, iIdx);
         2402  +  sqlite3VdbeAddOp1(v, OP_Close, iSorter);
  2390   2403   }
  2391   2404   
  2392   2405   /*
  2393   2406   ** Create a new index for an SQL table.  pName1.pName2 is the name of the index 
  2394   2407   ** and pTblList is the name of the table that is to be indexed.  Both will 
  2395   2408   ** be NULL for a primary key or an index that is created to satisfy a
  2396   2409   ** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable

Changes to src/ctime.c.

   252    252     "OMIT_LOCALTIME",
   253    253   #endif
   254    254   #ifdef SQLITE_OMIT_LOOKASIDE
   255    255     "OMIT_LOOKASIDE",
   256    256   #endif
   257    257   #ifdef SQLITE_OMIT_MEMORYDB
   258    258     "OMIT_MEMORYDB",
          259  +#endif
          260  +#ifdef SQLITE_OMIT_MERGE_SORT
          261  +  "OMIT_MERGE_SORT",
   259    262   #endif
   260    263   #ifdef SQLITE_OMIT_OR_OPTIMIZATION
   261    264     "OMIT_OR_OPTIMIZATION",
   262    265   #endif
   263    266   #ifdef SQLITE_OMIT_PAGER_PRAGMAS
   264    267     "OMIT_PAGER_PRAGMAS",
   265    268   #endif

Changes to src/test_config.c.

   358    358   #endif
   359    359   
   360    360   #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   361    361     Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL_GLOBAL_ONLY);
   362    362   #else
   363    363     Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "0", TCL_GLOBAL_ONLY);
   364    364   #endif
          365  +
          366  +#ifdef SQLITE_OMIT_MERGE_SORT
          367  +  Tcl_SetVar2(interp, "sqlite_options", "mergesort", "0", TCL_GLOBAL_ONLY);
          368  +#else
          369  +  Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
          370  +#endif
   365    371   
   366    372   #ifdef SQLITE_OMIT_OR_OPTIMIZATION
   367    373     Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY);
   368    374   #else
   369    375     Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY);
   370    376   #endif
   371    377   

Changes to src/vdbe.c.

   153    153   
   154    154   /*
   155    155   ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*)
   156    156   ** P if required.
   157    157   */
   158    158   #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0)
   159    159   
          160  +/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
          161  +#ifdef SQLITE_OMIT_MERGE_SORT
          162  +# define isSorter(x) 0
          163  +#else
          164  +# define isSorter(x) ((x)->pSorter!=0)
          165  +#endif
          166  +
   160    167   /*
   161    168   ** Argument pMem points at a register that will be passed to a
   162    169   ** user-defined function or returned to the user as the result of a query.
   163    170   ** This routine sets the pMem->type variable used by the sqlite3_value_*() 
   164    171   ** routines.
   165    172   */
   166    173   void sqlite3VdbeMemStoreType(Mem *pMem){
................................................................................
  3151   3158     static const int vfsFlags = 
  3152   3159         SQLITE_OPEN_READWRITE |
  3153   3160         SQLITE_OPEN_CREATE |
  3154   3161         SQLITE_OPEN_EXCLUSIVE |
  3155   3162         SQLITE_OPEN_DELETEONCLOSE |
  3156   3163         SQLITE_OPEN_TRANSIENT_DB;
  3157   3164   
  3158         -  int btflags = BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5;
  3159         -
  3160   3165     assert( pOp->p1>=0 );
  3161   3166     pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
  3162   3167     if( pCx==0 ) goto no_mem;
  3163   3168     pCx->nullRow = 1;
  3164         -  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, btflags, vfsFlags);
         3169  +  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, 
         3170  +                        BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
  3165   3171     if( rc==SQLITE_OK ){
  3166   3172       rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
  3167   3173     }
  3168   3174     if( rc==SQLITE_OK ){
  3169   3175       /* If a transient index is required, create it by calling
  3170   3176       ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
  3171   3177       ** opening it. If a transient table is required, just use the
................................................................................
  3176   3182         assert( pOp->p4type==P4_KEYINFO );
  3177   3183         rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5); 
  3178   3184         if( rc==SQLITE_OK ){
  3179   3185           assert( pgno==MASTER_ROOT+1 );
  3180   3186           rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, 
  3181   3187                                   (KeyInfo*)pOp->p4.z, pCx->pCursor);
  3182   3188           pCx->pKeyInfo = pOp->p4.pKeyInfo;
  3183         -        pCx->pKeyInfo->enc = ENC(db);
         3189  +        pCx->pKeyInfo->enc = ENC(p->db);
  3184   3190         }
  3185   3191         pCx->isTable = 0;
  3186   3192       }else{
  3187   3193         rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
  3188   3194         pCx->isTable = 1;
  3189   3195       }
  3190   3196     }
  3191   3197     pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
  3192   3198     pCx->isIndex = !pCx->isTable;
         3199  +#ifndef SQLITE_OMIT_MERGE_SORT
  3193   3200     if( rc==SQLITE_OK && pOp->opcode==OP_OpenSorter ){
  3194   3201       rc = sqlite3VdbeSorterInit(db, pCx);
  3195   3202     }
         3203  +#endif
  3196   3204     break;
  3197   3205   }
  3198   3206   
  3199   3207   /* Opcode: OpenPseudo P1 P2 P3 * *
  3200   3208   **
  3201   3209   ** Open a new cursor that points to a fake table that contains a single
  3202   3210   ** row of data.  The content of that one row in the content of memory
................................................................................
  4079   4087     pC = p->apCsr[pOp->p1];
  4080   4088     assert( pC->isTable || pOp->opcode==OP_RowKey );
  4081   4089     assert( pC->isIndex || pOp->opcode==OP_RowData );
  4082   4090     assert( pC!=0 );
  4083   4091     assert( pC->nullRow==0 );
  4084   4092     assert( pC->pseudoTableReg==0 );
  4085   4093   
  4086         -  if( pC->pSorter ){
         4094  +  if( isSorter(pC) ){
         4095  +    assert( pOp->opcode==OP_RowKey );
  4087   4096       rc = sqlite3VdbeSorterRowkey(db, pC, pOut);
  4088   4097       break;
  4089   4098     }
  4090   4099   
  4091   4100     assert( pC->pCursor!=0 );
  4092   4101     pCrsr = pC->pCursor;
  4093   4102     assert( sqlite3BtreeCursorIsValid(pCrsr) );
................................................................................
  4264   4273     BtCursor *pCrsr;
  4265   4274     int res;
  4266   4275   
  4267   4276     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4268   4277     pC = p->apCsr[pOp->p1];
  4269   4278     assert( pC!=0 );
  4270   4279     res = 1;
  4271         -  if( pC->pSorter ){
         4280  +  if( isSorter(pC) ){
  4272   4281       rc = sqlite3VdbeSorterRewind(db, pC, &res);
  4273   4282     }else if( (pCrsr = pC->pCursor)!=0 ){
  4274   4283       rc = sqlite3BtreeFirst(pCrsr, &res);
  4275   4284       pC->atFirst = res==0 ?1:0;
  4276   4285       pC->deferredMoveto = 0;
  4277   4286       pC->cacheStatus = CACHE_STALE;
  4278   4287       pC->rowidIsValid = 0;
................................................................................
  4320   4329     CHECK_FOR_INTERRUPT;
  4321   4330     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4322   4331     assert( pOp->p5<=ArraySize(p->aCounter) );
  4323   4332     pC = p->apCsr[pOp->p1];
  4324   4333     if( pC==0 ){
  4325   4334       break;  /* See ticket #2273 */
  4326   4335     }
  4327         -  if( pC->pSorter ){
         4336  +  if( isSorter(pC) ){
  4328   4337       assert( pOp->opcode==OP_Next );
  4329   4338       rc = sqlite3VdbeSorterNext(db, pC, &res);
  4330   4339     }else{
  4331   4340       pCrsr = pC->pCursor;
  4332   4341       if( pCrsr==0 ){
  4333   4342         pC->nullRow = 1;
  4334   4343         break;
................................................................................
  4336   4345       res = 1;
  4337   4346       assert( pC->deferredMoveto==0 );
  4338   4347       rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) :
  4339   4348                                   sqlite3BtreePrevious(pCrsr, &res);
  4340   4349     }
  4341   4350     pC->nullRow = (u8)res;
  4342   4351     pC->cacheStatus = CACHE_STALE;
  4343         -
  4344   4352     if( res==0 ){
  4345   4353       pc = pOp->p2 - 1;
  4346   4354       if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
  4347   4355   #ifdef SQLITE_TEST
  4348   4356       sqlite3_search_count++;
  4349   4357   #endif
  4350   4358     }

Changes to src/vdbeInt.h.

   388    388   const char *sqlite3OpcodeName(int);
   389    389   int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
   390    390   int sqlite3VdbeCloseStatement(Vdbe *, int);
   391    391   void sqlite3VdbeFrameDelete(VdbeFrame*);
   392    392   int sqlite3VdbeFrameRestore(VdbeFrame *);
   393    393   void sqlite3VdbeMemStoreType(Mem *pMem);
   394    394   
          395  +#ifdef SQLITE_OMIT_MERGE_SORT
          396  +# define sqlite3VdbeSorterInit(Y,Z)      SQLITE_OK
          397  +# define sqlite3VdbeSorterWrite(X,Y,Z)   SQLITE_OK
          398  +# define sqlite3VdbeSorterClose(Y,Z)
          399  +# define sqlite3VdbeSorterRowkey(X,Y,Z)  SQLITE_OK
          400  +# define sqlite3VdbeSorterRewind(X,Y,Z)  SQLITE_OK
          401  +# define sqlite3VdbeSorterNext(X,Y,Z)    SQLITE_OK
          402  +#else
   395    403   int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
   396    404   int sqlite3VdbeSorterWrite(sqlite3 *, VdbeCursor *, int);
   397    405   void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
   398         -
   399    406   int sqlite3VdbeSorterRowkey(sqlite3 *, VdbeCursor *, Mem *);
   400    407   int sqlite3VdbeSorterRewind(sqlite3 *, VdbeCursor *, int *);
   401    408   int sqlite3VdbeSorterNext(sqlite3 *, VdbeCursor *, int *);
          409  +#endif
   402    410   
   403    411   #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
   404    412     void sqlite3VdbeEnter(Vdbe*);
   405    413     void sqlite3VdbeLeave(Vdbe*);
   406    414   #else
   407    415   # define sqlite3VdbeEnter(X)
   408    416   # define sqlite3VdbeLeave(X)

Changes to src/vdbesort.c.

    13     13   ** a VdbeCursor to sort large numbers of keys (as may be required, for
    14     14   ** example, by CREATE INDEX statements on tables too large to fit in main
    15     15   ** memory).
    16     16   */
    17     17   
    18     18   #include "sqliteInt.h"
    19     19   #include "vdbeInt.h"
           20  +
           21  +#ifndef SQLITE_OMIT_MERGE_SORT
    20     22   
    21     23   typedef struct VdbeSorterIter VdbeSorterIter;
    22     24   
    23     25   /*
    24     26   ** As keys are added to the sorter, they are written to disk in a series
    25     27   ** of sorted packed-memory-arrays (PMAs). The size of each PMA is roughly
    26     28   ** the same as the cache-size allowed for temporary databases. In order
................................................................................
   680    682     pOut->n = pIter->nKey;
   681    683     MemSetTypeFlag(pOut, MEM_Blob);
   682    684     memcpy(pOut->z, pIter->aKey, pIter->nKey);
   683    685   
   684    686     return SQLITE_OK;
   685    687   }
   686    688   
          689  +#endif /* #ifndef SQLITE_OMIT_MERGE_SORT */

Changes to test/indexfault.test.

    10     10   #***********************************************************************
    11     11   #
    12     12   
    13     13   set testdir [file dirname $argv0]
    14     14   source $testdir/tester.tcl
    15     15   source $testdir/lock_common.tcl
    16     16   source $testdir/malloc_common.tcl
           17  +
           18  +ifcapable !mergesort {
           19  +  finish_test
           20  +  return
           21  +}
    17     22   
    18     23   set testprefix indexfault
    19     24   
    20     25   # Set up the custom fault-injector. This is further configured by using
    21     26   # different values for $::custom_filter and different implementations
    22     27   # of Tcl proc [xCustom] for each test case.
    23     28   #