bool MultiDynamicFnCallIterator::nextImpl(
    store::Item_t& result,
    PlanState& planState) const
{
  store::Item_t item;
  store::Item_t targetItem;
  FunctionItem* fnItem;
  zstring key;

  MultiDynamicFnCallIteratorState* state;

  DEFAULT_STACK_INIT(MultiDynamicFnCallIteratorState, state, planState);

  while (consumeNext(targetItem, theChild, planState))
  {
    if (targetItem->isFunction())
    {
      fnItem = static_cast<FunctionItem*>(targetItem.getp());

      if (fnItem->getArity() != 0)
      {
        RAISE_ERROR(err::XPTY0004, loc,
        ERROR_PARAMS("dynamic function invoked with incorrect number of arguments"));
      }

      state->thePlan = fnItem->getImplementation(planState.theCompilerCB);
      
      // must be opened after vars and params are set
      state->thePlan->open(planState, state->theUDFStateOffset);
      state->theIsOpen = true;

      while (consumeNext(result, state->thePlan, planState))
      {
        STACK_PUSH(true, state);
      }

      // Need to close here early in case the plan is completely consumed.
      // Otherwise, the plan would still be opened if destroyed from the
      // state's destructor.
      state->thePlan->close(planState);
      state->theIsOpen = false;
    } // if (targetItem->isFunction())

    else if (targetItem->isJSONItem())
    {
      if (targetItem->isObject())
      {
        if (!state->theKeysSet.get())
          state->theKeysSet.reset(new HashSet<zstring, HashMapZStringCmp>(64, false));

        state->theIterator = targetItem->getObjectKeys();

        state->theIterator->open();

        while (state->theIterator->next(result))
        {
          key = result->getStringValue();

          if (!state->theKeysSet->exists(key))
          {
            state->theKeysSet->insert(key);
            STACK_PUSH(true, state);
          }
        }
      }
      else
      {
        state->theIterator = targetItem->getArrayValues();

        state->theIterator->open();

        while (state->theIterator->next(result))
        {
          STACK_PUSH(true, state);
        }
      }

      state->theIterator->close();
    } // jsoniq item
#if 0
    else if (theSctx->language_kind() == StaticContextConsts::language_kind_xquery)
    {
      xqtref_t type = theSctx->get_typemanager()->create_value_type(targetItem);

      RAISE_ERROR(err::XPTY0004, loc, 
      ERROR_PARAMS(ZED(XPTY0004_NoTypePromote_23),
                   type->toSchemaString(),
                   GENV_TYPESYSTEM.ANY_FUNCTION_TYPE_ONE->toSchemaString()));
    }
#endif
  }

  STACK_END(state);
};
bool SingleDynamicFnCallIterator::nextImpl(
    store::Item_t& result,
    PlanState& planState) const
{
  store::Item_t item;
  store::Item_t targetItem;
  FunctionItem* fnItem;
  store::Item_t selectorItem1;
  store::Item_t selectorItem2;
  store::Item_t selectorItem3;

  SingleDynamicFnCallIteratorState* state;

  DEFAULT_STACK_INIT(SingleDynamicFnCallIteratorState, state, planState);

  // first child must return exactly one item which is a function item
  // otherwise XPTY0004 is raised
  if (!consumeNext(targetItem, theChildren[0], planState) || targetItem == NULL)
  {
    RAISE_ERROR(err::XPTY0004, loc, 
    ERROR_PARAMS(ZED(XPTY0004_NoTypePromote_23),
                 "empty-sequence()",
                 GENV_TYPESYSTEM.ANY_FUNCTION_TYPE_ONE->toSchemaString()));
  }

  if (targetItem->isFunction())
  {
    if (consumeNext(item, theChildren[0], planState))
    {
      RAISE_ERROR(err::XPTY0004, loc, 
      ERROR_PARAMS(ZED(XPTY0004_NoMultiSeqTypePromotion_2),
                   GENV_TYPESYSTEM.ANY_FUNCTION_TYPE_ONE->toSchemaString()));
    }

    fnItem = static_cast<FunctionItem*>(targetItem.getp());

    if (theChildren.size() - 1 != fnItem->getArity())
    {
      RAISE_ERROR(err::XPTY0004, loc,
      ERROR_PARAMS("dynamic function invoked with incorrect number of arguments"));
    }

    if (theIsPartialApply)
    {
      for (csize i = 1, pos = 0; i < theChildren.size(); ++i)
      {
        if (dynamic_cast<ArgumentPlaceholderIterator*>(theChildren[i].getp()) == NULL)
        {
          // The argument needs to be materialized only for local vars and only
          // if the function item is returned and used outside of the current
          // function. It might be impossible to determine if the partially
          // applied function item will be used outside of the current function,
          // so it is quite probable that it always needs to be materialized.          
          std::vector<store::Item_t> argValues;
          store::Item_t tempItem;

          while (consumeNext(tempItem, theChildren[i], planState))
            argValues.push_back(tempItem);

          store::TempSeq_t argSeq = GENV_STORE.createTempSeq(argValues);
          store::Iterator_t argSeqIter = argSeq->getIterator();
          PlanIter_t value = new PlanStateIteratorWrapper(argSeqIter);
                    
          fnItem->setArgumentValue(pos, value);
        }
        else
        {
          ++pos;
        }
      }

      result = fnItem;
      STACK_PUSH(true, state);
    }
    else
    {
      state->thePlan = fnItem->getImplementation(theChildren, planState.theCompilerCB);
      
      // must be opened after vars and params are set
      state->thePlan->open(planState, state->theUDFStateOffset);
      state->theIsOpen = true;

      while (consumeNext(result, state->thePlan, planState))
      {
        STACK_PUSH(true, state);
      }

      // Need to close here early in case the plan is completely consumed.
      // Otherwise, the plan would still be opened if destroyed from the
      // state's destructor.
      state->thePlan->close(planState);
      state->theIsOpen = false;
    } // if (!theIsPartialApply)
  } // if (targetItem->isFunction())

  else if (targetItem->isJSONItem())
  {
    if (theChildren.size() > 2)
    {
      RAISE_ERROR_NO_PARAMS(jerr::JNTY0018, loc);
    }
    else if (theChildren.size() == 2)
    {
      if (consumeNext(selectorItem1, theChildren[1], planState))
      {
        if (consumeNext(item, theChildren[1], planState))
        {
          RAISE_ERROR(err::XPTY0004, loc,
          ERROR_PARAMS(ZED(NoSeqCastToTypeWithQuantOneOrQuestion)));
        }

        // Atomize the selector item
        switch (selectorItem1->getKind())
        {
        case store::Item::ATOMIC:
        {
          selectorItem2.transfer(selectorItem1);
          break;
        }
        case store::Item::NODE:
        {
          store::Iterator_t iter;
          selectorItem1->getTypedValue(selectorItem2, iter);

          if (iter != NULL && iter->next(selectorItem2))
          {
            if (iter->next(item))
            {
              RAISE_ERROR(err::XPTY0004, loc,
              ERROR_PARAMS(ZED(NoSeqCastToTypeWithQuantOneOrQuestion)));
            }
          }

          break;
        }
        case store::Item::OBJECT:
        {
          RAISE_ERROR(jerr::JNTY0004, loc, ERROR_PARAMS("object"));
        }
        case store::Item::ARRAY:
        {
          RAISE_ERROR(jerr::JNTY0004, loc, ERROR_PARAMS("array"));
        }
        case store::Item::FUNCTION:
        {
          store::Item_t fnName = selectorItem1->getFunctionName();
          RAISE_ERROR(err::FOTY0013, loc, 
          ERROR_PARAMS(fnName.getp() ?
                       result->getFunctionName()->getStringValue() :
                       zstring("???")));
        }
        default:
        {
          ZORBA_ASSERT(false);
        }
        }
        
        if (selectorItem2 != NULL)
        {
          if (targetItem->isObject())
          {
            GenericCast::castToBuiltinAtomic(selectorItem3,
                                             selectorItem2,
                                             store::XS_STRING,
                                             NULL,
                                             loc);
        
            result = targetItem->getObjectValue(selectorItem3);
          }
          else
          {
            GenericCast::castToBuiltinAtomic(selectorItem3,
                                             selectorItem2,
                                             store::XS_INTEGER,
                                             NULL,
                                             loc);

            result = targetItem->getArrayValue(selectorItem3->getIntegerValue());
          }

          STACK_PUSH(result != NULL, state);
        }
      } // there is a selector item
    } // 1 argument 
    else // no arguments
    {
      if (targetItem->isObject())
        state->theIterator = targetItem->getObjectKeys();
      else
        state->theIterator = targetItem->getArrayValues();

      state->theIterator->open();

      while (state->theIterator->next(result))
      {
        STACK_PUSH(true, state);
      }

      state->theIterator->close();
    }
  }
#if 0
  else if (theSctx->language_kind() == StaticContextConsts::language_kind_xquery)
  {
    xqtref_t type = theSctx->get_typemanager()->create_value_type(targetItem);

    RAISE_ERROR(err::XPTY0004, loc, 
    ERROR_PARAMS(ZED(XPTY0004_NoTypePromote_23),
                 type->toSchemaString(),
                 GENV_TYPESYSTEM.ANY_FUNCTION_TYPE_ONE->toSchemaString()));
  }
#endif

  STACK_END(state);
};