Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch sorter-exp Excluding Merge-Ins
This is equivalent to a diff from a5431c86 to 2bb8c492
2012-08-15
| ||
16:06 | Change autoconf so that the --with-tcl=DIR option will override the TCL configuration that is found using tclsh. (check-in: 772d0de3 user: drh tags: trunk) | |
15:57 | Experimental change to speed up ORDER BY clauses that sort based on a single expression. (Leaf check-in: 2bb8c492 user: dan tags: sorter-exp) | |
2012-08-14
| ||
19:04 | Silence three harmless compiler warnings in vdbesort.c. (check-in: a5431c86 user: drh tags: trunk) | |
18:43 | Add an assert() to the btree rebalancer in order to silence a clang/scan-build warning. (check-in: 6730579c user: drh tags: trunk) | |
Changes to src/vdbe.c.
︙ | ︙ | |||
4146 4147 4148 4149 4150 4151 4152 | ** P1 is a sorter cursor. This instruction compares the record blob in ** register P3 with the entry that the sorter cursor currently points to. ** If, excluding the rowid fields at the end, the two records are a match, ** fall through to the next instruction. Otherwise, jump to instruction P2. */ case OP_SorterCompare: { VdbeCursor *pC; | < | < | 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 | ** P1 is a sorter cursor. This instruction compares the record blob in ** register P3 with the entry that the sorter cursor currently points to. ** If, excluding the rowid fields at the end, the two records are a match, ** fall through to the next instruction. Otherwise, jump to instruction P2. */ case OP_SorterCompare: { VdbeCursor *pC; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); pIn3 = &aMem[pOp->p3]; if( sqlite3VdbeSorterCompare(pC, pIn3) ){ pc = pOp->p2-1; } break; }; /* Opcode: SorterData P1 P2 * * * ** |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
423 424 425 426 427 428 429 | #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK | | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterNext(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterCompare(X,Y) 0 #else int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *); #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0 void sqlite3VdbeEnter(Vdbe*); void sqlite3VdbeLeave(Vdbe*); #else # define sqlite3VdbeEnter(X) |
︙ | ︙ |
Changes to src/vdbesort.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | ** describes the data structure used to do so. The structure supports ** merging any number of arrays in a single pass with no redundant comparison ** operations. ** ** The aIter[] array contains an iterator for each of the PMAs being merged. ** An aIter[] iterator either points to a valid key or else is at EOF. For ** the purposes of the paragraphs below, we assume that the array is actually | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | ** describes the data structure used to do so. The structure supports ** merging any number of arrays in a single pass with no redundant comparison ** operations. ** ** The aIter[] array contains an iterator for each of the PMAs being merged. ** An aIter[] iterator either points to a valid key or else is at EOF. For ** the purposes of the paragraphs below, we assume that the array is actually ** N elements in size, where N is the smallest power of 2 greater to or equal ** to the number of iterators being merged. The extra aIter[] elements are ** treated as if they are empty (always at EOF). ** ** The aTree[] array is also N elements in size. The value of N is stored in ** the VdbeSorter.nTree variable. ** ** The final (N/2) elements of aTree[] contain the results of comparing |
︙ | ︙ | |||
100 101 102 103 104 105 106 | int nTree; /* Used size of aTree/aIter (power of 2) */ int nPMA; /* Number of PMAs stored in pTemp1 */ int mnPmaSize; /* Minimum PMA size, in bytes */ int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */ VdbeSorterIter *aIter; /* Array of iterators to merge */ int *aTree; /* Current state of incremental merge */ sqlite3_file *pTemp1; /* PMA file 1 */ | | > > > > > > > > > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | int nTree; /* Used size of aTree/aIter (power of 2) */ int nPMA; /* Number of PMAs stored in pTemp1 */ int mnPmaSize; /* Minimum PMA size, in bytes */ int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */ VdbeSorterIter *aIter; /* Array of iterators to merge */ int *aTree; /* Current state of incremental merge */ sqlite3_file *pTemp1; /* PMA file 1 */ SorterRecord *aRec[9]; /* Nine different types of records */ SorterRecord **aLastRec[9]; /* Locations to write the next pointers to */ UnpackedRecord *pUnpacked; /* Used to unpack keys */ }; #define SORTER_NULL 0 #define SORTER_INT_NEG 1 #define SORTER_INT_ZERO 2 #define SORTER_INT_ONE 3 #define SORTER_INT_POS 4 #define SORTER_DOUBLE 5 #define SORTER_TEXT 6 #define SORTER_BLOB 7 #define SORTER_LARGE 8 /* ** The following type is an iterator for a PMA. It caches the current key in ** variables nKey/aKey. If the iterator is at EOF, pFile==0. */ struct VdbeSorterIter { i64 iReadOff; /* Current read offset */ |
︙ | ︙ | |||
362 363 364 365 366 367 368 | if( rc==SQLITE_OK ){ rc = vdbeSorterIterNext(db, pIter); } return rc; } | < < < < < < | < | | < > < | < > | | > > > > > | > > > > > > > > > > | | > | | < | > | < | > > > > > > > > > > > > > > > > > > > > | > > > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | if( rc==SQLITE_OK ){ rc = vdbeSorterIterNext(db, pIter); } return rc; } /* ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, ** size nKey2 bytes). Argument pKeyInfo supplies the collation functions ** used by the comparison. If an error occurs, return an SQLite error code. ** Otherwise, return SQLITE_OK and set *pRes to a negative, zero or positive ** value, depending on whether key1 is smaller, equal to or larger than key2. ** ** If pKey2 is passed a NULL pointer, then it is assumed that the pCsr->aSpace ** has been allocated and contains an unpacked record that is used as key2. */ static int vdbeSorterCompareRec( void *p, /* VdbeCursor object */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ const VdbeCursor *pCsr = (VdbeCursor *)p; KeyInfo *pKeyInfo = pCsr->pKeyInfo; UnpackedRecord *r2 = pCsr->pSorter->pUnpacked; if( pKey2 ){ sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); } return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); } /* ** Buffers pKey1 and pKey2 both contain encoded records. The first elements ** of each are both either negative integers (if p!=0) or positive integers ** greater than 1 (if p==0). Return a values less than, equal to or greater ** than zero if the first field in pKey1 is less than, equal to or greater ** than the first field in pKey2, respectively. */ static int vdbeSorterCompareInt( void *p, const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ static const int aLen[] = {0, 1, 2, 3, 4, 6, 8}; const u8 *aKey1 = (u8 *)pKey1; const u8 *aKey2 = (u8 *)pKey2; int res = (int)aKey1[1] - (int)aKey2[1]; if( res==0 ){ res = memcmp(&aKey1[aKey1[0]], &aKey2[aKey2[0]], aLen[aKey1[1]]); }else if( aKey1[aKey1[0]] & 0x80 ){ res = res * -1; } return res; } /* ** Buffers pKey1 and pKey2 both contain encoded records. The first elements ** of each are both either text or blob values. ** ** Argument p points to a CollSeq structure. If the pKey1 and pKey2 buffers ** contain blobs, then this is always the BINARY collation sequence. Either ** way, compare the contents of the two buffers and return an integer less ** than, equal to or greater than zero if the value in pKey1 is less than, ** equal to or greater than that in pKey2, respectively. */ static int vdbeSorterCompareString( void *p, /* Pointer to CollSeq object */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2 /* Right side of comparison */ ){ CollSeq *pColl = (CollSeq *)p; const u8 *aKey1 = (u8 *)pKey1; const u8 *aKey2 = (u8 *)pKey2; int n1, n2; int res; n1 = (aKey1[1] - 12) / 2; n2 = (aKey2[1] - 12) / 2; res = pColl->xCmp(pColl->pUser, n1, &aKey1[aKey1[0]], n2, &aKey2[aKey2[0]]); return res; } /* ** This function is called to compare two iterator keys when merging ** multiple b-tree segments. Parameter iOut is the index of the aTree[] ** value to recalculate. */ |
︙ | ︙ | |||
442 443 444 445 446 447 448 | if( p1->pFile==0 ){ iRes = i2; }else if( p2->pFile==0 ){ iRes = i1; }else{ int res; assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */ | | | > > > > > > > > > > > > | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | if( p1->pFile==0 ){ iRes = i2; }else if( p2->pFile==0 ){ iRes = i1; }else{ int res; assert( pCsr->pSorter->pUnpacked!=0 ); /* allocated in vdbeSorterMerge() */ res = vdbeSorterCompareRec( (void *)pCsr, p1->aKey, p1->nKey, p2->aKey, p2->nKey ); if( res<=0 ){ iRes = i1; }else{ iRes = i2; } } pSorter->aTree[iOut] = iRes; return SQLITE_OK; } /* ** Set each entry of the aLastRec[] array to point to the corresponding entry ** in the aRec[] array. */ static void vdbeSorterSetLastRec(VdbeSorter *pSorter){ int i; for(i=0; i<ArraySize(pSorter->aLastRec); i++){ pSorter->aLastRec[i] = &pSorter->aRec[i]; } } /* ** Initialize the temporary index cursor just opened as a sorter cursor. */ int sqlite3VdbeSorterInit(sqlite3 *db, VdbeCursor *pCsr){ int pgsz; /* Page size of main database */ int mxCache; /* Cache size */ VdbeSorter *pSorter; /* The new sorter */ |
︙ | ︙ | |||
483 484 485 486 487 488 489 490 491 492 493 494 495 496 | pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; mxCache = db->aDb[0].pSchema->cache_size; if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING; pSorter->mxPmaSize = mxCache * pgsz; } return SQLITE_OK; } /* ** Free the list of sorted records starting at pRecord. */ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ | > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; mxCache = db->aDb[0].pSchema->cache_size; if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING; pSorter->mxPmaSize = mxCache * pgsz; } vdbeSorterSetLastRec(pSorter); return SQLITE_OK; } /* ** Free the list of sorted records starting at pRecord. */ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ |
︙ | ︙ | |||
504 505 506 507 508 509 510 | /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ | < | > > > | > > | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | /* ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. */ void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ VdbeSorter *pSorter = pCsr->pSorter; if( pSorter ){ int i; if( pSorter->aIter ){ for(i=0; i<pSorter->nTree; i++){ vdbeSorterIterZero(db, &pSorter->aIter[i]); } sqlite3DbFree(db, pSorter->aIter); } if( pSorter->pTemp1 ){ sqlite3OsCloseFree(pSorter->pTemp1); } for(i=0; i<ArraySize(pSorter->aRec); i++){ vdbeSorterRecordFree(db, pSorter->aRec[i]); } sqlite3DbFree(db, pSorter->pUnpacked); sqlite3DbFree(db, pSorter); pCsr->pSorter = 0; } } /* |
︙ | ︙ | |||
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | /* ** Merge the two sorted lists p1 and p2 into a single list. ** Set *ppOut to the head of the new list. */ static void vdbeSorterMerge( const VdbeCursor *pCsr, /* For pKeyInfo */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2, /* Second list to merge */ SorterRecord **ppOut /* OUT: Head of merged list */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; void *pVal2 = p2 ? p2->pVal : 0; while( p1 && p2 ){ int res; | > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | > > > > > > > > | | > > > | | < < < | | | | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | /* ** Merge the two sorted lists p1 and p2 into a single list. ** Set *ppOut to the head of the new list. */ static void vdbeSorterMerge( const VdbeCursor *pCsr, /* For pKeyInfo */ int (*xCmp)(void*,const void*,int,const void*,int), void *pCtx, /* First argument to pass to xCmp() */ SorterRecord *p1, /* First list to merge */ SorterRecord *p2, /* Second list to merge */ SorterRecord **ppOut /* OUT: Head of merged list */ ){ SorterRecord *pFinal = 0; SorterRecord **pp = &pFinal; void *pVal2 = p2 ? p2->pVal : 0; while( p1 && p2 ){ int res; res = xCmp(pCtx, p1->pVal, p1->nVal, pVal2, p2->nVal); if( xCmp!=vdbeSorterCompareRec && pCsr->pKeyInfo->aSortOrder[0] ){ res = res * -1; } if( res<=0 ){ *pp = p1; pp = &p1->pNext; p1 = p1->pNext; if( xCmp==vdbeSorterCompareRec ) pVal2 = 0; }else{ *pp = p2; pp = &p2->pNext; p2 = p2->pNext; if( p2==0 ) break; pVal2 = p2->pVal; } } *pp = p1 ? p1 : p2; *ppOut = pFinal; } /* ** Concatenate the linked lists headed at elements iStart through iEnd ** (inclusive) of the pSorter->aRec[] array. Store the result in ** pSorter->aRec[iEnd]. Set entries iStart through iEnd-1 to zero. ** ** If parameter bReverse is false, the lists are concatenated so that ** all the elements of list iStart occur before those of iStart+1, and ** so on. Or, if bReverse is true, the original content of iEnd is at ** the start of the result, followed by the content of iEnd-1, etc. */ static void vdbeSorterConcatLists( VdbeSorter *pSorter, int bReverse, /* True to concenate in reverse order */ int iStart, int iEnd ){ int i; for(i=iStart; i<iEnd; i++){ if( bReverse ){ *pSorter->aLastRec[i] = pSorter->aRec[iEnd]; pSorter->aRec[iEnd] = pSorter->aRec[i]; }else{ *pSorter->aLastRec[iEnd] = pSorter->aRec[i]; if( pSorter->aRec[i] ) pSorter->aLastRec[iEnd] = pSorter->aLastRec[i]; } pSorter->aRec[i] = 0; pSorter->aLastRec[i] = &pSorter->aRec[i]; } } /* ** Sort the linked list of records headed at pCsr->pRecord. Return SQLITE_OK ** if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if an error ** occurs. */ static int vdbeSorterSort(const VdbeCursor *pCsr){ int i; int iRec; SorterRecord **aSlot; SorterRecord *p; KeyInfo *pKeyInfo = pCsr->pKeyInfo; VdbeSorter *pSorter = pCsr->pSorter; int bReverse = pCsr->pKeyInfo->aSortOrder[0]; aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ return SQLITE_NOMEM; } /* If there are one or more SORTER_LARGE records, or if there are ** SORTER_TEXT records that must be converted to a different encoding ** before they can be compared, move everything to the SORTER_LARGE slot. */ if( pSorter->aRec[SORTER_LARGE] || (pSorter->aRec[SORTER_TEXT] && pKeyInfo->enc!=pKeyInfo->aColl[0]->enc) ){ vdbeSorterConcatLists(pSorter, 0, 0, SORTER_LARGE); } /* If there are one or more SORTER_DOUBLE records, move all numeric ** records to the SORTER_DOUBLE slot. */ if( pSorter->aRec[SORTER_DOUBLE] ){ vdbeSorterConcatLists(pSorter, 0, SORTER_INT_NEG, SORTER_DOUBLE); } for(iRec=0; iRec<ArraySize(pSorter->aRec); iRec++){ void *pCtx = 0; int (*xCmp)(void*,const void*,int,const void*,int); switch( iRec ){ case SORTER_NULL: case SORTER_INT_ZERO: case SORTER_INT_ONE: xCmp = 0; break; case SORTER_INT_NEG: case SORTER_INT_POS: xCmp = vdbeSorterCompareInt; break; case SORTER_BLOB: pCtx = (void *)(pCsr->pKeyInfo->db->pDfltColl); xCmp = vdbeSorterCompareString; break; case SORTER_TEXT: pCtx = (void *)(pCsr->pKeyInfo->aColl[0]); xCmp = vdbeSorterCompareString; break; default: pCtx = (void *)pCsr; xCmp = vdbeSorterCompareRec; break; } if( !xCmp ) continue; p = pSorter->aRec[iRec]; while( p ){ SorterRecord *pNext = p->pNext; p->pNext = 0; for(i=0; aSlot[i]; i++){ vdbeSorterMerge(pCsr, xCmp, pCtx, aSlot[i], p, &p); aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<64; i++){ vdbeSorterMerge(pCsr, xCmp, pCtx, aSlot[i], p, &p); aSlot[i] = 0; } pSorter->aRec[iRec] = p; if( p ){ SorterRecord *pRec; for(pRec=pSorter->aRec[iRec]; pRec->pNext; pRec=pRec->pNext); pSorter->aLastRec[iRec] = &pRec->pNext; } } vdbeSorterConcatLists(pSorter, bReverse, 0, SORTER_LARGE); vdbeSorterSetLastRec(pSorter); sqlite3_free(aSlot); return SQLITE_OK; } /* ** Initialize a file-writer object. */ |
︙ | ︙ | |||
707 708 709 710 711 712 713 | ** in the PMA (not including the varint itself). ** ** * One or more records packed end-to-end in order of ascending keys. ** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){ | | < | | | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 | ** in the PMA (not including the varint itself). ** ** * One or more records packed end-to-end in order of ascending keys. ** Each record consists of a varint followed by a blob of data (the ** key). The varint is the number of bytes in the blob of data. */ static int vdbeSorterListToPMA(sqlite3 *db, const VdbeCursor *pCsr){ int rc; /* Return code */ VdbeSorter *pSorter = pCsr->pSorter; FileWriter writer; memset(&writer, 0, sizeof(FileWriter)); if( pSorter->nInMemory==0 ){ return SQLITE_OK; } rc = vdbeSorterSort(pCsr); /* If the first temporary PMA file has not been opened, open it now. */ if( rc==SQLITE_OK && pSorter->pTemp1==0 ){ rc = vdbeSorterOpenTempFile(db, &pSorter->pTemp1); assert( rc!=SQLITE_OK || pSorter->pTemp1 ); assert( pSorter->iWriteOff==0 ); assert( pSorter->nPMA==0 ); } if( rc==SQLITE_OK ){ SorterRecord *p; SorterRecord *pNext = 0; fileWriterInit(db, pSorter->pTemp1, &writer, pSorter->iWriteOff); pSorter->nPMA++; fileWriterWriteVarint(&writer, pSorter->nInMemory); for(p=pSorter->aRec[SORTER_LARGE]; rc==SQLITE_OK && p; p=pNext){ pNext = p->pNext; fileWriterWriteVarint(&writer, p->nVal); fileWriterWrite(&writer, p->pVal, p->nVal); sqlite3DbFree(db, p); } pSorter->aRec[SORTER_LARGE] = p; rc = fileWriterFinish(db, &writer, &pSorter->iWriteOff); } return rc; } /* |
︙ | ︙ | |||
767 768 769 770 771 772 773 | assert( pSorter ); pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n; pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 | assert( pSorter ); pSorter->nInMemory += sqlite3VarintLen(pVal->n) + pVal->n; pNew = (SorterRecord *)sqlite3DbMallocRaw(db, pVal->n + sizeof(SorterRecord)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ int iSlot; u8 *aVal = pNew->pVal = (void *)&pNew[1]; memcpy(pNew->pVal, pVal->z, pVal->n); pNew->nVal = pVal->n; u8 n = aVal[0]; u8 t = aVal[1]; if( pCsr->pKeyInfo->nField!=1 || (t & 0x80) || (n & 0x80) ){ iSlot = SORTER_LARGE; }else{ u8 t = aVal[1]; switch( t ){ case 0: iSlot = SORTER_NULL; break; case 1: case 2: case 3: case 4: case 5: case 6: iSlot = (aVal[n] & 0x80) ? SORTER_INT_NEG : SORTER_INT_POS; break; case 7: iSlot = SORTER_DOUBLE; break; case 8: iSlot = SORTER_INT_ZERO; break; case 9: iSlot = SORTER_INT_ONE; break; default: iSlot = SORTER_BLOB - (t & 0x01); break; } } pNew->pNext = 0; *pSorter->aLastRec[iSlot] = pNew; pSorter->aLastRec[iSlot] = &(pNew->pNext); } /* See if the contents of the sorter should now be written out. They ** are written out when either of the following are true: ** ** * The total memory allocated for the in-memory list is greater ** than (page-size * cache-size), or |
︙ | ︙ | |||
850 851 852 853 854 855 856 | assert( pSorter ); /* If no data has been written to disk, then do not do so now. Instead, ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly ** from the in-memory list. */ if( pSorter->nPMA==0 ){ | | | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | assert( pSorter ); /* If no data has been written to disk, then do not do so now. Instead, ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly ** from the in-memory list. */ if( pSorter->nPMA==0 ){ *pbEof = (pSorter->nInMemory==0); assert( pSorter->aTree==0 ); return vdbeSorterSort(pCsr); } /* Write the current in-memory list to a PMA. */ rc = vdbeSorterListToPMA(db, pCsr); if( rc!=SQLITE_OK ) return rc; |
︙ | ︙ | |||
959 960 961 962 963 964 965 | rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ rc = vdbeSorterDoCompare(pCsr, i); } *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); }else{ | | | | | | < | < > > > > > | > > > > > > | > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | rc = vdbeSorterIterNext(db, &pSorter->aIter[iPrev]); for(i=(pSorter->nTree+iPrev)/2; rc==SQLITE_OK && i>0; i=i/2){ rc = vdbeSorterDoCompare(pCsr, i); } *pbEof = (pSorter->aIter[pSorter->aTree[1]].pFile==0); }else{ SorterRecord *pFree = pSorter->aRec[SORTER_LARGE]; pSorter->aRec[SORTER_LARGE] = pFree->pNext; pFree->pNext = 0; vdbeSorterRecordFree(db, pFree); *pbEof = !pSorter->aRec[SORTER_LARGE]; rc = SQLITE_OK; } return rc; } /* ** Return a pointer to a buffer owned by the sorter that contains the ** current key. */ static void *vdbeSorterRowkey( const VdbeSorter *pSorter, /* Sorter object */ int *pnKey /* OUT: Size of current key in bytes */ ){ void *pKey; if( pSorter->aTree ){ VdbeSorterIter *pIter; pIter = &pSorter->aIter[ pSorter->aTree[1] ]; *pnKey = pIter->nKey; pKey = pIter->aKey; }else{ *pnKey = pSorter->aRec[SORTER_LARGE]->nVal; pKey = pSorter->aRec[SORTER_LARGE]->pVal; } return pKey; } /* ** Copy the current sorter key into the memory cell pOut. */ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to copy into pOut */ pKey = vdbeSorterRowkey(pSorter, &nKey); if( sqlite3VdbeMemGrow(pOut, nKey, 0) ){ return SQLITE_NOMEM; } pOut->n = nKey; MemSetTypeFlag(pOut, MEM_Blob); memcpy(pOut->z, pKey, nKey); return SQLITE_OK; } /* ** Compare the key in memory cell pVal with the key that the sorter cursor ** passed as the first argument currently points to. For the purposes of ** the comparison, ignore the rowid field at the end of each record. ** ** If an error occurs, return an SQLite error code (i.e. SQLITE_NOMEM). ** Otherwise, set *pRes to a negative, zero or positive value if the ** key in pVal is smaller than, equal to or larger than the current sorter ** key. */ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal /* Value to compare to current sorter key */ ){ KeyInfo *pKeyInfo = pCsr->pKeyInfo; VdbeSorter *pSorter = pCsr->pSorter; UnpackedRecord *r2 = pSorter->pUnpacked; int i; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); assert( pKey && pVal->z ); sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); r2->nField = pKeyInfo->nField; assert( r2->nField>0 ); for(i=0; i<r2->nField; i++){ if( r2->aMem[i].flags & MEM_Null ) return -1; } r2->flags |= UNPACKED_PREFIX_MATCH; return sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); } #endif /* #ifndef SQLITE_OMIT_MERGE_SORT */ |
Changes to test/sort.test.
︙ | ︙ | |||
459 460 461 462 463 464 465 466 467 | insert into b values (2, 1, 'xxx'); insert into b values (1, 1, 'zzz'); insert into b values (3, 1, 'yyy'); select a.id, b.id, b.text from a join b on (a.id = b.aId) order by a.id, b.text; } } {1 2 xxx 1 3 yyy 1 1 zzz} finish_test | > > > > > > > > > > > > > > > | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | insert into b values (2, 1, 'xxx'); insert into b values (1, 1, 'zzz'); insert into b values (3, 1, 'yyy'); select a.id, b.id, b.text from a join b on (a.id = b.aId) order by a.id, b.text; } } {1 2 xxx 1 3 yyy 1 1 zzz} foreach {tn shuffle} { 1 {1 2 3 4} 2 {1 3 2 4} 3 {4 3 2 1} 4 {1 3 2 4} } { do_test sort-13.$tn { execsql { DROP TABLE IF EXISTS w1 } execsql { CREATE TABLE w1(x) } foreach i $shuffle { execsql { INSERT INTO w1 VALUES($i) } } execsql { SELECT x FROM w1 ORDER BY x } } {1 2 3 4} } finish_test |