OLD | NEW |
1 /* | 1 /* |
2 ** 2011-07-09 | 2 ** 2011-07-09 |
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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 ** multi-threaded mode then up to (N+1) temporary files may be opened, where | 93 ** multi-threaded mode then up to (N+1) temporary files may be opened, where |
94 ** N is the configured number of worker threads. In this case, instead of | 94 ** N is the configured number of worker threads. In this case, instead of |
95 ** sorting the records and writing the PMA to a temporary file itself, the | 95 ** sorting the records and writing the PMA to a temporary file itself, the |
96 ** calling thread usually launches a worker thread to do so. Except, if | 96 ** calling thread usually launches a worker thread to do so. Except, if |
97 ** there are already N worker threads running, the main thread does the work | 97 ** there are already N worker threads running, the main thread does the work |
98 ** itself. | 98 ** itself. |
99 ** | 99 ** |
100 ** The sorter is running in multi-threaded mode if (a) the library was built | 100 ** The sorter is running in multi-threaded mode if (a) the library was built |
101 ** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater | 101 ** with pre-processor symbol SQLITE_MAX_WORKER_THREADS set to a value greater |
102 ** than zero, and (b) worker threads have been enabled at runtime by calling | 102 ** than zero, and (b) worker threads have been enabled at runtime by calling |
103 ** sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, ...). | 103 ** "PRAGMA threads=N" with some value of N greater than 0. |
104 ** | 104 ** |
105 ** When Rewind() is called, any data remaining in memory is flushed to a | 105 ** When Rewind() is called, any data remaining in memory is flushed to a |
106 ** final PMA. So at this point the data is stored in some number of sorted | 106 ** final PMA. So at this point the data is stored in some number of sorted |
107 ** PMAs within temporary files on disk. | 107 ** PMAs within temporary files on disk. |
108 ** | 108 ** |
109 ** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the | 109 ** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the |
110 ** sorter is running in single-threaded mode, then these PMAs are merged | 110 ** sorter is running in single-threaded mode, then these PMAs are merged |
111 ** incrementally as keys are retreived from the sorter by the VDBE. The | 111 ** incrementally as keys are retreived from the sorter by the VDBE. The |
112 ** MergeEngine object, described in further detail below, performs this | 112 ** MergeEngine object, described in further detail below, performs this |
113 ** merge. | 113 ** merge. |
(...skipping 27 matching lines...) Expand all Loading... |
141 /* | 141 /* |
142 ** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various | 142 ** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various |
143 ** messages to stderr that may be helpful in understanding the performance | 143 ** messages to stderr that may be helpful in understanding the performance |
144 ** characteristics of the sorter in multi-threaded mode. | 144 ** characteristics of the sorter in multi-threaded mode. |
145 */ | 145 */ |
146 #if 0 | 146 #if 0 |
147 # define SQLITE_DEBUG_SORTER_THREADS 1 | 147 # define SQLITE_DEBUG_SORTER_THREADS 1 |
148 #endif | 148 #endif |
149 | 149 |
150 /* | 150 /* |
| 151 ** Hard-coded maximum amount of data to accumulate in memory before flushing |
| 152 ** to a level 0 PMA. The purpose of this limit is to prevent various integer |
| 153 ** overflows. 512MiB. |
| 154 */ |
| 155 #define SQLITE_MAX_PMASZ (1<<29) |
| 156 |
| 157 /* |
151 ** Private objects used by the sorter | 158 ** Private objects used by the sorter |
152 */ | 159 */ |
153 typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ | 160 typedef struct MergeEngine MergeEngine; /* Merge PMAs together */ |
154 typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ | 161 typedef struct PmaReader PmaReader; /* Incrementally read one PMA */ |
155 typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ | 162 typedef struct PmaWriter PmaWriter; /* Incrementally write one PMA */ |
156 typedef struct SorterRecord SorterRecord; /* A record being sorted */ | 163 typedef struct SorterRecord SorterRecord; /* A record being sorted */ |
157 typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ | 164 typedef struct SortSubtask SortSubtask; /* A sub-task in the sort process */ |
158 typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ | 165 typedef struct SorterFile SorterFile; /* Temporary file object wrapper */ |
159 typedef struct SorterList SorterList; /* In-memory list of records */ | 166 typedef struct SorterList SorterList; /* In-memory list of records */ |
160 typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ | 167 typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */ |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 ** to block until it finishes). | 284 ** to block until it finishes). |
278 ** | 285 ** |
279 ** 2. If SQLITE_DEBUG_SORTER_THREADS is defined, to determine if a call | 286 ** 2. If SQLITE_DEBUG_SORTER_THREADS is defined, to determine if a call |
280 ** to sqlite3ThreadJoin() is likely to block. Cases that are likely to | 287 ** to sqlite3ThreadJoin() is likely to block. Cases that are likely to |
281 ** block provoke debugging output. | 288 ** block provoke debugging output. |
282 ** | 289 ** |
283 ** In both cases, the effects of the main thread seeing (bDone==0) even | 290 ** In both cases, the effects of the main thread seeing (bDone==0) even |
284 ** after the thread has finished are not dire. So we don't worry about | 291 ** after the thread has finished are not dire. So we don't worry about |
285 ** memory barriers and such here. | 292 ** memory barriers and such here. |
286 */ | 293 */ |
| 294 typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int); |
287 struct SortSubtask { | 295 struct SortSubtask { |
288 SQLiteThread *pThread; /* Background thread, if any */ | 296 SQLiteThread *pThread; /* Background thread, if any */ |
289 int bDone; /* Set if thread is finished but not joined */ | 297 int bDone; /* Set if thread is finished but not joined */ |
290 VdbeSorter *pSorter; /* Sorter that owns this sub-task */ | 298 VdbeSorter *pSorter; /* Sorter that owns this sub-task */ |
291 UnpackedRecord *pUnpacked; /* Space to unpack a record */ | 299 UnpackedRecord *pUnpacked; /* Space to unpack a record */ |
292 SorterList list; /* List for thread to write to a PMA */ | 300 SorterList list; /* List for thread to write to a PMA */ |
293 int nPMA; /* Number of PMAs currently in file */ | 301 int nPMA; /* Number of PMAs currently in file */ |
| 302 SorterCompare xCompare; /* Compare function to use */ |
294 SorterFile file; /* Temp file for level-0 PMAs */ | 303 SorterFile file; /* Temp file for level-0 PMAs */ |
295 SorterFile file2; /* Space for other PMAs */ | 304 SorterFile file2; /* Space for other PMAs */ |
296 }; | 305 }; |
297 | 306 |
| 307 |
298 /* | 308 /* |
299 ** Main sorter structure. A single instance of this is allocated for each | 309 ** Main sorter structure. A single instance of this is allocated for each |
300 ** sorter cursor created by the VDBE. | 310 ** sorter cursor created by the VDBE. |
301 ** | 311 ** |
302 ** mxKeysize: | 312 ** mxKeysize: |
303 ** As records are added to the sorter by calls to sqlite3VdbeSorterWrite(), | 313 ** As records are added to the sorter by calls to sqlite3VdbeSorterWrite(), |
304 ** this variable is updated so as to be set to the size on disk of the | 314 ** this variable is updated so as to be set to the size on disk of the |
305 ** largest record in the sorter. | 315 ** largest record in the sorter. |
306 */ | 316 */ |
307 struct VdbeSorter { | 317 struct VdbeSorter { |
308 int mnPmaSize; /* Minimum PMA size, in bytes */ | 318 int mnPmaSize; /* Minimum PMA size, in bytes */ |
309 int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */ | 319 int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */ |
310 int mxKeysize; /* Largest serialized key seen so far */ | 320 int mxKeysize; /* Largest serialized key seen so far */ |
311 int pgsz; /* Main database page size */ | 321 int pgsz; /* Main database page size */ |
312 PmaReader *pReader; /* Readr data from here after Rewind() */ | 322 PmaReader *pReader; /* Readr data from here after Rewind() */ |
313 MergeEngine *pMerger; /* Or here, if bUseThreads==0 */ | 323 MergeEngine *pMerger; /* Or here, if bUseThreads==0 */ |
314 sqlite3 *db; /* Database connection */ | 324 sqlite3 *db; /* Database connection */ |
315 KeyInfo *pKeyInfo; /* How to compare records */ | 325 KeyInfo *pKeyInfo; /* How to compare records */ |
316 UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */ | 326 UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */ |
317 SorterList list; /* List of in-memory records */ | 327 SorterList list; /* List of in-memory records */ |
318 int iMemory; /* Offset of free space in list.aMemory */ | 328 int iMemory; /* Offset of free space in list.aMemory */ |
319 int nMemory; /* Size of list.aMemory allocation in bytes */ | 329 int nMemory; /* Size of list.aMemory allocation in bytes */ |
320 u8 bUsePMA; /* True if one or more PMAs created */ | 330 u8 bUsePMA; /* True if one or more PMAs created */ |
321 u8 bUseThreads; /* True to use background threads */ | 331 u8 bUseThreads; /* True to use background threads */ |
322 u8 iPrev; /* Previous thread used to flush PMA */ | 332 u8 iPrev; /* Previous thread used to flush PMA */ |
323 u8 nTask; /* Size of aTask[] array */ | 333 u8 nTask; /* Size of aTask[] array */ |
| 334 u8 typeMask; |
324 SortSubtask aTask[1]; /* One or more subtasks */ | 335 SortSubtask aTask[1]; /* One or more subtasks */ |
325 }; | 336 }; |
326 | 337 |
| 338 #define SORTER_TYPE_INTEGER 0x01 |
| 339 #define SORTER_TYPE_TEXT 0x02 |
| 340 |
327 /* | 341 /* |
328 ** An instance of the following object is used to read records out of a | 342 ** An instance of the following object is used to read records out of a |
329 ** PMA, in sorted order. The next key to be read is cached in nKey/aKey. | 343 ** PMA, in sorted order. The next key to be read is cached in nKey/aKey. |
330 ** aKey might point into aMap or into aBuffer. If neither of those locations | 344 ** aKey might point into aMap or into aBuffer. If neither of those locations |
331 ** contain a contiguous representation of the key, then aAlloc is allocated | 345 ** contain a contiguous representation of the key, then aAlloc is allocated |
332 ** and the key is copied into aAlloc and aKey is made to poitn to aAlloc. | 346 ** and the key is copied into aAlloc and aKey is made to poitn to aAlloc. |
333 ** | 347 ** |
334 ** pFd==0 at EOF. | 348 ** pFd==0 at EOF. |
335 */ | 349 */ |
336 struct PmaReader { | 350 struct PmaReader { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 /* The data for the record immediately follows this header */ | 448 /* The data for the record immediately follows this header */ |
435 }; | 449 }; |
436 | 450 |
437 /* Return a pointer to the buffer containing the record data for SorterRecord | 451 /* Return a pointer to the buffer containing the record data for SorterRecord |
438 ** object p. Should be used as if: | 452 ** object p. Should be used as if: |
439 ** | 453 ** |
440 ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } | 454 ** void *SRVAL(SorterRecord *p) { return (void*)&p[1]; } |
441 */ | 455 */ |
442 #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) | 456 #define SRVAL(p) ((void*)((SorterRecord*)(p) + 1)) |
443 | 457 |
444 /* The minimum PMA size is set to this value multiplied by the database | |
445 ** page size in bytes. */ | |
446 #define SORTER_MIN_WORKING 10 | |
447 | 458 |
448 /* Maximum number of PMAs that a single MergeEngine can merge */ | 459 /* Maximum number of PMAs that a single MergeEngine can merge */ |
449 #define SORTER_MAX_MERGE_COUNT 16 | 460 #define SORTER_MAX_MERGE_COUNT 16 |
450 | 461 |
451 static int vdbeIncrSwap(IncrMerger*); | 462 static int vdbeIncrSwap(IncrMerger*); |
452 static void vdbeIncrFree(IncrMerger *); | 463 static void vdbeIncrFree(IncrMerger *); |
453 | 464 |
454 /* | 465 /* |
455 ** Free all memory belonging to the PmaReader object passed as the | 466 ** Free all memory belonging to the PmaReader object passed as the |
456 ** argument. All structure fields are set to zero before returning. | 467 ** argument. All structure fields are set to zero before returning. |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 pReadr->iEof = pReadr->iReadOff + nByte; | 742 pReadr->iEof = pReadr->iReadOff + nByte; |
732 *pnByte += nByte; | 743 *pnByte += nByte; |
733 } | 744 } |
734 | 745 |
735 if( rc==SQLITE_OK ){ | 746 if( rc==SQLITE_OK ){ |
736 rc = vdbePmaReaderNext(pReadr); | 747 rc = vdbePmaReaderNext(pReadr); |
737 } | 748 } |
738 return rc; | 749 return rc; |
739 } | 750 } |
740 | 751 |
| 752 /* |
| 753 ** A version of vdbeSorterCompare() that assumes that it has already been |
| 754 ** determined that the first field of key1 is equal to the first field of |
| 755 ** key2. |
| 756 */ |
| 757 static int vdbeSorterCompareTail( |
| 758 SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ |
| 759 int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ |
| 760 const void *pKey1, int nKey1, /* Left side of comparison */ |
| 761 const void *pKey2, int nKey2 /* Right side of comparison */ |
| 762 ){ |
| 763 UnpackedRecord *r2 = pTask->pUnpacked; |
| 764 if( *pbKey2Cached==0 ){ |
| 765 sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); |
| 766 *pbKey2Cached = 1; |
| 767 } |
| 768 return sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, r2, 1); |
| 769 } |
741 | 770 |
742 /* | 771 /* |
743 ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, | 772 ** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2, |
744 ** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences | 773 ** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences |
745 ** used by the comparison. Return the result of the comparison. | 774 ** used by the comparison. Return the result of the comparison. |
746 ** | 775 ** |
747 ** Before returning, object (pTask->pUnpacked) is populated with the | 776 ** If IN/OUT parameter *pbKey2Cached is true when this function is called, |
748 ** unpacked version of key2. Or, if pKey2 is passed a NULL pointer, then it | 777 ** it is assumed that (pTask->pUnpacked) contains the unpacked version |
749 ** is assumed that the (pTask->pUnpacked) structure already contains the | 778 ** of key2. If it is false, (pTask->pUnpacked) is populated with the unpacked |
750 ** unpacked key to use as key2. | 779 ** version of key2 and *pbKey2Cached set to true before returning. |
751 ** | 780 ** |
752 ** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set | 781 ** If an OOM error is encountered, (pTask->pUnpacked->error_rc) is set |
753 ** to SQLITE_NOMEM. | 782 ** to SQLITE_NOMEM. |
754 */ | 783 */ |
755 static int vdbeSorterCompare( | 784 static int vdbeSorterCompare( |
756 SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ | 785 SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ |
| 786 int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ |
757 const void *pKey1, int nKey1, /* Left side of comparison */ | 787 const void *pKey1, int nKey1, /* Left side of comparison */ |
758 const void *pKey2, int nKey2 /* Right side of comparison */ | 788 const void *pKey2, int nKey2 /* Right side of comparison */ |
759 ){ | 789 ){ |
760 UnpackedRecord *r2 = pTask->pUnpacked; | 790 UnpackedRecord *r2 = pTask->pUnpacked; |
761 if( pKey2 ){ | 791 if( !*pbKey2Cached ){ |
762 sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); | 792 sqlite3VdbeRecordUnpack(pTask->pSorter->pKeyInfo, nKey2, pKey2, r2); |
| 793 *pbKey2Cached = 1; |
763 } | 794 } |
764 return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); | 795 return sqlite3VdbeRecordCompare(nKey1, pKey1, r2); |
765 } | 796 } |
766 | 797 |
767 /* | 798 /* |
| 799 ** A specially optimized version of vdbeSorterCompare() that assumes that |
| 800 ** the first field of each key is a TEXT value and that the collation |
| 801 ** sequence to compare them with is BINARY. |
| 802 */ |
| 803 static int vdbeSorterCompareText( |
| 804 SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ |
| 805 int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ |
| 806 const void *pKey1, int nKey1, /* Left side of comparison */ |
| 807 const void *pKey2, int nKey2 /* Right side of comparison */ |
| 808 ){ |
| 809 const u8 * const p1 = (const u8 * const)pKey1; |
| 810 const u8 * const p2 = (const u8 * const)pKey2; |
| 811 const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ |
| 812 const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ |
| 813 |
| 814 int n1; |
| 815 int n2; |
| 816 int res; |
| 817 |
| 818 getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2; |
| 819 getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2; |
| 820 res = memcmp(v1, v2, MIN(n1, n2)); |
| 821 if( res==0 ){ |
| 822 res = n1 - n2; |
| 823 } |
| 824 |
| 825 if( res==0 ){ |
| 826 if( pTask->pSorter->pKeyInfo->nField>1 ){ |
| 827 res = vdbeSorterCompareTail( |
| 828 pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 |
| 829 ); |
| 830 } |
| 831 }else{ |
| 832 if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ |
| 833 res = res * -1; |
| 834 } |
| 835 } |
| 836 |
| 837 return res; |
| 838 } |
| 839 |
| 840 /* |
| 841 ** A specially optimized version of vdbeSorterCompare() that assumes that |
| 842 ** the first field of each key is an INTEGER value. |
| 843 */ |
| 844 static int vdbeSorterCompareInt( |
| 845 SortSubtask *pTask, /* Subtask context (for pKeyInfo) */ |
| 846 int *pbKey2Cached, /* True if pTask->pUnpacked is pKey2 */ |
| 847 const void *pKey1, int nKey1, /* Left side of comparison */ |
| 848 const void *pKey2, int nKey2 /* Right side of comparison */ |
| 849 ){ |
| 850 const u8 * const p1 = (const u8 * const)pKey1; |
| 851 const u8 * const p2 = (const u8 * const)pKey2; |
| 852 const int s1 = p1[1]; /* Left hand serial type */ |
| 853 const int s2 = p2[1]; /* Right hand serial type */ |
| 854 const u8 * const v1 = &p1[ p1[0] ]; /* Pointer to value 1 */ |
| 855 const u8 * const v2 = &p2[ p2[0] ]; /* Pointer to value 2 */ |
| 856 int res; /* Return value */ |
| 857 |
| 858 assert( (s1>0 && s1<7) || s1==8 || s1==9 ); |
| 859 assert( (s2>0 && s2<7) || s2==8 || s2==9 ); |
| 860 |
| 861 if( s1>7 && s2>7 ){ |
| 862 res = s1 - s2; |
| 863 }else{ |
| 864 if( s1==s2 ){ |
| 865 if( (*v1 ^ *v2) & 0x80 ){ |
| 866 /* The two values have different signs */ |
| 867 res = (*v1 & 0x80) ? -1 : +1; |
| 868 }else{ |
| 869 /* The two values have the same sign. Compare using memcmp(). */ |
| 870 static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 }; |
| 871 int i; |
| 872 res = 0; |
| 873 for(i=0; i<aLen[s1]; i++){ |
| 874 if( (res = v1[i] - v2[i]) ) break; |
| 875 } |
| 876 } |
| 877 }else{ |
| 878 if( s2>7 ){ |
| 879 res = +1; |
| 880 }else if( s1>7 ){ |
| 881 res = -1; |
| 882 }else{ |
| 883 res = s1 - s2; |
| 884 } |
| 885 assert( res!=0 ); |
| 886 |
| 887 if( res>0 ){ |
| 888 if( *v1 & 0x80 ) res = -1; |
| 889 }else{ |
| 890 if( *v2 & 0x80 ) res = +1; |
| 891 } |
| 892 } |
| 893 } |
| 894 |
| 895 if( res==0 ){ |
| 896 if( pTask->pSorter->pKeyInfo->nField>1 ){ |
| 897 res = vdbeSorterCompareTail( |
| 898 pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 |
| 899 ); |
| 900 } |
| 901 }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ |
| 902 res = res * -1; |
| 903 } |
| 904 |
| 905 return res; |
| 906 } |
| 907 |
| 908 /* |
768 ** Initialize the temporary index cursor just opened as a sorter cursor. | 909 ** Initialize the temporary index cursor just opened as a sorter cursor. |
769 ** | 910 ** |
770 ** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) | 911 ** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField) |
771 ** to determine the number of fields that should be compared from the | 912 ** to determine the number of fields that should be compared from the |
772 ** records being sorted. However, if the value passed as argument nField | 913 ** records being sorted. However, if the value passed as argument nField |
773 ** is non-zero and the sorter is able to guarantee a stable sort, nField | 914 ** is non-zero and the sorter is able to guarantee a stable sort, nField |
774 ** is used instead. This is used when sorting records for a CREATE INDEX | 915 ** is used instead. This is used when sorting records for a CREATE INDEX |
775 ** statement. In this case, keys are always delivered to the sorter in | 916 ** statement. In this case, keys are always delivered to the sorter in |
776 ** order of the primary key, which happens to be make up the final part | 917 ** order of the primary key, which happens to be make up the final part |
777 ** of the records being sorted. So if the sort is stable, there is never | 918 ** of the records being sorted. So if the sort is stable, there is never |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
813 | 954 |
814 /* Do not allow the total number of threads (main thread + all workers) | 955 /* Do not allow the total number of threads (main thread + all workers) |
815 ** to exceed the maximum merge count */ | 956 ** to exceed the maximum merge count */ |
816 #if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT | 957 #if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT |
817 if( nWorker>=SORTER_MAX_MERGE_COUNT ){ | 958 if( nWorker>=SORTER_MAX_MERGE_COUNT ){ |
818 nWorker = SORTER_MAX_MERGE_COUNT-1; | 959 nWorker = SORTER_MAX_MERGE_COUNT-1; |
819 } | 960 } |
820 #endif | 961 #endif |
821 | 962 |
822 assert( pCsr->pKeyInfo && pCsr->pBt==0 ); | 963 assert( pCsr->pKeyInfo && pCsr->pBt==0 ); |
| 964 assert( pCsr->eCurType==CURTYPE_SORTER ); |
823 szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); | 965 szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*); |
824 sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); | 966 sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask); |
825 | 967 |
826 pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); | 968 pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo); |
827 pCsr->pSorter = pSorter; | 969 pCsr->uc.pSorter = pSorter; |
828 if( pSorter==0 ){ | 970 if( pSorter==0 ){ |
829 rc = SQLITE_NOMEM; | 971 rc = SQLITE_NOMEM; |
830 }else{ | 972 }else{ |
831 pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); | 973 pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); |
832 memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); | 974 memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); |
833 pKeyInfo->db = 0; | 975 pKeyInfo->db = 0; |
834 if( nField && nWorker==0 ) pKeyInfo->nField = nField; | 976 if( nField && nWorker==0 ){ |
| 977 pKeyInfo->nXField += (pKeyInfo->nField - nField); |
| 978 pKeyInfo->nField = nField; |
| 979 } |
835 pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); | 980 pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); |
836 pSorter->nTask = nWorker + 1; | 981 pSorter->nTask = nWorker + 1; |
| 982 pSorter->iPrev = (u8)(nWorker - 1); |
837 pSorter->bUseThreads = (pSorter->nTask>1); | 983 pSorter->bUseThreads = (pSorter->nTask>1); |
838 pSorter->db = db; | 984 pSorter->db = db; |
839 for(i=0; i<pSorter->nTask; i++){ | 985 for(i=0; i<pSorter->nTask; i++){ |
840 SortSubtask *pTask = &pSorter->aTask[i]; | 986 SortSubtask *pTask = &pSorter->aTask[i]; |
841 pTask->pSorter = pSorter; | 987 pTask->pSorter = pSorter; |
842 } | 988 } |
843 | 989 |
844 if( !sqlite3TempInMemory(db) ){ | 990 if( !sqlite3TempInMemory(db) ){ |
845 pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz; | 991 u32 szPma = sqlite3GlobalConfig.szPma; |
| 992 pSorter->mnPmaSize = szPma * pgsz; |
846 mxCache = db->aDb[0].pSchema->cache_size; | 993 mxCache = db->aDb[0].pSchema->cache_size; |
847 if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING; | 994 if( mxCache<(int)szPma ) mxCache = (int)szPma; |
848 pSorter->mxPmaSize = mxCache * pgsz; | 995 pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ); |
849 | 996 |
850 /* If the application has not configure scratch memory using | 997 /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of |
851 ** SQLITE_CONFIG_SCRATCH then we assume it is OK to do large memory | 998 ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary |
852 ** allocations. If scratch memory has been configured, then assume | 999 ** large heap allocations. |
853 ** large memory allocations should be avoided to prevent heap | |
854 ** fragmentation. | |
855 */ | 1000 */ |
856 if( sqlite3GlobalConfig.pScratch==0 ){ | 1001 if( sqlite3GlobalConfig.pScratch==0 ){ |
857 assert( pSorter->iMemory==0 ); | 1002 assert( pSorter->iMemory==0 ); |
858 pSorter->nMemory = pgsz; | 1003 pSorter->nMemory = pgsz; |
859 pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); | 1004 pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz); |
860 if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; | 1005 if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM; |
861 } | 1006 } |
862 } | 1007 } |
| 1008 |
| 1009 if( (pKeyInfo->nField+pKeyInfo->nXField)<13 |
| 1010 && (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl) |
| 1011 ){ |
| 1012 pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT; |
| 1013 } |
863 } | 1014 } |
864 | 1015 |
865 return rc; | 1016 return rc; |
866 } | 1017 } |
867 #undef nWorker /* Defined at the top of this function */ | 1018 #undef nWorker /* Defined at the top of this function */ |
868 | 1019 |
869 /* | 1020 /* |
870 ** Free the list of sorted records starting at pRecord. | 1021 ** Free the list of sorted records starting at pRecord. |
871 */ | 1022 */ |
872 static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ | 1023 static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){ |
873 SorterRecord *p; | 1024 SorterRecord *p; |
874 SorterRecord *pNext; | 1025 SorterRecord *pNext; |
875 for(p=pRecord; p; p=pNext){ | 1026 for(p=pRecord; p; p=pNext){ |
876 pNext = p->u.pNext; | 1027 pNext = p->u.pNext; |
877 sqlite3DbFree(db, p); | 1028 sqlite3DbFree(db, p); |
878 } | 1029 } |
879 } | 1030 } |
880 | 1031 |
881 /* | 1032 /* |
882 ** Free all resources owned by the object indicated by argument pTask. All | 1033 ** Free all resources owned by the object indicated by argument pTask. All |
883 ** fields of *pTask are zeroed before returning. | 1034 ** fields of *pTask are zeroed before returning. |
884 */ | 1035 */ |
885 static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ | 1036 static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){ |
886 sqlite3DbFree(db, pTask->pUnpacked); | 1037 sqlite3DbFree(db, pTask->pUnpacked); |
887 pTask->pUnpacked = 0; | |
888 #if SQLITE_MAX_WORKER_THREADS>0 | 1038 #if SQLITE_MAX_WORKER_THREADS>0 |
889 /* pTask->list.aMemory can only be non-zero if it was handed memory | 1039 /* pTask->list.aMemory can only be non-zero if it was handed memory |
890 ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ | 1040 ** from the main thread. That only occurs SQLITE_MAX_WORKER_THREADS>0 */ |
891 if( pTask->list.aMemory ){ | 1041 if( pTask->list.aMemory ){ |
892 sqlite3_free(pTask->list.aMemory); | 1042 sqlite3_free(pTask->list.aMemory); |
893 pTask->list.aMemory = 0; | |
894 }else | 1043 }else |
895 #endif | 1044 #endif |
896 { | 1045 { |
897 assert( pTask->list.aMemory==0 ); | 1046 assert( pTask->list.aMemory==0 ); |
898 vdbeSorterRecordFree(0, pTask->list.pList); | 1047 vdbeSorterRecordFree(0, pTask->list.pList); |
899 } | 1048 } |
900 pTask->list.pList = 0; | |
901 if( pTask->file.pFd ){ | 1049 if( pTask->file.pFd ){ |
902 sqlite3OsCloseFree(pTask->file.pFd); | 1050 sqlite3OsCloseFree(pTask->file.pFd); |
903 pTask->file.pFd = 0; | |
904 pTask->file.iEof = 0; | |
905 } | 1051 } |
906 if( pTask->file2.pFd ){ | 1052 if( pTask->file2.pFd ){ |
907 sqlite3OsCloseFree(pTask->file2.pFd); | 1053 sqlite3OsCloseFree(pTask->file2.pFd); |
908 pTask->file2.pFd = 0; | |
909 pTask->file2.iEof = 0; | |
910 } | 1054 } |
| 1055 memset(pTask, 0, sizeof(SortSubtask)); |
911 } | 1056 } |
912 | 1057 |
913 #ifdef SQLITE_DEBUG_SORTER_THREADS | 1058 #ifdef SQLITE_DEBUG_SORTER_THREADS |
914 static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ | 1059 static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){ |
915 i64 t; | 1060 i64 t; |
916 int iTask = (pTask - pTask->pSorter->aTask); | 1061 int iTask = (pTask - pTask->pSorter->aTask); |
917 sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); | 1062 sqlite3OsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t); |
918 fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); | 1063 fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent); |
919 } | 1064 } |
920 static void vdbeSorterRewindDebug(const char *zEvent){ | 1065 static void vdbeSorterRewindDebug(const char *zEvent){ |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 vdbePmaReaderClear(pSorter->pReader); | 1225 vdbePmaReaderClear(pSorter->pReader); |
1081 sqlite3DbFree(db, pSorter->pReader); | 1226 sqlite3DbFree(db, pSorter->pReader); |
1082 pSorter->pReader = 0; | 1227 pSorter->pReader = 0; |
1083 } | 1228 } |
1084 #endif | 1229 #endif |
1085 vdbeMergeEngineFree(pSorter->pMerger); | 1230 vdbeMergeEngineFree(pSorter->pMerger); |
1086 pSorter->pMerger = 0; | 1231 pSorter->pMerger = 0; |
1087 for(i=0; i<pSorter->nTask; i++){ | 1232 for(i=0; i<pSorter->nTask; i++){ |
1088 SortSubtask *pTask = &pSorter->aTask[i]; | 1233 SortSubtask *pTask = &pSorter->aTask[i]; |
1089 vdbeSortSubtaskCleanup(db, pTask); | 1234 vdbeSortSubtaskCleanup(db, pTask); |
| 1235 pTask->pSorter = pSorter; |
1090 } | 1236 } |
1091 if( pSorter->list.aMemory==0 ){ | 1237 if( pSorter->list.aMemory==0 ){ |
1092 vdbeSorterRecordFree(0, pSorter->list.pList); | 1238 vdbeSorterRecordFree(0, pSorter->list.pList); |
1093 } | 1239 } |
1094 pSorter->list.pList = 0; | 1240 pSorter->list.pList = 0; |
1095 pSorter->list.szPMA = 0; | 1241 pSorter->list.szPMA = 0; |
1096 pSorter->bUsePMA = 0; | 1242 pSorter->bUsePMA = 0; |
1097 pSorter->iMemory = 0; | 1243 pSorter->iMemory = 0; |
1098 pSorter->mxKeysize = 0; | 1244 pSorter->mxKeysize = 0; |
1099 sqlite3DbFree(db, pSorter->pUnpacked); | 1245 sqlite3DbFree(db, pSorter->pUnpacked); |
1100 pSorter->pUnpacked = 0; | 1246 pSorter->pUnpacked = 0; |
1101 } | 1247 } |
1102 | 1248 |
1103 /* | 1249 /* |
1104 ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. | 1250 ** Free any cursor components allocated by sqlite3VdbeSorterXXX routines. |
1105 */ | 1251 */ |
1106 void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ | 1252 void sqlite3VdbeSorterClose(sqlite3 *db, VdbeCursor *pCsr){ |
1107 VdbeSorter *pSorter = pCsr->pSorter; | 1253 VdbeSorter *pSorter; |
| 1254 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 1255 pSorter = pCsr->uc.pSorter; |
1108 if( pSorter ){ | 1256 if( pSorter ){ |
1109 sqlite3VdbeSorterReset(db, pSorter); | 1257 sqlite3VdbeSorterReset(db, pSorter); |
1110 sqlite3_free(pSorter->list.aMemory); | 1258 sqlite3_free(pSorter->list.aMemory); |
1111 sqlite3DbFree(db, pSorter); | 1259 sqlite3DbFree(db, pSorter); |
1112 pCsr->pSorter = 0; | 1260 pCsr->uc.pSorter = 0; |
1113 } | 1261 } |
1114 } | 1262 } |
1115 | 1263 |
1116 #if SQLITE_MAX_MMAP_SIZE>0 | 1264 #if SQLITE_MAX_MMAP_SIZE>0 |
1117 /* | 1265 /* |
1118 ** The first argument is a file-handle open on a temporary file. The file | 1266 ** The first argument is a file-handle open on a temporary file. The file |
1119 ** is guaranteed to be nByte bytes or smaller in size. This function | 1267 ** is guaranteed to be nByte bytes or smaller in size. This function |
1120 ** attempts to extend the file to nByte bytes in size and to ensure that | 1268 ** attempts to extend the file to nByte bytes in size and to ensure that |
1121 ** the VFS has memory mapped it. | 1269 ** the VFS has memory mapped it. |
1122 ** | 1270 ** |
1123 ** Whether or not the file does end up memory mapped of course depends on | 1271 ** Whether or not the file does end up memory mapped of course depends on |
1124 ** the specific VFS implementation. | 1272 ** the specific VFS implementation. |
1125 */ | 1273 */ |
1126 static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ | 1274 static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){ |
1127 if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ | 1275 if( nByte<=(i64)(db->nMaxSorterMmap) && pFd->pMethods->iVersion>=3 ){ |
1128 int rc = sqlite3OsTruncate(pFd, nByte); | 1276 void *p = 0; |
1129 if( rc==SQLITE_OK ){ | 1277 int chunksize = 4*1024; |
1130 void *p = 0; | 1278 sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize); |
1131 sqlite3OsFetch(pFd, 0, (int)nByte, &p); | 1279 sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte); |
1132 sqlite3OsUnfetch(pFd, 0, p); | 1280 sqlite3OsFetch(pFd, 0, (int)nByte, &p); |
1133 } | 1281 sqlite3OsUnfetch(pFd, 0, p); |
1134 } | 1282 } |
1135 } | 1283 } |
1136 #else | 1284 #else |
1137 # define vdbeSorterExtendFile(x,y,z) | 1285 # define vdbeSorterExtendFile(x,y,z) |
1138 #endif | 1286 #endif |
1139 | 1287 |
1140 /* | 1288 /* |
1141 ** Allocate space for a file-handle and open a temporary file. If successful, | 1289 ** Allocate space for a file-handle and open a temporary file. If successful, |
1142 ** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. | 1290 ** set *ppFd to point to the malloc'd file-handle and return SQLITE_OK. |
1143 ** Otherwise, set *ppFd to 0 and return an SQLite error code. | 1291 ** Otherwise, set *ppFd to 0 and return an SQLite error code. |
1144 */ | 1292 */ |
1145 static int vdbeSorterOpenTempFile( | 1293 static int vdbeSorterOpenTempFile( |
1146 sqlite3 *db, /* Database handle doing sort */ | 1294 sqlite3 *db, /* Database handle doing sort */ |
1147 i64 nExtend, /* Attempt to extend file to this size */ | 1295 i64 nExtend, /* Attempt to extend file to this size */ |
1148 sqlite3_file **ppFd | 1296 sqlite3_file **ppFd |
1149 ){ | 1297 ){ |
1150 int rc; | 1298 int rc; |
| 1299 if( sqlite3FaultSim(202) ) return SQLITE_IOERR_ACCESS; |
1151 rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, | 1300 rc = sqlite3OsOpenMalloc(db->pVfs, 0, ppFd, |
1152 SQLITE_OPEN_TEMP_JOURNAL | | 1301 SQLITE_OPEN_TEMP_JOURNAL | |
1153 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | | 1302 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | |
1154 SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc | 1303 SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE, &rc |
1155 ); | 1304 ); |
1156 if( rc==SQLITE_OK ){ | 1305 if( rc==SQLITE_OK ){ |
1157 i64 max = SQLITE_MAX_MMAP_SIZE; | 1306 i64 max = SQLITE_MAX_MMAP_SIZE; |
1158 sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); | 1307 sqlite3OsFileControlHint(*ppFd, SQLITE_FCNTL_MMAP_SIZE, (void*)&max); |
1159 if( nExtend>0 ){ | 1308 if( nExtend>0 ){ |
1160 vdbeSorterExtendFile(db, *ppFd, nExtend); | 1309 vdbeSorterExtendFile(db, *ppFd, nExtend); |
(...skipping 27 matching lines...) Expand all Loading... |
1188 ** Set *ppOut to the head of the new list. | 1337 ** Set *ppOut to the head of the new list. |
1189 */ | 1338 */ |
1190 static void vdbeSorterMerge( | 1339 static void vdbeSorterMerge( |
1191 SortSubtask *pTask, /* Calling thread context */ | 1340 SortSubtask *pTask, /* Calling thread context */ |
1192 SorterRecord *p1, /* First list to merge */ | 1341 SorterRecord *p1, /* First list to merge */ |
1193 SorterRecord *p2, /* Second list to merge */ | 1342 SorterRecord *p2, /* Second list to merge */ |
1194 SorterRecord **ppOut /* OUT: Head of merged list */ | 1343 SorterRecord **ppOut /* OUT: Head of merged list */ |
1195 ){ | 1344 ){ |
1196 SorterRecord *pFinal = 0; | 1345 SorterRecord *pFinal = 0; |
1197 SorterRecord **pp = &pFinal; | 1346 SorterRecord **pp = &pFinal; |
1198 void *pVal2 = p2 ? SRVAL(p2) : 0; | 1347 int bCached = 0; |
1199 | 1348 |
1200 while( p1 && p2 ){ | 1349 while( p1 && p2 ){ |
1201 int res; | 1350 int res; |
1202 res = vdbeSorterCompare(pTask, SRVAL(p1), p1->nVal, pVal2, p2->nVal); | 1351 res = pTask->xCompare( |
| 1352 pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal |
| 1353 ); |
| 1354 |
1203 if( res<=0 ){ | 1355 if( res<=0 ){ |
1204 *pp = p1; | 1356 *pp = p1; |
1205 pp = &p1->u.pNext; | 1357 pp = &p1->u.pNext; |
1206 p1 = p1->u.pNext; | 1358 p1 = p1->u.pNext; |
1207 pVal2 = 0; | |
1208 }else{ | 1359 }else{ |
1209 *pp = p2; | 1360 *pp = p2; |
1210 pp = &p2->u.pNext; | 1361 pp = &p2->u.pNext; |
1211 p2 = p2->u.pNext; | 1362 p2 = p2->u.pNext; |
1212 if( p2==0 ) break; | 1363 bCached = 0; |
1213 pVal2 = SRVAL(p2); | |
1214 } | 1364 } |
1215 } | 1365 } |
1216 *pp = p1 ? p1 : p2; | 1366 *pp = p1 ? p1 : p2; |
1217 *ppOut = pFinal; | 1367 *ppOut = pFinal; |
1218 } | 1368 } |
1219 | 1369 |
1220 /* | 1370 /* |
| 1371 ** Return the SorterCompare function to compare values collected by the |
| 1372 ** sorter object passed as the only argument. |
| 1373 */ |
| 1374 static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){ |
| 1375 if( p->typeMask==SORTER_TYPE_INTEGER ){ |
| 1376 return vdbeSorterCompareInt; |
| 1377 }else if( p->typeMask==SORTER_TYPE_TEXT ){ |
| 1378 return vdbeSorterCompareText; |
| 1379 } |
| 1380 return vdbeSorterCompare; |
| 1381 } |
| 1382 |
| 1383 /* |
1221 ** Sort the linked list of records headed at pTask->pList. Return | 1384 ** Sort the linked list of records headed at pTask->pList. Return |
1222 ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if | 1385 ** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if |
1223 ** an error occurs. | 1386 ** an error occurs. |
1224 */ | 1387 */ |
1225 static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ | 1388 static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){ |
1226 int i; | 1389 int i; |
1227 SorterRecord **aSlot; | 1390 SorterRecord **aSlot; |
1228 SorterRecord *p; | 1391 SorterRecord *p; |
1229 int rc; | 1392 int rc; |
1230 | 1393 |
1231 rc = vdbeSortAllocUnpacked(pTask); | 1394 rc = vdbeSortAllocUnpacked(pTask); |
1232 if( rc!=SQLITE_OK ) return rc; | 1395 if( rc!=SQLITE_OK ) return rc; |
1233 | 1396 |
| 1397 p = pList->pList; |
| 1398 pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); |
| 1399 |
1234 aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); | 1400 aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); |
1235 if( !aSlot ){ | 1401 if( !aSlot ){ |
1236 return SQLITE_NOMEM; | 1402 return SQLITE_NOMEM; |
1237 } | 1403 } |
1238 | 1404 |
1239 p = pList->pList; | |
1240 while( p ){ | 1405 while( p ){ |
1241 SorterRecord *pNext; | 1406 SorterRecord *pNext; |
1242 if( pList->aMemory ){ | 1407 if( pList->aMemory ){ |
1243 if( (u8*)p==pList->aMemory ){ | 1408 if( (u8*)p==pList->aMemory ){ |
1244 pNext = 0; | 1409 pNext = 0; |
1245 }else{ | 1410 }else{ |
1246 assert( p->u.iNext<sqlite3MallocSize(pList->aMemory) ); | 1411 assert( p->u.iNext<sqlite3MallocSize(pList->aMemory) ); |
1247 pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; | 1412 pNext = (SorterRecord*)&pList->aMemory[p->u.iNext]; |
1248 } | 1413 } |
1249 }else{ | 1414 }else{ |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1443 SortSubtask *pTask = pMerger->pTask; | 1608 SortSubtask *pTask = pMerger->pTask; |
1444 | 1609 |
1445 /* Advance the current PmaReader */ | 1610 /* Advance the current PmaReader */ |
1446 rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); | 1611 rc = vdbePmaReaderNext(&pMerger->aReadr[iPrev]); |
1447 | 1612 |
1448 /* Update contents of aTree[] */ | 1613 /* Update contents of aTree[] */ |
1449 if( rc==SQLITE_OK ){ | 1614 if( rc==SQLITE_OK ){ |
1450 int i; /* Index of aTree[] to recalculate */ | 1615 int i; /* Index of aTree[] to recalculate */ |
1451 PmaReader *pReadr1; /* First PmaReader to compare */ | 1616 PmaReader *pReadr1; /* First PmaReader to compare */ |
1452 PmaReader *pReadr2; /* Second PmaReader to compare */ | 1617 PmaReader *pReadr2; /* Second PmaReader to compare */ |
1453 u8 *pKey2; /* To pReadr2->aKey, or 0 if record cached */ | 1618 int bCached = 0; |
1454 | 1619 |
1455 /* Find the first two PmaReaders to compare. The one that was just | 1620 /* Find the first two PmaReaders to compare. The one that was just |
1456 ** advanced (iPrev) and the one next to it in the array. */ | 1621 ** advanced (iPrev) and the one next to it in the array. */ |
1457 pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; | 1622 pReadr1 = &pMerger->aReadr[(iPrev & 0xFFFE)]; |
1458 pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; | 1623 pReadr2 = &pMerger->aReadr[(iPrev | 0x0001)]; |
1459 pKey2 = pReadr2->aKey; | |
1460 | 1624 |
1461 for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ | 1625 for(i=(pMerger->nTree+iPrev)/2; i>0; i=i/2){ |
1462 /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ | 1626 /* Compare pReadr1 and pReadr2. Store the result in variable iRes. */ |
1463 int iRes; | 1627 int iRes; |
1464 if( pReadr1->pFd==0 ){ | 1628 if( pReadr1->pFd==0 ){ |
1465 iRes = +1; | 1629 iRes = +1; |
1466 }else if( pReadr2->pFd==0 ){ | 1630 }else if( pReadr2->pFd==0 ){ |
1467 iRes = -1; | 1631 iRes = -1; |
1468 }else{ | 1632 }else{ |
1469 iRes = vdbeSorterCompare(pTask, | 1633 iRes = pTask->xCompare(pTask, &bCached, |
1470 pReadr1->aKey, pReadr1->nKey, pKey2, pReadr2->nKey | 1634 pReadr1->aKey, pReadr1->nKey, pReadr2->aKey, pReadr2->nKey |
1471 ); | 1635 ); |
1472 } | 1636 } |
1473 | 1637 |
1474 /* If pReadr1 contained the smaller value, set aTree[i] to its index. | 1638 /* If pReadr1 contained the smaller value, set aTree[i] to its index. |
1475 ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this | 1639 ** Then set pReadr2 to the next PmaReader to compare to pReadr1. In this |
1476 ** case there is no cache of pReadr2 in pTask->pUnpacked, so set | 1640 ** case there is no cache of pReadr2 in pTask->pUnpacked, so set |
1477 ** pKey2 to point to the record belonging to pReadr2. | 1641 ** pKey2 to point to the record belonging to pReadr2. |
1478 ** | 1642 ** |
1479 ** Alternatively, if pReadr2 contains the smaller of the two values, | 1643 ** Alternatively, if pReadr2 contains the smaller of the two values, |
1480 ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() | 1644 ** set aTree[i] to its index and update pReadr1. If vdbeSorterCompare() |
1481 ** was actually called above, then pTask->pUnpacked now contains | 1645 ** was actually called above, then pTask->pUnpacked now contains |
1482 ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent | 1646 ** a value equivalent to pReadr2. So set pKey2 to NULL to prevent |
1483 ** vdbeSorterCompare() from decoding pReadr2 again. | 1647 ** vdbeSorterCompare() from decoding pReadr2 again. |
1484 ** | 1648 ** |
1485 ** If the two values were equal, then the value from the oldest | 1649 ** If the two values were equal, then the value from the oldest |
1486 ** PMA should be considered smaller. The VdbeSorter.aReadr[] array | 1650 ** PMA should be considered smaller. The VdbeSorter.aReadr[] array |
1487 ** is sorted from oldest to newest, so pReadr1 contains older values | 1651 ** is sorted from oldest to newest, so pReadr1 contains older values |
1488 ** than pReadr2 iff (pReadr1<pReadr2). */ | 1652 ** than pReadr2 iff (pReadr1<pReadr2). */ |
1489 if( iRes<0 || (iRes==0 && pReadr1<pReadr2) ){ | 1653 if( iRes<0 || (iRes==0 && pReadr1<pReadr2) ){ |
1490 pMerger->aTree[i] = (int)(pReadr1 - pMerger->aReadr); | 1654 pMerger->aTree[i] = (int)(pReadr1 - pMerger->aReadr); |
1491 pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; | 1655 pReadr2 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; |
1492 pKey2 = pReadr2->aKey; | 1656 bCached = 0; |
1493 }else{ | 1657 }else{ |
1494 if( pReadr1->pFd ) pKey2 = 0; | 1658 if( pReadr1->pFd ) bCached = 0; |
1495 pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); | 1659 pMerger->aTree[i] = (int)(pReadr2 - pMerger->aReadr); |
1496 pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; | 1660 pReadr1 = &pMerger->aReadr[ pMerger->aTree[i ^ 0x0001] ]; |
1497 } | 1661 } |
1498 } | 1662 } |
1499 *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); | 1663 *pbEof = (pMerger->aReadr[pMerger->aTree[1]].pFd==0); |
1500 } | 1664 } |
1501 | 1665 |
1502 return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); | 1666 return (rc==SQLITE_OK ? pTask->pUnpacked->errCode : rc); |
1503 } | 1667 } |
1504 | 1668 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1584 #endif /* SQLITE_MAX_WORKER_THREADS!=0 */ | 1748 #endif /* SQLITE_MAX_WORKER_THREADS!=0 */ |
1585 } | 1749 } |
1586 | 1750 |
1587 /* | 1751 /* |
1588 ** Add a record to the sorter. | 1752 ** Add a record to the sorter. |
1589 */ | 1753 */ |
1590 int sqlite3VdbeSorterWrite( | 1754 int sqlite3VdbeSorterWrite( |
1591 const VdbeCursor *pCsr, /* Sorter cursor */ | 1755 const VdbeCursor *pCsr, /* Sorter cursor */ |
1592 Mem *pVal /* Memory cell containing record */ | 1756 Mem *pVal /* Memory cell containing record */ |
1593 ){ | 1757 ){ |
1594 VdbeSorter *pSorter = pCsr->pSorter; | 1758 VdbeSorter *pSorter; |
1595 int rc = SQLITE_OK; /* Return Code */ | 1759 int rc = SQLITE_OK; /* Return Code */ |
1596 SorterRecord *pNew; /* New list element */ | 1760 SorterRecord *pNew; /* New list element */ |
1597 | |
1598 int bFlush; /* True to flush contents of memory to PMA */ | 1761 int bFlush; /* True to flush contents of memory to PMA */ |
1599 int nReq; /* Bytes of memory required */ | 1762 int nReq; /* Bytes of memory required */ |
1600 int nPMA; /* Bytes of PMA space required */ | 1763 int nPMA; /* Bytes of PMA space required */ |
| 1764 int t; /* serial type of first record field */ |
| 1765 |
| 1766 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 1767 pSorter = pCsr->uc.pSorter; |
| 1768 getVarint32((const u8*)&pVal->z[1], t); |
| 1769 if( t>0 && t<10 && t!=7 ){ |
| 1770 pSorter->typeMask &= SORTER_TYPE_INTEGER; |
| 1771 }else if( t>10 && (t & 0x01) ){ |
| 1772 pSorter->typeMask &= SORTER_TYPE_TEXT; |
| 1773 }else{ |
| 1774 pSorter->typeMask = 0; |
| 1775 } |
1601 | 1776 |
1602 assert( pSorter ); | 1777 assert( pSorter ); |
1603 | 1778 |
1604 /* Figure out whether or not the current contents of memory should be | 1779 /* Figure out whether or not the current contents of memory should be |
1605 ** flushed to a PMA before continuing. If so, do so. | 1780 ** flushed to a PMA before continuing. If so, do so. |
1606 ** | 1781 ** |
1607 ** If using the single large allocation mode (pSorter->aMemory!=0), then | 1782 ** If using the single large allocation mode (pSorter->aMemory!=0), then |
1608 ** flush the contents of memory to a new PMA if (a) at least one value is | 1783 ** flush the contents of memory to a new PMA if (a) at least one value is |
1609 ** already in memory and (b) the new value will not fit in memory. | 1784 ** already in memory and (b) the new value will not fit in memory. |
1610 ** | 1785 ** |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1856 } | 2031 } |
1857 | 2032 |
1858 p1 = &pMerger->aReadr[i1]; | 2033 p1 = &pMerger->aReadr[i1]; |
1859 p2 = &pMerger->aReadr[i2]; | 2034 p2 = &pMerger->aReadr[i2]; |
1860 | 2035 |
1861 if( p1->pFd==0 ){ | 2036 if( p1->pFd==0 ){ |
1862 iRes = i2; | 2037 iRes = i2; |
1863 }else if( p2->pFd==0 ){ | 2038 }else if( p2->pFd==0 ){ |
1864 iRes = i1; | 2039 iRes = i1; |
1865 }else{ | 2040 }else{ |
| 2041 SortSubtask *pTask = pMerger->pTask; |
| 2042 int bCached = 0; |
1866 int res; | 2043 int res; |
1867 assert( pMerger->pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ | 2044 assert( pTask->pUnpacked!=0 ); /* from vdbeSortSubtaskMain() */ |
1868 res = vdbeSorterCompare( | 2045 res = pTask->xCompare( |
1869 pMerger->pTask, p1->aKey, p1->nKey, p2->aKey, p2->nKey | 2046 pTask, &bCached, p1->aKey, p1->nKey, p2->aKey, p2->nKey |
1870 ); | 2047 ); |
1871 if( res<=0 ){ | 2048 if( res<=0 ){ |
1872 iRes = i1; | 2049 iRes = i1; |
1873 }else{ | 2050 }else{ |
1874 iRes = i2; | 2051 iRes = i2; |
1875 } | 2052 } |
1876 } | 2053 } |
1877 | 2054 |
1878 pMerger->aTree[iOut] = iRes; | 2055 pMerger->aTree[iOut] = iRes; |
1879 } | 2056 } |
1880 | 2057 |
1881 /* | 2058 /* |
1882 ** Allowed values for the eMode parameter to vdbeMergeEngineInit() | 2059 ** Allowed values for the eMode parameter to vdbeMergeEngineInit() |
1883 ** and vdbePmaReaderIncrMergeInit(). | 2060 ** and vdbePmaReaderIncrMergeInit(). |
1884 ** | 2061 ** |
1885 ** Only INCRINIT_NORMAL is valid in single-threaded builds (when | 2062 ** Only INCRINIT_NORMAL is valid in single-threaded builds (when |
1886 ** SQLITE_MAX_WORKER_THREADS==0). The other values are only used | 2063 ** SQLITE_MAX_WORKER_THREADS==0). The other values are only used |
1887 ** when there exists one or more separate worker threads. | 2064 ** when there exists one or more separate worker threads. |
1888 */ | 2065 */ |
1889 #define INCRINIT_NORMAL 0 | 2066 #define INCRINIT_NORMAL 0 |
1890 #define INCRINIT_TASK 1 | 2067 #define INCRINIT_TASK 1 |
1891 #define INCRINIT_ROOT 2 | 2068 #define INCRINIT_ROOT 2 |
1892 | 2069 |
1893 /* Forward reference. | 2070 /* |
1894 ** The vdbeIncrMergeInit() and vdbePmaReaderIncrMergeInit() routines call each | 2071 ** Forward reference required as the vdbeIncrMergeInit() and |
1895 ** other (when building a merge tree). | 2072 ** vdbePmaReaderIncrInit() routines are called mutually recursively when |
| 2073 ** building a merge tree. |
1896 */ | 2074 */ |
1897 static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode); | 2075 static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode); |
1898 | 2076 |
1899 /* | 2077 /* |
1900 ** Initialize the MergeEngine object passed as the second argument. Once this | 2078 ** Initialize the MergeEngine object passed as the second argument. Once this |
1901 ** function returns, the first key of merged data may be read from the | 2079 ** function returns, the first key of merged data may be read from the |
1902 ** MergeEngine object in the usual fashion. | 2080 ** MergeEngine object in the usual fashion. |
1903 ** | 2081 ** |
1904 ** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge | 2082 ** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge |
1905 ** objects attached to the PmaReader objects that the merger reads from have | 2083 ** objects attached to the PmaReader objects that the merger reads from have |
1906 ** already been populated, but that they have not yet populated aFile[0] and | 2084 ** already been populated, but that they have not yet populated aFile[0] and |
1907 ** set the PmaReader objects up to read from it. In this case all that is | 2085 ** set the PmaReader objects up to read from it. In this case all that is |
(...skipping 26 matching lines...) Expand all Loading... |
1934 if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){ | 2112 if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){ |
1935 /* PmaReaders should be normally initialized in order, as if they are | 2113 /* PmaReaders should be normally initialized in order, as if they are |
1936 ** reading from the same temp file this makes for more linear file IO. | 2114 ** reading from the same temp file this makes for more linear file IO. |
1937 ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is | 2115 ** However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is |
1938 ** in use it will block the vdbePmaReaderNext() call while it uses | 2116 ** in use it will block the vdbePmaReaderNext() call while it uses |
1939 ** the main thread to fill its buffer. So calling PmaReaderNext() | 2117 ** the main thread to fill its buffer. So calling PmaReaderNext() |
1940 ** on this PmaReader before any of the multi-threaded PmaReaders takes | 2118 ** on this PmaReader before any of the multi-threaded PmaReaders takes |
1941 ** better advantage of multi-processor hardware. */ | 2119 ** better advantage of multi-processor hardware. */ |
1942 rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); | 2120 rc = vdbePmaReaderNext(&pMerger->aReadr[nTree-i-1]); |
1943 }else{ | 2121 }else{ |
1944 rc = vdbePmaReaderIncrMergeInit(&pMerger->aReadr[i], INCRINIT_NORMAL); | 2122 rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i], INCRINIT_NORMAL); |
1945 } | 2123 } |
1946 if( rc!=SQLITE_OK ) return rc; | 2124 if( rc!=SQLITE_OK ) return rc; |
1947 } | 2125 } |
1948 | 2126 |
1949 for(i=pMerger->nTree-1; i>0; i--){ | 2127 for(i=pMerger->nTree-1; i>0; i--){ |
1950 vdbeMergeEngineCompare(pMerger, i); | 2128 vdbeMergeEngineCompare(pMerger, i); |
1951 } | 2129 } |
1952 return pTask->pUnpacked->errCode; | 2130 return pTask->pUnpacked->errCode; |
1953 } | 2131 } |
1954 | 2132 |
1955 /* | 2133 /* |
1956 ** Initialize the IncrMerge field of a PmaReader. | 2134 ** The PmaReader passed as the first argument is guaranteed to be an |
1957 ** | 2135 ** incremental-reader (pReadr->pIncr!=0). This function serves to open |
1958 ** If the PmaReader passed as the first argument is not an incremental-reader | 2136 ** and/or initialize the temp file related fields of the IncrMerge |
1959 ** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it serves | |
1960 ** to open and/or initialize the temp file related fields of the IncrMerge | |
1961 ** object at (pReadr->pIncr). | 2137 ** object at (pReadr->pIncr). |
1962 ** | 2138 ** |
1963 ** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders | 2139 ** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders |
1964 ** in the sub-tree headed by pReadr are also initialized. Data is then loaded | 2140 ** in the sub-tree headed by pReadr are also initialized. Data is then |
1965 ** into the buffers belonging to pReadr and it is set to | 2141 ** loaded into the buffers belonging to pReadr and it is set to point to |
1966 ** point to the first key in its range. | 2142 ** the first key in its range. |
1967 ** | 2143 ** |
1968 ** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed | 2144 ** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed |
1969 ** to be a multi-threaded PmaReader and this function is being called in a | 2145 ** to be a multi-threaded PmaReader and this function is being called in a |
1970 ** background thread. In this case all PmaReaders in the sub-tree are | 2146 ** background thread. In this case all PmaReaders in the sub-tree are |
1971 ** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to | 2147 ** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to |
1972 ** pReadr is populated. However, pReadr itself is not set up to point | 2148 ** pReadr is populated. However, pReadr itself is not set up to point |
1973 ** to its first key. A call to vdbePmaReaderNext() is still required to do | 2149 ** to its first key. A call to vdbePmaReaderNext() is still required to do |
1974 ** that. | 2150 ** that. |
1975 ** | 2151 ** |
1976 ** The reason this function does not call vdbePmaReaderNext() immediately | 2152 ** The reason this function does not call vdbePmaReaderNext() immediately |
1977 ** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has | 2153 ** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has |
1978 ** to block on thread (pTask->thread) before accessing aFile[1]. But, since | 2154 ** to block on thread (pTask->thread) before accessing aFile[1]. But, since |
1979 ** this entire function is being run by thread (pTask->thread), that will | 2155 ** this entire function is being run by thread (pTask->thread), that will |
1980 ** lead to the current background thread attempting to join itself. | 2156 ** lead to the current background thread attempting to join itself. |
1981 ** | 2157 ** |
1982 ** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed | 2158 ** Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed |
1983 ** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all | 2159 ** that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all |
1984 ** child-trees have already been initialized using IncrInit(INCRINIT_TASK). | 2160 ** child-trees have already been initialized using IncrInit(INCRINIT_TASK). |
1985 ** In this case vdbePmaReaderNext() is called on all child PmaReaders and | 2161 ** In this case vdbePmaReaderNext() is called on all child PmaReaders and |
1986 ** the current PmaReader set to point to the first key in its range. | 2162 ** the current PmaReader set to point to the first key in its range. |
1987 ** | 2163 ** |
1988 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. | 2164 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. |
1989 */ | 2165 */ |
1990 static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ | 2166 static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){ |
1991 int rc = SQLITE_OK; | 2167 int rc = SQLITE_OK; |
1992 IncrMerger *pIncr = pReadr->pIncr; | 2168 IncrMerger *pIncr = pReadr->pIncr; |
| 2169 SortSubtask *pTask = pIncr->pTask; |
| 2170 sqlite3 *db = pTask->pSorter->db; |
1993 | 2171 |
1994 /* eMode is always INCRINIT_NORMAL in single-threaded mode */ | 2172 /* eMode is always INCRINIT_NORMAL in single-threaded mode */ |
1995 assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); | 2173 assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); |
1996 | 2174 |
1997 if( pIncr ){ | 2175 rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); |
1998 SortSubtask *pTask = pIncr->pTask; | |
1999 sqlite3 *db = pTask->pSorter->db; | |
2000 | 2176 |
2001 rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode); | 2177 /* Set up the required files for pIncr. A multi-theaded IncrMerge object |
2002 | 2178 ** requires two temp files to itself, whereas a single-threaded object |
2003 /* Set up the required files for pIncr. A multi-theaded IncrMerge object | 2179 ** only requires a region of pTask->file2. */ |
2004 ** requires two temp files to itself, whereas a single-threaded object | 2180 if( rc==SQLITE_OK ){ |
2005 ** only requires a region of pTask->file2. */ | 2181 int mxSz = pIncr->mxSz; |
2006 if( rc==SQLITE_OK ){ | |
2007 int mxSz = pIncr->mxSz; | |
2008 #if SQLITE_MAX_WORKER_THREADS>0 | 2182 #if SQLITE_MAX_WORKER_THREADS>0 |
2009 if( pIncr->bUseThread ){ | 2183 if( pIncr->bUseThread ){ |
2010 rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); | 2184 rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[0].pFd); |
2011 if( rc==SQLITE_OK ){ | 2185 if( rc==SQLITE_OK ){ |
2012 rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); | 2186 rc = vdbeSorterOpenTempFile(db, mxSz, &pIncr->aFile[1].pFd); |
2013 } | 2187 } |
2014 }else | 2188 }else |
2015 #endif | 2189 #endif |
2016 /*if( !pIncr->bUseThread )*/{ | 2190 /*if( !pIncr->bUseThread )*/{ |
2017 if( pTask->file2.pFd==0 ){ | 2191 if( pTask->file2.pFd==0 ){ |
2018 assert( pTask->file2.iEof>0 ); | 2192 assert( pTask->file2.iEof>0 ); |
2019 rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); | 2193 rc = vdbeSorterOpenTempFile(db, pTask->file2.iEof, &pTask->file2.pFd); |
2020 pTask->file2.iEof = 0; | 2194 pTask->file2.iEof = 0; |
2021 } | 2195 } |
2022 if( rc==SQLITE_OK ){ | 2196 if( rc==SQLITE_OK ){ |
2023 pIncr->aFile[1].pFd = pTask->file2.pFd; | 2197 pIncr->aFile[1].pFd = pTask->file2.pFd; |
2024 pIncr->iStartOff = pTask->file2.iEof; | 2198 pIncr->iStartOff = pTask->file2.iEof; |
2025 pTask->file2.iEof += mxSz; | 2199 pTask->file2.iEof += mxSz; |
2026 } | |
2027 } | 2200 } |
2028 } | 2201 } |
| 2202 } |
2029 | 2203 |
2030 #if SQLITE_MAX_WORKER_THREADS>0 | 2204 #if SQLITE_MAX_WORKER_THREADS>0 |
2031 if( rc==SQLITE_OK && pIncr->bUseThread ){ | 2205 if( rc==SQLITE_OK && pIncr->bUseThread ){ |
2032 /* Use the current thread to populate aFile[1], even though this | 2206 /* Use the current thread to populate aFile[1], even though this |
2033 ** PmaReader is multi-threaded. The reason being that this function | 2207 ** PmaReader is multi-threaded. If this is an INCRINIT_TASK object, |
2034 ** is already running in background thread pIncr->pTask->thread. */ | 2208 ** then this function is already running in background thread |
2035 assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); | 2209 ** pIncr->pTask->thread. |
2036 rc = vdbeIncrPopulate(pIncr); | 2210 ** |
2037 } | 2211 ** If this is the INCRINIT_ROOT object, then it is running in the |
| 2212 ** main VDBE thread. But that is Ok, as that thread cannot return |
| 2213 ** control to the VDBE or proceed with anything useful until the |
| 2214 ** first results are ready from this merger object anyway. |
| 2215 */ |
| 2216 assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK ); |
| 2217 rc = vdbeIncrPopulate(pIncr); |
| 2218 } |
2038 #endif | 2219 #endif |
2039 | 2220 |
2040 if( rc==SQLITE_OK | 2221 if( rc==SQLITE_OK && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) ){ |
2041 && (SQLITE_MAX_WORKER_THREADS==0 || eMode!=INCRINIT_TASK) | 2222 rc = vdbePmaReaderNext(pReadr); |
2042 ){ | |
2043 rc = vdbePmaReaderNext(pReadr); | |
2044 } | |
2045 } | 2223 } |
| 2224 |
2046 return rc; | 2225 return rc; |
2047 } | 2226 } |
2048 | 2227 |
2049 #if SQLITE_MAX_WORKER_THREADS>0 | 2228 #if SQLITE_MAX_WORKER_THREADS>0 |
2050 /* | 2229 /* |
2051 ** The main routine for vdbePmaReaderIncrMergeInit() operations run in | 2230 ** The main routine for vdbePmaReaderIncrMergeInit() operations run in |
2052 ** background threads. | 2231 ** background threads. |
2053 */ | 2232 */ |
2054 static void *vdbePmaReaderBgInit(void *pCtx){ | 2233 static void *vdbePmaReaderBgIncrInit(void *pCtx){ |
2055 PmaReader *pReader = (PmaReader*)pCtx; | 2234 PmaReader *pReader = (PmaReader*)pCtx; |
2056 void *pRet = SQLITE_INT_TO_PTR( | 2235 void *pRet = SQLITE_INT_TO_PTR( |
2057 vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) | 2236 vdbePmaReaderIncrMergeInit(pReader,INCRINIT_TASK) |
2058 ); | 2237 ); |
2059 pReader->pIncr->pTask->bDone = 1; | 2238 pReader->pIncr->pTask->bDone = 1; |
2060 return pRet; | 2239 return pRet; |
2061 } | 2240 } |
2062 | |
2063 /* | |
2064 ** Use a background thread to invoke vdbePmaReaderIncrMergeInit(INCRINIT_TASK) | |
2065 ** on the PmaReader object passed as the first argument. | |
2066 ** | |
2067 ** This call will initialize the various fields of the pReadr->pIncr | |
2068 ** structure and, if it is a multi-threaded IncrMerger, launch a | |
2069 ** background thread to populate aFile[1]. | |
2070 */ | |
2071 static int vdbePmaReaderBgIncrInit(PmaReader *pReadr){ | |
2072 void *pCtx = (void*)pReadr; | |
2073 return vdbeSorterCreateThread(pReadr->pIncr->pTask, vdbePmaReaderBgInit, pCtx)
; | |
2074 } | |
2075 #endif | 2241 #endif |
2076 | 2242 |
2077 /* | 2243 /* |
| 2244 ** If the PmaReader passed as the first argument is not an incremental-reader |
| 2245 ** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes |
| 2246 ** the vdbePmaReaderIncrMergeInit() function with the parameters passed to |
| 2247 ** this routine to initialize the incremental merge. |
| 2248 ** |
| 2249 ** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1), |
| 2250 ** then a background thread is launched to call vdbePmaReaderIncrMergeInit(). |
| 2251 ** Or, if the IncrMerger is single threaded, the same function is called |
| 2252 ** using the current thread. |
| 2253 */ |
| 2254 static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){ |
| 2255 IncrMerger *pIncr = pReadr->pIncr; /* Incremental merger */ |
| 2256 int rc = SQLITE_OK; /* Return code */ |
| 2257 if( pIncr ){ |
| 2258 #if SQLITE_MAX_WORKER_THREADS>0 |
| 2259 assert( pIncr->bUseThread==0 || eMode==INCRINIT_TASK ); |
| 2260 if( pIncr->bUseThread ){ |
| 2261 void *pCtx = (void*)pReadr; |
| 2262 rc = vdbeSorterCreateThread(pIncr->pTask, vdbePmaReaderBgIncrInit, pCtx); |
| 2263 }else |
| 2264 #endif |
| 2265 { |
| 2266 rc = vdbePmaReaderIncrMergeInit(pReadr, eMode); |
| 2267 } |
| 2268 } |
| 2269 return rc; |
| 2270 } |
| 2271 |
| 2272 /* |
2078 ** Allocate a new MergeEngine object to merge the contents of nPMA level-0 | 2273 ** Allocate a new MergeEngine object to merge the contents of nPMA level-0 |
2079 ** PMAs from pTask->file. If no error occurs, set *ppOut to point to | 2274 ** PMAs from pTask->file. If no error occurs, set *ppOut to point to |
2080 ** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut | 2275 ** the new object and return SQLITE_OK. Or, if an error does occur, set *ppOut |
2081 ** to NULL and return an SQLite error code. | 2276 ** to NULL and return an SQLite error code. |
2082 ** | 2277 ** |
2083 ** When this function is called, *piOffset is set to the offset of the | 2278 ** When this function is called, *piOffset is set to the offset of the |
2084 ** first PMA to read from pTask->file. Assuming no error occurs, it is | 2279 ** first PMA to read from pTask->file. Assuming no error occurs, it is |
2085 ** set to the offset immediately following the last byte of the last | 2280 ** set to the offset immediately following the last byte of the last |
2086 ** PMA before returning. If an error does occur, then the final value of | 2281 ** PMA before returning. If an error does occur, then the final value of |
2087 ** *piOffset is undefined. | 2282 ** *piOffset is undefined. |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2277 ** all records stored in the sorter. | 2472 ** all records stored in the sorter. |
2278 ** | 2473 ** |
2279 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. | 2474 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. |
2280 */ | 2475 */ |
2281 static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ | 2476 static int vdbeSorterSetupMerge(VdbeSorter *pSorter){ |
2282 int rc; /* Return code */ | 2477 int rc; /* Return code */ |
2283 SortSubtask *pTask0 = &pSorter->aTask[0]; | 2478 SortSubtask *pTask0 = &pSorter->aTask[0]; |
2284 MergeEngine *pMain = 0; | 2479 MergeEngine *pMain = 0; |
2285 #if SQLITE_MAX_WORKER_THREADS | 2480 #if SQLITE_MAX_WORKER_THREADS |
2286 sqlite3 *db = pTask0->pSorter->db; | 2481 sqlite3 *db = pTask0->pSorter->db; |
| 2482 int i; |
| 2483 SorterCompare xCompare = vdbeSorterGetCompare(pSorter); |
| 2484 for(i=0; i<pSorter->nTask; i++){ |
| 2485 pSorter->aTask[i].xCompare = xCompare; |
| 2486 } |
2287 #endif | 2487 #endif |
2288 | 2488 |
2289 rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); | 2489 rc = vdbeSorterMergeTreeBuild(pSorter, &pMain); |
2290 if( rc==SQLITE_OK ){ | 2490 if( rc==SQLITE_OK ){ |
2291 #if SQLITE_MAX_WORKER_THREADS | 2491 #if SQLITE_MAX_WORKER_THREADS |
2292 assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); | 2492 assert( pSorter->bUseThreads==0 || pSorter->nTask>1 ); |
2293 if( pSorter->bUseThreads ){ | 2493 if( pSorter->bUseThreads ){ |
2294 int iTask; | 2494 int iTask; |
2295 PmaReader *pReadr = 0; | 2495 PmaReader *pReadr = 0; |
2296 SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; | 2496 SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; |
2297 rc = vdbeSortAllocUnpacked(pLast); | 2497 rc = vdbeSortAllocUnpacked(pLast); |
2298 if( rc==SQLITE_OK ){ | 2498 if( rc==SQLITE_OK ){ |
2299 pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); | 2499 pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader)); |
2300 pSorter->pReader = pReadr; | 2500 pSorter->pReader = pReadr; |
2301 if( pReadr==0 ) rc = SQLITE_NOMEM; | 2501 if( pReadr==0 ) rc = SQLITE_NOMEM; |
2302 } | 2502 } |
2303 if( rc==SQLITE_OK ){ | 2503 if( rc==SQLITE_OK ){ |
2304 rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); | 2504 rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr); |
2305 if( rc==SQLITE_OK ){ | 2505 if( rc==SQLITE_OK ){ |
2306 vdbeIncrMergerSetThreads(pReadr->pIncr); | 2506 vdbeIncrMergerSetThreads(pReadr->pIncr); |
2307 for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ | 2507 for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ |
2308 IncrMerger *pIncr; | 2508 IncrMerger *pIncr; |
2309 if( (pIncr = pMain->aReadr[iTask].pIncr) ){ | 2509 if( (pIncr = pMain->aReadr[iTask].pIncr) ){ |
2310 vdbeIncrMergerSetThreads(pIncr); | 2510 vdbeIncrMergerSetThreads(pIncr); |
2311 assert( pIncr->pTask!=pLast ); | 2511 assert( pIncr->pTask!=pLast ); |
2312 } | 2512 } |
2313 } | 2513 } |
2314 for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){ | 2514 for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){ |
| 2515 /* Check that: |
| 2516 ** |
| 2517 ** a) The incremental merge object is configured to use the |
| 2518 ** right task, and |
| 2519 ** b) If it is using task (nTask-1), it is configured to run |
| 2520 ** in single-threaded mode. This is important, as the |
| 2521 ** root merge (INCRINIT_ROOT) will be using the same task |
| 2522 ** object. |
| 2523 */ |
2315 PmaReader *p = &pMain->aReadr[iTask]; | 2524 PmaReader *p = &pMain->aReadr[iTask]; |
2316 assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] ); | 2525 assert( p->pIncr==0 || ( |
2317 if( p->pIncr ){ | 2526 (p->pIncr->pTask==&pSorter->aTask[iTask]) /* a */ |
2318 if( iTask==pSorter->nTask-1 ){ | 2527 && (iTask!=pSorter->nTask-1 || p->pIncr->bUseThread==0) /* b */ |
2319 rc = vdbePmaReaderIncrMergeInit(p, INCRINIT_TASK); | 2528 )); |
2320 }else{ | 2529 rc = vdbePmaReaderIncrInit(p, INCRINIT_TASK); |
2321 rc = vdbePmaReaderBgIncrInit(p); | |
2322 } | |
2323 } | |
2324 } | 2530 } |
2325 } | 2531 } |
2326 pMain = 0; | 2532 pMain = 0; |
2327 } | 2533 } |
2328 if( rc==SQLITE_OK ){ | 2534 if( rc==SQLITE_OK ){ |
2329 rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); | 2535 rc = vdbePmaReaderIncrMergeInit(pReadr, INCRINIT_ROOT); |
2330 } | 2536 } |
2331 }else | 2537 }else |
2332 #endif | 2538 #endif |
2333 { | 2539 { |
2334 rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); | 2540 rc = vdbeMergeEngineInit(pTask0, pMain, INCRINIT_NORMAL); |
2335 pSorter->pMerger = pMain; | 2541 pSorter->pMerger = pMain; |
2336 pMain = 0; | 2542 pMain = 0; |
2337 } | 2543 } |
2338 } | 2544 } |
2339 | 2545 |
2340 if( rc!=SQLITE_OK ){ | 2546 if( rc!=SQLITE_OK ){ |
2341 vdbeMergeEngineFree(pMain); | 2547 vdbeMergeEngineFree(pMain); |
2342 } | 2548 } |
2343 return rc; | 2549 return rc; |
2344 } | 2550 } |
2345 | 2551 |
2346 | 2552 |
2347 /* | 2553 /* |
2348 ** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, | 2554 ** Once the sorter has been populated by calls to sqlite3VdbeSorterWrite, |
2349 ** this function is called to prepare for iterating through the records | 2555 ** this function is called to prepare for iterating through the records |
2350 ** in sorted order. | 2556 ** in sorted order. |
2351 */ | 2557 */ |
2352 int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ | 2558 int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){ |
2353 VdbeSorter *pSorter = pCsr->pSorter; | 2559 VdbeSorter *pSorter; |
2354 int rc = SQLITE_OK; /* Return code */ | 2560 int rc = SQLITE_OK; /* Return code */ |
2355 | 2561 |
| 2562 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 2563 pSorter = pCsr->uc.pSorter; |
2356 assert( pSorter ); | 2564 assert( pSorter ); |
2357 | 2565 |
2358 /* If no data has been written to disk, then do not do so now. Instead, | 2566 /* If no data has been written to disk, then do not do so now. Instead, |
2359 ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly | 2567 ** sort the VdbeSorter.pRecord list. The vdbe layer will read data directly |
2360 ** from the in-memory list. */ | 2568 ** from the in-memory list. */ |
2361 if( pSorter->bUsePMA==0 ){ | 2569 if( pSorter->bUsePMA==0 ){ |
2362 if( pSorter->list.pList ){ | 2570 if( pSorter->list.pList ){ |
2363 *pbEof = 0; | 2571 *pbEof = 0; |
2364 rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); | 2572 rc = vdbeSorterSort(&pSorter->aTask[0], &pSorter->list); |
2365 }else{ | 2573 }else{ |
(...skipping 23 matching lines...) Expand all Loading... |
2389 } | 2597 } |
2390 | 2598 |
2391 vdbeSorterRewindDebug("rewinddone"); | 2599 vdbeSorterRewindDebug("rewinddone"); |
2392 return rc; | 2600 return rc; |
2393 } | 2601 } |
2394 | 2602 |
2395 /* | 2603 /* |
2396 ** Advance to the next element in the sorter. | 2604 ** Advance to the next element in the sorter. |
2397 */ | 2605 */ |
2398 int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ | 2606 int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){ |
2399 VdbeSorter *pSorter = pCsr->pSorter; | 2607 VdbeSorter *pSorter; |
2400 int rc; /* Return code */ | 2608 int rc; /* Return code */ |
2401 | 2609 |
| 2610 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 2611 pSorter = pCsr->uc.pSorter; |
2402 assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); | 2612 assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) ); |
2403 if( pSorter->bUsePMA ){ | 2613 if( pSorter->bUsePMA ){ |
2404 assert( pSorter->pReader==0 || pSorter->pMerger==0 ); | 2614 assert( pSorter->pReader==0 || pSorter->pMerger==0 ); |
2405 assert( pSorter->bUseThreads==0 || pSorter->pReader ); | 2615 assert( pSorter->bUseThreads==0 || pSorter->pReader ); |
2406 assert( pSorter->bUseThreads==1 || pSorter->pMerger ); | 2616 assert( pSorter->bUseThreads==1 || pSorter->pMerger ); |
2407 #if SQLITE_MAX_WORKER_THREADS>0 | 2617 #if SQLITE_MAX_WORKER_THREADS>0 |
2408 if( pSorter->bUseThreads ){ | 2618 if( pSorter->bUseThreads ){ |
2409 rc = vdbePmaReaderNext(pSorter->pReader); | 2619 rc = vdbePmaReaderNext(pSorter->pReader); |
2410 *pbEof = (pSorter->pReader->pFd==0); | 2620 *pbEof = (pSorter->pReader->pFd==0); |
2411 }else | 2621 }else |
2412 #endif | 2622 #endif |
2413 /*if( !pSorter->bUseThreads )*/ { | 2623 /*if( !pSorter->bUseThreads )*/ { |
| 2624 assert( pSorter->pMerger!=0 ); |
2414 assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); | 2625 assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) ); |
2415 rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); | 2626 rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof); |
2416 } | 2627 } |
2417 }else{ | 2628 }else{ |
2418 SorterRecord *pFree = pSorter->list.pList; | 2629 SorterRecord *pFree = pSorter->list.pList; |
2419 pSorter->list.pList = pFree->u.pNext; | 2630 pSorter->list.pList = pFree->u.pNext; |
2420 pFree->u.pNext = 0; | 2631 pFree->u.pNext = 0; |
2421 if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); | 2632 if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree); |
2422 *pbEof = !pSorter->list.pList; | 2633 *pbEof = !pSorter->list.pList; |
2423 rc = SQLITE_OK; | 2634 rc = SQLITE_OK; |
(...skipping 26 matching lines...) Expand all Loading... |
2450 *pnKey = pSorter->list.pList->nVal; | 2661 *pnKey = pSorter->list.pList->nVal; |
2451 pKey = SRVAL(pSorter->list.pList); | 2662 pKey = SRVAL(pSorter->list.pList); |
2452 } | 2663 } |
2453 return pKey; | 2664 return pKey; |
2454 } | 2665 } |
2455 | 2666 |
2456 /* | 2667 /* |
2457 ** Copy the current sorter key into the memory cell pOut. | 2668 ** Copy the current sorter key into the memory cell pOut. |
2458 */ | 2669 */ |
2459 int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ | 2670 int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ |
2460 VdbeSorter *pSorter = pCsr->pSorter; | 2671 VdbeSorter *pSorter; |
2461 void *pKey; int nKey; /* Sorter key to copy into pOut */ | 2672 void *pKey; int nKey; /* Sorter key to copy into pOut */ |
2462 | 2673 |
| 2674 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 2675 pSorter = pCsr->uc.pSorter; |
2463 pKey = vdbeSorterRowkey(pSorter, &nKey); | 2676 pKey = vdbeSorterRowkey(pSorter, &nKey); |
2464 if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ | 2677 if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){ |
2465 return SQLITE_NOMEM; | 2678 return SQLITE_NOMEM; |
2466 } | 2679 } |
2467 pOut->n = nKey; | 2680 pOut->n = nKey; |
2468 MemSetTypeFlag(pOut, MEM_Blob); | 2681 MemSetTypeFlag(pOut, MEM_Blob); |
2469 memcpy(pOut->z, pKey, nKey); | 2682 memcpy(pOut->z, pKey, nKey); |
2470 | 2683 |
2471 return SQLITE_OK; | 2684 return SQLITE_OK; |
2472 } | 2685 } |
(...skipping 13 matching lines...) Expand all Loading... |
2486 ** | 2699 ** |
2487 ** This routine forms the core of the OP_SorterCompare opcode, which in | 2700 ** This routine forms the core of the OP_SorterCompare opcode, which in |
2488 ** turn is used to verify uniqueness when constructing a UNIQUE INDEX. | 2701 ** turn is used to verify uniqueness when constructing a UNIQUE INDEX. |
2489 */ | 2702 */ |
2490 int sqlite3VdbeSorterCompare( | 2703 int sqlite3VdbeSorterCompare( |
2491 const VdbeCursor *pCsr, /* Sorter cursor */ | 2704 const VdbeCursor *pCsr, /* Sorter cursor */ |
2492 Mem *pVal, /* Value to compare to current sorter key */ | 2705 Mem *pVal, /* Value to compare to current sorter key */ |
2493 int nKeyCol, /* Compare this many columns */ | 2706 int nKeyCol, /* Compare this many columns */ |
2494 int *pRes /* OUT: Result of comparison */ | 2707 int *pRes /* OUT: Result of comparison */ |
2495 ){ | 2708 ){ |
2496 VdbeSorter *pSorter = pCsr->pSorter; | 2709 VdbeSorter *pSorter; |
2497 UnpackedRecord *r2 = pSorter->pUnpacked; | 2710 UnpackedRecord *r2; |
2498 KeyInfo *pKeyInfo = pCsr->pKeyInfo; | 2711 KeyInfo *pKeyInfo; |
2499 int i; | 2712 int i; |
2500 void *pKey; int nKey; /* Sorter key to compare pVal with */ | 2713 void *pKey; int nKey; /* Sorter key to compare pVal with */ |
2501 | 2714 |
| 2715 assert( pCsr->eCurType==CURTYPE_SORTER ); |
| 2716 pSorter = pCsr->uc.pSorter; |
| 2717 r2 = pSorter->pUnpacked; |
| 2718 pKeyInfo = pCsr->pKeyInfo; |
2502 if( r2==0 ){ | 2719 if( r2==0 ){ |
2503 char *p; | 2720 char *p; |
2504 r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); | 2721 r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p); |
2505 assert( pSorter->pUnpacked==(UnpackedRecord*)p ); | 2722 assert( pSorter->pUnpacked==(UnpackedRecord*)p ); |
2506 if( r2==0 ) return SQLITE_NOMEM; | 2723 if( r2==0 ) return SQLITE_NOMEM; |
2507 r2->nField = nKeyCol; | 2724 r2->nField = nKeyCol; |
2508 } | 2725 } |
2509 assert( r2->nField==nKeyCol ); | 2726 assert( r2->nField==nKeyCol ); |
2510 | 2727 |
2511 pKey = vdbeSorterRowkey(pSorter, &nKey); | 2728 pKey = vdbeSorterRowkey(pSorter, &nKey); |
2512 sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); | 2729 sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, r2); |
2513 for(i=0; i<nKeyCol; i++){ | 2730 for(i=0; i<nKeyCol; i++){ |
2514 if( r2->aMem[i].flags & MEM_Null ){ | 2731 if( r2->aMem[i].flags & MEM_Null ){ |
2515 *pRes = -1; | 2732 *pRes = -1; |
2516 return SQLITE_OK; | 2733 return SQLITE_OK; |
2517 } | 2734 } |
2518 } | 2735 } |
2519 | 2736 |
2520 *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); | 2737 *pRes = sqlite3VdbeRecordCompare(pVal->n, pVal->z, r2); |
2521 return SQLITE_OK; | 2738 return SQLITE_OK; |
2522 } | 2739 } |
OLD | NEW |