Index: src/vdbesort.c ================================================================== --- src/vdbesort.c +++ src/vdbesort.c @@ -441,14 +441,17 @@ assert( pIter->aBuffer==0 ); pIter->pFile = pThread->pTemp1; pIter->iReadOff = iStart; pIter->nAlloc = 128; pIter->aAlloc = (u8*)sqlite3Malloc(pIter->nAlloc); - - /* Try to xFetch() a mapping of the entire temp file. If this is possible, - ** the PMA will be read via the mapping. Otherwise, use xRead(). */ - rc = sqlite3OsFetch(pIter->pFile, 0, pThread->iTemp1Off, &pMap); + if( pIter->aAlloc ){ + /* Try to xFetch() a mapping of the entire temp file. If this is possible, + ** the PMA will be read via the mapping. Otherwise, use xRead(). */ + rc = sqlite3OsFetch(pIter->pFile, 0, pThread->iTemp1Off, &pMap); + }else{ + rc = SQLITE_NOMEM; + } if( rc==SQLITE_OK ){ if( pMap ){ pIter->aMap = (u8*)pMap; }else{ @@ -696,44 +699,37 @@ } return pNew; } /* -** Reset a merger +** Free the SorterMerger object passed as the only argument. */ -static void vdbeSorterMergerReset(SorterMerger *pMerger){ +static void vdbeSorterMergerFree(SorterMerger *pMerger){ int i; if( pMerger ){ for(i=0; inTree; i++){ vdbeSorterIterZero(&pMerger->aIter[i]); } } -} - - -/* -** Free the SorterMerger object passed as the only argument. -*/ -static void vdbeSorterMergerFree(SorterMerger *pMerger){ - vdbeSorterMergerReset(pMerger); sqlite3_free(pMerger); } /* ** Reset a sorting cursor back to its original empty state. */ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){ int i; vdbeSorterJoinAll(pSorter, SQLITE_OK); + vdbeSorterMergerFree(pSorter->pMerger); + pSorter->pMerger = 0; for(i=0; inThread; i++){ SortSubtask *pThread = &pSorter->aThread[i]; vdbeSortSubtaskCleanup(db, pThread); } if( pSorter->aMemory==0 ){ vdbeSorterRecordFree(0, pSorter->pRecord); } - vdbeSorterMergerReset(pSorter->pMerger); pSorter->pRecord = 0; pSorter->nInMemory = 0; pSorter->bUsePMA = 0; pSorter->iMemory = 0; } @@ -1290,15 +1286,17 @@ rc = sqlite3ThreadCreate(&pThread->pThread, vdbeSortSubtaskMain, pCtx); }else #endif { /* Use the foreground thread for this operation */ - u8 *aMem; rc = vdbeSorterRunThread(pThread); - aMem = pThread->aListMemory; - pThread->aListMemory = pSorter->aMemory; - pSorter->aMemory = aMem; + if( rc==SQLITE_OK ){ + u8 *aMem = pThread->aListMemory; + pThread->aListMemory = pSorter->aMemory; + pSorter->aMemory = aMem; + assert( pThread->pList==0 ); + } } } return rc; } Index: test/mallocA.test ================================================================== --- test/mallocA.test +++ test/mallocA.test @@ -23,11 +23,10 @@ puts "Skipping mallocA tests: not compiled with -DSQLITE_MEMDEBUG..." finish_test return } - # Construct a test database # forcedelete test.db.bu db eval { CREATE TABLE t1(a COLLATE NOCASE,b,c); @@ -113,14 +112,36 @@ } } -test { faultsim_test_result [list 0 {1 2}] } } + +do_execsql_test 7.0 { + PRAGMA cache_size = 5; +} +do_faultsim_test 7 -faults oom-trans* -prep { + if {$iFail < 500} { set iFail 2000 } + if {$iFail > 1215} { set iFail 2000 } +} -body { + execsql { + WITH r(x,y) AS ( + SELECT 1, randomblob(100) + UNION ALL + SELECT x+1, randomblob(100) FROM r + LIMIT 1000 + ) + SELECT count(x), length(y) FROM r GROUP BY (x%5) + } +} -test { + set res [list 200 100 200 100 200 100 200 100 200 100] + faultsim_test_result [list 0 $res] +} + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} set sqlite_open_file_count } {0} forcedelete test.db.bu finish_test