|         |      1 /* | 
|         |      2 ** 2005 June 16 | 
|         |      3 ** | 
|         |      4 ** The author disclaims copyright to this source code.  In place of | 
|         |      5 ** a legal notice, here is a blessing: | 
|         |      6 ** | 
|         |      7 **    May you do good and not evil. | 
|         |      8 **    May you find forgiveness for yourself and forgive others. | 
|         |      9 **    May you share freely, never taking more than you give. | 
|         |     10 ** | 
|         |     11 ************************************************************************* | 
|         |     12 ** This file implements a FIFO queue of rowids used for processing | 
|         |     13 ** UPDATE and DELETE statements. | 
|         |     14 ** | 
|         |     15 ** $Id: vdbefifo.c,v 1.8 2008/07/28 19:34:54 drh Exp $ | 
|         |     16 */ | 
|         |     17 #include "sqliteInt.h" | 
|         |     18 #include "vdbeInt.h" | 
|         |     19  | 
|         |     20 /* | 
|         |     21 ** Constants FIFOSIZE_FIRST and FIFOSIZE_MAX are the initial | 
|         |     22 ** number of entries in a fifo page and the maximum number of | 
|         |     23 ** entries in a fifo page. | 
|         |     24 */ | 
|         |     25 #define FIFOSIZE_FIRST (((128-sizeof(FifoPage))/8)+1) | 
|         |     26 #ifdef SQLITE_MALLOC_SOFT_LIMIT | 
|         |     27 # define FIFOSIZE_MAX   (((SQLITE_MALLOC_SOFT_LIMIT-sizeof(FifoPage))/8)+1) | 
|         |     28 #else | 
|         |     29 # define FIFOSIZE_MAX   (((262144-sizeof(FifoPage))/8)+1) | 
|         |     30 #endif | 
|         |     31  | 
|         |     32 /* | 
|         |     33 ** Allocate a new FifoPage and return a pointer to it.  Return NULL if | 
|         |     34 ** we run out of memory.  Leave space on the page for nEntry entries. | 
|         |     35 */ | 
|         |     36 static FifoPage *allocateFifoPage(sqlite3 *db, int nEntry){ | 
|         |     37   FifoPage *pPage; | 
|         |     38   if( nEntry>FIFOSIZE_MAX ){ | 
|         |     39     nEntry = FIFOSIZE_MAX; | 
|         |     40   } | 
|         |     41   pPage = sqlite3DbMallocRaw(db, sizeof(FifoPage) + sizeof(i64)*(nEntry-1) ); | 
|         |     42   if( pPage ){ | 
|         |     43     pPage->nSlot = nEntry; | 
|         |     44     pPage->iWrite = 0; | 
|         |     45     pPage->iRead = 0; | 
|         |     46     pPage->pNext = 0; | 
|         |     47   } | 
|         |     48   return pPage; | 
|         |     49 } | 
|         |     50  | 
|         |     51 /* | 
|         |     52 ** Initialize a Fifo structure. | 
|         |     53 */ | 
|         |     54 void sqlite3VdbeFifoInit(Fifo *pFifo, sqlite3 *db){ | 
|         |     55   memset(pFifo, 0, sizeof(*pFifo)); | 
|         |     56   pFifo->db = db; | 
|         |     57 } | 
|         |     58  | 
|         |     59 /* | 
|         |     60 ** Push a single 64-bit integer value into the Fifo.  Return SQLITE_OK | 
|         |     61 ** normally.   SQLITE_NOMEM is returned if we are unable to allocate | 
|         |     62 ** memory. | 
|         |     63 */ | 
|         |     64 int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){ | 
|         |     65   FifoPage *pPage; | 
|         |     66   pPage = pFifo->pLast; | 
|         |     67   if( pPage==0 ){ | 
|         |     68     pPage = pFifo->pLast = pFifo->pFirst = | 
|         |     69          allocateFifoPage(pFifo->db, FIFOSIZE_FIRST); | 
|         |     70     if( pPage==0 ){ | 
|         |     71       return SQLITE_NOMEM; | 
|         |     72     } | 
|         |     73   }else if( pPage->iWrite>=pPage->nSlot ){ | 
|         |     74     pPage->pNext = allocateFifoPage(pFifo->db, pFifo->nEntry); | 
|         |     75     if( pPage->pNext==0 ){ | 
|         |     76       return SQLITE_NOMEM; | 
|         |     77     } | 
|         |     78     pPage = pFifo->pLast = pPage->pNext; | 
|         |     79   } | 
|         |     80   pPage->aSlot[pPage->iWrite++] = val; | 
|         |     81   pFifo->nEntry++; | 
|         |     82   return SQLITE_OK; | 
|         |     83 } | 
|         |     84  | 
|         |     85 /* | 
|         |     86 ** Extract a single 64-bit integer value from the Fifo.  The integer | 
|         |     87 ** extracted is the one least recently inserted.  If the Fifo is empty | 
|         |     88 ** return SQLITE_DONE. | 
|         |     89 */ | 
|         |     90 int sqlite3VdbeFifoPop(Fifo *pFifo, i64 *pVal){ | 
|         |     91   FifoPage *pPage; | 
|         |     92   if( pFifo->nEntry==0 ){ | 
|         |     93     return SQLITE_DONE; | 
|         |     94   } | 
|         |     95   assert( pFifo->nEntry>0 ); | 
|         |     96   pPage = pFifo->pFirst; | 
|         |     97   assert( pPage!=0 ); | 
|         |     98   assert( pPage->iWrite>pPage->iRead ); | 
|         |     99   assert( pPage->iWrite<=pPage->nSlot ); | 
|         |    100   assert( pPage->iRead<pPage->nSlot ); | 
|         |    101   assert( pPage->iRead>=0 ); | 
|         |    102   *pVal = pPage->aSlot[pPage->iRead++]; | 
|         |    103   pFifo->nEntry--; | 
|         |    104   if( pPage->iRead>=pPage->iWrite ){ | 
|         |    105     pFifo->pFirst = pPage->pNext; | 
|         |    106     sqlite3DbFree(pFifo->db, pPage); | 
|         |    107     if( pFifo->nEntry==0 ){ | 
|         |    108       assert( pFifo->pLast==pPage ); | 
|         |    109       pFifo->pLast = 0; | 
|         |    110     }else{ | 
|         |    111       assert( pFifo->pFirst!=0 ); | 
|         |    112     } | 
|         |    113   }else{ | 
|         |    114     assert( pFifo->nEntry>0 ); | 
|         |    115   } | 
|         |    116   return SQLITE_OK; | 
|         |    117 } | 
|         |    118  | 
|         |    119 /* | 
|         |    120 ** Delete all information from a Fifo object.   Free all memory held | 
|         |    121 ** by the Fifo. | 
|         |    122 */ | 
|         |    123 void sqlite3VdbeFifoClear(Fifo *pFifo){ | 
|         |    124   FifoPage *pPage, *pNextPage; | 
|         |    125   for(pPage=pFifo->pFirst; pPage; pPage=pNextPage){ | 
|         |    126     pNextPage = pPage->pNext; | 
|         |    127     sqlite3DbFree(pFifo->db, pPage); | 
|         |    128   } | 
|         |    129   sqlite3VdbeFifoInit(pFifo, pFifo->db); | 
|         |    130 } |