← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/count-opt into lp:zorba

 

Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/count-opt into lp:zorba.

Commit message:
Introduced generic framework for optimizing fn:count() during runtime: Virtual PlanIterator::count() method provides the base (unoptimized) implementation of fn:count(). This base method is redefined by other plan iterators who have a way of returning the cardinality of their result sequence without actually computing the full result sequence.


Requested reviews:
  Markos Zaharioudakis (markos-za)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/count-opt/+merge/148586

Introduced generic framework for optimizing fn:count() during runtime: Virtual PlanIterator::count() method provides the base (unoptimized) implementation of fn:count(). This base method is redefined by other plan iterators who have a way of returning the cardinality of their result sequence without actually computing the full result sequence.
-- 
https://code.launchpad.net/~zorba-coders/zorba/count-opt/+merge/148586
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'src/functions/func_sequences_impl.cpp'
--- src/functions/func_sequences_impl.cpp	2013-01-22 18:48:07 +0000
+++ src/functions/func_sequences_impl.cpp	2013-02-15 00:39:22 +0000
@@ -818,36 +818,7 @@
 {
   const std::type_info& counted_type = typeid(*argv[0]);
 
-  if (typeid(ZorbaCollectionIterator) == counted_type)
-  {
-    ZorbaCollectionIterator& collection =
-    static_cast<ZorbaCollectionIterator&>(*argv[0]);
-
-    if (collection.isCountOptimizable())
-    {
-      return new CountCollectionIterator(
-                   sctx,
-                   loc,
-                   collection.getChildren(),
-                   (
-                     collection.isDynamic()
-                       ? CountCollectionIterator::ZORBADYNAMIC
-                       : CountCollectionIterator::ZORBASTATIC
-                   )
-                 );
-    }
-  }
-  else if (typeid(FnCollectionIterator) == counted_type)
-  {
-    FnCollectionIterator& collection =
-    static_cast<FnCollectionIterator&>(*argv[0]);
-
-    return new CountCollectionIterator(sctx,
-                                       loc,
-                                       collection.getChildren(),
-                                       CountCollectionIterator::W3C);
-  }
-  else if (typeid(ProbeIndexPointValueIterator) == counted_type)
+  if (typeid(ProbeIndexPointValueIterator) == counted_type)
   {
     ProbeIndexPointValueIterator& lIter
       = static_cast<ProbeIndexPointValueIterator&>(*argv[0]);

=== modified file 'src/runtime/base/plan_iterator.cpp'
--- src/runtime/base/plan_iterator.cpp	2012-09-19 21:16:15 +0000
+++ src/runtime/base/plan_iterator.cpp	2013-02-15 00:39:22 +0000
@@ -23,6 +23,12 @@
 
 #include "runtime/util/flowctl_exception.h"
 
+#include "system/globalenv.h"
+
+#include "store/api/store.h"
+#include "store/api/item_factory.h"
+
+
 namespace zorba
 {
 
@@ -93,6 +99,22 @@
 }
 
 
+void PlanIterator::count(store::Item_t& result, PlanState& planState) const
+{
+  store::Item_t item;
+  ulong count = 0;
+
+  while (consumeNext(item, this, planState))
+  {
+    ++count;
+  }
+
+  GENV_ITEMFACTORY->createInteger(result, Integer(count));
+}
+
+
+#if ZORBA_BATCHING_TYPE == 0
+
 #ifndef NDEBUG
 
 bool PlanIterator::consumeNext(
@@ -120,6 +142,7 @@
 }
 #endif
 
+#endif
 
 } // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/runtime/base/plan_iterator.h'
--- src/runtime/base/plan_iterator.h	2012-09-19 21:16:15 +0000
+++ src/runtime/base/plan_iterator.h	2013-02-15 00:39:22 +0000
@@ -111,6 +111,7 @@
   theBlock        : Pointer to the memory block that stores the local state of
                     each individual plan iterator.
   theBlockSize    : Size (in bytes) of the block.
+
   theHasToQuit    : Boolean that indicates if the query execution has to quit.
                     Checking this value is done in each consumeNext call,
                     i.e. between every two iterator next calls. This value is
@@ -128,9 +129,6 @@
 
   uint32_t                  theMaxStackDepth;
 
-  // TODO this guy should become const because nothing can change anymore during
-  // runtime. We need to make all accessor in the control block and static context
-  // (see also shortcut below) const before doing that
   CompilerCB              * theCompilerCB;
 
   XQueryImpl              * theQuery;
@@ -168,16 +166,18 @@
   static const uint32_t DUFFS_ALLOCATE_RESOURCES = 0;
 
 private:
-  uint32_t         theDuffsLine;
+  uint32_t        theDuffsLine;
 
 public:
 #if ZORBA_BATCHING_TYPE == 1
 public:
-  uint32_t        theCurrItem;
-  store::Item_t   theBatch[ZORBA_BATCHING_BATCHSIZE];
+  bool             theIsDone;
+  store::Item_t  * theEndItem;
+  store::Item_t  * theCurrItem;
+  store::Item_t    theBatch[ZORBA_BATCHING_BATCHSIZE];
 #endif
 #ifndef NDEBUG
-  bool            theIsOpened;
+  bool             theIsOpened;
 #endif
 
 public:
@@ -185,16 +185,19 @@
     :
     theDuffsLine(DUFFS_ALLOCATE_RESOURCES)
 #if ZORBA_BATCHING_TYPE == 1
-    , theCurrItem(ZORBA_BATCHING_BATCHSIZE)
+    , theIsDone(false)
+    , theEndItem(NULL)
+    , theCurrItem(NULL)
 #endif
 #ifndef NDEBUG
     , theIsOpened(false)
 #endif
-  {}
+  {
+  }
 
   ~PlanIteratorState() {}
 
-  void setDuffsLine(uint32_t aVal) { theDuffsLine = aVal; }
+  void setDuffsLine(uint32_t v) { theDuffsLine = v; }
 
   uint32_t getDuffsLine() const { return theDuffsLine; }
 
@@ -210,13 +213,7 @@
    * Each subclass implementation of this method must call the init() method of
    * their parent class explicitly in order to guarantee proper initialization.
    */
-  void init(PlanState&)
-  {
-    theDuffsLine = DUFFS_ALLOCATE_RESOURCES;
-#if ZORBA_BATCHING_TYPE == 1
-    theCurrItem = ZORBA_BATCHING_BATCHSIZE;
-#endif
-  }
+  void init(PlanState& s) { reset(s); }
 
   /**
    * Reset the current state object.
@@ -234,10 +231,9 @@
   {
     theDuffsLine = DUFFS_ALLOCATE_RESOURCES;
 #if ZORBA_BATCHING_TYPE == 1
-    theCurrItem = ZORBA_BATCHING_BATCHSIZE;
-    // seeting the first item to NULL only is sufficient so
-    // that produceNext knows that it's not finished yet
-    theBatch[0] = NULL;
+    theIsDone = false;
+    theEndItem = NULL;
+    theCurrItem = NULL;
 #endif
   }
 };
@@ -286,12 +282,6 @@
   }
 };
 
-#if ZORBA_BATCHING_TYPE == 1
-
-#error "Batching not implemented with the new iterator contract."
-
-#endif
-
 
 /*******************************************************************************
   Base class of all plan iterators.
@@ -393,6 +383,11 @@
    */
   virtual void close(PlanState& planState) = 0;
 
+  /**
+   * 
+   */
+  virtual void count(store::Item_t& result, PlanState& planState) const;
+
 
 #if ZORBA_BATCHING_TYPE == 1
 
@@ -411,33 +406,34 @@
    * batch buffer have been consumed already, then it makes the iterator produce
    * its next batch of results and retrieves the 1st item from this new batch.
    */
-  static store::Item_t consumeNext(
+  static bool consumeNext(
         store::Item_t& result,
         const PlanIterator* iter,
         PlanState& planState)
   {
-    try
-    {
-      // use the given iterator's planstate to access it's batch
-      PlanIteratorState* lState =
-      StateTraitsImpl<PlanIteratorState>::getState(planState, iter->getStateOffset());
-
-      if ( lState->theCurrItem == ZORBA_BATCHING_BATCHSIZE )
-      {
-        iter->produceNext(planState);
-        lState->theCurrItem = 0;
-      }
-    }
-    catch(ZorbaException& e)
-    {
-      if(loc != NULL)
-      {
-        set_source(e, loc);
-        throw;
-      }
-    }
-
-    return lState->theBatch[lState->theCurrItem++];
+    PlanIteratorState* state =
+    StateTraitsImpl<PlanIteratorState>::getState(planState, iter->getStateOffset());
+
+    if (state->theCurrItem == state->theEndItem)
+    {
+      // there are no more buffered items, so pruduce the next batch, if any
+
+      if (state->theIsDone)
+        return false;
+
+      iter->produceNext(planState);
+
+      if (state->theCurrItem == state->theEndItem)
+      {
+        // nothing was produced.
+        assert(state->theIsDone);
+        return false;
+      }
+    }
+
+    result.transfer(*state->theCurrItem);
+    ++state->theCurrItem;
+    return true;
   }
 
 
@@ -502,74 +498,93 @@
 
   ~Batcher() {}
 
-
 #if ZORBA_BATCHING_TYPE == 1
 
   void produceNext(PlanState& planState) const
   {
-    PlanIteratorState* lState =
-    StateTraitsImpl<PlanIteratorState>::getState(planState, stateOffset);
-#ifndef NDEBUG
-    ZORBA_ASSERT(lState->theIsOpened);
-#endif
-    bool more;
-    uint32_t i = 0;
+    PlanIteratorState* state =
+    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
+    assert(state->theIsOpened);
+    state->theEndItem = &state->theBatch[ZORBA_BATCHING_BATCHSIZE];
+    state->theCurrItem = &state->theBatch[0];
     do
     {
       // In general, to compute this iterator's next result, nextImpl() will
       // call consumeNext() on one or more of this iterator's child iterators.
-      more = static_cast<const IterType*>(this)->nextImpl(lState->theBatch[i], planState);
+      if (!static_cast<const IterType*>(this)->nextImpl(*state->theCurrItem, planState))
+      {
+        state->theEndItem = state->theCurrItem;
+        state->theCurrItem = &state->theBatch[0];
+        state->theIsDone = true;
+        return;
+      }
+
+      ++state->theCurrItem;
     }
-    while ( more && ++i < ZORBA_BATCHING_BATCHSIZE );
+    while (state->theCurrItem < state->theEndItem);
+
+    state->theCurrItem = &state->theBatch[0];
   }
 
-#else
+#else // ZORBA_BATCHING_TYPE
 
   bool produceNext(store::Item_t& result, PlanState& planState) const
   {
 #ifndef NDEBUG
-    PlanIteratorState* lState =
+    PlanIteratorState* state =
     StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
-    ZORBA_ASSERT(lState->theIsOpened);
+    ZORBA_ASSERT(state->theIsOpened);
 #endif
     return static_cast<const IterType*>(this)->nextImpl(result, planState);
   }
 
 #endif // ZORBA_BATCHING_TYPE
 
+#ifndef NDEBUG
   void open(PlanState& planState, uint32_t& offset)
   {
     static_cast<IterType*>(this)->openImpl(planState, offset);
-#ifndef NDEBUG
     // do this after openImpl because the state is created there
-    PlanIteratorState* lState =
-    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
-    ZORBA_ASSERT( ! lState->theIsOpened ); // don't call open twice
-    lState->theIsOpened = true;
-#endif
-  }
-
-  void reset(PlanState& planState) const
-  {
-#ifndef NDEBUG
-    PlanIteratorState* lState =
-    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
-    ZORBA_ASSERT( lState->theIsOpened );
-#endif
-    static_cast<const IterType*>(this)->resetImpl(planState);
-  }
-
-  void close(PlanState& planState)
-  {
-#ifndef NDEBUG
-    PlanIteratorState* lState =
-    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
-    static_cast<IterType*>(this)->closeImpl(planState);
-    lState->theIsOpened = false;
-#else
-    static_cast<IterType*>(this)->closeImpl(planState);
-#endif
-  }
+    PlanIteratorState* state =
+    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
+    ZORBA_ASSERT(!state->theIsOpened); // don't call open twice
+    state->theIsOpened = true;
+  }
+
+  void reset(PlanState& planState) const
+  {
+    PlanIteratorState* state =
+    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
+    ZORBA_ASSERT(state->theIsOpened);
+    static_cast<const IterType*>(this)->resetImpl(planState);
+  }
+
+  void close(PlanState& planState)
+  {
+    PlanIteratorState* state =
+    StateTraitsImpl<PlanIteratorState>::getState(planState, theStateOffset);
+    static_cast<IterType*>(this)->closeImpl(planState);
+    state->theIsOpened = false;
+  }
+
+#else // NDEBUG
+
+  void open(PlanState& planState, uint32_t& offset)
+  {
+    static_cast<IterType*>(this)->openImpl(planState, offset);
+  }
+
+  void reset(PlanState& planState) const
+  {
+    static_cast<const IterType*>(this)->resetImpl(planState);
+  }
+
+  void close(PlanState& planState)
+  {
+    static_cast<IterType*>(this)->closeImpl(planState);
+  }
+
+#endif // NDEBUG
 
   inline bool nextImpl(store::Item_t& result, PlanState& planState) const;
 

=== modified file 'src/runtime/collections/collections_impl.cpp'
--- src/runtime/collections/collections_impl.cpp	2013-01-31 11:32:47 +0000
+++ src/runtime/collections/collections_impl.cpp	2013-02-15 00:39:22 +0000
@@ -132,206 +132,95 @@
 
 bool FnCollectionIterator::nextImpl(store::Item_t& result, PlanState& planState) const
 {
-  store::Item_t lURI, resolvedURIItem;
   store::Collection_t coll;
-  std::auto_ptr<internal::Resource> lResource;
-  internal::CollectionResource* lCollResource;
-  zstring resolvedURIString;
   zstring lErrorMessage;
 
-  FnCollectionIteratorState *state;
+  FnCollectionIteratorState* state;
   DEFAULT_STACK_INIT(FnCollectionIteratorState, state, planState);
 
-  if (theChildren.size() == 1 &&
-      consumeNext(lURI, theChildren[0].getp(), planState))
-  {
-    try
-    {
-      resolvedURIString = theSctx->resolve_relative_uri(lURI->getStringValue());
-    }
-    catch (ZorbaException const&)
-    {
-      RAISE_ERROR(err::FODC0004, loc,
-      ERROR_PARAMS(lURI->getStringValue(), ZED(BadAnyURI)));
-    }
-  }
-  else
-  {
-    resolvedURIItem = planState.theGlobalDynCtx->get_default_collection();
-
-    if (NULL == resolvedURIItem)
-    {
-      RAISE_ERROR(err::FODC0002, loc,
-      ERROR_PARAMS(ZED(DefaultCollation), ZED(NotDefInDynamicCtx)));
-    }
-
-    resolvedURIString = theSctx->resolve_relative_uri(resolvedURIItem->getStringValue());
-  }
-
-  lResource = theSctx->resolve_uri(resolvedURIString,
-                                   internal::EntityData::COLLECTION,
-                                   lErrorMessage);
-
-  lCollResource = dynamic_cast<internal::CollectionResource*>(lResource.get());
-
-  if ( lCollResource == 0 || !(coll = lCollResource->getCollection()) )
-  {
-    RAISE_ERROR(err::FODC0002, loc,
-    ERROR_PARAMS(resolvedURIString, lErrorMessage));
-  }
-
-  /** return the nodes of the collection */
+  coll = getCollection(planState);
+
   state->theIterator = coll->getIterator();
   ZORBA_ASSERT(state->theIterator!=NULL);
   state->theIterator->open();
   state->theIteratorOpened = true;
 
   while(state->theIterator->next(result))
+  {
     STACK_PUSH (true, state);
+  }
 
   // close as early as possible
   state->theIterator->close();
   state->theIteratorOpened = false;
 
-  STACK_END (state);
-}
-
-
-/*******************************************************************************
-  Iterator for optimizing fn:count when applied to collections
-********************************************************************************/
-CountCollectionIterator::CountCollectionIterator(
-    static_context* sctx,
-    const QueryLoc& loc,
-    std::vector<PlanIter_t>& children,
-    CollectionType collectionType)
-  :
-  NaryBaseIterator<CountCollectionIterator, PlanIteratorState>(sctx, loc, children),
-  theCollectionType(collectionType)
-{
-}
-
-
-CountCollectionIterator::~CountCollectionIterator() 
-{
-}
-
-
-void CountCollectionIterator::serialize(::zorba::serialization::Archiver& ar)
-{
-  serialize_baseclass(ar,
-  (NaryBaseIterator<CountCollectionIterator, PlanIteratorState>*)this);
-
-  SERIALIZE_ENUM(enum CollectionType, theCollectionType);
-}
-
-
-bool CountCollectionIterator::nextImpl(store::Item_t& result, PlanState& planState) const
-{
-  store::Collection_t coll;
-  store::Item_t name;
-  xs_integer lCount;
-
-  PlanIteratorState* state;
-  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
-
-  if (isZorbaCollection())
-  {
-    ZORBA_ASSERT(consumeNext(name, theChildren[0].getp(), planState));
-
-    (void)getCollection(theSctx, name, loc, isDynamic(), coll);
-  }
-  else
-  {
-    coll = getW3CCollection(planState);
-  }
-
-  lCount = coll->size();
-  if (theChildren.size() == 2) 
-  {
-    // skip parameter passed
-    store::Item_t lSkipItem;
-    consumeNext(lSkipItem, theChildren[1].getp(), planState);
-    xs_integer lSkip = lSkipItem->getIntegerValue(); 
-    // negative is transformed into 0
-    lCount -= ( lSkip <= xs_integer::zero() ? xs_integer::zero() : lSkip );
-    // negative is transformed into 0
-    lCount = ( lCount < xs_integer::zero() ? xs_integer::zero() : lCount );
-  }
-  else if(theChildren.size() > 2)
-  {
-    // if ref is passed to the collections function, count cannot be 
-    // optimized anymore. Hence this iterator must not be used.
-    // In this case ZorbaCollectionIterator::isCountOptimizable() returns 
-    // false.
-    assert(false);
-  }
-
-  STACK_PUSH(GENV_ITEMFACTORY->createInteger(result, lCount), state);
-
   STACK_END(state);
 }
 
 
-store::Collection_t CountCollectionIterator::getW3CCollection(PlanState& planState) const
-{
-  store::Item_t lURI;
+void FnCollectionIterator::count(store::Item_t& result, PlanState& planState) const
+{
+  store::Collection_t collection;
+  xs_integer count;
+
+  collection = getCollection(planState);
+
+  count = collection->size();
+
+  GENV_ITEMFACTORY->createInteger(result, count);
+}
+
+
+store::Collection_t FnCollectionIterator::getCollection(PlanState& planState) const
+{
+  store::Item_t uriItem;
   store::Collection_t coll;
-  std::auto_ptr<internal::Resource> lResource;
-  internal::CollectionResource* lCollResource;
-  zstring resolvedURIString;
-  zstring lErrorMessage;
+  std::auto_ptr<internal::Resource> resource;
+  internal::CollectionResource* collResource;
+  zstring resolvedURI;
+  zstring errorMessage;
 
-  if (!theChildren.empty()) //if a URI was given
+  if (!theChildren.empty() && 
+      consumeNext(uriItem, theChildren[0].getp(), planState))
   {
-    ZORBA_ASSERT(consumeNext(lURI, theChildren[0].getp(), planState));
-
     try
     {
-      resolvedURIString = theSctx->resolve_relative_uri(lURI->getStringValue());
+      resolvedURI = theSctx->resolve_relative_uri(uriItem->getStringValue());
     }
     catch (ZorbaException const&)
     {
       RAISE_ERROR(err::FODC0004, loc,
-      ERROR_PARAMS(lURI->getStringValue(), ZED(BadAnyURI)));
+      ERROR_PARAMS(uriItem->getStringValue(), ZED(BadAnyURI)));
     }
   }
   else
   {
-    lURI = planState.theGlobalDynCtx->get_default_collection();
+    uriItem = planState.theGlobalDynCtx->get_default_collection();
 
-    if( NULL == lURI)
+    if (NULL == uriItem)
     {
       RAISE_ERROR(err::FODC0002, loc,
       ERROR_PARAMS(ZED(DefaultCollation), ZED(NotDefInDynamicCtx)));
     }
 
-    resolvedURIString = theSctx->resolve_relative_uri(lURI->getStringValue());
+    resolvedURI = theSctx->resolve_relative_uri(uriItem->getStringValue());
   }
 
-
-  lResource = theSctx->resolve_uri(resolvedURIString, 
-                                   internal::EntityData::COLLECTION,
-                                   lErrorMessage);
-
-  lCollResource = dynamic_cast<internal::CollectionResource*>(lResource.get());
-
-  if (lCollResource == 0 || !(coll = lCollResource->getCollection()))
+  resource = theSctx->resolve_uri(resolvedURI, 
+                                  internal::EntityData::COLLECTION,
+                                  errorMessage);
+
+  collResource = dynamic_cast<internal::CollectionResource*>(resource.get());
+
+  if (collResource == 0 || !(coll = collResource->getCollection()))
   {
-    RAISE_ERROR(err::FODC0004, loc,
-    ERROR_PARAMS(resolvedURIString, lErrorMessage));
+    RAISE_ERROR(err::FODC0004, loc, ERROR_PARAMS(resolvedURI, errorMessage));
   }
 
   return coll;
 }
 
 
-SERIALIZABLE_CLASS_VERSIONS(CountCollectionIterator)
-
-
-NARY_ACCEPT(CountCollectionIterator);
-
-
 /*******************************************************************************
 
 ********************************************************************************/
@@ -449,12 +338,8 @@
   }
   catch ( std::range_error const& )
   {
-    throw XQUERY_EXCEPTION(
-      zerr::ZXQD0004_INVALID_PARAMETER,
-      ERROR_PARAMS(ZED(ZXQD0004_NOT_WITHIN_RANGE),
-                  lSkip),
-      ERROR_LOC( loc )
-    );
+    RAISE_ERROR(zerr::ZXQD0004_INVALID_PARAMETER, loc,
+    ERROR_PARAMS(ZED(ZXQD0004_NOT_WITHIN_RANGE), lSkip));
   }
 
   state->theIteratorOpened = true;
@@ -469,6 +354,38 @@
   STACK_END(state);
 }
 
+
+void ZorbaCollectionIterator::count(store::Item_t& result, PlanState& planState) const
+{
+  if (!isCountOptimizable())
+    return PlanIterator::count(result, planState);
+
+  store::Item_t name;
+  store::Collection_t collection;
+  xs_integer count;
+
+  consumeNext(name, theChildren[0].getp(), planState);
+
+  (void)getCollection(theSctx, name, loc, theIsDynamic, collection);
+
+  count = collection->size();
+
+  if (theChildren.size() == 2) 
+  {
+    // skip parameter passed
+    store::Item_t skipItem;
+    consumeNext(skipItem, theChildren[1].getp(), planState);
+    xs_integer skip = skipItem->getIntegerValue(); 
+
+    count -= (skip <= xs_integer::zero() ? xs_integer::zero() : skip);
+
+    count = (count < xs_integer::zero() ? xs_integer::zero() : count);
+  }
+
+  GENV_ITEMFACTORY->createInteger(result, count);
+}
+
+
 /*******************************************************************************
   declare function index-of($name as xs:QName,
                             $target as node()) as xs:integer

=== modified file 'src/runtime/collections/collections_impl.h'
--- src/runtime/collections/collections_impl.h	2012-09-19 21:16:15 +0000
+++ src/runtime/collections/collections_impl.h	2013-02-15 00:39:22 +0000
@@ -24,58 +24,6 @@
 
 namespace zorba{
 
-/*******************************************************************************
-  Iterator to optimize a fn:count(collection) expression
-
-  theCollectionType:
-  ------------------
-  Whether the Collection is a W3C or Zorba Collection and if it's dynamic or 
-  static collection module.
-********************************************************************************/
-class CountCollectionIterator : public NaryBaseIterator<CountCollectionIterator, 
-                                                        PlanIteratorState>
-{
-public:
-  enum CollectionType 
-  { 
-    W3C = 0,
-    ZORBASTATIC = 1,
-    ZORBADYNAMIC = 2 
-  };
-
-protected:
-  CollectionType theCollectionType;
-
-public:
-  SERIALIZABLE_CLASS(CountCollectionIterator);
-
-  SERIALIZABLE_CLASS_CONSTRUCTOR2T(CountCollectionIterator,
-  NaryBaseIterator<CountCollectionIterator, PlanIteratorState>);
-
-  void serialize(::zorba::serialization::Archiver& ar);
-
-public:
-  CountCollectionIterator(
-      static_context* sctx,
-      const QueryLoc& loc,
-      std::vector<PlanIter_t>& children,
-      CollectionType collectionType);
-
-  ~CountCollectionIterator();
-
-  bool isZorbaCollection() const { return W3C != theCollectionType; }
-
-  bool isDynamic() const { return ZORBADYNAMIC == theCollectionType; }
-
-  void accept(PlanIterVisitor& v) const;
-
-  bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
-
-protected:
-  store::Collection_t getZorbaCollection(PlanState& planState) const;
-
-  store::Collection_t getW3CCollection(PlanState& planState) const;
-};
 
 } //namespace zorba
 #endif /* ZORBA_RUNTIME_COLLECTIONS_COLLECTIONS_IMPL_H */

=== modified file 'src/runtime/collections/pregenerated/collections.h'
--- src/runtime/collections/pregenerated/collections.h	2012-12-11 13:33:18 +0000
+++ src/runtime/collections/pregenerated/collections.h	2013-02-15 00:39:22 +0000
@@ -233,6 +233,9 @@
 
   virtual ~FnCollectionIterator();
 
+public:
+  void count(store::Item_t& result, PlanState& planState) const;
+  store::Collection_t getCollection(PlanState& planState) const;
   void accept(PlanIterVisitor& v) const;
 
   bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;
@@ -287,6 +290,7 @@
 
 public:
   bool isCountOptimizable() const;
+  void count(store::Item_t& result, PlanState& planState) const;
   void accept(PlanIterVisitor& v) const;
 
   bool nextImpl(store::Item_t& result, PlanState& aPlanState) const;

=== modified file 'src/runtime/core/path_iterators.cpp'
--- src/runtime/core/path_iterators.cpp	2012-10-12 21:07:51 +0000
+++ src/runtime/core/path_iterators.cpp	2013-02-15 00:39:22 +0000
@@ -1245,7 +1245,7 @@
     {
       if (!consumeNext(state->theContextNode, theChild.getp(), planState))
       {
-        state->reset(planState);
+        //state->reset(planState);
         return false;
       }
 

=== modified file 'src/runtime/sequences/sequences_impl.cpp'
--- src/runtime/sequences/sequences_impl.cpp	2013-01-11 10:18:14 +0000
+++ src/runtime/sequences/sequences_impl.cpp	2013-02-15 00:39:22 +0000
@@ -1205,27 +1205,35 @@
 //                                                                             //
 /////////////////////////////////////////////////////////////////////////////////
 
+
 /*******************************************************************************
   15.4.1 fn:count
 ********************************************************************************/
 bool FnCountIterator::nextImpl(store::Item_t& result, PlanState& planState) const
 {
-  store::Item_t lSequenceItem;
-  ulong lCount = 0;
+  store::Item_t item;
+  ulong count = 0;
 
   PlanIteratorState* state;
   DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
 
-  while (consumeNext(lSequenceItem, theChildren[0].getp(), planState))
+  theChildren[0]->count(result, planState);
+
+  STACK_PUSH(result, state);
+
+#if 0
+  while (consumeNext(item, theChildren[0].getp(), planState))
   {
-    ++lCount;
+    ++count;
   }
 
-  STACK_PUSH(GENV_ITEMFACTORY->createInteger(result, Integer(lCount)), state);
+  STACK_PUSH(GENV_ITEMFACTORY->createInteger(result, Integer(count)), state);
+#endif
 
   STACK_END(state);
 }
 
+
 /*******************************************************************************
   15.4.2 fn:avg
 ********************************************************************************/

=== modified file 'src/runtime/spec/collections/collections.xml'
--- src/runtime/spec/collections/collections.xml	2012-12-11 13:33:18 +0000
+++ src/runtime/spec/collections/collections.xml	2013-02-15 00:39:22 +0000
@@ -230,6 +230,15 @@
                     brief="flag indicating whether theIterator was opened"/>
     </zorba:state>
 
+    <zorba:method name="count" const="true" return="void">
+       <zorba:param name="result" type="store::Item_t&amp;"/>
+       <zorba:param name="planState" type="PlanState&amp;"/>
+    </zorba:method>
+
+    <zorba:method name="getCollection" const="true" return="store::Collection_t">
+       <zorba:param name="planState" type="PlanState&amp;"/>
+    </zorba:method>
+
 </zorba:iterator>
 
 <!--
@@ -298,10 +307,13 @@
 
     <zorba:member type="bool" name="theIsDynamic" getterName="isDynamic"/>
 
-    <zorba:method const="true"
-                  name="isCountOptimizable"
-                  return="bool" />
+    <zorba:method const="true" name="isCountOptimizable" return="bool" />
     
+    <zorba:method const="true" name="count" return="void">
+       <zorba:param name="result" type="store::Item_t&amp;"/>
+       <zorba:param name="planState" type="PlanState&amp;"/>
+    </zorba:method>
+
     <zorba:state generateInit="false" generateReset="false" generateDestructor="false">
       <zorba:member type="store::Iterator_t" name="theIterator"/>
       <zorba:member type="bool" name="theIteratorOpened" defaultValue="false"/>

=== modified file 'src/runtime/spec/iterator_h.xq'
--- src/runtime/spec/iterator_h.xq	2012-09-19 21:16:15 +0000
+++ src/runtime/spec/iterator_h.xq	2013-02-15 00:39:22 +0000
@@ -251,38 +251,36 @@
 
 declare function local:add-methods ($iter) as xs:string?
 {
-  fn:concat("public:", $gen:newline,
-    fn:string-join(
+  fn:concat(
+    "public:",
+    $gen:newline,
+    fn:string-join
+    (
       for $method in $iter/zorba:method
-      return fn:concat(
-        $gen:indent,
-        if ($method/@static eq "true")
-        then
-         "static "
-        else
-          "",
-        $method/@return,
-        " ",
-        $method/@name,
-        "(",
-        local:get-method-arguments($method),
-        ")",
-        if ($method/@const eq "true") then
-          " const;"
-        else ";"), $gen:newline),
-      $gen:newline)
+      return fn:concat($gen:indent,
+                       if ($method/@static eq "true") then "static " else "",
+                       $method/@return,
+                       " ",
+                       $method/@name,
+                       "(",
+                       local:get-method-arguments($method),
+                       ")",
+                       if ($method/@const eq "true") then " const;" else ";"),
+      $gen:newline
+    ),
+    $gen:newline
+  )
 };
 
 
 declare function local:get-method-arguments($method) as xs:string?
 {
-  fn:string-join(
+  fn:string-join
+  (
     for $param in $method/zorba:param
-    return fn:concat(
-      $param/@type,
-      " ",
-      $param/@name),
-    ", ")
+    return fn:concat($param/@type, " ", $param/@name),
+    ", "
+  )
 };
 
 

=== modified file 'src/runtime/visitors/planiter_visitor_impl_code.h'
--- src/runtime/visitors/planiter_visitor_impl_code.h	2013-01-11 22:58:12 +0000
+++ src/runtime/visitors/planiter_visitor_impl_code.h	2013-02-15 00:39:22 +0000
@@ -362,6 +362,4 @@
 PLAN_ITER_VISITOR(ExitCatcherIterator);
 PLAN_ITER_VISITOR(FlowCtlIterator);
 
-PLAN_ITER_VISITOR(CountCollectionIterator);
-
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/runtime/visitors/planiter_visitor_impl_include.h'
--- src/runtime/visitors/planiter_visitor_impl_include.h	2013-01-11 22:58:12 +0000
+++ src/runtime/visitors/planiter_visitor_impl_include.h	2013-02-15 00:39:22 +0000
@@ -184,8 +184,6 @@
 class LoopIterator;
 class FlowCtlIterator;
 
-class CountCollectionIterator;
-
 #define PLAN_ITER_VISITOR(class)                \
 virtual void beginVisit ( const class& ) = 0;  \
 virtual void endVisit ( const class& ) = 0

=== modified file 'src/runtime/visitors/printer_visitor_impl.cpp'
--- src/runtime/visitors/printer_visitor_impl.cpp	2013-01-11 22:58:12 +0000
+++ src/runtime/visitors/printer_visitor_impl.cpp	2013-02-15 00:39:22 +0000
@@ -1522,7 +1522,5 @@
   PRINTER_VISITOR_DEFINITION(ExitCatcherIterator);
   PRINTER_VISITOR_DEFINITION(LoopIterator);
   PRINTER_VISITOR_DEFINITION(FlowCtlIterator);
-
-  PRINTER_VISITOR_DEFINITION(CountCollectionIterator);
 }
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/runtime/visitors/printer_visitor_impl.h'
--- src/runtime/visitors/printer_visitor_impl.h	2013-01-11 22:58:12 +0000
+++ src/runtime/visitors/printer_visitor_impl.h	2013-02-15 00:39:22 +0000
@@ -317,6 +317,4 @@
   DECLARE_VISITOR(LoopIterator);
   DECLARE_VISITOR(FlowCtlIterator);
 
-  DECLARE_VISITOR(CountCollectionIterator);
-
 /* vim:set et sw=2 ts=2: */

=== modified file 'test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_dynamic_zorba_collection.iter'
--- test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_dynamic_zorba_collection.iter	2012-12-06 22:49:35 +0000
+++ test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_dynamic_zorba_collection.iter	2013-02-15 00:39:22 +0000
@@ -9,9 +9,11 @@
         <CtxVarIterator varid="4" varname="coll" varkind="global"/>
       </ZorbaCreateCollectionIterator>
     </ApplyIterator>
-    <CountCollectionIterator>
-      <CtxVarIterator varid="4" varname="coll" varkind="global"/>
-    </CountCollectionIterator>
+    <FnCountIterator>
+      <ZorbaCollectionIterator>
+        <CtxVarIterator varid="4" varname="coll" varkind="global"/>
+      </ZorbaCollectionIterator>
+    </FnCountIterator>
   </SequentialIterator>
 </SequentialIterator>
 

=== modified file 'test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_static_zorba_collection.iter'
--- test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_static_zorba_collection.iter	2012-12-06 22:49:35 +0000
+++ test/rbkt/ExpCompilerResults/IterPlan/zorba/collections/count_static_zorba_collection.iter	2013-02-15 00:39:22 +0000
@@ -27,9 +27,11 @@
         <CtxVarIterator varid="10" varname="coll" varkind="global"/>
       </ZorbaCreateCollectionIterator>
     </ApplyIterator>
-    <CountCollectionIterator>
-      <CtxVarIterator varid="10" varname="coll" varkind="global"/>
-    </CountCollectionIterator>
+    <FnCountIterator>
+      <ZorbaCollectionIterator>
+        <CtxVarIterator varid="10" varname="coll" varkind="global"/>
+      </ZorbaCollectionIterator>
+    </FnCountIterator>
   </SequentialIterator>
 </SequentialIterator>
 


Follow ups