Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: third_party/sqlite/src/src/rowset.c

Issue 2751253002: [sql] Import SQLite 3.17.0. (Closed)
Patch Set: also clang on Linux i386 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/sqlite/src/src/resolve.c ('k') | third_party/sqlite/src/src/select.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 ** 2008 December 3 2 ** 2008 December 3
3 ** 3 **
4 ** The author disclaims copyright to this source code. In place of 4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing: 5 ** a legal notice, here is a blessing:
6 ** 6 **
7 ** May you do good and not evil. 7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others. 8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give. 9 ** May you share freely, never taking more than you give.
10 ** 10 **
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 ** No INSERTs may occurs after a SMALLEST. An assertion will fail if 50 ** No INSERTs may occurs after a SMALLEST. An assertion will fail if
51 ** that is attempted. 51 ** that is attempted.
52 ** 52 **
53 ** The cost of an INSERT is roughly constant. (Sometimes new memory 53 ** The cost of an INSERT is roughly constant. (Sometimes new memory
54 ** has to be allocated on an INSERT.) The cost of a TEST with a new 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. 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 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 57 ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
58 ** primitives are constant time. The cost of DESTROY is O(N). 58 ** primitives are constant time. The cost of DESTROY is O(N).
59 ** 59 **
60 ** There is an added cost of O(N) when switching between TEST and 60 ** TEST and SMALLEST may not be used by the same RowSet. This used to
61 ** SMALLEST primitives. 61 ** be possible, but the feature was not used, so it was removed in order
62 ** to simplify the code.
62 */ 63 */
63 #include "sqliteInt.h" 64 #include "sqliteInt.h"
64 65
65 66
66 /* 67 /*
67 ** Target size for allocation chunks. 68 ** Target size for allocation chunks.
68 */ 69 */
69 #define ROWSET_ALLOCATION_SIZE 1024 70 #define ROWSET_ALLOCATION_SIZE 1024
70 71
71 /* 72 /*
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 /* 173 /*
173 ** Allocate a new RowSetEntry object that is associated with the 174 ** Allocate a new RowSetEntry object that is associated with the
174 ** given RowSet. Return a pointer to the new and completely uninitialized 175 ** given RowSet. Return a pointer to the new and completely uninitialized
175 ** objected. 176 ** objected.
176 ** 177 **
177 ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this 178 ** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
178 ** routine returns NULL. 179 ** routine returns NULL.
179 */ 180 */
180 static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){ 181 static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
181 assert( p!=0 ); 182 assert( p!=0 );
182 if( p->nFresh==0 ){ 183 if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/
184 /* We could allocate a fresh RowSetEntry each time one is needed, but it
185 ** is more efficient to pull a preallocated entry from the pool */
183 struct RowSetChunk *pNew; 186 struct RowSetChunk *pNew;
184 pNew = sqlite3DbMallocRaw(p->db, sizeof(*pNew)); 187 pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
185 if( pNew==0 ){ 188 if( pNew==0 ){
186 return 0; 189 return 0;
187 } 190 }
188 pNew->pNextChunk = p->pChunk; 191 pNew->pNextChunk = p->pChunk;
189 p->pChunk = pNew; 192 p->pChunk = pNew;
190 p->pFresh = pNew->aEntry; 193 p->pFresh = pNew->aEntry;
191 p->nFresh = ROWSET_ENTRY_PER_CHUNK; 194 p->nFresh = ROWSET_ENTRY_PER_CHUNK;
192 } 195 }
193 p->nFresh--; 196 p->nFresh--;
194 return p->pFresh++; 197 return p->pFresh++;
(...skipping 11 matching lines...) Expand all
206 209
207 /* This routine is never called after sqlite3RowSetNext() */ 210 /* This routine is never called after sqlite3RowSetNext() */
208 assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); 211 assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
209 212
210 pEntry = rowSetEntryAlloc(p); 213 pEntry = rowSetEntryAlloc(p);
211 if( pEntry==0 ) return; 214 if( pEntry==0 ) return;
212 pEntry->v = rowid; 215 pEntry->v = rowid;
213 pEntry->pRight = 0; 216 pEntry->pRight = 0;
214 pLast = p->pLast; 217 pLast = p->pLast;
215 if( pLast ){ 218 if( pLast ){
216 if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){ 219 if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/
220 /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
221 ** where possible */
217 p->rsFlags &= ~ROWSET_SORTED; 222 p->rsFlags &= ~ROWSET_SORTED;
218 } 223 }
219 pLast->pRight = pEntry; 224 pLast->pRight = pEntry;
220 }else{ 225 }else{
221 p->pEntry = pEntry; 226 p->pEntry = pEntry;
222 } 227 }
223 p->pLast = pEntry; 228 p->pLast = pEntry;
224 } 229 }
225 230
226 /* 231 /*
227 ** Merge two lists of RowSetEntry objects. Remove duplicates. 232 ** Merge two lists of RowSetEntry objects. Remove duplicates.
228 ** 233 **
229 ** The input lists are connected via pRight pointers and are 234 ** The input lists are connected via pRight pointers and are
230 ** assumed to each already be in sorted order. 235 ** assumed to each already be in sorted order.
231 */ 236 */
232 static struct RowSetEntry *rowSetEntryMerge( 237 static struct RowSetEntry *rowSetEntryMerge(
233 struct RowSetEntry *pA, /* First sorted list to be merged */ 238 struct RowSetEntry *pA, /* First sorted list to be merged */
234 struct RowSetEntry *pB /* Second sorted list to be merged */ 239 struct RowSetEntry *pB /* Second sorted list to be merged */
235 ){ 240 ){
236 struct RowSetEntry head; 241 struct RowSetEntry head;
237 struct RowSetEntry *pTail; 242 struct RowSetEntry *pTail;
238 243
239 pTail = &head; 244 pTail = &head;
240 while( pA && pB ){ 245 assert( pA!=0 && pB!=0 );
246 for(;;){
241 assert( pA->pRight==0 || pA->v<=pA->pRight->v ); 247 assert( pA->pRight==0 || pA->v<=pA->pRight->v );
242 assert( pB->pRight==0 || pB->v<=pB->pRight->v ); 248 assert( pB->pRight==0 || pB->v<=pB->pRight->v );
243 if( pA->v<pB->v ){ 249 if( pA->v<=pB->v ){
244 pTail->pRight = pA; 250 if( pA->v<pB->v ) pTail = pTail->pRight = pA;
245 pA = pA->pRight; 251 pA = pA->pRight;
246 pTail = pTail->pRight; 252 if( pA==0 ){
247 }else if( pB->v<pA->v ){ 253 pTail->pRight = pB;
248 pTail->pRight = pB; 254 break;
255 }
256 }else{
257 pTail = pTail->pRight = pB;
249 pB = pB->pRight; 258 pB = pB->pRight;
250 pTail = pTail->pRight; 259 if( pB==0 ){
251 }else{ 260 pTail->pRight = pA;
252 pA = pA->pRight; 261 break;
262 }
253 } 263 }
254 } 264 }
255 if( pA ){
256 assert( pA->pRight==0 || pA->v<=pA->pRight->v );
257 pTail->pRight = pA;
258 }else{
259 assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
260 pTail->pRight = pB;
261 }
262 return head.pRight; 265 return head.pRight;
263 } 266 }
264 267
265 /* 268 /*
266 ** Sort all elements on the list of RowSetEntry objects into order of 269 ** Sort all elements on the list of RowSetEntry objects into order of
267 ** increasing v. 270 ** increasing v.
268 */ 271 */
269 static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){ 272 static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
270 unsigned int i; 273 unsigned int i;
271 struct RowSetEntry *pNext, *aBucket[40]; 274 struct RowSetEntry *pNext, *aBucket[40];
272 275
273 memset(aBucket, 0, sizeof(aBucket)); 276 memset(aBucket, 0, sizeof(aBucket));
274 while( pIn ){ 277 while( pIn ){
275 pNext = pIn->pRight; 278 pNext = pIn->pRight;
276 pIn->pRight = 0; 279 pIn->pRight = 0;
277 for(i=0; aBucket[i]; i++){ 280 for(i=0; aBucket[i]; i++){
278 pIn = rowSetEntryMerge(aBucket[i], pIn); 281 pIn = rowSetEntryMerge(aBucket[i], pIn);
279 aBucket[i] = 0; 282 aBucket[i] = 0;
280 } 283 }
281 aBucket[i] = pIn; 284 aBucket[i] = pIn;
282 pIn = pNext; 285 pIn = pNext;
283 } 286 }
284 pIn = 0; 287 pIn = aBucket[0];
285 for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){ 288 for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
286 pIn = rowSetEntryMerge(pIn, aBucket[i]); 289 if( aBucket[i]==0 ) continue;
290 pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i];
287 } 291 }
288 return pIn; 292 return pIn;
289 } 293 }
290 294
291 295
292 /* 296 /*
293 ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects. 297 ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects.
294 ** Convert this tree into a linked list connected by the pRight pointers 298 ** Convert this tree into a linked list connected by the pRight pointers
295 ** and return pointers to the first and last elements of the new list. 299 ** and return pointers to the first and last elements of the new list.
296 */ 300 */
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 ** and leave *ppList set to NULL. 332 ** and leave *ppList set to NULL.
329 ** 333 **
330 ** Return a pointer to the root of the constructed binary tree. 334 ** Return a pointer to the root of the constructed binary tree.
331 */ 335 */
332 static struct RowSetEntry *rowSetNDeepTree( 336 static struct RowSetEntry *rowSetNDeepTree(
333 struct RowSetEntry **ppList, 337 struct RowSetEntry **ppList,
334 int iDepth 338 int iDepth
335 ){ 339 ){
336 struct RowSetEntry *p; /* Root of the new tree */ 340 struct RowSetEntry *p; /* Root of the new tree */
337 struct RowSetEntry *pLeft; /* Left subtree */ 341 struct RowSetEntry *pLeft; /* Left subtree */
338 if( *ppList==0 ){ 342 if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
339 return 0; 343 /* Prevent unnecessary deep recursion when we run out of entries */
344 return 0;
340 } 345 }
341 if( iDepth==1 ){ 346 if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
347 /* This branch causes a *balanced* tree to be generated. A valid tree
348 ** is still generated without this branch, but the tree is wildly
349 ** unbalanced and inefficient. */
350 pLeft = rowSetNDeepTree(ppList, iDepth-1);
351 p = *ppList;
352 if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/
353 /* It is safe to always return here, but the resulting tree
354 ** would be unbalanced */
355 return pLeft;
356 }
357 p->pLeft = pLeft;
358 *ppList = p->pRight;
359 p->pRight = rowSetNDeepTree(ppList, iDepth-1);
360 }else{
342 p = *ppList; 361 p = *ppList;
343 *ppList = p->pRight; 362 *ppList = p->pRight;
344 p->pLeft = p->pRight = 0; 363 p->pLeft = p->pRight = 0;
345 return p;
346 } 364 }
347 pLeft = rowSetNDeepTree(ppList, iDepth-1);
348 p = *ppList;
349 if( p==0 ){
350 return pLeft;
351 }
352 p->pLeft = pLeft;
353 *ppList = p->pRight;
354 p->pRight = rowSetNDeepTree(ppList, iDepth-1);
355 return p; 365 return p;
356 } 366 }
357 367
358 /* 368 /*
359 ** Convert a sorted list of elements into a binary tree. Make the tree 369 ** Convert a sorted list of elements into a binary tree. Make the tree
360 ** as deep as it needs to be in order to contain the entire list. 370 ** as deep as it needs to be in order to contain the entire list.
361 */ 371 */
362 static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){ 372 static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
363 int iDepth; /* Depth of the tree so far */ 373 int iDepth; /* Depth of the tree so far */
364 struct RowSetEntry *p; /* Current tree root */ 374 struct RowSetEntry *p; /* Current tree root */
365 struct RowSetEntry *pLeft; /* Left subtree */ 375 struct RowSetEntry *pLeft; /* Left subtree */
366 376
367 assert( pList!=0 ); 377 assert( pList!=0 );
368 p = pList; 378 p = pList;
369 pList = p->pRight; 379 pList = p->pRight;
370 p->pLeft = p->pRight = 0; 380 p->pLeft = p->pRight = 0;
371 for(iDepth=1; pList; iDepth++){ 381 for(iDepth=1; pList; iDepth++){
372 pLeft = p; 382 pLeft = p;
373 p = pList; 383 p = pList;
374 pList = p->pRight; 384 pList = p->pRight;
375 p->pLeft = pLeft; 385 p->pLeft = pLeft;
376 p->pRight = rowSetNDeepTree(&pList, iDepth); 386 p->pRight = rowSetNDeepTree(&pList, iDepth);
377 } 387 }
378 return p; 388 return p;
379 } 389 }
380 390
381 /* 391 /*
382 ** Take all the entries on p->pEntry and on the trees in p->pForest and
383 ** sort them all together into one big ordered list on p->pEntry.
384 **
385 ** This routine should only be called once in the life of a RowSet.
386 */
387 static void rowSetToList(RowSet *p){
388
389 /* This routine is called only once */
390 assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
391
392 if( (p->rsFlags & ROWSET_SORTED)==0 ){
393 p->pEntry = rowSetEntrySort(p->pEntry);
394 }
395
396 /* While this module could theoretically support it, sqlite3RowSetNext()
397 ** is never called after sqlite3RowSetText() for the same RowSet. So
398 ** there is never a forest to deal with. Should this change, simply
399 ** remove the assert() and the #if 0. */
400 assert( p->pForest==0 );
401 #if 0
402 while( p->pForest ){
403 struct RowSetEntry *pTree = p->pForest->pLeft;
404 if( pTree ){
405 struct RowSetEntry *pHead, *pTail;
406 rowSetTreeToList(pTree, &pHead, &pTail);
407 p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
408 }
409 p->pForest = p->pForest->pRight;
410 }
411 #endif
412 p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
413 }
414
415 /*
416 ** Extract the smallest element from the RowSet. 392 ** Extract the smallest element from the RowSet.
417 ** Write the element into *pRowid. Return 1 on success. Return 393 ** Write the element into *pRowid. Return 1 on success. Return
418 ** 0 if the RowSet is already empty. 394 ** 0 if the RowSet is already empty.
419 ** 395 **
420 ** After this routine has been called, the sqlite3RowSetInsert() 396 ** After this routine has been called, the sqlite3RowSetInsert()
421 ** routine may not be called again. 397 ** routine may not be called again.
398 **
399 ** This routine may not be called after sqlite3RowSetTest() has
400 ** been used. Older versions of RowSet allowed that, but as the
401 ** capability was not used by the code generator, it was removed
402 ** for code economy.
422 */ 403 */
423 int sqlite3RowSetNext(RowSet *p, i64 *pRowid){ 404 int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
424 assert( p!=0 ); 405 assert( p!=0 );
406 assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */
425 407
426 /* Merge the forest into a single sorted list on first call */ 408 /* Merge the forest into a single sorted list on first call */
427 if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p); 409 if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/
410 if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
411 p->pEntry = rowSetEntrySort(p->pEntry);
412 }
413 p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
414 }
428 415
429 /* Return the next entry on the list */ 416 /* Return the next entry on the list */
430 if( p->pEntry ){ 417 if( p->pEntry ){
431 *pRowid = p->pEntry->v; 418 *pRowid = p->pEntry->v;
432 p->pEntry = p->pEntry->pRight; 419 p->pEntry = p->pEntry->pRight;
433 if( p->pEntry==0 ){ 420 if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
421 /* Free memory immediately, rather than waiting on sqlite3_finalize() */
434 sqlite3RowSetClear(p); 422 sqlite3RowSetClear(p);
435 } 423 }
436 return 1; 424 return 1;
437 }else{ 425 }else{
438 return 0; 426 return 0;
439 } 427 }
440 } 428 }
441 429
442 /* 430 /*
443 ** Check to see if element iRowid was inserted into the rowset as 431 ** Check to see if element iRowid was inserted into the rowset as
444 ** part of any insert batch prior to iBatch. Return 1 or 0. 432 ** part of any insert batch prior to iBatch. Return 1 or 0.
445 ** 433 **
446 ** If this is the first test of a new batch and if there exist entries 434 ** If this is the first test of a new batch and if there exist entries
447 ** on pRowSet->pEntry, then sort those entries into the forest at 435 ** on pRowSet->pEntry, then sort those entries into the forest at
448 ** pRowSet->pForest so that they can be tested. 436 ** pRowSet->pForest so that they can be tested.
449 */ 437 */
450 int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){ 438 int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64 iRowid){
451 struct RowSetEntry *p, *pTree; 439 struct RowSetEntry *p, *pTree;
452 440
453 /* This routine is never called after sqlite3RowSetNext() */ 441 /* This routine is never called after sqlite3RowSetNext() */
454 assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); 442 assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
455 443
456 /* Sort entries into the forest on the first test of a new batch 444 /* Sort entries into the forest on the first test of a new batch.
445 ** To save unnecessary work, only do this when the batch number changes.
457 */ 446 */
458 if( iBatch!=pRowSet->iBatch ){ 447 if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/
459 p = pRowSet->pEntry; 448 p = pRowSet->pEntry;
460 if( p ){ 449 if( p ){
461 struct RowSetEntry **ppPrevTree = &pRowSet->pForest; 450 struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
462 if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ 451 if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
452 /* Only sort the current set of entiries if they need it */
463 p = rowSetEntrySort(p); 453 p = rowSetEntrySort(p);
464 } 454 }
465 for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ 455 for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
466 ppPrevTree = &pTree->pRight; 456 ppPrevTree = &pTree->pRight;
467 if( pTree->pLeft==0 ){ 457 if( pTree->pLeft==0 ){
468 pTree->pLeft = rowSetListToTree(p); 458 pTree->pLeft = rowSetListToTree(p);
469 break; 459 break;
470 }else{ 460 }else{
471 struct RowSetEntry *pAux, *pTail; 461 struct RowSetEntry *pAux, *pTail;
472 rowSetTreeToList(pTree->pLeft, &pAux, &pTail); 462 rowSetTreeToList(pTree->pLeft, &pAux, &pTail);
(...skipping 26 matching lines...) Expand all
499 p = p->pRight; 489 p = p->pRight;
500 }else if( p->v>iRowid ){ 490 }else if( p->v>iRowid ){
501 p = p->pLeft; 491 p = p->pLeft;
502 }else{ 492 }else{
503 return 1; 493 return 1;
504 } 494 }
505 } 495 }
506 } 496 }
507 return 0; 497 return 0;
508 } 498 }
OLDNEW
« no previous file with comments | « third_party/sqlite/src/src/resolve.c ('k') | third_party/sqlite/src/src/select.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698