bool SimpleLazyTempSeqIter::next(store::Item_t& result) { if (theCurPos < theEndPos && theTempSeq->containsItem(xs_integer(theCurPos+1))) { theTempSeq->getItem(xs_integer(++theCurPos), result); return true; } else { result = NULL; return false; } }
bool ForIterator::nextImpl(store::Item_t& aResult, PlanState& aPlanState) const { ForState* lState; store::Item_t lItem; DEFAULT_STACK_INIT(ForState, lState, aPlanState); while (consumeNext(aResult, theChild0, aPlanState)) { while (consumeNext(lItem, theChild1, aPlanState)) { bindVariables(lItem, theVarRefs, aPlanState); if (theHasPosVars) { store::Item_t lPosItem; GENV_ITEMFACTORY->createInteger(lPosItem, xs_integer(lState->incReturnPosition())); bindVariables(lPosItem, thePosVarRefs, aPlanState); } STACK_PUSH(true, lState); } lState->resetPosition(); theChild1->reset(aPlanState); } STACK_END(lState); }
/***************************************************************************//** The theMaxNeededHistory has to be determined by the compiler e.g. for $seq[$startPos - 4] cases ********************************************************************************/ void WindowIterator::doGarbageCollection(WindowState* state) const { if (theMaxNeededHistory != MAX_HISTORY) { if (state->theOpenWindows.empty()) { if (state->theCurInputPos > theMaxNeededHistory) state->theDomainSeq-> purgeUpTo(xs_integer(state->theCurInputPos - theMaxNeededHistory)); } else { int64_t purgeTo = state->theOpenWindows.front().theStartPos - theMaxNeededHistory; if (purgeTo > 0) state->theDomainSeq->purgeUpTo(xs_integer(purgeTo)); } } }
/******************************************************************************* Binds the variables outside the window clause. @param planState The PlanState @param inputSeq The underlying input sequence @param pos The position of the current item within the input sequence (counting starts with 1). ********************************************************************************/ void WindowVars::bindExtern( PlanState& planState, const store::TempSeq_t& inputSeq, const ulong pos) const { store::Item_t item; if (!theCurOuterVars.empty()) { inputSeq->getItem(xs_integer(pos), item); bindVariables(item, theCurOuterVars, planState); } if (!thePrevOuterVars.empty()) { if (pos > 1) inputSeq->getItem(xs_integer(pos - 1), item); else item = NULL; bindVariables(item, thePrevOuterVars, planState); } if (!theNextOuterVars.empty()) { inputSeq->getItem(xs_integer(pos + 1), item); bindVariables(item, theNextOuterVars, planState); } if (!thePosOuterVars.empty()) { GENV_ITEMFACTORY->createInteger(item, Integer(pos)); bindVariables(item, thePosOuterVars, planState); } }
bool PlanIterator::count(store::Item_t& result, PlanState& planState) const { store::Item_t item; xs_integer count(0); PlanIteratorState* state; DEFAULT_STACK_INIT(PlanIteratorState, state, planState); while (consumeNext(item, this, planState)) { ++count; } STACK_PUSH(GENV_ITEMFACTORY->createInteger(result, xs_integer(count)), state); STACK_END(state); }
/******************************************************************************* Reads the whole Sequence from beginning to end; it is allowed to have several concurrent iterators on the same TempSeq. @return Iterator which iterates over the complete TempSeq ********************************************************************************/ store::Iterator_t SimpleLazyTempSeq::getIterator() const { return new SimpleLazyTempSeqIter(this, xs_integer(1), xs_integer(std::numeric_limits<long>::max())); }
xs_integer SimpleLazyTempSeq::getSize() const { ZORBA_ASSERT(false); return xs_integer(thePurgedUpTo + theItems.size()); }
/***************************************************************************//** ********************************************************************************/ bool WindowIterator::nextImpl(store::Item_t& aResult, PlanState& planState) const { store::Iterator_t iterator; WindowState* state; DEFAULT_STACK_INIT(WindowState, state, planState); // Pull the next tuple from the input stream while (consumeNext(aResult, theTupleIter, planState)) { // Create the temp sequence where to materialize the result of the domain // expr (lazily if theLazyEval flag is true). iterator = new PlanIteratorWrapper(theInputIter, planState); state->theDomainSeq = GENV_STORE.createTempSeq(iterator, theLazyEval); // Its clever to switch quite early to avoid a lot of if-else statements if (theWindowType == WindowIterator::SLIDING) { // Get the next item from the domain sequence // TODO: can the xs_integer be hoisted? while (state->theDomainSeq->containsItem(xs_integer(state->theCurInputPos))) { // If the current item satisfies the start condition, create a candidate // window starting at the current domain item. if (theStartClause.evaluate(planState, state->theDomainSeq, state->theCurInputPos)) { state->theOpenWindows.push_back(WindowDef(state->theCurInputPos)); } // For each candidate window, check if the current domain item satisfies // the end condition. Notice that before evaluating the end condition // expr, we must rebind the internal vars of the start condition, because // those varaibles may be refrenced in the end cond expr. state->theCurWindow = state->theOpenWindows.begin(); while ( state->theCurWindow != state->theOpenWindows.end() ) { if (state->theCurWindow->theEndPos == 0) { theStartClause.bindIntern(planState, state->theDomainSeq, state->theCurWindow->theStartPos); ulong lCurPos = state->theCurInputPos; if ( theEndClause.evaluate(planState, state->theDomainSeq, lCurPos)) { state->theCurWindow->theEndPos = lCurPos; } } ++state->theCurWindow; } // Try to return closed windows to the consumer iterator. Notice that // windows must be sorted according to the position of their starting // items in the domain sequence. So, we can return a closed window only // if it appears as the first window in state->theOpenWindows. state->theCurWindow = state->theOpenWindows.begin(); while (!state->theOpenWindows.empty()) { if (state->theCurWindow->theEndPos != 0) { // The current window is closed and its starting item is before the // stating items of all other windows (open or closed) in the domain // sequence. So, (a) bind the window var and the external vars of // the start and end conditions, (b) remove the window from the set // of candidate windows, (c) purge from the domain temp seq any item // that we know for sure they will not be needed in subsequent // evaluations of the start and/or end conditions, and (d) return to // the caller a new tuple that consists of the current input tuple // augmented with one column per variable that was bound in this step. theStartClause.bindExtern(planState, state->theDomainSeq, state->theCurWindow->theStartPos); theEndClause.bindExtern(planState, state->theDomainSeq, state->theCurWindow->theEndPos); bindVariable(planState, state->theDomainSeq, state->theCurWindow->theStartPos, state->theCurWindow->theEndPos); state->theCurWindow = state->theOpenWindows.erase(state->theCurWindow); //doGarbageCollection(state); if (theTreatIter) { store::Item_t tmp; while (consumeNext(tmp, theTreatIter, planState)) { ; } theTreatIter->reset(planState); } STACK_PUSH(true, state); } else { break; } } ++state->theCurInputPos; } } else //Tumpling window { // Doing this switch now also avoids further overhad if (theEndClause.theHasEndClause) { while (state->theDomainSeq->containsItem(xs_integer(state->theCurInputPos))) { if (state->theOpenWindows.empty() && theStartClause.evaluate(planState, state->theDomainSeq, state->theCurInputPos)) { theStartClause.bindExtern(planState, state->theDomainSeq, state->theCurInputPos); state->theOpenWindows.push_back(state->theCurInputPos); } if ( !state->theOpenWindows.empty() && theEndClause.evaluate(planState, state->theDomainSeq, state->theCurInputPos)) { theEndClause.bindExtern(planState, state->theDomainSeq, state->theCurInputPos); bindVariable(planState, state->theDomainSeq, state->theOpenWindows[0].theStartPos, state->theCurInputPos); state->theOpenWindows.pop_back(); assert(state->theOpenWindows.empty()); if (theTreatIter) { store::Item_t tmp; while (consumeNext(tmp, theTreatIter, planState)) { ; } theTreatIter->reset(planState); } STACK_PUSH(true, state); doGarbageCollection(state); } ++state->theCurInputPos; } } else { while (state->theDomainSeq->containsItem(xs_integer(state->theCurInputPos))) { if (theStartClause.evaluate(planState, state->theDomainSeq, state->theCurInputPos)) { if (!state->theOpenWindows.empty()) { //In no case there should be more than 1 position inside assert(state->theOpenWindows.size() == 1); theStartClause.bindExtern(planState, state->theDomainSeq, state->theOpenWindows[0].theStartPos); bindVariable(planState, state->theDomainSeq, state->theOpenWindows[0].theStartPos, state->theCurInputPos - 1); state->theOpenWindows.pop_back(); assert(state->theOpenWindows.empty()); if (theTreatIter) { store::Item_t tmp; while (consumeNext(tmp, theTreatIter, planState)) { ; } theTreatIter->reset(planState); } STACK_PUSH(true, state); --state->theCurInputPos; doGarbageCollection(state); ++state->theCurInputPos; } state->theOpenWindows.push_back(state->theCurInputPos); } ++state->theCurInputPos; } } } // Check if we have open and/or closed windows state->theCurWindow = state->theOpenWindows.begin(); while (state->theCurWindow != state->theOpenWindows.end()) { if (!theEndClause.theOnlyEnd || state->theCurWindow->theEndPos != 0) { if (state->theCurWindow->theEndPos == 0) state->theCurWindow->theEndPos = state->theCurInputPos - 1; bindVariable(planState, state->theDomainSeq, state->theOpenWindows[0].theStartPos, state->theCurWindow->theEndPos); theStartClause.bindExtern(planState, state->theDomainSeq, state->theOpenWindows[0].theStartPos); theEndClause.bindExtern(planState, state->theDomainSeq, state->theCurWindow->theEndPos); state->theCurWindow = state->theOpenWindows.erase(state->theCurWindow); if (theTreatIter) { store::Item_t tmp; while (consumeNext(tmp, theTreatIter, planState)) { ; } theTreatIter->reset(planState); } STACK_PUSH(true, state); } else { ++state->theCurWindow; } } theInputIter->reset(planState); state->reset(planState); } STACK_PUSH(false, state); STACK_END(state); }