drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 1 | /* |
| 2 | ** 2008 December 3 |
| 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 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 13 | ** This module implements an object we call a "RowSet". |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 14 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 15 | ** The RowSet object is a collection of rowids. Rowids |
| 16 | ** are inserted into the RowSet in an arbitrary order. Inserts |
| 17 | ** can be intermixed with tests to see if a given rowid has been |
| 18 | ** previously inserted into the RowSet. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 19 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 20 | ** After all inserts are finished, it is possible to extract the |
| 21 | ** elements of the RowSet in sorted order. Once this extraction |
| 22 | ** process has started, no new elements may be inserted. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 23 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 24 | ** Hence, the primitive operations for a RowSet are: |
drh | a9e364f | 2009-01-13 20:14:15 +0000 | [diff] [blame] | 25 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 26 | ** CREATE |
| 27 | ** INSERT |
| 28 | ** TEST |
| 29 | ** SMALLEST |
| 30 | ** DESTROY |
| 31 | ** |
| 32 | ** The CREATE and DESTROY primitives are the constructor and destructor, |
| 33 | ** obviously. The INSERT primitive adds a new element to the RowSet. |
| 34 | ** TEST checks to see if an element is already in the RowSet. SMALLEST |
| 35 | ** extracts the least value from the RowSet. |
| 36 | ** |
| 37 | ** The INSERT primitive might allocate additional memory. Memory is |
| 38 | ** allocated in chunks so most INSERTs do no allocation. There is an |
| 39 | ** upper bound on the size of allocated memory. No memory is freed |
| 40 | ** until DESTROY. |
| 41 | ** |
| 42 | ** The TEST primitive includes a "batch" number. The TEST primitive |
| 43 | ** will only see elements that were inserted before the last change |
| 44 | ** in the batch number. In other words, if an INSERT occurs between |
| 45 | ** two TESTs where the TESTs have the same batch nubmer, then the |
| 46 | ** value added by the INSERT will not be visible to the second TEST. |
| 47 | ** The initial batch number is zero, so if the very first TEST contains |
| 48 | ** a non-zero batch number, it will see all prior INSERTs. |
| 49 | ** |
| 50 | ** No INSERTs may occurs after a SMALLEST. An assertion will fail if |
| 51 | ** that is attempted. |
| 52 | ** |
| 53 | ** The cost of an INSERT is roughly constant. (Sometime new memory |
| 54 | ** has to be allocated on an INSERT.) The cost of a TEST with a new |
| 55 | ** batch number is O(NlogN) where N is the number of elements in the RowSet. |
| 56 | ** The cost of a TEST using the same batch number is O(logN). The cost |
| 57 | ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST |
| 58 | ** primitives are constant time. The cost of DESTROY is O(N). |
| 59 | ** |
| 60 | ** There is an added cost of O(N) when switching between TEST and |
| 61 | ** SMALLEST primitives. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 62 | */ |
| 63 | #include "sqliteInt.h" |
| 64 | |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 65 | |
| 66 | /* |
| 67 | ** Target size for allocation chunks. |
| 68 | */ |
| 69 | #define ROWSET_ALLOCATION_SIZE 1024 |
| 70 | |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 71 | /* |
| 72 | ** The number of rowset entries per allocation chunk. |
| 73 | */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 74 | #define ROWSET_ENTRY_PER_CHUNK \ |
| 75 | ((ROWSET_ALLOCATION_SIZE-8)/sizeof(struct RowSetEntry)) |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 76 | |
| 77 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 78 | ** Each entry in a RowSet is an instance of the following object. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 79 | */ |
| 80 | struct RowSetEntry { |
| 81 | i64 v; /* ROWID value for this entry */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 82 | struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */ |
| 83 | struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 84 | }; |
| 85 | |
| 86 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 87 | ** RowSetEntry objects are allocated in large chunks (instances of the |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 88 | ** following structure) to reduce memory allocation overhead. The |
| 89 | ** chunks are kept on a linked list so that they can be deallocated |
| 90 | ** when the RowSet is destroyed. |
| 91 | */ |
| 92 | struct RowSetChunk { |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 93 | struct RowSetChunk *pNextChunk; /* Next chunk on list of them all */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 94 | struct RowSetEntry aEntry[ROWSET_ENTRY_PER_CHUNK]; /* Allocated entries */ |
| 95 | }; |
| 96 | |
| 97 | /* |
| 98 | ** A RowSet in an instance of the following structure. |
| 99 | ** |
| 100 | ** A typedef of this structure if found in sqliteInt.h. |
| 101 | */ |
| 102 | struct RowSet { |
| 103 | struct RowSetChunk *pChunk; /* List of all chunk allocations */ |
| 104 | sqlite3 *db; /* The database connection */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 105 | struct RowSetEntry *pEntry; /* List of entries using pRight */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 106 | struct RowSetEntry *pLast; /* Last entry on the pEntry list */ |
| 107 | struct RowSetEntry *pFresh; /* Source of new entry objects */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 108 | struct RowSetEntry *pTree; /* Binary tree of entries */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 109 | u16 nFresh; /* Number of objects on pFresh */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 110 | u8 isSorted; /* True if pEntry is sorted */ |
| 111 | u8 iBatch; /* Current insert batch */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 112 | }; |
| 113 | |
| 114 | /* |
| 115 | ** Turn bulk memory into a RowSet object. N bytes of memory |
| 116 | ** are available at pSpace. The db pointer is used as a memory context |
| 117 | ** for any subsequent allocations that need to occur. |
| 118 | ** Return a pointer to the new RowSet object. |
| 119 | ** |
drh | e2f02ba | 2009-01-09 01:12:27 +0000 | [diff] [blame] | 120 | ** It must be the case that N is sufficient to make a Rowset. If not |
| 121 | ** an assertion fault occurs. |
| 122 | ** |
| 123 | ** If N is larger than the minimum, use the surplus as an initial |
| 124 | ** allocation of entries available to be filled. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 125 | */ |
| 126 | RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ |
| 127 | RowSet *p; |
drh | 49145af | 2009-05-22 01:00:12 +0000 | [diff] [blame] | 128 | assert( N >= ROUND8(sizeof(*p)) ); |
drh | e2f02ba | 2009-01-09 01:12:27 +0000 | [diff] [blame] | 129 | p = pSpace; |
| 130 | p->pChunk = 0; |
| 131 | p->db = db; |
| 132 | p->pEntry = 0; |
| 133 | p->pLast = 0; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 134 | p->pTree = 0; |
drh | 49145af | 2009-05-22 01:00:12 +0000 | [diff] [blame] | 135 | p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); |
| 136 | p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); |
drh | e2f02ba | 2009-01-09 01:12:27 +0000 | [diff] [blame] | 137 | p->isSorted = 1; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 138 | p->iBatch = 0; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 139 | return p; |
| 140 | } |
| 141 | |
| 142 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 143 | ** Deallocate all chunks from a RowSet. This frees all memory that |
| 144 | ** the RowSet has allocated over its lifetime. This routine is |
| 145 | ** the destructor for the RowSet. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 146 | */ |
| 147 | void sqlite3RowSetClear(RowSet *p){ |
| 148 | struct RowSetChunk *pChunk, *pNextChunk; |
| 149 | for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 150 | pNextChunk = pChunk->pNextChunk; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 151 | sqlite3DbFree(p->db, pChunk); |
| 152 | } |
| 153 | p->pChunk = 0; |
| 154 | p->nFresh = 0; |
| 155 | p->pEntry = 0; |
| 156 | p->pLast = 0; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 157 | p->pTree = 0; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 158 | p->isSorted = 1; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** Insert a new value into a RowSet. |
| 163 | ** |
| 164 | ** The mallocFailed flag of the database connection is set if a |
| 165 | ** memory allocation fails. |
| 166 | */ |
| 167 | void sqlite3RowSetInsert(RowSet *p, i64 rowid){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 168 | struct RowSetEntry *pEntry; /* The new entry */ |
| 169 | struct RowSetEntry *pLast; /* The last prior entry */ |
drh | 4b2b8b7 | 2009-04-01 19:35:55 +0000 | [diff] [blame] | 170 | assert( p!=0 ); |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 171 | if( p->nFresh==0 ){ |
| 172 | struct RowSetChunk *pNew; |
| 173 | pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); |
| 174 | if( pNew==0 ){ |
| 175 | return; |
| 176 | } |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 177 | pNew->pNextChunk = p->pChunk; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 178 | p->pChunk = pNew; |
| 179 | p->pFresh = pNew->aEntry; |
| 180 | p->nFresh = ROWSET_ENTRY_PER_CHUNK; |
| 181 | } |
| 182 | pEntry = p->pFresh++; |
| 183 | p->nFresh--; |
| 184 | pEntry->v = rowid; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 185 | pEntry->pRight = 0; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 186 | pLast = p->pLast; |
| 187 | if( pLast ){ |
| 188 | if( p->isSorted && rowid<=pLast->v ){ |
| 189 | p->isSorted = 0; |
| 190 | } |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 191 | pLast->pRight = pEntry; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 192 | }else{ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 193 | assert( p->pEntry==0 ); /* Fires if INSERT after SMALLEST */ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 194 | p->pEntry = pEntry; |
| 195 | } |
| 196 | p->pLast = pEntry; |
| 197 | } |
| 198 | |
| 199 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 200 | ** Merge two lists of RowSetEntry objects. Remove duplicates. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 201 | ** |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 202 | ** The input lists are connected via pRight pointers and are |
| 203 | ** assumed to each already be in sorted order. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 204 | */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 205 | static struct RowSetEntry *rowSetMerge( |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 206 | struct RowSetEntry *pA, /* First sorted list to be merged */ |
| 207 | struct RowSetEntry *pB /* Second sorted list to be merged */ |
| 208 | ){ |
| 209 | struct RowSetEntry head; |
| 210 | struct RowSetEntry *pTail; |
| 211 | |
| 212 | pTail = &head; |
| 213 | while( pA && pB ){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 214 | assert( pA->pRight==0 || pA->v<=pA->pRight->v ); |
| 215 | assert( pB->pRight==0 || pB->v<=pB->pRight->v ); |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 216 | if( pA->v<pB->v ){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 217 | pTail->pRight = pA; |
| 218 | pA = pA->pRight; |
| 219 | pTail = pTail->pRight; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 220 | }else if( pB->v<pA->v ){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 221 | pTail->pRight = pB; |
| 222 | pB = pB->pRight; |
| 223 | pTail = pTail->pRight; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 224 | }else{ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 225 | pA = pA->pRight; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 226 | } |
| 227 | } |
| 228 | if( pA ){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 229 | assert( pA->pRight==0 || pA->v<=pA->pRight->v ); |
| 230 | pTail->pRight = pA; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 231 | }else{ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 232 | assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v ); |
| 233 | pTail->pRight = pB; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 234 | } |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 235 | return head.pRight; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 239 | ** Sort all elements on the pEntry list of the RowSet into ascending order. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 240 | */ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 241 | static void rowSetSort(RowSet *p){ |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 242 | unsigned int i; |
| 243 | struct RowSetEntry *pEntry; |
| 244 | struct RowSetEntry *aBucket[40]; |
| 245 | |
| 246 | assert( p->isSorted==0 ); |
| 247 | memset(aBucket, 0, sizeof(aBucket)); |
| 248 | while( p->pEntry ){ |
| 249 | pEntry = p->pEntry; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 250 | p->pEntry = pEntry->pRight; |
| 251 | pEntry->pRight = 0; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 252 | for(i=0; aBucket[i]; i++){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 253 | pEntry = rowSetMerge(aBucket[i], pEntry); |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 254 | aBucket[i] = 0; |
| 255 | } |
| 256 | aBucket[i] = pEntry; |
| 257 | } |
| 258 | pEntry = 0; |
| 259 | for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 260 | pEntry = rowSetMerge(pEntry, aBucket[i]); |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 261 | } |
| 262 | p->pEntry = pEntry; |
| 263 | p->pLast = 0; |
| 264 | p->isSorted = 1; |
| 265 | } |
| 266 | |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 267 | |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 268 | /* |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 269 | ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects. |
| 270 | ** Convert this tree into a linked list connected by the pRight pointers |
| 271 | ** and return pointers to the first and last elements of the new list. |
| 272 | */ |
| 273 | static void rowSetTreeToList( |
| 274 | struct RowSetEntry *pIn, /* Root of the input tree */ |
| 275 | struct RowSetEntry **ppFirst, /* Write head of the output list here */ |
| 276 | struct RowSetEntry **ppLast /* Write tail of the output list here */ |
| 277 | ){ |
drh | 6149526 | 2009-04-22 15:32:59 +0000 | [diff] [blame] | 278 | assert( pIn!=0 ); |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 279 | if( pIn->pLeft ){ |
| 280 | struct RowSetEntry *p; |
| 281 | rowSetTreeToList(pIn->pLeft, ppFirst, &p); |
| 282 | p->pRight = pIn; |
| 283 | }else{ |
| 284 | *ppFirst = pIn; |
| 285 | } |
| 286 | if( pIn->pRight ){ |
| 287 | rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast); |
| 288 | }else{ |
| 289 | *ppLast = pIn; |
| 290 | } |
| 291 | assert( (*ppLast)->pRight==0 ); |
| 292 | } |
| 293 | |
| 294 | |
| 295 | /* |
| 296 | ** Convert a sorted list of elements (connected by pRight) into a binary |
| 297 | ** tree with depth of iDepth. A depth of 1 means the tree contains a single |
| 298 | ** node taken from the head of *ppList. A depth of 2 means a tree with |
| 299 | ** three nodes. And so forth. |
| 300 | ** |
| 301 | ** Use as many entries from the input list as required and update the |
| 302 | ** *ppList to point to the unused elements of the list. If the input |
| 303 | ** list contains too few elements, then construct an incomplete tree |
| 304 | ** and leave *ppList set to NULL. |
| 305 | ** |
| 306 | ** Return a pointer to the root of the constructed binary tree. |
| 307 | */ |
| 308 | static struct RowSetEntry *rowSetNDeepTree( |
| 309 | struct RowSetEntry **ppList, |
| 310 | int iDepth |
| 311 | ){ |
| 312 | struct RowSetEntry *p; /* Root of the new tree */ |
| 313 | struct RowSetEntry *pLeft; /* Left subtree */ |
| 314 | if( *ppList==0 ){ |
| 315 | return 0; |
| 316 | } |
| 317 | if( iDepth==1 ){ |
| 318 | p = *ppList; |
| 319 | *ppList = p->pRight; |
| 320 | p->pLeft = p->pRight = 0; |
| 321 | return p; |
| 322 | } |
| 323 | pLeft = rowSetNDeepTree(ppList, iDepth-1); |
| 324 | p = *ppList; |
| 325 | if( p==0 ){ |
| 326 | return pLeft; |
| 327 | } |
| 328 | p->pLeft = pLeft; |
| 329 | *ppList = p->pRight; |
| 330 | p->pRight = rowSetNDeepTree(ppList, iDepth-1); |
| 331 | return p; |
| 332 | } |
| 333 | |
| 334 | /* |
| 335 | ** Convert a sorted list of elements into a binary tree. Make the tree |
| 336 | ** as deep as it needs to be in order to contain the entire list. |
| 337 | */ |
| 338 | static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){ |
| 339 | int iDepth; /* Depth of the tree so far */ |
| 340 | struct RowSetEntry *p; /* Current tree root */ |
| 341 | struct RowSetEntry *pLeft; /* Left subtree */ |
| 342 | |
drh | 6149526 | 2009-04-22 15:32:59 +0000 | [diff] [blame] | 343 | assert( pList!=0 ); |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 344 | p = pList; |
| 345 | pList = p->pRight; |
| 346 | p->pLeft = p->pRight = 0; |
| 347 | for(iDepth=1; pList; iDepth++){ |
| 348 | pLeft = p; |
| 349 | p = pList; |
| 350 | pList = p->pRight; |
| 351 | p->pLeft = pLeft; |
| 352 | p->pRight = rowSetNDeepTree(&pList, iDepth); |
| 353 | } |
| 354 | return p; |
| 355 | } |
| 356 | |
| 357 | /* |
| 358 | ** Convert the list in p->pEntry into a sorted list if it is not |
| 359 | ** sorted already. If there is a binary tree on p->pTree, then |
| 360 | ** convert it into a list too and merge it into the p->pEntry list. |
| 361 | */ |
| 362 | static void rowSetToList(RowSet *p){ |
| 363 | if( !p->isSorted ){ |
| 364 | rowSetSort(p); |
| 365 | } |
| 366 | if( p->pTree ){ |
| 367 | struct RowSetEntry *pHead, *pTail; |
| 368 | rowSetTreeToList(p->pTree, &pHead, &pTail); |
| 369 | p->pTree = 0; |
| 370 | p->pEntry = rowSetMerge(p->pEntry, pHead); |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | /* |
| 375 | ** Extract the smallest element from the RowSet. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 376 | ** Write the element into *pRowid. Return 1 on success. Return |
| 377 | ** 0 if the RowSet is already empty. |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 378 | ** |
| 379 | ** After this routine has been called, the sqlite3RowSetInsert() |
| 380 | ** routine may not be called again. |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 381 | */ |
| 382 | int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 383 | rowSetToList(p); |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 384 | if( p->pEntry ){ |
| 385 | *pRowid = p->pEntry->v; |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 386 | p->pEntry = p->pEntry->pRight; |
drh | 3d4501e | 2008-12-04 20:40:10 +0000 | [diff] [blame] | 387 | if( p->pEntry==0 ){ |
| 388 | sqlite3RowSetClear(p); |
| 389 | } |
| 390 | return 1; |
| 391 | }else{ |
| 392 | return 0; |
| 393 | } |
| 394 | } |
drh | 733bf1b | 2009-04-22 00:47:00 +0000 | [diff] [blame] | 395 | |
| 396 | /* |
| 397 | ** Check to see if element iRowid was inserted into the the rowset as |
| 398 | ** part of any insert batch prior to iBatch. Return 1 or 0. |
| 399 | */ |
| 400 | int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ |
| 401 | struct RowSetEntry *p; |
| 402 | if( iBatch!=pRowSet->iBatch ){ |
| 403 | if( pRowSet->pEntry ){ |
| 404 | rowSetToList(pRowSet); |
| 405 | pRowSet->pTree = rowSetListToTree(pRowSet->pEntry); |
| 406 | pRowSet->pEntry = 0; |
| 407 | pRowSet->pLast = 0; |
| 408 | } |
| 409 | pRowSet->iBatch = iBatch; |
| 410 | } |
| 411 | p = pRowSet->pTree; |
| 412 | while( p ){ |
| 413 | if( p->v<iRowid ){ |
| 414 | p = p->pRight; |
| 415 | }else if( p->v>iRowid ){ |
| 416 | p = p->pLeft; |
| 417 | }else{ |
| 418 | return 1; |
| 419 | } |
| 420 | } |
| 421 | return 0; |
| 422 | } |