/* ** Take all the entries on p->pEntry and on the trees in p->pForest and ** sort them all together into one big ordered list on p->pEntry. ** ** This routine should only be called once in the life of a RowSet. */ static void rowSetToList(RowSet *p){ /* This routine is called only once */ assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 ); if( (p->rsFlags & ROWSET_SORTED)==0 ){ p->pEntry = rowSetEntrySort(p->pEntry); } /* While this module could theoretically support it, sqlite3RowSetNext() ** is never called after sqlite3RowSetText() for the same RowSet. So ** there is never a forest to deal with. Should this change, simply ** remove the assert() and the #if 0. */ assert( p->pForest==0 ); #if 0 while( p->pForest ){ struct RowSetEntry *pTree = p->pForest->pLeft; if( pTree ){ struct RowSetEntry *pHead, *pTail; rowSetTreeToList(pTree, &pHead, &pTail); p->pEntry = rowSetEntryMerge(p->pEntry, pHead); } p->pForest = p->pForest->pRight; } #endif p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */ }
/* ** Check to see if element iRowid was inserted into the rowset as ** part of any insert batch prior to iBatch. Return 1 or 0. ** ** If this is the first test of a new batch and if there exist entires ** on pRowSet->pEntry, then sort those entires into the forest at ** pRowSet->pForest so that they can be tested. */ int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 iRowid){ struct RowSetEntry *p, *pTree; /* This routine is never called after sqlite3RowSetNext() */ assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 ); /* Sort entries into the forest on the first test of a new batch */ if( iBatch!=pRowSet->iBatch ){ p = pRowSet->pEntry; if( p ){ struct RowSetEntry **ppPrevTree = &pRowSet->pForest; if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ p = rowSetEntrySort(p); } for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ ppPrevTree = &pTree->pRight; if( pTree->pLeft==0 ){ pTree->pLeft = rowSetListToTree(p); break; }else{ struct RowSetEntry *pAux, *pTail; rowSetTreeToList(pTree->pLeft, &pAux, &pTail); pTree->pLeft = 0; p = rowSetEntryMerge(pAux, p); } } if( pTree==0 ){ *ppPrevTree = pTree = rowSetEntryAlloc(pRowSet); if( pTree ){ pTree->v = 0; pTree->pRight = 0; pTree->pLeft = rowSetListToTree(p); } } pRowSet->pEntry = 0; pRowSet->pLast = 0; pRowSet->rsFlags |= ROWSET_SORTED; } pRowSet->iBatch = iBatch; } /* Test to see if the iRowid value appears anywhere in the forest. ** Return 1 if it does and 0 if not. */ for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){ p = pTree->pLeft; while( p ){ if( p->v<iRowid ){ p = p->pRight; }else if( p->v>iRowid ){ p = p->pLeft; }else{ return 1; } } } return 0; }
/* ** Convert the list in p->pEntry into a sorted list if it is not ** sorted already. If there is a binary tree on p->pTree, then ** convert it into a list too and merge it into the p->pEntry list. */ static void rowSetToList(RowSet *p){ if( !p->isSorted ){ rowSetSort(p); } if( p->pTree ){ struct RowSetEntry *pHead, *pTail; rowSetTreeToList(p->pTree, &pHead, &pTail); p->pTree = 0; p->pEntry = rowSetMerge(p->pEntry, pHead); } }
/* ** The input, pIn, is a binary tree (or subtree) of RowSetEntry objects. ** Convert this tree into a linked list connected by the pRight pointers ** and return pointers to the first and last elements of the new list. */ static void rowSetTreeToList( struct RowSetEntry *pIn, /* Root of the input tree */ struct RowSetEntry **ppFirst, /* Write head of the output list here */ struct RowSetEntry **ppLast /* Write tail of the output list here */ ){ assert( pIn!=0 ); if( pIn->pLeft ){ struct RowSetEntry *p; rowSetTreeToList(pIn->pLeft, ppFirst, &p); p->pRight = pIn; }else{ *ppFirst = pIn; } if( pIn->pRight ){ rowSetTreeToList(pIn->pRight, &pIn->pRight, ppLast); }else{ *ppLast = pIn; } assert( (*ppLast)->pRight==0 ); }