Merge lp:~zorba-coders/zorba/skip-items into lp:zorba

Proposed by Nicolae Brinza
Status: Merged
Approved by: Nicolae Brinza
Approved revision: 11550
Merged at revision: 11568
Proposed branch: lp:~zorba-coders/zorba/skip-items
Merge into: lp:zorba
Diff against target: 720 lines (+233/-238)
13 files modified
src/functions/func_sequences_impl.cpp (+3/-155)
src/runtime/api/plan_wrapper.cpp (+11/-0)
src/runtime/api/plan_wrapper.h (+2/-0)
src/runtime/base/plan_iterator.cpp (+22/-1)
src/runtime/base/plan_iterator.h (+13/-0)
src/runtime/collections/collections_impl.cpp (+53/-11)
src/runtime/collections/pregenerated/collections.h (+2/-0)
src/runtime/eval/eval.cpp (+94/-56)
src/runtime/eval/eval.h (+6/-0)
src/runtime/sequences/sequences_impl.cpp (+6/-15)
src/runtime/spec/collections/collections.xml (+10/-0)
test/rbkt/ExpQueryResults/zorba/eval/eval16.xml.res (+2/-0)
test/rbkt/Queries/zorba/eval/eval16.xq (+9/-0)
To merge this branch: bzr merge lp:~zorba-coders/zorba/skip-items
Reviewer Review Type Date Requested Status
Matthias Brantner Approve
Nicolae Brinza Approve
Review via email: mp+174723@code.launchpad.net

Commit message

Implemented the Skip-items facility

Description of the change

Implemented the Skip-items facility

To post a comment you must log in.
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Stage "TestZorbaUbuntu" failed.
3 tests failed (8344 total tests run).

Check test results at http://jenkins.lambda.nu/job/TestZorbaUbuntu/81/testReport/ to view the results.

Revision history for this message
Nicolae Brinza (nbrinza) :
review: Approve
Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

- Shouldn't skip take an unsigned integer?
- Why is the while loop in collections_impl.cpp:397 necessary if initCollection is called before? I think there might be a bug in initCollection. Specifically, the else block in line 298 is never called because the CollectionIterator is not rewritten anymore (i.e. theChildren.size() will always return one)
- state->theIteratorOpened == false => !state->theIteratorOpened
- could we implement and test skip for the EvalIterator as well?
- What about the index probe iterators (e.g. ProbeIndexPointValueIterator), they also skip

review: Needs Fixing
Revision history for this message
Nicolae Brinza (nbrinza) wrote :

> - Shouldn't skip take an unsigned integer?

The parameters to fn:subsequence and co are all signed. E.g. you can pass a negative skip.

> - Why is the while loop in collections_impl.cpp:397 necessary if
> initCollection is called before? I think there might be a bug in
> initCollection. Specifically, the else block in line 298 is never called
> because the CollectionIterator is not rewritten anymore (i.e.
> theChildren.size() will always return one)

You're very right. It was not really a bug, but the skip optimization didn't really happen because it was the while() that was doing the skipping instead of the getIterator(skip). I've fixed that. But the else block at line 298 cannot be deleted as the 3-parameter function was not only used by the rewriter, e.g. the collections/paging_1 to _5 use it.

> - state->theIteratorOpened == false => !state->theIteratorOpened

Fixed.

> - could we implement and test skip for the EvalIterator as well?

All iterators have the default implementation of skip in plan_iterator.cpp. How can we improve that implementation for EvalIterator?

> - What about the index probe iterators (e.g. ProbeIndexPointValueIterator),
> they also skip

I was not aware they do. I'll write an optimization for them as well.

--

lp:~zorba-coders/zorba/skip-items updated
11551. By Nicolae Brinza

Fixed review issues.

11552. By Nicolae Brinza

Merged with Zorba trunk

Revision history for this message
Nicolae Brinza (nbrinza) wrote :

I've looked into the index probe iterators but they already optimize any skipping. They take a Skip parameter and then they push it into an underlying iterator e.g. ProbeValueTreeIndexIterator which handles the skip internally. So there is nothing to be done there.

I've pushed the pending fixes and the branch is ready for merging.

Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

Looks good to me. Only two issues.

- The thing with the probe iterators is that there are additional functions called probe-*-skip that allow
you to skip explicitly. However, subsequence is not rewritten into these functions. We will need to override the skip function in all the probe iterators (similar to count) such that subsequence(probe-*) will be executed efficiently. We can do this is a second step though. I'll create a follow up story for this.

- In ZorbaCollectionIterator::initCollection lines 307 and 326, you eventually add skipCount twice. Something smells spooky here.

review: Needs Information
lp:~zorba-coders/zorba/skip-items updated
11553. By Nicolae Brinza

Fixed the double addition of skipCount in ZorbaCollectionIterator::initCollection; added skip() to the EvalIterator.

Revision history for this message
Nicolae Brinza (nbrinza) wrote :

> - In ZorbaCollectionIterator::initCollection lines 307 and 326, you eventually
> add skipCount twice. Something smells spooky here.

Yes, it seems it was added twice. I've fixed it.

I've also added the skip() function to the EvalIterator.

--

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Stage "TestZorbaUbuntu" failed.
1 tests failed (8415 total tests run).

Check test results at http://jenkins.lambda.nu/job/TestZorbaUbuntu/123/testReport/ to view the results.

lp:~zorba-coders/zorba/skip-items updated
11554. By Nicolae Brinza

Fixed a regression

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Voting criteria failed for the following merge proposals:

https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723 :
Votes: {'Needs Information': 1, 'Approve': 1}

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Stage "CommitZorba" failed.

Check console output at http://jenkins.lambda.nu/job/CommitZorba/56/console to view the results.

Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

The following query crashes:

xquery version "3.0";

import module namespace ddl = "http://www.zorba-xquery.com/modules/store/dynamic/collections/ddl";
import module namespace dml = "http://www.zorba-xquery.com/modules/store/dynamic/collections/dml";
import module namespace e = "http://www.zorba-xquery.com/modules/reflection";

ddl:create(xs:QName("ddl:test2"),(<center1/>,<oldlast/>));

subsequence(e:eval("dml:collection(xs:QName('ddl:test2'))"), 2, 1)

review: Needs Fixing
lp:~zorba-coders/zorba/skip-items updated
11555. By Nicolae Brinza

Fixed a bug with eval() and the new skip() functionality.

11556. By Nicolae Brinza

Cleanup

Revision history for this message
Nicolae Brinza (nbrinza) wrote :

I've fixed the crash and added the query as zorba/eval/eval16.xq.

--

Revision history for this message
Matthias Brantner (matthias-brantner) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue result for https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Stage "AddTestSuitesUbuntu" failed.

Check console output at http://jenkins.lambda.nu/job/AddTestSuitesUbuntu/125/console to view the results.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue starting for the following merge proposals:
https://code.launchpad.net/~zorba-coders/zorba/skip-items/+merge/174723

Progress dashboard at http://jenkins.lambda.nu/view/ValidationQueue

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue succeeded - proposal merged!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/functions/func_sequences_impl.cpp'
2--- src/functions/func_sequences_impl.cpp 2013-05-14 05:21:11 +0000
3+++ src/functions/func_sequences_impl.cpp 2013-07-26 12:54:41 +0000
4@@ -43,127 +43,6 @@
5
6
7 /*******************************************************************************
8-
9-********************************************************************************/
10-bool rewriteSubsequenceCollection(
11- static_context* aSctx,
12- const QueryLoc& aLoc,
13- std::vector<PlanIter_t>& aArgs,
14- bool aIsIntSubsequence)
15-{
16- ZorbaCollectionIterator* collIter =
17- dynamic_cast<ZorbaCollectionIterator*>(aArgs[0].getp());
18- assert(collIter);
19-
20- std::vector<PlanIter_t>& lCollectionArgs = collIter->getChildren();
21-
22- SingletonIterator* lPosIter = dynamic_cast<SingletonIterator*>(aArgs[1].getp());
23- if (lPosIter == NULL)
24- {
25- return false;
26- }
27-
28- xs_long pos;
29- const store::Item_t& lPosItem = lPosIter->getValue();
30-
31- try
32- {
33- if (aIsIntSubsequence)
34- {
35- pos = lPosItem->getLongValue();
36- }
37- else
38- {
39- xs_double dpos = lPosItem->getDoubleValue().round();
40- xs_integer ipos(dpos.getNumber());
41- pos = to_xs_long(ipos);
42- }
43- }
44- catch (std::exception const&)
45- {
46- return false;
47- }
48-
49- if (pos <= 1)
50- {
51- // if the start position is less than 1 we can't push this down into
52- // the collection skip parameter because the result won't be equivalent.
53- return false;
54- }
55-
56- // prepare helper
57- store::Item_t lItemOne;
58- GENV_ITEMFACTORY->createInteger(lItemOne, Integer(1));
59-
60- int lNumCollArgs = lCollectionArgs.size();
61- if (lNumCollArgs == 1)
62- {
63- // argument is of type collection(qname)
64- // simply move the (pos-1) of subsequence into the skip of
65- // collection function
66- // subsequence(collection(qname), 10, 20)
67- // -> subsequence(collection(qname, 10-1), 1, 20)
68- PlanIter_t& lNewCollSkipIter = aArgs[1];
69- PlanIter_t lOneIter = new SingletonIterator(aSctx, aLoc, lItemOne);
70-
71- lCollectionArgs.push_back(
72- new NumArithIterator<zorba::SubtractOperation>(aSctx,
73- collIter->getLocation(),
74- lNewCollSkipIter,
75- lOneIter)
76- );
77- }
78- else if (lNumCollArgs <= 3 && lNumCollArgs != 0)
79- {
80- // argument is of type collection(qname,skip) or
81- // collection(qname,start_uri,skip)
82- int lSkipPosition = 1;
83- if (lNumCollArgs == 3)
84- {
85- // collection function with start reference -> skip is the 3rd param
86- lSkipPosition = 2;
87- }
88-
89- // add position-1 of subsequence to collection skip
90- // subsequence(collection(qname, 10), 10, 20)
91- // -> subsequence(collection(qname, 10+10-1), 10, 20)
92- PlanIter_t& lOldCollSkipIter = lCollectionArgs[lSkipPosition];
93- PlanIter_t lOneIter = new SingletonIterator (aSctx, aLoc, lItemOne);
94- PlanIter_t& lSubseqPosIter = aArgs[1];
95-
96- PlanIter_t lCollSkipAdditionIter =
97- new NumArithIterator<zorba::SubtractOperation>(aSctx,
98- collIter->getLocation(),
99- lSubseqPosIter,
100- lOneIter);
101- lCollectionArgs[lSkipPosition] =
102- new NumArithIterator<zorba::AddOperation>(aSctx,
103- collIter->getLocation(),
104- lOldCollSkipIter,
105- lCollSkipAdditionIter);
106- }
107- else
108- {
109- // no collection function with 0 or >3 params
110- assert(false);
111- }
112-
113- aArgs[0] = new ZorbaCollectionIterator(aSctx,
114- collIter->getLocation(),
115- lCollectionArgs,
116- collIter->isDynamic());
117-
118- // after pushing the position param down we need to rewrite the actual
119- // position to 1:
120- // subsequence(collection(qname, 10+10-1), 10, 20)
121- // -> subsequence(collection(qname, 10+10-1), 1, 20)
122- aArgs[1] = new SingletonIterator(aSctx, aLoc, lItemOne);
123-
124- return true;
125-}
126-
127-
128-/*******************************************************************************
129 ********************************************************************************/
130 xqtref_t fn_unordered::getReturnType(const fo_expr* caller) const
131 {
132@@ -573,8 +452,7 @@
133 const QueryLoc& aLoc,
134 std::vector<PlanIter_t>& aArgs,
135 expr& aAnn) const
136-{
137- const std::type_info& lFirstArgType = typeid(*aArgs[0]);
138+{
139 fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);
140 const expr* inputExpr = subseqExpr.get_arg(0);
141 const expr* posExpr = subseqExpr.get_arg(1);
142@@ -619,23 +497,8 @@
143 return aArgs[0];
144 }
145 }
146- else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
147- {
148- // push down position param into collection skip if possible
149- if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, false /*no int*/))
150- {
151- // we have rewritten the subsequence to start at the beginning.
152- // if there is no length param we can remove the entire
153- // subsequence function
154- // subsequence(collection(qname, 10), 1) -> collection(qname, 10)
155- if (aArgs.size() == 2)
156- {
157- return aArgs[0];
158- }
159- }
160- }
161
162- done:
163+done:
164 return new FnSubsequenceIterator(aSctx, aLoc, aArgs);
165 }
166
167@@ -736,23 +599,8 @@
168 return aArgs[0];
169 }
170 }
171- else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
172- {
173- // push down position param into collection skip if possible
174- if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, true /*flag int*/))
175- {
176- // we have rewritten the subsequence to start from the beginning.
177- // if there is no length param we can remove the entire
178- // subsequence function
179- // subsequence(collection(qname, 10), 1) -> collection(qname, 10)
180- if (aArgs.size() == 2)
181- {
182- return aArgs[0];
183- }
184- }
185- }
186
187- done:
188+done:
189 return new SubsequenceIntIterator(aSctx, aLoc, aArgs);
190 }
191
192
193=== modified file 'src/runtime/api/plan_wrapper.cpp'
194--- src/runtime/api/plan_wrapper.cpp 2013-03-17 13:55:28 +0000
195+++ src/runtime/api/plan_wrapper.cpp 2013-07-26 12:54:41 +0000
196@@ -162,6 +162,17 @@
197 /*******************************************************************************
198
199 ********************************************************************************/
200+bool PlanWrapper::skip(int64_t count)
201+{
202+ ZORBA_ASSERT(theIsOpen);
203+
204+ return theIterator->skip(count, *thePlanState);
205+}
206+
207+
208+/*******************************************************************************
209+
210+********************************************************************************/
211 void PlanWrapper::reset()
212 {
213 ZORBA_ASSERT(theIsOpen);
214
215=== modified file 'src/runtime/api/plan_wrapper.h'
216--- src/runtime/api/plan_wrapper.h 2013-03-04 21:00:58 +0000
217+++ src/runtime/api/plan_wrapper.h 2013-07-26 12:54:41 +0000
218@@ -97,6 +97,8 @@
219
220 bool next(store::Item_t& item);
221
222+ bool skip(int64_t count);
223+
224 void reset();
225
226 void close();
227
228=== modified file 'src/runtime/base/plan_iterator.cpp'
229--- src/runtime/base/plan_iterator.cpp 2013-05-28 18:20:54 +0000
230+++ src/runtime/base/plan_iterator.cpp 2013-07-26 12:54:41 +0000
231@@ -31,6 +31,10 @@
232
233 #include "diagnostics/util_macros.h"
234
235+#ifndef NDEBUG
236+#include "system/properties.h"
237+#endif
238+
239 namespace zorba
240 {
241
242@@ -180,6 +184,18 @@
243 }
244
245
246+bool PlanIterator::skip(int64_t count, PlanState& planState) const
247+{
248+ bool have_more_items = true;
249+ store::Item_t item;
250+
251+ while (count-- > 0 && (have_more_items = consumeNext(item, this, planState)))
252+ ;
253+
254+ return have_more_items;
255+}
256+
257+
258 #ifndef NDEBUG
259 bool PlanIterator::consumeNext(
260 store::Item_t& result,
261@@ -196,7 +212,12 @@
262
263 if (planState.theCompilerCB->theConfig.print_item_flow)
264 {
265- std::cout << "next (" << iter << " = " << typeid (*iter).name()
266+ if (Properties::instance()->stableIteratorIds())
267+ std::cout << "next (" << iter->getId();
268+ else
269+ std::cout << "next (" << iter;
270+
271+ std::cout << " = " << typeid (*iter).name()
272 << ") -> "
273 << "status: " << status << " -> "
274 << ((status && result != NULL) ? result->show().c_str() : "null")
275
276=== modified file 'src/runtime/base/plan_iterator.h'
277--- src/runtime/base/plan_iterator.h 2013-05-28 18:20:54 +0000
278+++ src/runtime/base/plan_iterator.h 2013-07-26 12:54:41 +0000
279@@ -401,6 +401,19 @@
280 virtual bool count(store::Item_t& result, PlanState& planState) const;
281
282 /**
283+ * Skip a number of items from the Plan's sequence. Classes can overwrite
284+ * this functions to optimize the skipping by jumping directly to the
285+ * desired position in the sequence.
286+ *
287+ * Returns true if the entire sequence has been consumed, false otherwise.
288+ *
289+ * @param count the number of items to be skipped
290+ * @param planState the state plan
291+ *
292+ */
293+ virtual bool skip(int64_t count, PlanState &planState) const;
294+
295+ /**
296 * Produce the next item and return it to the caller. Implicitly, the first
297 * call of 'producNext' initializes the iterator and allocates resources
298 * (main memory, file descriptors, etc.).
299
300=== modified file 'src/runtime/collections/collections_impl.cpp'
301--- src/runtime/collections/collections_impl.cpp 2013-05-02 18:34:27 +0000
302+++ src/runtime/collections/collections_impl.cpp 2013-07-26 12:54:41 +0000
303@@ -277,17 +277,13 @@
304 }
305
306
307-bool ZorbaCollectionIterator::nextImpl(
308- store::Item_t& result,
309- PlanState& planState) const
310+void ZorbaCollectionIterator::initCollection(PlanState& planState, int64_t skipCount) const
311 {
312 store::Item_t name;
313+ xs_integer lSkip;
314 store::Collection_t collection;
315- xs_integer lSkip;
316- zstring lStart;
317
318- ZorbaCollectionIteratorState* state;
319- DEFAULT_STACK_INIT(ZorbaCollectionIteratorState, state, planState);
320+ ZorbaCollectionIteratorState* state = StateTraitsImpl<ZorbaCollectionIteratorState>::getState(planState, theStateOffset);
321
322 consumeNext(name, theChildren[0].getp(), planState);
323
324@@ -295,16 +291,20 @@
325
326 if (theChildren.size() == 1)
327 {
328- state->theIterator = collection->getIterator();
329+ if (skipCount < 0)
330+ skipCount = 0;
331+ lSkip = skipCount;
332+ state->theIterator = collection->getIterator(lSkip);
333 }
334 else
335 {
336+ zstring lStart;
337 bool lRefPassed = theChildren.size() >= 3;
338-
339+
340 // read positional skip parameter
341 store::Item_t lSkipItem;
342 consumeNext(lSkipItem, theChildren[(lRefPassed ? 2 : 1)].getp(), planState);
343- lSkip = lSkipItem->getIntegerValue();
344+ lSkip = lSkipItem->getIntegerValue() + skipCount;
345
346 // negative skip is not allowed
347 if (lSkip.sign() < 0)
348@@ -320,7 +320,7 @@
349 {
350 store::Item_t lRefItem;
351 consumeNext(lRefItem, theChildren[1].getp(), planState);
352- lStart = lRefItem->getString();
353+ lStart = lRefItem->getString();
354 try
355 {
356 state->theIterator = collection->getIterator(lSkip, lStart);
357@@ -346,6 +346,29 @@
358 }
359
360 state->theIteratorOpened = true;
361+}
362+
363+
364+bool ZorbaCollectionIterator::nextImpl(
365+ store::Item_t& result,
366+ PlanState& planState) const
367+{
368+ store::Item_t name;
369+ xs_integer lSkip;
370+ store::Collection_t collection;
371+
372+ ZorbaCollectionIteratorState* state;
373+ DEFAULT_STACK_INIT(ZorbaCollectionIteratorState, state, planState);
374+
375+ if (state->theIterator.getp() != NULL && state->theIteratorOpened == false)
376+ {
377+ ZORBA_ASSERT (false && "nextImpl() called past iterator end");
378+ return false;
379+ }
380+ else if ( ! state->theIteratorOpened)
381+ {
382+ initCollection(planState, 0);
383+ }
384
385 while (state->theIterator->next(result))
386 STACK_PUSH(true, state);
387@@ -358,6 +381,25 @@
388 }
389
390
391+bool ZorbaCollectionIterator::skip(int64_t count, PlanState& planState) const
392+{
393+ ZorbaCollectionIteratorState* state = StateTraitsImpl<ZorbaCollectionIteratorState>::getState(planState, theStateOffset);
394+
395+ if (state->theIterator.getp() != NULL && state->theIteratorOpened == false)
396+ {
397+ ZORBA_ASSERT (false && "nextImpl() called past iterator end");
398+ return false;
399+ }
400+ else if ( ! state->theIteratorOpened)
401+ {
402+ initCollection(planState, count);
403+ return true;
404+ }
405+ else
406+ return false;
407+}
408+
409+
410 bool ZorbaCollectionIterator::count(store::Item_t& result, PlanState& planState) const
411 {
412 if (!isCountOptimizable())
413
414=== modified file 'src/runtime/collections/pregenerated/collections.h'
415--- src/runtime/collections/pregenerated/collections.h 2013-03-24 20:40:03 +0000
416+++ src/runtime/collections/pregenerated/collections.h 2013-07-26 12:54:41 +0000
417@@ -291,6 +291,8 @@
418 public:
419 bool isCountOptimizable() const;
420 bool count(store::Item_t& result, PlanState& planState) const;
421+ bool skip(int64_t count, PlanState& planState) const;
422+ void initCollection(PlanState& planState, int64_t skipCount) const;
423 void accept(PlanIterVisitor& v) const;
424
425 bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
426
427=== modified file 'src/runtime/eval/eval.cpp'
428--- src/runtime/eval/eval.cpp 2013-03-24 20:40:03 +0000
429+++ src/runtime/eval/eval.cpp 2013-07-26 12:54:41 +0000
430@@ -71,6 +71,17 @@
431 /****************************************************************************//**
432
433 ********************************************************************************/
434+void EvalIteratorState::reset(PlanState& planState)
435+{
436+ PlanIteratorState::reset(planState);
437+
438+ thePlanWrapper = NULL;
439+}
440+
441+
442+/****************************************************************************//**
443+
444+********************************************************************************/
445 EvalIterator::EvalIterator(
446 static_context* sctx,
447 const QueryLoc& loc,
448@@ -126,6 +137,73 @@
449 /****************************************************************************//**
450
451 ********************************************************************************/
452+void EvalIterator::init(
453+ bool doCount,
454+ PlanState& planState) const
455+{
456+ store::Item_t item;
457+ EvalIteratorState* state = StateTraitsImpl<EvalIteratorState>::getState(planState, theStateOffset);
458+
459+ CONSUME(item, 0);
460+
461+ // Create the "import" sctx. The importOuterEnv() method (called below) will
462+ // register into the importSctx (a) the outer vars of the eval query and (b)
463+ // the expression-level ns bindings of the outer query at the place where
464+ // the eval call appears at.
465+ static_context* importSctx = theSctx->create_child_context();
466+
467+ // Create the root sctx for the eval query
468+ static_context* evalSctx = importSctx->create_child_context();
469+
470+ // Create the ccb for the eval query
471+ CompilerCB* evalCCB = new CompilerCB(*planState.theCompilerCB);
472+ evalCCB->theIsEval = true;
473+ evalCCB->theRootSctx = evalSctx;
474+ evalCCB->theConfig.for_serialization_only = !theDoNodeCopy;
475+ (evalCCB->theSctxMap)[1] = evalSctx;
476+
477+ state->ccb.reset(evalCCB);
478+
479+ // Create the dynamic context for the eval query
480+ dynamic_context* evalDctx = new dynamic_context(planState.theGlobalDynCtx);
481+ state->dctx.reset(evalDctx);
482+
483+ // Import the outer environment.
484+ ulong maxOuterVarId;
485+ importOuterEnv(planState, evalCCB, importSctx, evalDctx, maxOuterVarId);
486+
487+ // If we are here after a reset, we must set state->thePlanWrapper to NULL
488+ // before reseting the state->thePlan. Otherwise, the current state->thePlan
489+ // will be destroyed first, and then we will attempt to close it when
490+ // state->thePlanWrapper is reset later.
491+ state->thePlanWrapper = NULL;
492+
493+ // Compile
494+ state->thePlan = compile(evalCCB, item->getStringValue(), maxOuterVarId, doCount);
495+
496+ planState.theCompilerCB->theNextVisitId = evalCCB->theNextVisitId + 1;
497+
498+ // Set the values for the (explicit) external vars of the eval query
499+ setExternalVariables(evalCCB, importSctx, evalSctx, evalDctx);
500+
501+ // Execute
502+ state->thePlanWrapper = new PlanWrapper(state->thePlan,
503+ evalCCB,
504+ evalDctx,
505+ planState.theQuery,
506+ planState.theStackDepth + 1,
507+ state->ccb->theHaveTimeout,
508+ state->ccb->theTimeout);
509+
510+ state->thePlanWrapper->checkDepth(loc);
511+
512+ state->thePlanWrapper->open();
513+}
514+
515+
516+/****************************************************************************//**
517+
518+********************************************************************************/
519 bool EvalIterator::nextORcount(
520 bool doCount,
521 store::Item_t& result,
522@@ -136,62 +214,8 @@
523
524 DEFAULT_STACK_INIT(EvalIteratorState, state, planState);
525
526- CONSUME(item, 0);
527-
528- {
529- // Create the "import" sctx. The importOuterEnv() method (called below) will
530- // register into the importSctx (a) the outer vars of the eval query and (b)
531- // the expression-level ns bindings of the outer query at the place where
532- // the eval call appears at.
533- static_context* importSctx = theSctx->create_child_context();
534-
535- // Create the root sctx for the eval query
536- static_context* evalSctx = importSctx->create_child_context();
537-
538- // Create the ccb for the eval query
539- CompilerCB* evalCCB = new CompilerCB(*planState.theCompilerCB);
540- evalCCB->theIsEval = true;
541- evalCCB->theRootSctx = evalSctx;
542- evalCCB->theConfig.for_serialization_only = !theDoNodeCopy;
543- (evalCCB->theSctxMap)[1] = evalSctx;
544-
545- state->ccb.reset(evalCCB);
546-
547- // Create the dynamic context for the eval query
548- dynamic_context* evalDctx = new dynamic_context(planState.theGlobalDynCtx);
549- state->dctx.reset(evalDctx);
550-
551- // Import the outer environment.
552- ulong maxOuterVarId;
553- importOuterEnv(planState, evalCCB, importSctx, evalDctx, maxOuterVarId);
554-
555- // If we are here after a reset, we must set state->thePlanWrapper to NULL
556- // before reseting the state->thePlan. Otherwise, the current state->thePlan
557- // will be destroyed first, and then we will attempt to close it when
558- // state->thePlanWrapper is reset later.
559- state->thePlanWrapper = NULL;
560-
561- // Compile
562- state->thePlan = compile(evalCCB, item->getStringValue(), maxOuterVarId, doCount);
563-
564- planState.theCompilerCB->theNextVisitId = evalCCB->theNextVisitId + 1;
565-
566- // Set the values for the (explicit) external vars of the eval query
567- setExternalVariables(evalCCB, importSctx, evalSctx, evalDctx);
568-
569- // Execute
570- state->thePlanWrapper = new PlanWrapper(state->thePlan,
571- evalCCB,
572- evalDctx,
573- planState.theQuery,
574- planState.theStackDepth + 1,
575- state->ccb->theHaveTimeout,
576- state->ccb->theTimeout);
577-
578- state->thePlanWrapper->checkDepth(loc);
579-
580- state->thePlanWrapper->open();
581- }
582+ if (state->thePlanWrapper.getp() == NULL)
583+ init(doCount, planState);
584
585 while (state->thePlanWrapper->next(result))
586 {
587@@ -205,6 +229,20 @@
588
589
590 /****************************************************************************//**
591+
592+********************************************************************************/
593+bool EvalIterator::skip(int64_t count, PlanState &planState) const
594+{
595+ EvalIteratorState* state = StateTraitsImpl<EvalIteratorState>::getState(planState, theStateOffset);
596+
597+ if (state->thePlanWrapper.getp() == NULL)
598+ init(false, planState);
599+
600+ return state->thePlanWrapper->skip(count);
601+}
602+
603+
604+/****************************************************************************//**
605 This method imports a static and dynamic environment from the quter query into
606 the eval query. In particular:
607
608
609=== modified file 'src/runtime/eval/eval.h'
610--- src/runtime/eval/eval.h 2013-03-24 20:40:03 +0000
611+++ src/runtime/eval/eval.h 2013-07-26 12:54:41 +0000
612@@ -38,6 +38,8 @@
613 EvalIteratorState();
614
615 ~EvalIteratorState();
616+
617+ void reset(PlanState& planState);
618 };
619
620
621@@ -130,7 +132,11 @@
622 return nextORcount(true, result, planState);
623 }
624
625+ bool skip(int64_t count, PlanState &planState) const;
626+
627 private:
628+ void init(bool doCount, PlanState& planState) const;
629+
630 void importOuterEnv(
631 PlanState& planState,
632 CompilerCB* evalCCB,
633
634=== modified file 'src/runtime/sequences/sequences_impl.cpp'
635--- src/runtime/sequences/sequences_impl.cpp 2013-06-18 18:55:33 +0000
636+++ src/runtime/sequences/sequences_impl.cpp 2013-07-26 12:54:41 +0000
637@@ -533,11 +533,8 @@
638 goto done;
639
640 // Consume and skip all input items that are before the startPos
641- for (; startPos > 1; --startPos)
642- {
643- if (!CONSUME(result, 0))
644- goto done;
645- }
646+ if (!theChildren[0]->skip(startPos-1, planState))
647+ goto done;
648
649 if (theChildren.size() < 3 || lengthDouble.isPosInf())
650 {
651@@ -619,11 +616,8 @@
652 goto done;
653
654 // Consume and skip all input items that are before the startPos
655- for (; startPos > 0; --startPos)
656- {
657- if (!CONSUME(result, 0))
658- goto done;
659- }
660+ if (!theChildren[0]->skip(startPos, planState))
661+ goto done;
662
663 if (theChildren.size() < 3)
664 {
665@@ -694,11 +688,8 @@
666 --startPos;
667
668 // Consume and skip all input items that are before the startPos
669- for (; startPos > 0; --startPos)
670- {
671- if (!CONSUME(result, 0))
672- goto done;
673- }
674+ if (!theChildren[0]->skip(startPos, planState))
675+ goto done;
676
677 if (CONSUME(result, 0))
678 {
679
680=== modified file 'src/runtime/spec/collections/collections.xml'
681--- src/runtime/spec/collections/collections.xml 2013-04-02 22:54:20 +0000
682+++ src/runtime/spec/collections/collections.xml 2013-07-26 12:54:41 +0000
683@@ -313,6 +313,16 @@
684 <zorba:param name="result" type="store::Item_t&amp;"/>
685 <zorba:param name="planState" type="PlanState&amp;"/>
686 </zorba:method>
687+
688+ <zorba:method name="skip" const="true" return="bool">
689+ <zorba:param name="count" type="int64_t"/>
690+ <zorba:param name="planState" type="PlanState&amp;"/>
691+ </zorba:method>
692+
693+ <zorba:method name="initCollection" const="true" return="void">
694+ <zorba:param name="planState" type="PlanState&amp;"/>
695+ <zorba:param name="skipCount" type="int64_t"/>
696+ </zorba:method>
697
698 <zorba:state generateInit="false" generateReset="false" generateDestructor="false">
699 <zorba:member type="store::Iterator_t" name="theIterator"/>
700
701=== added file 'test/rbkt/ExpQueryResults/zorba/eval/eval16.xml.res'
702--- test/rbkt/ExpQueryResults/zorba/eval/eval16.xml.res 1970-01-01 00:00:00 +0000
703+++ test/rbkt/ExpQueryResults/zorba/eval/eval16.xml.res 2013-07-26 12:54:41 +0000
704@@ -0,0 +1,2 @@
705+<?xml version="1.0" encoding="UTF-8"?>
706+<oldlast/>
707
708=== added file 'test/rbkt/Queries/zorba/eval/eval16.xq'
709--- test/rbkt/Queries/zorba/eval/eval16.xq 1970-01-01 00:00:00 +0000
710+++ test/rbkt/Queries/zorba/eval/eval16.xq 2013-07-26 12:54:41 +0000
711@@ -0,0 +1,9 @@
712+xquery version "3.0";
713+
714+import module namespace ddl = "http://www.zorba-xquery.com/modules/store/dynamic/collections/ddl";
715+import module namespace dml = "http://www.zorba-xquery.com/modules/store/dynamic/collections/dml";
716+import module namespace e = "http://www.zorba-xquery.com/modules/reflection";
717+
718+ddl:create(xs:QName("ddl:test2"),(<center1/>,<oldlast/>));
719+
720+subsequence(e:eval("dml:collection(xs:QName('ddl:test2'))"), 2, 1)

Subscribers

People subscribed via source and target branches