Dennis Knochenwefel has proposed merging 
lp:~dennis-knochenwefel/zorba/dennis-misc into lp:zorba.

Commit message:
subsequence rewrite if source sequence is coming from db:collection() function 
(pushing start position into collection skip).

Requested reviews:
  Matthias Brantner (matthias-brantner)

For more details, see:
https://code.launchpad.net/~dennis-knochenwefel/zorba/dennis-misc/+merge/144373

subsequence rewrite if first parameter is db:collection() function.
-- 
https://code.launchpad.net/~dennis-knochenwefel/zorba/dennis-misc/+merge/144373
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'src/functions/func_sequences_impl.cpp'
--- src/functions/func_sequences_impl.cpp	2012-10-24 11:32:56 +0000
+++ src/functions/func_sequences_impl.cpp	2013-01-22 18:54:32 +0000
@@ -23,6 +23,9 @@
 #include "runtime/sequences/sequences.h"
 #include "runtime/sequences/SequencesImpl.h"
 #include "runtime/core/var_iterators.h"
+#include "runtime/core/item_iterator.h"
+#include "runtime/core/arithmetic_impl.h"
+#include "runtime/numerics/NumericsImpl.h"
 
 #include "runtime/collections/collections_impl.h"
 #include "runtime/collections/collections.h"
@@ -42,7 +45,114 @@
 
 
 /*******************************************************************************
-
+********************************************************************************/
+bool
+rewriteSubsequenceCollection(static_context* aSctx,
+                             const QueryLoc& aLoc,
+                             std::vector<PlanIter_t>& aArgs,
+                             bool aIsIntSubsequence)
+{
+  ZorbaCollectionIterator* collIter 
+    = dynamic_cast<ZorbaCollectionIterator*>(aArgs[0].getp());
+  assert(collIter);
+  std::vector<PlanIter_t>& lCollectionArgs = collIter->getChildren();
+
+  SingletonIterator* lPosIter = dynamic_cast<SingletonIterator*>(aArgs[1].getp());
+  if (lPosIter == NULL)
+  {
+    return false;
+  }
+  xs_long pos;
+  const store::Item_t& lPosItem = lPosIter->getValue();
+  try
+  {
+    if (aIsIntSubsequence)
+    {
+      pos = lPosItem->getLongValue();
+    }
+    else
+    {
+      xs_double dpos = lPosItem->getDoubleValue().round();
+      xs_integer ipos(dpos.getNumber());
+      pos = to_xs_long(ipos);
+    }
+  }
+  catch (std::range_error&)
+  {
+    return false;
+  }
+  if (pos <= 1)
+  {
+    // if the start position is less than 1 we can't push this down into
+    // the collection skip parameter because the result won't be equivalent.
+    return false;
+  }
+
+  // prepare helper
+  store::Item_t lItemOne;
+  GENV_ITEMFACTORY->createInteger(lItemOne, Integer(1));
+
+  int lNumCollArgs = lCollectionArgs.size();
+  if (lNumCollArgs == 1)
+  {
+    // argument is of type collection(qname)
+    // simply move the (pos-1) of subsequence into the skip of 
+    // collection function
+    // subsequence(collection(qname), 10, 20) 
+    //   -> subsequence(collection(qname, 10-1), 10, 20)
+    PlanIter_t& lNewCollSkipIter = aArgs[1];
+    PlanIter_t lOneIter = new SingletonIterator (aSctx, aLoc, lItemOne);
+    lCollectionArgs.push_back(
+        new NumArithIterator<zorba::SubtractOperation>(
+          collIter->getStaticContext(), collIter->getLocation(),
+          lNewCollSkipIter, lOneIter)
+        );
+  }
+  else if (lNumCollArgs <= 3 && lNumCollArgs != 0)
+  {
+    // argument is of type collection(qname,skip) or 
+    // collection(qname,start_uri,skip)
+    int lSkipPosition = 1;
+    if (lNumCollArgs == 3) 
+    {
+      // collection function with start reference -> skip is the 3rd param
+      lSkipPosition = 2;
+    }
+      
+    // add position-1 of subsequence to collection skip
+    // subsequence(collection(qname, 10), 10, 20) 
+    //   -> subsequence(collection(qname, 10+10-1), 10, 20)
+    PlanIter_t& lOldCollSkipIter = lCollectionArgs[lSkipPosition];
+    PlanIter_t lOneIter = new SingletonIterator (aSctx, aLoc, lItemOne);
+    PlanIter_t& lSubseqPosIter = aArgs[1];
+    PlanIter_t lCollSkipAdditionIter
+      = new NumArithIterator<zorba::SubtractOperation>(
+          collIter->getStaticContext(), collIter->getLocation(),
+          lSubseqPosIter, lOneIter);
+    lCollectionArgs[lSkipPosition] 
+      = new NumArithIterator<zorba::AddOperation>(
+          collIter->getStaticContext(), collIter->getLocation(), 
+          lOldCollSkipIter, lCollSkipAdditionIter);
+  }
+  else
+  {
+    // no collection function with 0 or >3 params
+    assert(false);
+  }
+  aArgs[0] = new ZorbaCollectionIterator(collIter->getStaticContext(),
+      collIter->getLocation(), lCollectionArgs, collIter->isDynamic());
+
+  // after pushing the position param down we need to rewrite the actual 
+  // position to 1:
+  // subsequence(collection(qname, 10+10-1), 10, 20) 
+  //   -> subsequence(collection(qname, 10+10-1), 1, 20)
+  aArgs[1] = new SingletonIterator (aSctx, aLoc, lItemOne);
+
+  return true;
+}
+
+
+/*******************************************************************************
 ********************************************************************************/
 xqtref_t fn_unordered::getReturnType(const fo_expr* caller) const
 {
@@ -408,12 +518,10 @@
     std::vector<PlanIter_t>& aArgs,
     expr& aAnn) const
 {
+  const std::type_info& lFirstArgType = typeid(*aArgs[0]);
   fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);
-
   const expr* inputExpr = subseqExpr.get_arg(0);
-
   const expr* posExpr = subseqExpr.get_arg(1);
-
   const expr* lenExpr = (subseqExpr.num_args() > 2 ? subseqExpr.get_arg(2) : NULL);
 
   if (inputExpr->get_expr_kind() == relpath_expr_kind &&
@@ -455,6 +563,22 @@
         return aArgs[0];
     }
   }
+  else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
+  {
+    // push down position param into collection skip if possible
+    if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, false /*no int*/))
+    {
+      // we have rewritten the subsequence to start at the beginning.
+      // if there is no length param we can remove the entire
+      // subsequence function
+      // subsequence(collection(qname, 10),1)
+      //   -> collection(qname, 10)
+      if (aArgs.size() == 2)
+      {
+        return aArgs[0];
+      }
+    }
+  }
 
  done:
   return new FnSubsequenceIterator(aSctx, aLoc, aArgs);
@@ -491,17 +615,12 @@
     std::vector<PlanIter_t>& aArgs,
     expr& aAnn) const
 {
+  const std::type_info& lFirstArgType = typeid(*aArgs[0]);
   fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);
-
   const expr* inputExpr = subseqExpr.get_arg(0);
-
   const expr* posExpr = subseqExpr.get_arg(1);
-
   const expr* lenExpr = (subseqExpr.num_args() > 2 ? subseqExpr.get_arg(2) : NULL);
 
-  LetVarIterator* letVarIter;
-  CtxVarIterator* ctxVarIter;
-
   if (inputExpr->get_expr_kind() == relpath_expr_kind &&
       posExpr->get_expr_kind() == const_expr_kind &&
       lenExpr != NULL &&
@@ -533,32 +652,50 @@
         return aArgs[0];
     }
   }
-  else if ((letVarIter = dynamic_cast<LetVarIterator*>(aArgs[0].getp())) != NULL)
+  else if (typeid(LetVarIterator) == lFirstArgType)
   {
+    LetVarIterator& letVarIter = static_cast<LetVarIterator&>(*aArgs[0]);
     const var_expr* inputVar = inputExpr->get_var();
 
     if (inputVar != NULL &&
         (inputVar->get_kind() == var_expr::let_var ||
          inputVar->get_kind() == var_expr::win_var ||
          inputVar->get_kind() == var_expr::non_groupby_var) &&
-        letVarIter->setTargetPosIter(aArgs[1]) &&
-        letVarIter->setTargetLenIter(lenExpr ? aArgs[2] : NULL))
+        letVarIter.setTargetPosIter(aArgs[1]) &&
+        letVarIter.setTargetLenIter(lenExpr ? aArgs[2] : NULL))
     {
       return aArgs[0];
     }
   }
-  else if ((ctxVarIter = dynamic_cast<CtxVarIterator*>(aArgs[0].getp())) != NULL)
+  else if (typeid(CtxVarIterator) == lFirstArgType)
   {
+    CtxVarIterator& ctxVarIter = static_cast<CtxVarIterator&>(*aArgs[0]);
     const var_expr* inputVar = inputExpr->get_var();
 
     if (inputVar != NULL &&
         !inputVar->is_context_item() &&
-        ctxVarIter->setTargetPosIter(aArgs[1]) &&
-        ctxVarIter->setTargetLenIter(lenExpr ? aArgs[2] : NULL))
+        ctxVarIter.setTargetPosIter(aArgs[1]) &&
+        ctxVarIter.setTargetLenIter(lenExpr ? aArgs[2] : NULL))
     {
       return aArgs[0];
     }
   }
+  else if (typeid(ZorbaCollectionIterator) == lFirstArgType)
+  {
+    // push down position param into collection skip if possible
+    if (rewriteSubsequenceCollection(aSctx, aLoc, aArgs, true /*flag int*/))
+    {
+      // we have rewritten the subsequence to start from the beginning.
+      // if there is no length param we can remove the entire
+      // subsequence function
+      // subsequence(collection(qname, 10),1)
+      //   -> collection(qname, 10)
+      if (aArgs.size() == 2)
+      {
+        return aArgs[0];
+      }
+    }
+  }
 
  done:
   return new SubsequenceIntIterator(aSctx, aLoc, aArgs);

=== modified file 'src/runtime/collections/collections_impl.cpp'
--- src/runtime/collections/collections_impl.cpp	2012-12-14 13:23:51 +0000
+++ src/runtime/collections/collections_impl.cpp	2013-01-22 18:54:32 +0000
@@ -247,7 +247,7 @@
   }
 
   lCount = coll->size();
-  if (theChildren.size() > 1) 
+  if (theChildren.size() == 2) 
   {
     // skip parameter passed
     store::Item_t lSkipItem;
@@ -258,6 +258,14 @@
     // 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);
 

-- 
Mailing list: https://launchpad.net/~zorba-coders
Post to     : zorba-coders@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zorba-coders
More help   : https://help.launchpad.net/ListHelp

Reply via email to