← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/index-maintenance into lp:zorba

 

Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/index-maintenance into lp:zorba.

Requested reviews:
  Markos Zaharioudakis (markos-za)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/index-maintenance/+merge/114682

Incremental maintenance for general indexes.
-- 
https://code.launchpad.net/~zorba-coders/zorba/index-maintenance/+merge/114682
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2012-07-12 15:34:50 +0000
+++ ChangeLog	2012-07-12 16:38:27 +0000
@@ -15,7 +15,8 @@
     http://www.zorba-xquery.com/modules/store/data-structures/unordered-map module.
   * Added support for fragments to fn:path
   * Positional pagination support for collections
-
+  * Incremental maintenance for general indexes.
+	
 Optimizations:
   * Small optimization of comparison operations.
   * Improved hoist rule: tighter hoisting of expressions (also fixes bug #967428,

=== modified file 'src/compiler/xqddf/value_index.cpp'
--- src/compiler/xqddf/value_index.cpp	2012-07-11 04:46:41 +0000
+++ src/compiler/xqddf/value_index.cpp	2012-07-12 16:38:27 +0000
@@ -295,7 +295,7 @@
   if (theIsGeneral && numKeys > 1)
   {
     RAISE_ERROR(zerr::ZDST0035_INDEX_GENERAL_MULTIKEY, theKeyExprs[1]->get_loc(),
-		ERROR_PARAMS(theName->getStringValue()));
+    ERROR_PARAMS(theName->getStringValue()));
   }
 
   // Check constraints on the key exprs
@@ -579,7 +579,7 @@
 
   if (theDocIndexerPlan != NULL)
   {
-    theDocIndexer = new DocIndexer(numKeys, theDocIndexerPlan, docVarName);
+    theDocIndexer = new DocIndexer(isGeneral(), numKeys, theDocIndexerPlan, docVarName);
 
     return theDocIndexer.getp();
   }
@@ -689,7 +689,7 @@
   //
   // Create theDocIndexer obj
   //
-  theDocIndexer = new DocIndexer(numKeys, theDocIndexerPlan, docVarName);
+  theDocIndexer = new DocIndexer(isGeneral(), numKeys, theDocIndexerPlan, docVarName);
 
   return theDocIndexer.getp();
 }

=== modified file 'src/functions/func_index_ddl.cpp'
--- src/functions/func_index_ddl.cpp	2012-07-11 04:46:41 +0000
+++ src/functions/func_index_ddl.cpp	2012-07-12 16:38:27 +0000
@@ -97,7 +97,8 @@
   std::vector<PlanIter_t>& argv,
   expr& ann) const
 {
-  return new GeneralIndexEntryBuilderIterator(sctx, loc, argv);
+  assert(argv.size() == 2);
+  return new GeneralIndexEntryBuilderIterator(sctx, loc, argv[0], argv[1]);
 }
 
 
@@ -158,7 +159,7 @@
   DECL(sctx, op_general_index_entry_builder,
        (createQName(zorba_op_ns, "", "general-index-entry-builder"),
         GENV_TYPESYSTEM.ANY_NODE_TYPE_ONE,
-        true,
+        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
         GENV_TYPESYSTEM.ITEM_TYPE_STAR));
 
   DECL(sctx, op_create_internal_index,

=== modified file 'src/functions/func_index_ddl.h'
--- src/functions/func_index_ddl.h	2012-07-11 04:46:41 +0000
+++ src/functions/func_index_ddl.h	2012-07-12 16:38:27 +0000
@@ -121,7 +121,7 @@
 
 
 /*******************************************************************************
-  op:value-index-entry-builder($node as node(), .....)
+  op:value-index-entry-builder($node as node(), xs:anyAtomic?, ..., xs:anyAtomic?)
 
   This is a variadic function. The 1st input is a domain node, and the rest of
   the inputs are the key items that comprise the key tuple for that node
@@ -144,7 +144,7 @@
 
 
 /*******************************************************************************
-  op:general-index-entry-builder($node as node(), .....)
+  op:general-index-entry-builder($node as node(), xs:anyAtomic*)
 ********************************************************************************/
 class op_general_index_entry_builder : public function
 {
@@ -157,7 +157,7 @@
 
   bool accessesDynCtx() const { return true; }
 
-  bool mustCopyInputNodes(expr* fo, csize input) const {  return false;  }
+  bool mustCopyInputNodes(expr* fo, csize input) const { return false; }
 
   CODEGEN_DECL();
 };

=== modified file 'src/runtime/core/apply_updates.cpp'
--- src/runtime/core/apply_updates.cpp	2012-07-11 04:46:41 +0000
+++ src/runtime/core/apply_updates.cpp	2012-07-12 16:38:27 +0000
@@ -37,6 +37,8 @@
 
 #include "common/shared_types.h"
 
+#include "diagnostics/util_macros.h"
+
 
 namespace zorba 
 {
@@ -154,21 +156,18 @@
   // maintained incrementally, and pass this info back to the pul.
   pul->getIndicesToRefresh(indexes, truncate_indexes);
 
-  ulong numIndices = (ulong)indexes.size();
+  csize numIndices = indexes.size();
 
   std::vector<IndexDecl*> zorbaIndexes(numIndices); 
 
-  for (ulong i = 0; i < numIndices; ++i)
+  for (csize i = 0; i < numIndices; ++i)
   {
     IndexDecl* indexDecl = sctx->lookup_index(indexes[i]->getName());
     
     if (indexDecl == NULL)
     {
-      throw XQUERY_EXCEPTION(
-        zerr::ZDDY0021_INDEX_NOT_DECLARED,
-        ERROR_PARAMS( indexes[i]->getName()->getStringValue() ),
-        ERROR_LOC( loc )
-      );
+      RAISE_ERROR(zerr::ZDDY0021_INDEX_NOT_DECLARED, loc,
+      ERROR_PARAMS(indexes[i]->getName()->getStringValue()));
     }
 
     if (indexDecl->getMaintenanceMode() == IndexDecl::DOC_MAP)
@@ -184,8 +183,8 @@
     zorbaIndexes[i] = indexDecl;
   }
 
-  numIndices = (ulong)truncate_indexes.size();
-  for (ulong i = 0; i < numIndices; ++i)
+  numIndices = truncate_indexes.size();
+  for (csize i = 0; i < numIndices; ++i)
   {
     IndexDecl* indexDecl = sctx->lookup_index(indexes[i]->getName());
 
@@ -233,17 +232,15 @@
   }
   catch (XQueryException& e)
   {
-    if ( e.has_source() &&
-         ( e.diagnostic() == err::XUDY0021 ||
-           e.diagnostic() == err::XUDY0015 ||
-           e.diagnostic() == err::XUDY0016 ||
-           e.diagnostic() == err::XUDY0017 ||
-           e.diagnostic() == err::XUDY0014 ) ) 
+    if (e.has_source() &&
+        (e.diagnostic() == err::XUDY0021 ||
+         e.diagnostic() == err::XUDY0015 ||
+         e.diagnostic() == err::XUDY0016 ||
+         e.diagnostic() == err::XUDY0017 ||
+         e.diagnostic() == err::XUDY0014)) 
     {
-      XQueryException lNewE = XQUERY_EXCEPTION(
-        err::XUDY0021,
-        ERROR_PARAMS(ZED(XUDY0021_AppliedAt), loc)
-      );
+      XQueryException lNewE = 
+      XQUERY_EXCEPTION(err::XUDY0021, ERROR_PARAMS(ZED(XUDY0021_AppliedAt), loc));
 
       QueryLoc lLoc;
       lLoc.setFilename(e.source_uri());

=== modified file 'src/runtime/indexing/doc_indexer.cpp'
--- src/runtime/indexing/doc_indexer.cpp	2012-07-11 04:46:41 +0000
+++ src/runtime/indexing/doc_indexer.cpp	2012-07-12 16:38:27 +0000
@@ -33,8 +33,13 @@
 /*******************************************************************************
 
 ********************************************************************************/
-DocIndexer::DocIndexer(csize numColumns, PlanIterator* plan, store::Item* varName)
+DocIndexer::DocIndexer(
+    bool general,
+    csize numColumns,
+    PlanIterator* plan,
+    store::Item* varName)
   :
+  theIsGeneral(general),
   theNumColumns(numColumns),
   theIndexerPlan(plan),
   theNodeVarName(varName),
@@ -81,41 +86,80 @@
   store::Item_t tmp = docNode;
   theDctx->set_variable(theNodeVarId, theNodeVarName, QueryLoc::null, tmp);
 
-  csize numEntries = delta.size();
   store::Item_t domainNode;
-  store::IndexKey* key = NULL;
 
   try
   {
-    while (thePlanWrapper->next(domainNode))
+    if (theIsGeneral)
     {
-      key = new store::IndexKey(theNumColumns);
-
-      //std::cout << domainNode.getp() << "  " << key << std::endl;
-
-      for (csize i = 0; i < theNumColumns; ++i)
+      if (thePlanWrapper->next(domainNode))
       {
-        if (!thePlanWrapper->next((*key)[i]))
-          throw ZORBA_EXCEPTION(zerr::ZXQP0003_INTERNAL_ERROR,
-          ERROR_PARAMS(ZED(IncompleteKeyInIndexRefresh)));
+        store::Item_t key;
+        bool more = true;
+
+        while (more)
+        {
+          assert(domainNode->isNode());
+
+          while ((more = thePlanWrapper->next(key)))
+          {
+            if (key->isNode())
+            {
+              domainNode.transfer(key);
+              break;
+            }
+
+            store::Item_t node = domainNode;
+            delta.addGeneralPair(node, key);
+          }
+        }
       }
+    }
+    else
+    {
+      store::IndexKey* key = NULL;
+
+      //std::cout << "Computing value index delta" << std::endl;
+
+      try
+      {
+        while (thePlanWrapper->next(domainNode))
+        {
+          key = new store::IndexKey(theNumColumns);
+
+          for (csize i = 0; i < theNumColumns; ++i)
+          {
+            if (!thePlanWrapper->next((*key)[i]))
+            {
+              throw ZORBA_EXCEPTION(zerr::ZXQP0003_INTERNAL_ERROR,
+              ERROR_PARAMS(ZED(IncompleteKeyInIndexRefresh)));
+            }
+          }
       
-      delta.resize(numEntries + 1);
-      delta[numEntries].first.transfer(domainNode); 
-      delta[numEntries].second = key;
-      key = NULL;
-      ++numEntries;
+          /*
+          std::cout << "[ node: " << domainNode.getp()
+                    << " , key: " << key
+                    << " , keyval: " << (*key)[0]->getStringValue()
+                    << " ]" << std::endl;
+          */
+          delta.addValuePair(domainNode, key);
+          key = NULL;
+        }
+
+        //std::cout << std::endl;
+      }
+      catch(...)
+      {
+        if (key != NULL)
+          delete key;
+
+        throw;
+      }
     }
   }
   catch(...)
   {
-    if (key != NULL)
-      delete key;
-
-    for (ulong i = 0; i < delta.size(); ++i)
-    {
-      delete delta[i].second;
-    }
+    delta.clear();
 
     theDctx->unset_variable(theNodeVarId, theNodeVarName, QueryLoc::null);
 

=== modified file 'src/runtime/indexing/doc_indexer.h'
--- src/runtime/indexing/doc_indexer.h	2012-07-11 04:46:41 +0000
+++ src/runtime/indexing/doc_indexer.h	2012-07-12 16:38:27 +0000
@@ -26,11 +26,13 @@
 
 
 /*******************************************************************************
-
+  See IndexEntryCreator class in store/api/index.h
 ********************************************************************************/
 class DocIndexer : public store::IndexEntryCreator
 {
 protected:
+  bool                theIsGeneral;
+
   csize               theNumColumns;
 
   PlanIter_t          theIndexerPlan;
@@ -42,7 +44,11 @@
   store::Iterator_t   thePlanWrapper;
   
 public:
-  DocIndexer(csize numColumns, PlanIterator* plan, store::Item* varName);
+  DocIndexer(
+      bool general,
+      csize numColumns,
+      PlanIterator* plan,
+      store::Item* varName);
 
   ~DocIndexer();
 

=== modified file 'src/runtime/indexing/index_ddl.cpp'
--- src/runtime/indexing/index_ddl.cpp	2012-07-11 04:46:41 +0000
+++ src/runtime/indexing/index_ddl.cpp	2012-07-12 16:38:27 +0000
@@ -471,27 +471,15 @@
   GeneralIndexEntryBuilderIterator
 ********************************************************************************/
 
-GeneralIndexEntryBuilderIteratorState::GeneralIndexEntryBuilderIteratorState() 
-{
-}
-
-
-GeneralIndexEntryBuilderIteratorState::~GeneralIndexEntryBuilderIteratorState() 
-{
-}
-
-
-void GeneralIndexEntryBuilderIteratorState::init(PlanState& planState) 
-{
-  PlanIteratorState::init(planState);
-  theCurChild = 0;
-}
-
-
-void GeneralIndexEntryBuilderIteratorState::reset(PlanState& planState) 
-{
-  PlanIteratorState::reset(planState);
-  theCurChild = 0;
+GeneralIndexEntryBuilderIterator::GeneralIndexEntryBuilderIterator(
+    static_context* sctx,
+    const QueryLoc& loc,
+    PlanIter_t& child0,
+    PlanIter_t& child1)
+  : 
+  BinaryBaseIterator<GeneralIndexEntryBuilderIterator,
+                     PlanIteratorState>(sctx, loc, child0, child1)
+{
 }
 
 
@@ -500,38 +488,36 @@
 }
 
 
+void GeneralIndexEntryBuilderIterator::serialize(::zorba::serialization::Archiver& ar)
+{
+  serialize_baseclass(ar,
+  (BinaryBaseIterator<GeneralIndexEntryBuilderIterator,
+                      PlanIteratorState>*)this);
+}
+
+
 bool GeneralIndexEntryBuilderIterator::nextImpl(
     store::Item_t& result,
     PlanState& planState) const
 {
-  GeneralIndexEntryBuilderIteratorState* state;
-  DEFAULT_STACK_INIT(GeneralIndexEntryBuilderIteratorState, state, planState);
-
-  for (; state->theCurChild < theChildren.size(); ++state->theCurChild) 
+  PlanIteratorState* state;
+  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
+
+  consumeNext(result, theChild0.getp(), planState);
+  ZORBA_ASSERT(result);
+
+  STACK_PUSH(true, state);
+
+  while (consumeNext(result, theChild1.getp(), planState))
   {
-    while (consumeNext(result, theChildren[state->theCurChild].getp(), planState))
-    {
-      STACK_PUSH(true, state);
-    }
+    STACK_PUSH(true, state);
   }
   
   STACK_END(state);
 }
 
 
-void GeneralIndexEntryBuilderIterator::accept(PlanIterVisitor& v) const 
-{
-  v.beginVisit(*this);
-
-  std::vector<PlanIter_t>::const_iterator lIter = theChildren.begin();
-  std::vector<PlanIter_t>::const_iterator lEnd = theChildren.end();
-  for ( ; lIter != lEnd; ++lIter )
-  {
-    (*lIter)->accept(v);
-  }
-
-  v.endVisit(*this);
-}
+BINARY_ACCEPT(GeneralIndexEntryBuilderIterator)
 
 
 /*******************************************************************************

=== modified file 'src/runtime/indexing/index_ddl.h'
--- src/runtime/indexing/index_ddl.h	2012-07-11 04:46:41 +0000
+++ src/runtime/indexing/index_ddl.h	2012-07-12 16:38:27 +0000
@@ -19,9 +19,9 @@
 
 
 #include "common/shared_types.h"
+
 #include "runtime/base/unarybase.h"
-
-
+#include "runtime/base/binarybase.h"
 #include "runtime/base/narybase.h"
 
 
@@ -231,12 +231,12 @@
 
 
 /******************************************************************************
-
+  zorba-op:value-index-entry-builder(node(), xs:anyAtomic)
 *******************************************************************************/
 class ValueIndexEntryBuilderIteratorState : public PlanIteratorState
 {
 public:
-  uint32_t theCurChild;
+  csize theCurChild;
 
 public:
   ValueIndexEntryBuilderIteratorState();
@@ -283,50 +283,25 @@
 
 
 /******************************************************************************
-
+  zorba-op:general-index-entry-builder(node(), xs:anyAtomic*)
 *******************************************************************************/
-class GeneralIndexEntryBuilderIteratorState : public PlanIteratorState
-{
-public:
-  uint32_t theCurChild;
-
-public:
-  GeneralIndexEntryBuilderIteratorState();
-
-  ~GeneralIndexEntryBuilderIteratorState();
-
-  void init(PlanState&);
-
-  void reset(PlanState&);
-};
-
-
 class GeneralIndexEntryBuilderIterator :
-public NaryBaseIterator<GeneralIndexEntryBuilderIterator, 
-                        GeneralIndexEntryBuilderIteratorState>
+public BinaryBaseIterator<GeneralIndexEntryBuilderIterator, 
+                          PlanIteratorState>
 { 
 public:
   SERIALIZABLE_CLASS(GeneralIndexEntryBuilderIterator);
-
   SERIALIZABLE_CLASS_CONSTRUCTOR2T(GeneralIndexEntryBuilderIterator,
-  NaryBaseIterator<GeneralIndexEntryBuilderIterator,
-                   GeneralIndexEntryBuilderIteratorState>);
-
-  void serialize( ::zorba::serialization::Archiver& ar)
-  {
-    serialize_baseclass(ar,
-    (NaryBaseIterator<GeneralIndexEntryBuilderIterator,
-                      GeneralIndexEntryBuilderIteratorState>*)this);
-  }
-
+  BinaryBaseIterator<GeneralIndexEntryBuilderIterator,
+                     PlanIteratorState>);
+  void serialize(::zorba::serialization::Archiver& ar);
+
+public:
   GeneralIndexEntryBuilderIterator(
-    static_context* sctx,
-    const QueryLoc& loc,
-    std::vector<PlanIter_t>& children)
-    : 
-    NaryBaseIterator<GeneralIndexEntryBuilderIterator,
-                     GeneralIndexEntryBuilderIteratorState>(sctx, loc, children)
-  {}
+      static_context* sctx,
+      const QueryLoc& loc,
+      PlanIter_t& child0,
+      PlanIter_t& child1);
 
   virtual ~GeneralIndexEntryBuilderIterator();
 

=== modified file 'src/store/api/index.h'
--- src/store/api/index.h	2012-07-11 04:46:41 +0000
+++ src/store/api/index.h	2012-07-12 16:38:27 +0000
@@ -90,7 +90,7 @@
 class IndexSpecification
 {
 public:
-  ulong                          theNumKeyColumns;
+  csize                          theNumKeyColumns;
   std::vector<store::Item_t>     theKeyTypes;
   std::vector<std::string>       theCollations;
   long                           theTimezone;
@@ -126,14 +126,14 @@
     theIsGeneral = theIsUnique = theIsSorted = theIsTemp = theIsThreadSafe = false;
   }
 
-  void resize(ulong numColumns)
+  void resize(csize numColumns)
   {
     theNumKeyColumns = numColumns;
     theKeyTypes.resize(numColumns);
     theCollations.resize(numColumns);
   }
 
-  ulong getNumColumns() const { return theNumKeyColumns; }
+  csize getNumColumns() const { return theNumKeyColumns; }
 
   long getTimezone() const { return theTimezone; }
 };
@@ -145,14 +145,38 @@
 class IndexKey : public ItemVector
 {
 public:
-  IndexKey(ulong size = 0) : ItemVector(size) {}
+  IndexKey(csize size = 0) : ItemVector(size) {}
 };
 
 
 /**************************************************************************//**
-  An index delta is a set of [domain-node, associated-key] pairs.
+  A index delta is a set of [domain-node, associated-key(s)] pairs.
 *******************************************************************************/
-typedef std::vector<std::pair<store::Item_t, store::IndexKey*> > IndexDelta;
+class IndexDelta
+{
+public:
+  typedef std::pair<Item_t, IndexKey*> ValuePair;
+
+  typedef std::vector<ValuePair> ValueDelta;
+
+  typedef std::pair<Item_t, Item_t> GeneralPair;
+
+  typedef std::vector<GeneralPair> GeneralDelta;
+
+protected:
+  ValueDelta       theValueDelta;
+  GeneralDelta     theGeneralDelta;
+
+public:
+  void addValuePair(Item_t& node, IndexKey* key);
+
+  void addGeneralPair(Item_t& node, Item_t& key);
+
+  void clear();
+
+protected:
+  IndexDelta() {}
+};
 
 
 /***************************************************************************//**
@@ -388,7 +412,7 @@
   /**
    *  Return the number of columns in the jeys of this index.
    */
-  virtual ulong getNumColumns() const = 0;
+  virtual csize getNumColumns() const = 0;
 
   /**
    * Return the timezone that is used when comparing date-time related items
@@ -399,7 +423,7 @@
    *  Return pointer to the collator used by this index when comparing items at
    *  its i-th column (return NULL if no collator is used for the i-th column).
    */
-  virtual const XQPCollator* getCollator(ulong i) const = 0;
+  virtual const XQPCollator* getCollator(csize i) const = 0;
 
   /**
    * Create an index condition (see class IndexCondition below)
@@ -409,7 +433,7 @@
   /**
    * Returns the number of entries in the index
    */
-  virtual ulong size() const = 0;
+  virtual csize size() const = 0;
 
   /**
    * Returns all keys stored in this index
@@ -423,23 +447,34 @@
    * The index wil take the ownership of the key if it was not already in the
    * index.
    *
+   * NOTE: this method is needed here because it is invoked from the
+   * UDFunctionCallIterator to implement the function cache.
+   *
    * @error ZDDY0035 if a key with more than one item is inserted into
    *  a general index
    */
   virtual bool insert(store::IndexKey*& key, store::Item_t& item) = 0;
 
   virtual bool remove(
-        const store::IndexKey* key,
-        const store::Item_t& item,
-        bool all = false) = 0;
+      const store::IndexKey* key,
+      const store::Item_t& item,
+      bool all = false) = 0;
 };
 
 
 
 /*******************************************************************************
- An abstract class that provides a callback method for the store to call in order
- to perform index maintenance.  The method computes [domain_item, associated-key]
- pairs for a given node that has some relationship to the domain expression.
+  An abstract class that provides a callback method for the store to call during
+  index maintenance. The method computes [domain_node, associated-key] pairs for
+  a given node that has some relationship to the domain expression.
+
+  Instances of IndexEntryCreator are created by the ApplyIterator for each
+  incrementally-maintenable index that needs maintenance. Such an instance is
+  stored inside the IndexDecl of the associated index, so that it can be
+  reused every time the index needs maintenance.
+
+  A concrete implementation of this class is provided in 
+  runtime/index/doc_indexer.h
 ********************************************************************************/
 class IndexEntryCreator : public SimpleRCObject
 {

=== modified file 'src/store/naive/atomic_items.cpp'
--- src/store/naive/atomic_items.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/atomic_items.cpp	2012-07-12 16:38:27 +0000
@@ -245,7 +245,21 @@
 
     xs_long longValue = static_cast<xs_long>(doubleValue.getNumber());
 
+    /*
+    std::cout << "original long value = " << item->theValue << std::endl
+              << "double value        = " << doubleValue << std::endl
+              << "new long value      = " << longValue << std::endl << std::endl;
+    
+    */
     lossy = (longValue != item->theValue);
+
+    /*    
+    std::cout << "original long value = " << item->theValue << std::endl
+              << "double value        = " << doubleValue << std::endl
+              << "new long value      = " << longValue << std::endl << std::endl;
+    */
+    std::cout << "lossy = " << lossy << std::endl << std::endl;
+    
     break;
   }
 

=== modified file 'src/store/naive/item.cpp'
--- src/store/naive/item.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/item.cpp	2012-07-12 16:38:27 +0000
@@ -19,6 +19,8 @@
 
 #include <zorba/error.h>
 #include "diagnostics/xquery_diagnostics.h"
+#include "diagnostics/assert.h"
+
 #include "zorbatypes/datetime.h"
 
 #include "store/api/item.h"
@@ -32,6 +34,9 @@
 
 #include "runtime/function_item/function_item.h"
 
+# include <cstdlib>
+# include <execinfo.h>
+
 
 namespace zorba
 {
@@ -490,11 +495,50 @@
 }
 
 
+static void print_stack_trace( std::ostream& o ) 
+{
+  int BUF_SIZE = 250;
+  void* buf[ BUF_SIZE ];
+
+  int const size = backtrace(buf, BUF_SIZE);
+
+  if (char** symbols = backtrace_symbols(buf, size)) 
+  {
+    for ( int i = 0; i < size; ++i )
+      o << symbols[i] << std::endl;
+
+    free( symbols );
+  }
+  else
+  {
+    o << "allocation of backtrace symbols failed" << std::endl;
+  }
+}
+
+
 /**
  * Accessor for xs:untypedAtomic and xs:string and its subtypes
  */
 const zstring& Item::getString() const
 {
+  if (isAtomic())
+  {
+    std::cerr << "Atomic item value: " << getStringValue() << std::endl;
+  }
+  else if (isNode())
+  {
+    std::cerr << "Node item: " << this << std::endl
+              << " node name: " << getNodeName()->getStringValue() << std::endl
+              << " node string value: " << getStringValue() << std::endl;
+  }
+  else
+  {
+    std::cerr << "???????" << std::endl;
+  }
+
+  
+  print_stack_trace(std::cerr);
+
   throw ZORBA_EXCEPTION(
     zerr::ZSTR0040_TYPE_ERROR,
     ERROR_PARAMS(

=== modified file 'src/store/naive/simple_index.cpp'
--- src/store/naive/simple_index.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index.cpp	2012-07-12 16:38:27 +0000
@@ -594,7 +594,60 @@
 }
 
 
-}
+} // namespace simplestore
+
+
+namespace store 
+{
+
+/////////////////////////////////////////////////////////////////////////////////
+//                                                                             //
+//  IndexDelta                                                                 //
+//                                                                             //
+/////////////////////////////////////////////////////////////////////////////////
+
+/*******************************************************************************
+
+********************************************************************************/
+void IndexDelta::addValuePair(store::Item_t& node, store::IndexKey* key)
+{
+  theValueDelta.resize(theValueDelta.size() + 1);
+  theValueDelta.back().first.transfer(node);
+  theValueDelta.back().second = key;
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void IndexDelta::addGeneralPair(store::Item_t& node, store::Item_t& key)
+{
+  assert(node->isNode() && key->isAtomic());
+
+  theGeneralDelta.resize(theGeneralDelta.size() + 1);
+  theGeneralDelta.back().first.transfer(node);
+  theGeneralDelta.back().second.transfer(key);
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void IndexDelta::clear()
+{
+  for (csize i = 0; i < theValueDelta.size(); ++i)
+  {
+    delete theValueDelta[i].second;
+  }
+
+  theValueDelta.clear();
+  theGeneralDelta.clear();
+}
+
+
+} // namespace store
+
+
 }
 
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/store/naive/simple_index.h'
--- src/store/naive/simple_index.h	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index.h	2012-07-12 16:38:27 +0000
@@ -59,13 +59,13 @@
 
   const store::IndexSpecification& getSpecification() const { return theSpec; }
 
-  ulong getNumColumns() const { return theSpec.getNumColumns(); }
+  csize getNumColumns() const { return theSpec.getNumColumns(); }
 
   long getTimezone() const { return theSpec.theTimezone; }
 
   const std::vector<std::string>& getCollations() const { return theSpec.theCollations; }
 
-  virtual ulong size() const = 0;
+  virtual csize size() const = 0;
 
   virtual KeyIterator_t keys() const = 0;
 
@@ -298,7 +298,7 @@
   {
   }
 
-  ulong numRanges() const { return theLowerBounds.size(); }
+  csize numRanges() const { return theLowerBounds.size(); }
 
   void clear();
 
@@ -319,6 +319,33 @@
 std::ostream& operator<<(std::ostream& os, const IndexBoxValueCondition& cond);
 
 
+/**************************************************************************//**
+  A index delta is a set of [domain-node, associated-key(s)] pairs.
+*******************************************************************************/
+class IndexDeltaImpl : public store::IndexDelta 
+{
+public:
+  typedef std::vector<store::IndexDelta::ValuePair>::iterator
+  ValueIterator;
+
+  typedef std::vector<store::IndexDelta::ValuePair>::reverse_iterator
+  ReverseValueIterator;
+
+  typedef std::vector<store::IndexDelta::GeneralPair>::iterator
+  GeneralIterator;
+
+  typedef std::vector<store::IndexDelta::GeneralPair>::reverse_iterator
+  ReverseGeneralIterator;
+
+public:
+  IndexDeltaImpl() { }
+
+  ValueDelta& getValueDelta() { return theValueDelta; }
+
+  GeneralDelta& getGeneralDelta() { return theGeneralDelta; }
+};
+
+
 }
 }
 

=== modified file 'src/store/naive/simple_index_general.cpp'
--- src/store/naive/simple_index_general.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index_general.cpp	2012-07-12 16:38:27 +0000
@@ -156,6 +156,27 @@
 /******************************************************************************
 
 *******************************************************************************/
+bool GeneralIndexValue::removeNode(const store::Item_t& node)
+{
+  GeneralIndexValue::iterator ite = theNodes.begin();
+  GeneralIndexValue::iterator end = theNodes.end();
+
+  for (; ite != end; ++ite)
+  {
+    if ((*ite).theNode == node)
+    {
+      theNodes.erase(ite);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+/******************************************************************************
+
+*******************************************************************************/
 void GeneralIndexValue::addNode(store::Item_t& node, bool untyped)
 {
   csize numNodes = theNodes.size();
@@ -191,8 +212,8 @@
   IndexImpl(qname, spec),
   theKeyTypeCode(store::XS_LAST),
   theCompFunction(spec.theTimezone, spec.theCollations[0]),
-  theUntypedFlag(false),
-  theMultiKeyFlag(false)
+  theNumUntypedEntries(0),
+  theNumMultiKeyNodes(0)
 {
   store::Item* typeName = spec.theKeyTypes[0].getp();
 
@@ -216,7 +237,7 @@
 /******************************************************************************
 
 *******************************************************************************/
-const XQPCollator* GeneralIndex::getCollator(ulong i) const
+const XQPCollator* GeneralIndex::getCollator(csize i) const
 {
   ZORBA_ASSERT(i == 0);
   return theCompFunction.getCollator();
@@ -226,7 +247,7 @@
 /******************************************************************************
 
 *******************************************************************************/
-ulong GeneralIndex::size() const
+csize GeneralIndex::size() const
 {
   assert(false);
   return 0;
@@ -348,6 +369,7 @@
   {
     // try lossless cast to xs:long
     keyItem->castToLong(castItem);
+
     if (castItem != NULL)
     {
       keyItem = static_cast<AtomicItem*>(castItem.getp());
@@ -363,7 +385,8 @@
     if (lossy)
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DECIMAL, false);
+      if (insertInMap(castItem, node2, store::XS_DECIMAL, false))
+        found = true;
     }
 
     return found;
@@ -389,10 +412,18 @@
 
       if (lossy)
       {
+        /*
+        std::cout << "Lossy LONG insertion in index" << getName()->getStringValue()
+                  << std::endl
+                  << "long value = " << longValue
+                  << " double value = " << castItem->getDoubleValue()
+                  << std::endl << std::endl;
+        */
         node2 = node;
         found = insertInMap(key, node2, store::XS_LONG, false);
 
-        found = found || insertInMap(castItem, node, store::XS_DOUBLE, false);
+        if (insertInMap(castItem, node, store::XS_DOUBLE, false))
+          found = true;
       }
       else
       {
@@ -440,7 +471,8 @@
       xs_long longValue = longItem->getLongValue();
 
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_LONG, true);
+      if (insertInMap(castItem, node2, store::XS_LONG, true))
+        found = true;
 
       if (longValue > theMaxLong || longValue < theMinLong)
       {
@@ -458,7 +490,8 @@
         if (lossy)
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_DOUBLE, true);
+          if (insertInMap(castItem, node2, store::XS_DOUBLE, true))
+            found = true;
         }
       }
 
@@ -468,19 +501,22 @@
         if (untypedItem->castToGYear(castItem))
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_GYEAR, true);
+          if (insertInMap(castItem, node2, store::XS_GYEAR, true))
+            found = true;
         }
 
         if (untypedItem->castToHexBinary(castItem))
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_HEXBINARY, true);
+          if (insertInMap(castItem, node2, store::XS_HEXBINARY, true))
+            found = true;
         }
 
         if (untypedItem->castToBase64Binary(castItem))
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_BASE64BINARY, true);
+          if (insertInMap(castItem, node2, store::XS_BASE64BINARY, true))
+            found = true;
         }
       }
     }
@@ -494,13 +530,15 @@
       decimalItem->coerceToDouble(castItem, true, lossy);
 
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DOUBLE, true);
+      if (insertInMap(castItem, node2, store::XS_DOUBLE, true))
+        found = true;
 
       if (lossy)
       {
         castItem.transfer(decimalItem);
         node2 = node;
-        found = found || insertInMap(castItem, node2, store::XS_DECIMAL, true);
+        if (insertInMap(castItem, node2, store::XS_DECIMAL, true))
+          found = true;
       }
 
       // may also be hexBinary or base64Binary
@@ -509,13 +547,15 @@
         if (untypedItem->castToHexBinary(castItem))
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_HEXBINARY, true);
+          if (insertInMap(castItem, node2, store::XS_HEXBINARY, true))
+            found = true;
         }
 
         if (untypedItem->castToBase64Binary(castItem))
         {
           node2 = node;
-          found = found || insertInMap(castItem, node2, store::XS_BASE64BINARY, true);
+          if (insertInMap(castItem, node2, store::XS_BASE64BINARY, true))
+            found = true;
         }
       }
     }
@@ -524,77 +564,88 @@
     else if (untypedItem->castToDouble(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DOUBLE, true);
+      if (insertInMap(castItem, node2, store::XS_DOUBLE, true))
+        found = true;
     }
 
     // try casting to xs:datetime
     else if (untypedItem->castToDateTime(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DATETIME, true);
+      if (insertInMap(castItem, node2, store::XS_DATETIME, true))
+        found = true;
     }
 
     // try casting to xs:date
     else if (untypedItem->castToDate(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DATE, true);
+      if (insertInMap(castItem, node2, store::XS_DATE, true))
+        found = true;
     }
 
     // try casting to xs:time
     else if (untypedItem->castToTime(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_TIME, true);
+      if (insertInMap(castItem, node2, store::XS_TIME, true))
+        found = true;
     }
 
     // try casting to xs:gYearMonth
     if (!sorted && untypedItem->castToGYearMonth(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_GYEAR_MONTH, true);
+      if (insertInMap(castItem, node2, store::XS_GYEAR_MONTH, true))
+        found = true;
     }
 
     // try casting to xs:gMonthDay
     else if (!sorted && untypedItem->castToGMonthDay(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_GMONTH_DAY, true);
+      if (insertInMap(castItem, node2, store::XS_GMONTH_DAY, true))
+        found = true;
     }
 
     // try casting to xs:gDay
     else if (!sorted && untypedItem->castToGDay(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_GDAY, true);
+      if (insertInMap(castItem, node2, store::XS_GDAY, true))
+        found = true;
     }
 
     // try casting to xs:gMonth
     else if (!sorted && untypedItem->castToGMonth(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_GMONTH, true);
+      if (insertInMap(castItem, node2, store::XS_GMONTH, true))
+        found = true;
     }
 
     // try casting to xs:duration
     else if (untypedItem->castToDuration(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_DURATION, true);
+      if (insertInMap(castItem, node2, store::XS_DURATION, true))
+        found = true;
     }
 
     // try casting to xs:hexBinary
     else if (!sorted && untypedItem->castToHexBinary(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_HEXBINARY, true);
+      if (insertInMap(castItem, node2, store::XS_HEXBINARY, true))
+        found = true;
     }
 
     // try casting to xs:base64Binary
     else if (!sorted && untypedItem->castToBase64Binary(castItem))
     {
       node2 = node;
-      found = found || insertInMap(castItem, node2, store::XS_BASE64BINARY, true);
+      if (insertInMap(castItem, node2, store::XS_BASE64BINARY, true))
+        found = true;
     }
 
     return found;
@@ -620,17 +671,420 @@
     bool untyped)
 {
   if (untyped)
-    theUntypedFlag = true;
-
-  if (isSorted())
-  {
-    GeneralTreeIndex* idx = static_cast<GeneralTreeIndex*>(this);
-    return idx->insertInMap(key, node, idx->theMaps[targetMap], untyped);
-  }
-  else
-  {
-    GeneralHashIndex* idx = static_cast<GeneralHashIndex*>(this);
-    return idx->insertInMap(key, node, idx->theMaps[targetMap], untyped);
+    ++theNumUntypedEntries;
+
+  if (isSorted())
+  {
+    GeneralTreeIndex* idx = static_cast<GeneralTreeIndex*>(this);
+    return idx->insertInMap(key, node, idx->theMaps[targetMap], untyped);
+  }
+  else
+  {
+    GeneralHashIndex* idx = static_cast<GeneralHashIndex*>(this);
+    return idx->insertInMap(key, node, idx->theMaps[targetMap], untyped);
+  }
+}
+
+
+/******************************************************************************
+
+*******************************************************************************/
+bool GeneralIndex::remove(const store::Item_t& key, const store::Item_t& node)
+{
+  bool lossy = false;
+  bool found = false;
+  store::Item_t castItem;
+
+  bool sorted = isSorted();
+
+  AtomicItem* keyItem = static_cast<AtomicItem*>(key.getp());
+
+  if (keyItem == NULL)
+  {
+    std::vector<store::Item_t>::iterator ite =
+    std::find(theEmptyKeyNodes.begin(), theEmptyKeyNodes.end(), node);
+
+    ZORBA_ASSERT(ite != theEmptyKeyNodes.end());
+
+    theEmptyKeyNodes.erase(ite);
+    return true;
+  }
+
+  if (keyItem->getBaseItem() != NULL)
+  {
+    keyItem = static_cast<AtomicItem*>(keyItem->getBaseItem());
+  }
+
+  if (isTyped())
+  {
+    return removeFromMap(key, node, theKeyTypeCode, false);
+  }
+
+  store::SchemaTypeCode keyType = keyItem->getTypeCode();
+
+  switch (keyType)
+  {
+  case store::XS_BASE64BINARY:
+  case store::XS_HEXBINARY:
+
+  case store::XS_QNAME:
+  case store::XS_NOTATION:
+
+  case store::XS_GYEAR_MONTH:
+  case store::XS_GYEAR:
+  case store::XS_GMONTH_DAY:
+  case store::XS_GDAY:
+  case store::XS_GMONTH:
+  {
+    assert(!sorted);
+    // falth through
+  }
+
+  case store::XS_ANY_URI:
+
+  case store::XS_BOOLEAN:
+
+  case store::XS_DATETIME:
+  case store::XS_DATE:
+  case store::XS_TIME:
+  {
+    return removeFromMap(key, node, keyType, false);
+  }
+
+  case store::XS_DURATION:
+  case store::XS_YM_DURATION:
+  case store::XS_DT_DURATION:
+  {
+    return removeFromMap(key, node, store::XS_DURATION, false);
+  }
+
+  case store::XS_STRING:
+  case store::XS_NORMALIZED_STRING:
+  case store::XS_TOKEN:
+  case store::XS_NMTOKEN:
+  case store::XS_LANGUAGE:
+  case store::XS_NAME:
+  case store::XS_NCNAME:
+  case store::XS_ID:
+  case store::XS_IDREF:
+  case store::XS_ENTITY:
+  {
+    return removeFromMap(key, node, store::XS_STRING, false);
+  }
+
+  case store::XS_DOUBLE:
+  case store::XS_FLOAT:
+  {
+    return removeFromMap(key, node, store::XS_DOUBLE, false);
+  }
+
+  case store::XS_DECIMAL:
+  case store::XS_INTEGER:
+  case store::XS_NON_POSITIVE_INTEGER:
+  case store::XS_NEGATIVE_INTEGER:
+  case store::XS_NON_NEGATIVE_INTEGER:
+  case store::XS_POSITIVE_INTEGER:
+  case store::XS_UNSIGNED_LONG:
+  {
+    // try lossless cast to xs:long
+    keyItem->castToLong(castItem);
+
+    if (castItem != NULL)
+    {
+      keyItem = static_cast<AtomicItem*>(castItem.getp());
+      goto longmap;
+    }
+
+    // Coerce to xs:double 
+    keyItem->coerceToDouble(castItem, true, lossy);
+
+    found = removeFromMap(key, node, store::XS_DOUBLE, false);
+
+    if (lossy)
+    {
+      if (removeFromMap(castItem, node, store::XS_DECIMAL, false))
+        found = true;
+    }
+
+    return found;
+  }
+
+  case store::XS_LONG:
+  {
+    // NOTE: here we use KeyItem, instead of key, as arg to removeFromMap, because
+    // we can reach here from the store::XS_DECIMAL case.
+longmap:
+    xs_long longValue = static_cast<LongItem*>(keyItem)->getLongValue();
+
+    if (longValue > theMaxLong || longValue < theMinLong)
+    {
+      if (sorted)
+      {
+        lossy = true;
+        xs_double doubleValue(longValue);
+        GET_FACTORY().createDouble(castItem, doubleValue);
+      }
+      else
+      {
+        keyItem->coerceToDouble(castItem, false, lossy);
+      }
+
+      if (lossy)
+      {
+        /*
+        std::cout << "Lossy LONG insertion in index" << getName()->getStringValue()
+                  << std::endl
+                  << "long value = " << longValue
+                  << " double value = " << castItem->getDoubleValue()
+                  << std::endl << std::endl;
+        */
+        found = removeFromMap(keyItem, node, store::XS_LONG, false);
+
+        if (removeFromMap(castItem, node, store::XS_DOUBLE, false))
+          found = true;
+      }
+      else
+      {
+        found = removeFromMap(keyItem, node, store::XS_LONG, false);
+      }
+    }
+    else
+    {
+      found = removeFromMap(keyItem, node, store::XS_LONG, false);
+    }
+
+    return found;
+  }
+
+  case store::XS_INT:
+  case store::XS_SHORT:
+  case store::XS_BYTE:
+  case store::XS_UNSIGNED_INT:
+  case store::XS_UNSIGNED_SHORT:
+  case store::XS_UNSIGNED_BYTE:
+  {
+    return removeFromMap(key, node, store::XS_LONG, false);
+  }
+
+  case store::XS_UNTYPED_ATOMIC:
+  {
+    store::ItemHandle<UntypedAtomicItem> untypedItem = 
+    static_cast<UntypedAtomicItem*>(key.getp());
+
+    // cast to xs:string
+    untypedItem->castToString(castItem);
+
+    found = removeFromMap(castItem, node, store::XS_STRING, false);
+
+    // try casting to xs:long
+    if (untypedItem->castToLong(castItem))
+    {
+      store::ItemHandle<LongItem> longItem = static_cast<LongItem*>(castItem.getp());
+
+      xs_long longValue = longItem->getLongValue();
+
+      if (removeFromMap(castItem, node, store::XS_LONG, true))
+        found = true;
+
+      if (longValue > theMaxLong || longValue < theMinLong)
+      {
+        if (sorted)
+        {
+          lossy = true;
+          xs_double doubleValue(longValue);
+          GET_FACTORY().createDouble(castItem, doubleValue);
+        }
+        else
+        {
+          longItem->coerceToDouble(castItem, false, lossy);
+        }
+
+        if (lossy)
+        {
+          if (removeFromMap(castItem, node, store::XS_DOUBLE, true))
+            found = true;
+        }
+      }
+
+      // may also be gYear, hexBinary, base64Binary, or boolean
+      if (!sorted)
+      {
+        if (untypedItem->castToGYear(castItem))
+        {
+          if (removeFromMap(castItem, node, store::XS_GYEAR, true))
+            found = true;
+        }
+
+        if (untypedItem->castToHexBinary(castItem))
+        {
+          if (removeFromMap(castItem, node, store::XS_HEXBINARY, true))
+            found = true;
+        }
+
+        if (untypedItem->castToBase64Binary(castItem))
+        {
+          if (removeFromMap(castItem, node, store::XS_BASE64BINARY, true))
+            found = true;
+        }
+      }
+    }
+
+    // try casting to xs:decimal
+    else if (untypedItem->castToDecimal(castItem))
+    {
+      store::ItemHandle<DecimalItem> decimalItem = 
+      static_cast<DecimalItem*>(castItem.getp());
+
+      decimalItem->coerceToDouble(castItem, true, lossy);
+
+      if (removeFromMap(castItem, node, store::XS_DOUBLE, true))
+        found = true;
+
+      if (lossy)
+      {
+        castItem.transfer(decimalItem);
+        if (removeFromMap(castItem, node, store::XS_DECIMAL, true))
+          found = true;
+      }
+
+      // may also be hexBinary or base64Binary
+      if (sorted)
+      {
+        if (untypedItem->castToHexBinary(castItem))
+        {
+          if (removeFromMap(castItem, node, store::XS_HEXBINARY, true))
+            found = true;
+        }
+
+        if (untypedItem->castToBase64Binary(castItem))
+        {
+          if (removeFromMap(castItem, node, store::XS_BASE64BINARY, true))
+            found = true;
+        }
+      }
+    }
+
+    // try casting to xs:double
+    else if (untypedItem->castToDouble(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_DOUBLE, true))
+        found = true;
+    }
+
+    // try casting to xs:datetime
+    else if (untypedItem->castToDateTime(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_DATETIME, true))
+        found = true;
+    }
+
+    // try casting to xs:date
+    else if (untypedItem->castToDate(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_DATE, true))
+        found = true;
+    }
+
+    // try casting to xs:time
+    else if (untypedItem->castToTime(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_TIME, true))
+        found = true;
+    }
+
+    // try casting to xs:gYearMonth
+    if (!sorted && untypedItem->castToGYearMonth(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_GYEAR_MONTH, true))
+        found = true;
+    }
+
+    // try casting to xs:gMonthDay
+    else if (!sorted && untypedItem->castToGMonthDay(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_GMONTH_DAY, true))
+        found = true;
+    }
+
+    // try casting to xs:gDay
+    else if (!sorted && untypedItem->castToGDay(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_GDAY, true))
+        found = true;
+    }
+
+    // try casting to xs:gMonth
+    else if (!sorted && untypedItem->castToGMonth(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_GMONTH, true))
+        found = true;
+    }
+
+    // try casting to xs:duration
+    else if (untypedItem->castToDuration(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_DURATION, true))
+        found = true;
+    }
+
+    // try casting to xs:hexBinary
+    else if (!sorted && untypedItem->castToHexBinary(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_HEXBINARY, true))
+        found = true;
+    }
+
+    // try casting to xs:base64Binary
+    else if (!sorted && untypedItem->castToBase64Binary(castItem))
+    {
+      if (removeFromMap(castItem, node, store::XS_BASE64BINARY, true))
+        found = true;
+    }
+
+    return found;
+  }
+
+  default:
+    ZORBA_ASSERT(false);
+  }
+
+  return true;
+}
+
+
+/******************************************************************************
+
+*******************************************************************************/
+bool GeneralIndex::remove(
+    const store::IndexKey* key,
+    const store::Item_t& node,
+    bool all)
+{
+  ZORBA_ASSERT(false);
+}
+
+
+/******************************************************************************
+
+*******************************************************************************/
+bool GeneralIndex::removeFromMap(
+    const store::Item_t& key,
+    const store::Item_t& node,
+    store::SchemaTypeCode targetMap,
+    bool untyped)
+{
+  if (untyped)
+    --theNumUntypedEntries;
+
+  if (isSorted())
+  {
+    GeneralTreeIndex* idx = static_cast<GeneralTreeIndex*>(this);
+    return idx->removeFromMap(key, node, idx->theMaps[targetMap]);
+  }
+  else
+  {
+    GeneralHashIndex* idx = static_cast<GeneralHashIndex*>(this);
+    return idx->removeFromMap(key, node, idx->theMaps[targetMap]);
   }
 }
 
@@ -670,7 +1124,7 @@
 *******************************************************************************/
 GeneralHashIndex::~GeneralHashIndex()
 {
-  for (ulong i = 0; i < store::XS_LAST; ++i)
+  for (csize i = 0; i < store::XS_LAST; ++i)
   {
     if (theMaps[i] == NULL)
       continue;
@@ -745,12 +1199,32 @@
 /******************************************************************************
 
 *******************************************************************************/
-bool GeneralHashIndex::remove(
+bool GeneralHashIndex::removeFromMap(
     const store::Item_t& key,
-    const store::Item_t& item,
-    bool all)
+    const store::Item_t& node,
+    IndexMap* targetMap)
 {
-  assert(false);
+  assert(targetMap);
+  assert(key != NULL);
+
+  IndexMap::iterator pos = targetMap->find(key);
+
+  if (pos != targetMap->end())
+  {
+    GeneralIndexValue* valueSet = (*pos).second;
+
+    bool found = valueSet->removeNode(node);
+
+    if (valueSet->empty())
+    {
+      const_cast<store::Item*>((*pos).first)->removeReference();
+      delete valueSet;
+      targetMap->erase(pos);
+    }
+
+    return found;
+  }
+
   return false;
 }
 
@@ -760,7 +1234,7 @@
 *******************************************************************************/
 void GeneralHashIndex::clear()
 {
-  for (ulong i = 0; i < store::XS_LAST; ++i)
+  for (csize i = 0; i < store::XS_LAST; ++i)
   {
     if (theMaps[i] == NULL)
       continue;
@@ -853,7 +1327,7 @@
 *******************************************************************************/
 GeneralTreeIndex::~GeneralTreeIndex()
 {
-  for (ulong i = 0; i < store::XS_LAST; ++i)
+  for (csize i = 0; i < store::XS_LAST; ++i)
   {
     if (theMaps[i] == NULL)
       continue;
@@ -920,12 +1394,33 @@
 /******************************************************************************
 
 *******************************************************************************/
-bool GeneralTreeIndex::remove(
+bool GeneralTreeIndex::removeFromMap(
     const store::Item_t& key,
-    const store::Item_t& item,
-    bool all)
+    const store::Item_t& node,
+    IndexMap* targetMap)
 {
-  return true;
+  assert(targetMap);
+  assert(key != NULL);
+
+  IndexMap::iterator pos = targetMap->find(key);
+
+  if (pos != targetMap->end())
+  {
+    GeneralIndexValue* valueSet = (*pos).second;
+
+    bool found = valueSet->removeNode(node);
+
+    if (valueSet->empty())
+    {
+      const_cast<store::Item*>((*pos).first)->removeReference();
+      delete valueSet;
+      targetMap->erase(pos);
+    }
+
+    return found;
+  }
+
+  return false;
 }
 
 
@@ -934,7 +1429,7 @@
 *******************************************************************************/
 void GeneralTreeIndex::clear()
 {
-  for (ulong i = 0; i < store::XS_LAST; ++i)
+  for (csize i = 0; i < store::XS_LAST; ++i)
   {
     if (theMaps[i] == NULL)
       continue;
@@ -1123,13 +1618,13 @@
   if (theProbeKind == store::IndexCondition::POINT_VALUE ||
       theProbeKind == store::IndexCondition::BOX_VALUE)
   {
-    if (theIndex->theMultiKeyFlag)
+    if (theIndex->theNumMultiKeyNodes > 0)
     {
       RAISE_ERROR_NO_LOC(err::XPTY0004,
       ERROR_PARAMS(ZED(NoMultiKeyNodeValues_2), theIndex->getName()->getStringValue()));
     }
 
-    if (theIndex->theUntypedFlag)
+    if (theIndex->theNumUntypedEntries > 0)
     {
       checkStringKeyType(theCondition->theKey.getp());
       checkStringKeyType(theCondition->theLowerBound.getp());
@@ -1871,7 +2366,7 @@
   {
     theIsFullProbe = true;
 
-    for (ulong i = 0; i < store::XS_LAST; ++i)
+    for (csize i = 0; i < store::XS_LAST; ++i)
     {
       if (idx->theMaps[i] == NULL)
         continue;

=== modified file 'src/store/naive/simple_index_general.h'
--- src/store/naive/simple_index_general.h	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index_general.h	2012-07-12 16:38:27 +0000
@@ -77,19 +77,25 @@
 
   typedef std::vector<NodeInfo>::const_iterator const_iterator;
 
+  typedef std::vector<NodeInfo>::iterator iterator;
+
 protected:
   std::vector<NodeInfo> theNodes;
 
 public:
-  GeneralIndexValue(ulong size = 0) : theNodes(size) {}
+  GeneralIndexValue(csize size = 0) : theNodes(size) {}
+
+  bool empty() const { return theNodes.empty(); }
 
   void clear() { theNodes.clear(); }
 
-  const_iterator begin() { return theNodes.begin(); }
+  const_iterator begin() const { return theNodes.begin(); }
 
-  const_iterator end()   { return theNodes.end(); }
+  const_iterator end() const { return theNodes.end(); }
 
   void addNode(store::Item_t& node, bool untyped);
+
+  bool removeNode(const store::Item_t& node);
 };
 
 
@@ -110,16 +116,17 @@
   A vector storing all domain nodes for which the key expr returns the empty
   sequence.
 
-  theUntypedFlag:
-  ---------------
-  Set to true if there is at least one domain node for which the key expression
-  returns an item with type xs:untypedAtomic and that item is sucessfully cast
-  to an item with a type other than xs:string.
+  theNumUntypedEntries:
+  ---------------------
+  The number of [key, node] index entries where the key is the result of casting
+  an originally untyped key to a non-string atomic item. If > 0, then any value
+  probes with a key (or keys) whose type cannot be promoted to xs:string will
+  raise an error.
 
-  theMultiKeyFlag:
-  ----------------
-  Set to true if there is at least one domain node for which the key expression
-  returns more than one items.
+  theNumMultiKeyNodes:
+  --------------------
+  The number of domain nodes for which the key expression returns more than one
+  items. If > 0, then any value probes on the general index raise an error.
 *******************************************************************************/
 class GeneralIndex : public IndexImpl
 {
@@ -144,9 +151,9 @@
 
   std::vector<store::Item_t>  theEmptyKeyNodes;
 
-  bool                        theUntypedFlag;
+  csize                       theNumUntypedEntries;
 
-  bool                        theMultiKeyFlag;
+  csize                       theNumMultiKeyNodes;
 
 protected:
   GeneralIndex(const store::Item_t& name, const store::IndexSpecification& spec);
@@ -161,27 +168,30 @@
       store::SchemaTypeCode targetMap,
       bool untyped);
 
-  bool probeMap(
-      const store::Item* key,
-      store::SchemaTypeCode targetMap);
+  bool removeFromMap(
+      const store::Item_t& key,
+      const store::Item_t& node,
+      store::SchemaTypeCode targetMap,
+      bool untyped);
+
+  bool probeMap(const store::Item* key, store::SchemaTypeCode targetMap);
 
 public:
-  const XQPCollator* getCollator(ulong i) const;
-
-  void setMultiKey() { theMultiKeyFlag = true; }
-
-  ulong size() const;
+  const XQPCollator* getCollator(csize i) const;
+
+  void addMultiKey() { ++theNumMultiKeyNodes; }
+
+  void removeMultiKey() { assert(theNumMultiKeyNodes > 0); --theNumMultiKeyNodes; }
+
+  csize size() const;
 
   bool insert(store::Item_t& key, store::Item_t& node);
 
-  bool insert(store::IndexKey*& key, store::Item_t& value);
-
-  virtual bool remove(const store::Item_t& key, const store::Item_t& item, bool all) = 0;
-
-  virtual bool remove(
-        const store::IndexKey* key,
-        const store::Item_t& item,
-        bool all = false) = 0;
+  bool insert(store::IndexKey*& key, store::Item_t& node);
+
+  bool remove(const store::IndexKey* key, const store::Item_t& node, bool all);
+
+  bool remove(const store::Item_t& key, const store::Item_t& node);
 };
 
 
@@ -233,6 +243,11 @@
       IndexMap*& targetMap,
       bool untyped);
 
+  bool removeFromMap(
+      const store::Item_t& key,
+      const store::Item_t& node,
+      IndexMap* targetMap);
+
 public:
   GeneralHashIndex(
       const store::Item_t& name,
@@ -242,17 +257,6 @@
 
   Index::KeyIterator_t keys() const;
 
-  bool remove(const store::Item_t& key, const store::Item_t& item, bool);
-
-  bool remove(
-        const store::IndexKey* key,
-        const store::Item_t& item,
-        bool all = false)
-  {
-    assert(key->size() == 1);
-    return remove(((*key)[0]), item, all);
-  }
-
   void clear();
 };
 
@@ -297,6 +301,11 @@
       IndexMap*& targetMap,
       bool untyped);
 
+  bool removeFromMap(
+      const store::Item_t& key,
+      const store::Item_t& item,
+      IndexMap* targetMap);
+
 public:
   GeneralTreeIndex(
       const store::Item_t& qname,
@@ -306,17 +315,6 @@
 
   Index::KeyIterator_t keys() const;
 
-  bool remove(const store::Item_t& key, const store::Item_t& item, bool all);
-
-  bool remove(
-        const store::IndexKey* key,
-        const store::Item_t& item,
-        bool all = false)
-  {
-    assert(key->size() == 1);
-    return remove(((*key)[0]), item, all);
-  }
-
   void clear();
 };
 

=== modified file 'src/store/naive/simple_index_value.cpp'
--- src/store/naive/simple_index_value.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index_value.cpp	2012-07-12 16:38:27 +0000
@@ -222,7 +222,7 @@
 /******************************************************************************
 
 ********************************************************************************/
-const XQPCollator* ValueIndex::getCollator(ulong i) const 
+const XQPCollator* ValueIndex::getCollator(csize i) const 
 {
   return theCompFunction.getCollator(i);
 }
@@ -345,7 +345,7 @@
 /*******************************************************************************
 
 ********************************************************************************/
-ulong ValueHashIndex::size() const
+csize ValueHashIndex::size() const
 {
   return theMap.size();
 }
@@ -429,9 +429,8 @@
     const store::IndexKey* keyp = (*pos).first;
     ValueIndexValue* valueSet = (*pos).second;
 
-    ValueIndexValue::iterator valIte = std::find(valueSet->begin(),
-                                                 valueSet->end(),
-                                                 value);
+    ValueIndexValue::iterator valIte = 
+    std::find(valueSet->begin(), valueSet->end(), value);
 
     if (all)
     {
@@ -642,10 +641,9 @@
 /******************************************************************************
 
 ********************************************************************************/
-ulong ValueTreeIndex::size() const
+csize ValueTreeIndex::size() const
 {
-  assert(false);
-  return 0;
+  return theMap.size();
 }
 
 
@@ -736,9 +734,8 @@
     const store::IndexKey* keyp = pos->first;
     ValueIndexValue* valueSet = (*pos).second;
 
-    ValueIndexValue::iterator valIte = std::find(valueSet->begin(),
-                                                   valueSet->end(),
-                                                   value);
+    ValueIndexValue::iterator valIte = 
+    std::find(valueSet->begin(), valueSet->end(), value);
 
     if (valIte != valueSet->end())
     {
@@ -821,7 +818,7 @@
 ********************************************************************************/
 void ProbeValueTreeIndexIterator::initBox()
 {
-  ulong numRanges = theBoxCond->numRanges();
+  csize numRanges = theBoxCond->numRanges();
 
   assert(numRanges > 0 && numRanges <= theIndex->getNumColumns());
 
@@ -874,7 +871,7 @@
   //
   // Adjust the lower and/or upper bound index keys before probing the index.
   //
-  for (ulong i = 0; i < numRanges; i++)
+  for (csize i = 0; i < numRanges; i++)
   {
     const XQPCollator* collator = theIndex->getCollator(i);
 

=== modified file 'src/store/naive/simple_index_value.h'
--- src/store/naive/simple_index_value.h	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_index_value.h	2012-07-12 16:38:27 +0000
@@ -43,7 +43,7 @@
 
   ~ValueIndexCompareFunction();
 
-  const XQPCollator* getCollator(ulong i) const { return theCollators[i]; }
+  const XQPCollator* getCollator(csize i) const { return theCollators[i]; }
 
   uint32_t hash(const store::IndexKey* key) const;
 
@@ -64,7 +64,7 @@
 class ValueIndexValue : public store::ItemVector
 {
 public:
-  ValueIndexValue(ulong size = 0) : store::ItemVector(size) {}
+  ValueIndexValue(csize size = 0) : store::ItemVector(size) {}
 };
 
 
@@ -86,16 +86,16 @@
   virtual ~ValueIndex();
 
 public:
-  const XQPCollator* getCollator(ulong i) const;
+  const XQPCollator* getCollator(csize i) const;
 
   virtual bool isTreeIndex() = 0;
 
   virtual bool insert(store::IndexKey*& key, store::Item_t& item) = 0;
 
   virtual bool remove(
-        const store::IndexKey* key,
-        const store::Item_t& item,
-        bool all = false) = 0;
+      const store::IndexKey* key,
+      const store::Item_t& node,
+      bool all) = 0;
 };
 
 
@@ -148,7 +148,7 @@
 
   void clear();
 
-  ulong size() const;
+  csize size() const;
 
   Index::KeyIterator_t keys() const;
 
@@ -237,13 +237,13 @@
 
   void clear();
 
-  ulong size() const;
+  csize size() const;
 
   Index::KeyIterator_t keys() const;
 
   bool insert(store::IndexKey*& key, store::Item_t& item);
 
-  bool remove(const store::IndexKey* key, const store::Item_t& item, bool all = false);
+  bool remove(const store::IndexKey* key, const store::Item_t& item, bool all);
 };
 
 

=== modified file 'src/store/naive/simple_pul.cpp'
--- src/store/naive/simple_pul.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_pul.cpp	2012-07-12 16:38:27 +0000
@@ -24,6 +24,7 @@
 #include "simple_store.h"
 #include "collection.h"
 #include "simple_index_value.h"
+#include "simple_index_general.h"
 #include "simple_pul.h"
 #include "pul_primitives.h"
 #include "node_items.h"
@@ -2756,7 +2757,7 @@
   modified by this pul, compute the index entries for I and D, and insert them
   into the given deltas vector
 ********************************************************************************/
-void CollectionPul::computeIndexDeltas(std::vector<store::IndexDelta>& deltas)
+void CollectionPul::computeIndexDeltas(std::vector<IndexDeltaImpl>& deltas)
 {
   csize numIncrementalIndices = theIncrementalIndices.size();
 
@@ -2785,14 +2786,18 @@
 
   for (csize idx = 0; idx < numIncrementalIndices; ++idx)
   {
-    store::IndexDelta::iterator ite;
-    store::IndexDelta::iterator end;
-    store::IndexDelta* delta;
-    csize numApplied;
+    if (theIncrementalIndices[idx]->isGeneral())
+    {
+      ;
+    }
+    else
+    {
+      IndexDeltaImpl::ValueIterator ite;
+      IndexDeltaImpl::ValueIterator end;
+      store::IndexDelta::ValueDelta* delta;
+      csize numApplied;
 
-    delta = &theInsertedDocsIndexDeltas[idx];
-    if (delta)
-    {
+      delta = &theInsertedDocsIndexDeltas[idx].getValueDelta();
       numApplied = theNumInsertedDocsIndexDeltasApplied[idx];
       ite = delta->begin() + numApplied;
       end = delta->end();
@@ -2800,11 +2805,8 @@
       {
         delete (*ite).second;
       }
-    }
 
-    delta = &theAfterIndexDeltas[idx];
-    if (delta)
-    {
+      delta = &theAfterIndexDeltas[idx].getValueDelta();
       numApplied = theNumAfterIndexDeltasApplied[idx];
       ite = delta->begin() + numApplied;
       end = delta->end();
@@ -2812,33 +2814,15 @@
       {
         delete (*ite).second;
       }
-    }
-
-    delta = &theDeletedDocsIndexDeltas[idx];
-    if (delta)
-    {
-      ite = delta->begin();
-      end = delta->end();
-      for (; ite != end; ++ite)
-      {
-        delete (*ite).second;
-      }
-    }
-
-    delta = &theBeforeIndexDeltas[idx];
-    if (delta)
-    {
-      ite = delta->begin();
-      end = delta->end();
-      for (; ite != end; ++ite)
-      {
-        delete (*ite).second;
-      }
+      
+      theDeletedDocsIndexDeltas[idx].clear();
+      
+      theBeforeIndexDeltas[idx].clear();
     }
   }
 }
-
-
+  
+  
 /*******************************************************************************
   Refresh the incrementally maintained indexes.
 ********************************************************************************/
@@ -2846,91 +2830,278 @@
 {
   csize numIncrementalIndices = theIncrementalIndices.size();
 
-  STORE_TRACE1("Refreshing indexes for collection "
-               << (theCollection ?
-                   theCollection->getName()->getStringValue().c_str() :
-                   "NULL")); 
-
-  for (csize idx = 0; idx < numIncrementalIndices; ++idx)
-  {
-    ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
-
-    STORE_TRACE2("Index size before do = " 
-                 << (!index->isTreeIndex() ? index->size() : 0));
-
-    store::IndexDelta& beforeDelta = theBeforeIndexDeltas[idx];
-    store::IndexDelta& afterDelta = theAfterIndexDeltas[idx];
-    store::IndexDelta& deletedDelta = theDeletedDocsIndexDeltas[idx];
-    store::IndexDelta& insertedDelta = theInsertedDocsIndexDeltas[idx];
-
-    csize& numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
-    csize& numAfterApplied = theNumAfterIndexDeltasApplied[idx];
-    csize& numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
-    csize& numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
-
-    store::IndexKey* key;
-    store::Item_t node;
-
-    store::IndexDelta::iterator ite;
-    store::IndexDelta::iterator end;
-
-    ite = beforeDelta.begin();
-    end = beforeDelta.end();
-    for (; ite != end; ++ite, ++numBeforeApplied)
-    {
-      index->remove((*ite).second, (*ite).first);
-    }
-
-    ite = afterDelta.begin();
-    end = afterDelta.end();
-    for (; ite != end; ++ite, ++numAfterApplied)
-    {
-      node = (*ite).first;
-      key = (*ite).second;
-
-      // If the index had its own key obj already, delete the key obj that was
-      // allocated during the delta creation.
-      if (index->insert((*ite).second, node))
-      {
-        assert(key != (*ite).second);
-        delete key;
-      }
-    }
-
-    STORE_TRACE2("deleted-delta size = " << deletedDelta.size());
- 
-    ite = deletedDelta.begin();
-    end = deletedDelta.end();
-    for (; ite != end; ++ite, ++numDeletedApplied)
-    {
-      index->remove((*ite).second, (*ite).first);
-    }
-
-    STORE_TRACE2("inserted-delta size = " << insertedDelta.size());
-
-    ite = insertedDelta.begin();
-    end = insertedDelta.end();
-    for (; ite != end; ++ite, ++numInsertedApplied)
-    {
-      node = (*ite).first;
-      key = (*ite).second;
-
-      if (index->insert((*ite).second, node))
-      {
-        assert(key != (*ite).second);
-        delete key;
-      }
-    }
-
-    STORE_TRACE2("Index size after do = " 
-                 << (!index->isTreeIndex() ? index->size() : 0));
-  }
-
-  STORE_TRACE1("Refreshed indexes for collection " 
-               << (theCollection ?
-                   theCollection->getName()->getStringValue().c_str() :
-                   "NULL")
-               << std::endl);
+  if (numIncrementalIndices > 0)
+  {
+    assert(theCollection);
+
+    STORE_TRACE1("Refreshing indexes for collection "
+                 << theCollection->getName()->getStringValue().c_str()); 
+
+    for (csize idx = 0; idx < numIncrementalIndices; ++idx)
+    {
+      if (theIncrementalIndices[idx]->isGeneral())
+        refreshGeneralIndex(idx);
+      else
+        refreshValueIndex(idx);
+    }
+    
+    STORE_TRACE1("Refreshed indexes for collection " 
+                 << theCollection->getName()->getStringValue().c_str()
+                 << std::endl);
+  }
+}
+
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void CollectionPul::refreshValueIndex(csize idx)
+{
+  ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
+
+  STORE_TRACE2("Index size before do = " << index->size());
+
+  store::IndexDelta::ValueDelta& 
+  beforeDelta = theBeforeIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta& 
+  afterDelta = theAfterIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta& 
+  deletedDelta = theDeletedDocsIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta&
+  insertedDelta = theInsertedDocsIndexDeltas[idx].getValueDelta();
+  
+  csize& numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
+  csize& numAfterApplied = theNumAfterIndexDeltasApplied[idx];
+  csize& numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
+  csize& numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
+
+  store::IndexKey* key;
+  store::Item_t node;
+
+  IndexDeltaImpl::ValueIterator ite;
+  IndexDeltaImpl::ValueIterator end;
+
+  ite = beforeDelta.begin();
+  end = beforeDelta.end();
+  for (; ite != end; ++ite, ++numBeforeApplied)
+  {
+    index->remove((*ite).second, (*ite).first, false);
+  }
+
+  ite = afterDelta.begin();
+  end = afterDelta.end();
+  for (; ite != end; ++ite, ++numAfterApplied)
+  {
+    node = (*ite).first;
+    key = (*ite).second;
+    
+    // If the index had its own key obj already, delete the key obj that was
+    // allocated during the delta creation.
+    if (index->insert((*ite).second, node))
+    {
+      assert(key != (*ite).second);
+      delete key;
+    }
+  }
+  
+  STORE_TRACE2("deleted-delta size = " << deletedDelta.size());
+  
+  ite = deletedDelta.begin();
+  end = deletedDelta.end();
+  for (; ite != end; ++ite, ++numDeletedApplied)
+  {
+    index->remove((*ite).second, (*ite).first, false);
+  }
+  
+  STORE_TRACE2("inserted-delta size = " << insertedDelta.size());
+  
+  ite = insertedDelta.begin();
+  end = insertedDelta.end();
+  for (; ite != end; ++ite, ++numInsertedApplied)
+  {
+    node = (*ite).first;
+    key = (*ite).second;
+    
+    if (index->insert((*ite).second, node))
+    {
+      assert(key != (*ite).second);
+      delete key;
+    }
+  }
+  
+  STORE_TRACE2("Index size after do = " << index->size());
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void CollectionPul::refreshGeneralIndex(csize idx)
+{
+  GeneralIndex* index = static_cast<GeneralIndex*>(theIncrementalIndices[idx]);
+
+  store::IndexDelta::GeneralDelta& 
+  beforeDelta = theBeforeIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta& 
+  afterDelta = theAfterIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta& 
+  deletedDelta = theDeletedDocsIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta&
+  insertedDelta = theInsertedDocsIndexDeltas[idx].getGeneralDelta();
+  
+  csize& numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
+  csize& numAfterApplied = theNumAfterIndexDeltasApplied[idx];
+  csize& numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
+  csize& numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
+
+  store::Item_t key;
+  store::Item_t node;
+
+  IndexDeltaImpl::GeneralIterator ite;
+  IndexDeltaImpl::GeneralIterator end;
+  std::vector<store::Item_t>::iterator keyIte;
+  std::vector<store::Item_t>::iterator keyEnd;
+
+  STORE_TRACE2("before-delta size = " << deletedDelta.size());
+
+  ite = beforeDelta.begin();
+  end = beforeDelta.end();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->remove((*ite).second, (*ite).first);
+    ++numBeforeApplied;
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->remove((*ite).second, (*ite).first);
+      ++numDeletedApplied;
+      ++ite;
+
+      // Call removeMultiKey() after removing the 2nd key for the same node.
+      // We do this to make undo easier.
+      index->removeMultiKey();
+
+      while (ite != end && (*ite).first.getp() == nodep)
+      {
+        index->remove((*ite).second, (*ite).first);
+        ++numBeforeApplied;
+        ++ite;
+      }
+    }
+  }
+
+  STORE_TRACE2("after-delta size = " << deletedDelta.size());
+
+  ite = afterDelta.begin();
+  end = afterDelta.end();
+
+  while (ite != end)
+  {
+    node = (*ite).first;
+    key = (*ite).second;
+    store::Item* nodep = node.getp();
+
+    index->insert(key, node);
+    ++numAfterApplied;
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      node = (*ite).first;
+      key = (*ite).second;
+
+      index->insert(key, node);
+      ++numAfterApplied;
+      ++ite;
+
+      index->addMultiKey();
+
+      while (ite != end && (*ite).first.getp() == nodep)
+      {
+        node = (*ite).first;
+        key = (*ite).second;
+
+        index->insert(key, node);
+        ++numAfterApplied;
+        ++ite;
+      }
+    }
+  }
+
+  STORE_TRACE2("deleted-delta size = " << deletedDelta.size());
+  
+  ite = deletedDelta.begin();
+  end = deletedDelta.end();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->remove((*ite).second, (*ite).first);
+    ++numDeletedApplied;
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->remove((*ite).second, (*ite).first);
+      ++numDeletedApplied;
+      ++ite;
+
+      // Call removeMultiKey() after removing the 2nd key for the same node.
+      // We do this to make undo easier.
+      index->removeMultiKey();
+
+      while (ite != end && (*ite).first.getp() == nodep)
+      {
+        index->remove((*ite).second, (*ite).first);
+        ++numDeletedApplied;
+        ++ite;
+      }
+    }
+  }
+
+  STORE_TRACE2("inserted-delta size = " << insertedDelta.size());
+  
+  ite = insertedDelta.begin();
+  end = insertedDelta.end();
+
+  while (ite != end)
+  {
+    node = (*ite).first;
+    key = (*ite).second;
+    store::Item* nodep = node.getp(); 
+      
+    index->insert(key, node);
+    ++numInsertedApplied;
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      node = (*ite).first;
+      key = (*ite).second;
+
+      index->insert(key, node);
+      ++numInsertedApplied;
+      ++ite;
+
+      index->addMultiKey();
+
+      while (ite != end && (*ite).first.getp() == nodep)
+      {
+        node = (*ite).first;
+        key = (*ite).second;
+
+        index->insert(key, node);
+        ++numInsertedApplied;
+        ++ite;
+      }
+    }
+  }
 }
 
 
@@ -2949,70 +3120,10 @@
 
   for (csize idx = 0; idx < numIncrementalIndices; ++idx)
   {
-    ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
-
-    STORE_TRACE2("Index size before undo = " 
-                 << (!index->isTreeIndex() ? index->size() : 0));
-    
-    store::IndexDelta& beforeDelta = theBeforeIndexDeltas[idx];
-    store::IndexDelta& afterDelta = theAfterIndexDeltas[idx];
-    store::IndexDelta& insertedDelta = theInsertedDocsIndexDeltas[idx];
-    store::IndexDelta& deletedDelta = theDeletedDocsIndexDeltas[idx];
-
-    csize numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
-    csize numAfterApplied = theNumAfterIndexDeltasApplied[idx];
-    csize numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
-    csize numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
-
-    store::IndexDelta::reverse_iterator ite;
-    store::IndexDelta::reverse_iterator end;
-
-    ite = insertedDelta.rbegin() + (insertedDelta.size() - numInsertedApplied);
-    end = insertedDelta.rend();
-    for (; ite != end; ++ite)
-    {
-      index->remove((*ite).second, (*ite).first);
-    }
-
-    ite = deletedDelta.rbegin() + (deletedDelta.size() - numDeletedApplied);
-    end = deletedDelta.rend();
-    for (; ite != end; ++ite)
-    {
-      store::IndexKey* key = (*ite).second;
-
-      // If the index takes ownership of the key obj, set the key ptr to null
-      // so that the key obj will not be deleted during cleanIndexDeltas().
-      if (!index->insert(key, (*ite).first))
-      {
-        assert(key == (*ite).second);
-        (*ite).second = NULL;
-      }
-    }
-
-    ite = afterDelta.rbegin() + (afterDelta.size() - numAfterApplied);
-    end = afterDelta.rend();
-    for (; ite != end; ++ite)
-    {
-      index->remove((*ite).second, (*ite).first);
-    }
-
-    ite = beforeDelta.rbegin() + (beforeDelta.size() - numBeforeApplied);
-    end = beforeDelta.rend();
-    for (; ite != end; ++ite)
-    {
-      store::IndexKey* key = (*ite).second;
-
-      // If the index takes ownership of the key obj, set the key ptr to null
-      // so that the key obj will not be deleted during cleanIndexDeltas().
-      if (!index->insert(key, (*ite).first))
-      {
-        assert(key == (*ite).second);
-        (*ite).second = NULL;
-      }
-    }
-
-    STORE_TRACE2("Index size after undo = " 
-                 << (!index->isTreeIndex() ? index->size() : 0));
+    if (theIncrementalIndices[idx]->isGeneral())
+      undoGeneralIndexRefresh(idx);
+    else
+      undoValueIndexRefresh(idx);
   }
 
   STORE_TRACE1("Reverted indexes for collection " 
@@ -3024,6 +3135,208 @@
 
 
 /*******************************************************************************
+
+********************************************************************************/
+void CollectionPul::undoValueIndexRefresh(csize idx)
+{
+  ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
+
+  STORE_TRACE2("Index size before undo = " << index->size());
+    
+  store::IndexDelta::ValueDelta& 
+  beforeDelta = theBeforeIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta&
+  afterDelta = theAfterIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta&
+  insertedDelta = theInsertedDocsIndexDeltas[idx].getValueDelta();
+  store::IndexDelta::ValueDelta&
+  deletedDelta = theDeletedDocsIndexDeltas[idx].getValueDelta();
+
+  csize numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
+  csize numAfterApplied = theNumAfterIndexDeltasApplied[idx];
+  csize numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
+  csize numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
+
+  IndexDeltaImpl::ReverseValueIterator ite;
+  IndexDeltaImpl::ReverseValueIterator end;
+
+  ite = insertedDelta.rbegin() + (insertedDelta.size() - numInsertedApplied);
+  end = insertedDelta.rend();
+  for (; ite != end; ++ite)
+  {
+    index->remove((*ite).second, (*ite).first, false);
+  }
+  
+  ite = deletedDelta.rbegin() + (deletedDelta.size() - numDeletedApplied);
+  end = deletedDelta.rend();
+  for (; ite != end; ++ite)
+  {
+    store::IndexKey* key = (*ite).second;
+
+    // If the index takes ownership of the key obj, set the key ptr to null
+    // so that the key obj will not be deleted during cleanIndexDeltas().
+    if (!index->insert(key, (*ite).first))
+    {
+      assert(key == (*ite).second);
+      (*ite).second = NULL;
+    }
+  }
+
+  ite = afterDelta.rbegin() + (afterDelta.size() - numAfterApplied);
+  end = afterDelta.rend();
+  for (; ite != end; ++ite)
+  {
+    index->remove((*ite).second, (*ite).first, false);
+  }
+
+  ite = beforeDelta.rbegin() + (beforeDelta.size() - numBeforeApplied);
+  end = beforeDelta.rend();
+  for (; ite != end; ++ite)
+  {
+    store::IndexKey* key = (*ite).second;
+    
+    // If the index takes ownership of the key obj, set the key ptr to null
+    // so that the key obj will not be deleted during cleanIndexDeltas().
+    if (!index->insert(key, (*ite).first))
+    {
+      assert(key == (*ite).second);
+      (*ite).second = NULL;
+    }
+  }
+  
+  STORE_TRACE2("Index size after undo = " << index->size());
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void CollectionPul::undoGeneralIndexRefresh(csize idx)
+{
+  GeneralIndex* index = static_cast<GeneralIndex*>(theIncrementalIndices[idx]);
+
+  store::IndexDelta::GeneralDelta& 
+  beforeDelta = theBeforeIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta&
+  afterDelta = theAfterIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta&
+  insertedDelta = theInsertedDocsIndexDeltas[idx].getGeneralDelta();
+  store::IndexDelta::GeneralDelta&
+  deletedDelta = theDeletedDocsIndexDeltas[idx].getGeneralDelta();
+
+  csize numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
+  csize numAfterApplied = theNumAfterIndexDeltasApplied[idx];
+  csize numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
+  csize numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
+
+  IndexDeltaImpl::ReverseGeneralIterator ite;
+  IndexDeltaImpl::ReverseGeneralIterator end;
+  std::vector<store::Item_t>::reverse_iterator keyIte;
+  std::vector<store::Item_t>::reverse_iterator keyEnd;
+
+  // Inserted delta
+
+  ite = insertedDelta.rbegin() + (insertedDelta.size() - numInsertedApplied);
+  end = insertedDelta.rend();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->remove((*ite).second, (*ite).first);
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->removeMultiKey();
+
+      do
+      {
+        index->remove((*ite).second, (*ite).first);
+        ++ite;
+      }
+      while (ite != end && (*ite).first.getp() == nodep);
+    }
+  }
+
+  // Deleted delta
+
+  ite = deletedDelta.rbegin() + (deletedDelta.size() - numDeletedApplied);
+  end = deletedDelta.rend();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->insert((*ite).second, (*ite).first);
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->addMultiKey();
+
+      do
+      {
+        index->insert((*ite).second, (*ite).first);
+        ++ite;
+      }
+      while (ite != end && (*ite).first.getp() == nodep);
+    }
+  }
+
+  // After delta
+
+  ite = afterDelta.rbegin() + (afterDelta.size() - numAfterApplied);
+  end = afterDelta.rend();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->remove((*ite).second, (*ite).first);
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->removeMultiKey();
+
+      do
+      {
+        index->remove((*ite).second, (*ite).first);
+        ++ite;
+      }
+      while (ite != end && (*ite).first.getp() == nodep);
+    }
+  }
+
+  // Before delta
+
+  ite = beforeDelta.rbegin() + (beforeDelta.size() - numBeforeApplied);
+  end = beforeDelta.rend();
+
+  while (ite != end)
+  {
+    store::Item* nodep = (*ite).first.getp(); 
+
+    index->insert((*ite).second, (*ite).first);
+    ++ite;
+
+    if (ite != end && (*ite).first.getp() == nodep)
+    {
+      index->addMultiKey();
+
+      do
+      {
+        index->insert((*ite).second, (*ite).first);
+        ++ite;
+      }
+      while (ite != end && (*ite).first.getp() == nodep);
+    }
+  }
+}
+
+
+/*******************************************************************************
   The method is called from CollectionPul::finalizeUpdates()
 ********************************************************************************/
 void CollectionPul::truncateIndexes()
@@ -3173,10 +3486,10 @@
           theMergeList.push_back(mergeInfo);
 
           (void)GET_NODE_FACTORY().createTextNode(node->getTree(),
-              node,
-              false,
-              i,
-              newContent);
+                                                  node,
+                                                  false,
+                                                  i,
+                                                  newContent);
         }
       }
     }
@@ -3215,16 +3528,12 @@
   }
   catch (const std::exception& e) 
   {
-#ifndef NDEBUG
-    std::cerr << "Exception thrown during pul::applyUpdates: " << e.what() << std::endl;
-#endif
+    //std::cerr << "Exception thrown during pul::applyUpdates: " << e.what() << std::endl;
     throw;
   }
   catch (...)
   {
-#ifndef NDEBUG
-    std::cerr << "Exception thrown during pul::applyUpdates " << std::endl;
-#endif
+    //std::cerr << "Exception thrown during pul::applyUpdates " << std::endl;
     throw;
   }
 

=== modified file 'src/store/naive/simple_pul.h'
--- src/store/naive/simple_pul.h	2012-07-11 04:46:41 +0000
+++ src/store/naive/simple_pul.h	2012-07-12 16:38:27 +0000
@@ -21,7 +21,7 @@
 #include "shared_types.h"
 
 #include "store/api/pul.h"
-#include "store/api/index.h"
+#include "store/naive/simple_index.h"
 
 #include "zorbautils/hashfun.h"
 #include "zorbautils/hashmap.h"
@@ -202,10 +202,10 @@
 
   std::vector<IndexEntryCreator_t>   theIndexEntryCreators;
 
-  std::vector<store::IndexDelta>     theBeforeIndexDeltas;
-  std::vector<store::IndexDelta>     theAfterIndexDeltas;
-  std::vector<store::IndexDelta>     theInsertedDocsIndexDeltas;
-  std::vector<store::IndexDelta>     theDeletedDocsIndexDeltas;
+  std::vector<IndexDeltaImpl>        theBeforeIndexDeltas;
+  std::vector<IndexDeltaImpl>        theAfterIndexDeltas;
+  std::vector<IndexDeltaImpl>        theInsertedDocsIndexDeltas;
+  std::vector<IndexDeltaImpl>        theDeletedDocsIndexDeltas;
 
 #ifdef ZORBA_WITH_JSON
   // jsoniq primitives
@@ -251,10 +251,18 @@
 protected:
   void switchPulInPrimitivesList(std::vector<UpdatePrimitive*>& list);
 
-  void computeIndexDeltas(std::vector<store::IndexDelta>& deltas);
+  void computeIndexDeltas(std::vector<IndexDeltaImpl>& deltas);
 
   void cleanIndexDeltas();
 
+  void refreshValueIndex(csize idx);
+
+  void refreshGeneralIndex(csize idx);
+
+  void undoValueIndexRefresh(csize idx);
+
+  void undoGeneralIndexRefresh(csize idx);
+
   void truncateIndexes();
 
   void undoRefreshIndexes();

=== modified file 'src/store/naive/store.cpp'
--- src/store/naive/store.cpp	2012-07-11 04:46:41 +0000
+++ src/store/naive/store.cpp	2012-07-12 16:38:27 +0000
@@ -672,7 +672,7 @@
         // Current domain node has at least 2 keys. So insert them in the index.
         // Note: we have to copy the domainNode rchandle because index->insert()
         // will transfer the given node.
-        index->setMultiKey();
+        index->addMultiKey();
 
         store::Item_t node = domainNode;
         index->insert(firstKeyItem, node);
@@ -724,10 +724,8 @@
 
   if (!theIndices.get(non_const_items, index))
   {
-    throw ZORBA_EXCEPTION(
-      zerr::ZSTR0002_INDEX_DOES_NOT_EXIST,
-      ERROR_PARAMS( qname->getStringValue() )
-    );
+    throw ZORBA_EXCEPTION(zerr::ZSTR0002_INDEX_DOES_NOT_EXIST,
+    ERROR_PARAMS(qname->getStringValue()));
   }
 
   deleteIndex(qname);

=== modified file 'src/store/util/item_vector.h'
--- src/store/util/item_vector.h	2012-07-11 04:46:41 +0000
+++ src/store/util/item_vector.h	2012-07-12 16:38:27 +0000
@@ -35,25 +35,25 @@
   std::vector<Item_t> theItems;
 
 public:
-  ItemVector(ulong size = 0) : theItems(size) {}
+  ItemVector(csize size = 0) : theItems(size) {}
 
   bool empty() const { return theItems.empty(); }
 
-  ulong size() const { return (ulong)theItems.size(); }
+  csize size() const { return theItems.size(); }
 
-  void resize(ulong newSize) { theItems.resize(newSize); }
+  void resize(csize newSize) { theItems.resize(newSize); }
 
   void clear() { theItems.clear(); }
 
-  const Item_t& operator[](ulong i) const { return theItems[i]; }
+  const Item_t& operator[](csize i) const { return theItems[i]; }
 
-  Item_t& operator[](ulong i) { return theItems[i]; }
+  Item_t& operator[](csize i) { return theItems[i]; }
 
   void push_back(const Item_t& item) { theItems.push_back(item); }
 
   void transfer_back(Item_t& item) 
   {
-    ulong size_ = size();
+    csize size_ = size();
     theItems.resize(size_+1);
     theItems[size_].transfer(item);
   }

=== added file 'test/rbkt/ExpQueryResults/zorba/index/auctions2u.xml.res'
--- test/rbkt/ExpQueryResults/zorba/index/auctions2u.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/index/auctions2u.xml.res	2012-07-12 16:38:27 +0000
@@ -0,0 +1,306 @@
+
+TEST 1:
+
+<person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person>
+
+TEST 2:
+
+<person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person203"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/></watches></person>
+
+TEST 3:
+
+<person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person>
+
+TEST 4:
+
+<person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person205"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/></watches></person>
+
+TEST 5:
+
+<person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person205"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/><watch open_auction="open_auction8"/></watches></person><person id="person203"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/></watches></person>
+
+TEST 6 (undo without do):
+
+<exception>err:XUDY0021 : updates violate constraint</exception><person id="person1"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+<watch open_auction="open_auction5"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+</watches></person><person id="person2"><watches>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person3"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction5"/>
+</watches></person><person id="person7"><watches>
+<watch open_auction="open_auction10"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction10"/>
+</watches></person><person id="person8"><watches>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person15"><watches>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction1"/>
+<watch open_auction="open_auction2"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction8"/>
+<watch open_auction="open_auction8"/>
+</watches></person><person id="person21"><watches>
+<watch open_auction="open_auction3"/>
+<watch open_auction="open_auction9"/>
+<watch open_auction="open_auction0"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction2"/>
+</watches></person><person id="person23"><watches>
+<watch open_auction="open_auction6"/>
+<watch open_auction="open_auction4"/>
+</watches></person><person id="person205"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/><watch open_auction="open_auction8"/></watches></person><person id="person203"><watches><watch open_auction="open_auction6"/><watch open_auction="open_auction2"/><watch open_auction="open_auction6"/><watch open_auction="open_auction5"/></watches></person>

=== added file 'test/rbkt/ExpQueryResults/zorba/index/numbers2.xml.res'
--- test/rbkt/ExpQueryResults/zorba/index/numbers2.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/index/numbers2.xml.res	2012-07-12 16:38:27 +0000
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+xs:long 
+
+TEST 1:
+
+<exception>err:XPTY0004 : node with untyped key value found during probe on index "num:idx-g-h-untyped"</exception>
+
+TEST 2:
+
+ 
+  <s:integer xmlns:s="http://www.zorba-xquery.com/numbers.xsd";>2</s:integer>
+
+TEST 3:
+
+<s:integer xmlns:s="http://www.zorba-xquery.com/numbers.xsd";>2</s:integer><untyped>2</untyped>
+<s:integer xmlns:s="http://www.zorba-xquery.com/numbers.xsd";>2</s:integer><untyped>2</untyped>
+<s:integer xmlns:s="http://www.zorba-xquery.com/numbers.xsd";>2</s:integer><untyped>2</untyped>
+<s:integer xmlns:s="http://www.zorba-xquery.com/numbers.xsd";>2</s:integer><untyped>2</untyped>
+<untyped>2</untyped>

=== modified file 'test/rbkt/ExpQueryResults/zorba/index/undo2.xml.res'
--- test/rbkt/ExpQueryResults/zorba/index/undo2.xml.res	2012-04-22 21:55:56 +0000
+++ test/rbkt/ExpQueryResults/zorba/index/undo2.xml.res	2012-07-12 16:38:27 +0000
@@ -1,2 +1,2 @@
 <?xml version="1.0" encoding="UTF-8"?>
-zerr:ZDDY0024<person id="1" key="5"/><person id="2" key="5"/><person id="1" key="5"/><person id="2" key="5"/>
+<exception>zerr:ZDDY0024 : "auctions:PersonId2": index uniqueness violation</exception><person id="1" key="5"/><person id="2" key="5"/><person id="1" key="5"/><person id="2" key="5"/>

=== added file 'test/rbkt/ExpQueryResults/zorba/index/undo4.xml.res'
--- test/rbkt/ExpQueryResults/zorba/index/undo4.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/index/undo4.xml.res	2012-07-12 16:38:27 +0000
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<person id="1"><car make="honda"/><car make="vw"/></person><person id="2"><car make="vw"/></person>
+
+TEST 0:
+
+<exception>err:XPTY0004 : node with more than one key value found during probe on index "f:PersonCars"</exception>
+
+TEST 1:
+
+<exception>zerr:ZDDY0024 : "f:PersonId": index uniqueness violation</exception>
+<person id="1"><car make="honda"/><car make="vw"/></person><person id="2"><car make="vw"/></person>
+
+TEST 2:
+
+<exception>zerr:ZDDY0024 : "f:PersonId": index uniqueness violation</exception>
+<person id="1"><car make="honda"/><car make="vw"/></person><person id="2"><car make="vw"/></person>
+
+TEST 3:
+
+<exception>zerr:ZDDY0024 : "f:PersonId": index uniqueness violation</exception>
+<person id="1"><car make="honda"/><car make="vw"/></person><person id="2"><car make="vw"/></person>
+
+TEST 4:
+
+<person id="1"><car make="vw"/></person><person id="2"><car make="vw"/></person>

=== modified file 'test/rbkt/Queries/zorba/index/auctions1u.xq'
--- test/rbkt/Queries/zorba/index/auctions1u.xq	2012-07-11 04:46:41 +0000
+++ test/rbkt/Queries/zorba/index/auctions1u.xq	2012-07-12 16:38:27 +0000
@@ -22,6 +22,8 @@
   as first into
     dml:collection($auctions:auctions)/site/people;
   
+  fn:trace("HELLO WORLD", "");
+
   index_dml:refresh-index($emp-id);
   (: don't refresh the emp-city index manually because it's done automatically :)
 }

=== added file 'test/rbkt/Queries/zorba/index/auctions2u.xq'
--- test/rbkt/Queries/zorba/index/auctions2u.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/index/auctions2u.xq	2012-07-12 16:38:27 +0000
@@ -0,0 +1,175 @@
+import module namespace ddl = "http://www.zorba-xquery.com/modules/store/static/collections/ddl";;
+import module namespace dml = "http://www.zorba-xquery.com/modules/store/static/collections/dml";;
+import module namespace index_ddl = "http://www.zorba-xquery.com/modules/store/static/indexes/ddl";;
+import module namespace index_dml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";;
+
+import module namespace auctions = "http://www.w3.org/TestModules/auctions"; at
+                                       "auctions_module1.xqlib";
+
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+
+
+variable $person := 
+  <doc>
+  <site>
+  <people>
+  <person id="person203">
+  <name>Ewing Andrade</name>
+  <emailaddress>mailto:Andrade@xxxxxxx</emailaddress>
+  <city>Portland</city>
+  <profile income="41889.41">
+  <interest category="category0"/>
+  <interest category="category0"/>
+  <business>Yes</business>
+  <age>18</age>
+  </profile>
+  <watches>
+  <watch open_auction="open_auction6"/>
+  <watch open_auction="open_auction2"/>
+  <watch open_auction="open_auction6"/>
+  <watch open_auction="open_auction5"/>
+  </watches>
+  </person>
+  </people>
+  </site>
+  </doc>;
+
+
+variable $person2 := 
+  <doc>
+  <site>
+  <people>
+  <person id="person205">
+  <name>Dr Who</name>
+  <emailaddress>mailto:boo@xxxxxxxx</emailaddress>
+  <city>Amsterdam</city>
+  <profile income="41000000000889.41">
+  <interest category="category0"/>
+  <interest category="category0"/>
+  <business>Yes</business>
+  <age>18000</age>
+  </profile>
+  <watches>
+  <watch open_auction="open_auction6"/>
+  <watch open_auction="open_auction2"/>
+  <watch open_auction="open_auction6"/>
+  <watch open_auction="open_auction5"/>
+  </watches>
+  </person>
+  </people>
+  </site>
+  </doc>;
+
+
+"
+TEST 1:
+
+"
+,
+{
+  auctions:create-db();
+
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+
+TEST 2:
+
+"
+,
+{
+  dml:insert-nodes($auctions:auctions, $person);
+
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+
+TEST 3:
+
+"
+,
+{
+  dml:delete-nodes(dml:collection($auctions:auctions)[2]);
+
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+
+TEST 4:
+
+"
+,
+{
+  dml:insert-nodes($auctions:auctions, $person);
+
+  (
+    dml:insert-nodes($auctions:auctions, $person2),
+
+    dml:delete-nodes(dml:collection($auctions:auctions)[2]),
+
+    insert node <watch open_auction="open_auction6"/> into 
+    (dml:collection($auctions:auctions)[2])//watches
+  );
+
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+
+TEST 5:
+
+"
+,
+{
+  (
+    dml:insert-nodes($auctions:auctions, $person),
+
+    insert node <watch open_auction="open_auction8"/> into 
+    (dml:collection($auctions:auctions)[2])//watches
+  );
+
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+
+TEST 6 (undo without do):
+
+"
+,
+{
+  try
+  {{
+  (
+    dml:insert-nodes($auctions:auctions, $person),
+
+    insert node (attribute id { 1 }) into $person//person
+  );
+  ()
+  }}
+  catch *
+  {
+    <exception>{$err:code} : {$err:description}</exception>
+  }
+  ,
+  for $x in auctions:probe-point-watch($auctions:PersonWatches,
+                                       ("open_auction6", "open_auction2"))
+  return <person id = "{$x/@id}">{$x//watches}</person>
+}
+,
+"
+"
+

=== modified file 'test/rbkt/Queries/zorba/index/auctions_module1.xqlib'
--- test/rbkt/Queries/zorba/index/auctions_module1.xqlib	2012-07-11 04:46:41 +0000
+++ test/rbkt/Queries/zorba/index/auctions_module1.xqlib	2012-07-12 16:38:27 +0000
@@ -44,7 +44,7 @@
   auction. A person may watch multiple open auctions.
 :)
 
-declare %ann:general-equality %ann:manual index auctions:PersonWatches
+declare %ann:general-equality %ann:automatic index auctions:PersonWatches
 on nodes dml:collection(xs:QName("auctions:auctions"))/site/people/person
 by (for $x in ./watches/watch/@open_auction return xs:string($x)) as xs:string*;
 

=== modified file 'test/rbkt/Queries/zorba/index/count.xqlib'
--- test/rbkt/Queries/zorba/index/count.xqlib	2012-05-11 20:30:16 +0000
+++ test/rbkt/Queries/zorba/index/count.xqlib	2012-07-12 16:38:27 +0000
@@ -11,18 +11,21 @@
 
 declare collection def:user as node()*;
 
+
 declare variable $def:user := xs:QName("def:user");
  
 declare %ann:automatic %ann:unique %ann:value-equality index def:user-by-uid
   on nodes dml:collection(xs:QName("def:user"))
   by xs:string(@uid) as xs:string;
 
+
 declare variable $def:user-by-uid := xs:QName("def:user-by-uid");
  
 declare %ann:automatic %ann:value-range index def:user-by-uid-range
   on nodes dml:collection(xs:QName("def:user"))
   by xs:string(@uid) as xs:string;
 
+
 declare variable $def:user-by-uid-range := xs:QName("def:user-by-uid-range");
 
 declare %ann:manual %ann:general-range index def:user-by-uid-general-range
@@ -31,6 +34,7 @@
 
 declare variable $def:user-by-uid-general-range := xs:QName("def:user-by-uid-general-range");
 
+
 declare %ann:sequential function def:init()
 {
   ddl:create($def:user);
@@ -57,6 +61,7 @@
   count(index_dml:probe-index-point-value(xs:QName("def:user-by-uid"), "1"))
 };
 
+
 declare function def:count-user-range()
 {
   count(
@@ -66,6 +71,7 @@
   )
 };
 
+
 declare function def:count-user-general-range()
 {
   count(

=== modified file 'test/rbkt/Queries/zorba/index/numbers.xml'
--- test/rbkt/Queries/zorba/index/numbers.xml	2012-07-11 04:46:41 +0000
+++ test/rbkt/Queries/zorba/index/numbers.xml	2012-07-12 16:38:27 +0000
@@ -8,3 +8,38 @@
 
 <xs_long num="9223372036854771200"/>
 </numbers>
+
+<!--
+
+RELEASE:
+
+92 23 37 20 36 85 47 70 17 8
+92 23 37 20 36 85 47 70 70 0
+
+92 23 37 20 36 85 47 70 68 8
+92 23 37 20 36 85 47 70 70 0
+
+92 23 37 20 36 85 47 70 88 8
+92 23 37 20 36 85 47 70 70 0
+
+92 23 37 20 36 85 47 71 20 0
+92 23 37 20 36 85 47 71 70 0
+
+probe:
+92 23 37 20 36 85 47 70 68 8 E0
+
+
+DEBUG:
+
+92 23 37 20 36 85 47 70 17 8
+
+
+92 23 37 20 36 85 47 70 68 8
+
+
+92 23 37 20 36 85 47 70 88 8
+
+
+92 23 37 20 36 85 47 71 20 0
+
+-->

=== modified file 'test/rbkt/Queries/zorba/index/numbers.xqlib'
--- test/rbkt/Queries/zorba/index/numbers.xqlib	2012-07-11 04:46:41 +0000
+++ test/rbkt/Queries/zorba/index/numbers.xqlib	2012-07-12 16:38:27 +0000
@@ -10,14 +10,19 @@
 
 
 declare variable $num:collname := xs:QName("num:numbers");
+declare variable $num:collname2 := xs:QName("num:numbers2");
 
 declare variable $num:idx-g-h-long := xs:QName("num:idx-g-h-long");
 declare variable $num:idx-g-t-long := xs:QName("num:idx-g-t-long");
+declare variable $num:idx-g-h-untyped := xs:QName("num:idx-g-h-untyped");
+
 
 declare collection num:numbers as node()*;
 
-
-declare %ann:general-equality %ann:manual index num:idx-g-h-long
+declare collection num:numbers2 as node()*;
+
+
+declare %ann:general-equality %ann:automatic index num:idx-g-h-long
 on nodes dml:collection(xs:QName("num:numbers"))//xs_long
 by xs:long(.//@num);
 
@@ -26,3 +31,7 @@
 on nodes dml:collection(xs:QName("num:numbers"))//xs_long
 by xs:long(.//@num);
 
+
+declare %ann:general-equality %ann:automatic index num:idx-g-h-untyped
+on nodes dml:collection(xs:QName("num:numbers2"))/*
+by data(.);

=== added file 'test/rbkt/Queries/zorba/index/numbers.xsd'
--- test/rbkt/Queries/zorba/index/numbers.xsd	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/index/numbers.xsd	2012-07-12 16:38:27 +0000
@@ -0,0 +1,10 @@
+<xs:schema  xmlns:xs="http://www.w3.org/2001/XMLSchema";
+            targetNamespace="http://www.zorba-xquery.com/numbers.xsd";
+            xmlns="http://www.zorba-xquery.com/numbers.xsd";
+            elementFormDefault="qualified">
+
+
+<xs:element name="long" type="xs:long"/>
+<xs:element name="integer" type="xs:integer"/>
+
+</xs:schema>

=== added file 'test/rbkt/Queries/zorba/index/numbers2.xq'
--- test/rbkt/Queries/zorba/index/numbers2.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/index/numbers2.xq	2012-07-12 16:38:27 +0000
@@ -0,0 +1,92 @@
+import module namespace num = "http://www.w3.org/TestModules/numbers"; at "numbers.xqlib";
+
+import module namespace ddl = "http://www.zorba-xquery.com/modules/store/static/collections/ddl";;
+import module namespace dml = "http://www.zorba-xquery.com/modules/store/static/collections/dml";;
+import module namespace iddl = "http://www.zorba-xquery.com/modules/store/static/indexes/ddl";;
+import module namespace idml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";;
+
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+
+import module namespace schema = "http://www.zorba-xquery.com/modules/schema";;
+
+import schema namespace s = "http://www.zorba-xquery.com/numbers.xsd"; at "numbers.xsd";
+
+declare variable $doc :=
+<numbers>
+<s:long>1</s:long>
+<s:integer>2</s:integer>
+<untyped>3</untyped>
+</numbers>
+;
+
+declare variable $vdoc := validate lax { $doc };
+
+
+ddl:create($num:collname2);
+
+iddl:create($num:idx-g-h-untyped);
+
+dml:insert-nodes($num:collname2, $vdoc);
+
+
+schema:schema-type(data(dml:collection($num:collname2)//s:long))
+,
+"
+
+TEST 1:
+
+"
+,
+try
+{
+  idml:probe-index-point-value($num:idx-g-h-untyped, 3) 
+}
+catch *
+{
+  <exception>{$err:code} : {$err:description}</exception>
+}
+,
+"
+
+TEST 2:
+
+"
+,
+{
+  delete node dml:collection($num:collname2)/untyped;
+
+  idml:probe-index-point-general($num:idx-g-h-untyped, 3)
+  ,
+  "
+  "
+  ,
+  idml:probe-index-point-value($num:idx-g-h-untyped, 2)
+}
+,
+"
+
+TEST 3:
+
+"
+,
+{
+  insert node <untyped>2</untyped> as last into dml:collection($num:collname2)[1];
+
+  idml:probe-index-point-general($num:idx-g-h-untyped, 2),
+"
+",
+  idml:probe-index-point-general($num:idx-g-h-untyped, 2.0),
+"
+",
+  idml:probe-index-point-general($num:idx-g-h-untyped, xs:double(2.0)),
+"
+",
+  idml:probe-index-point-general($num:idx-g-h-untyped, xs:int(2)),
+"
+",
+  idml:probe-index-point-general($num:idx-g-h-untyped, "2")
+}
+,
+"
+"
+

=== modified file 'test/rbkt/Queries/zorba/index/undo2.xq'
--- test/rbkt/Queries/zorba/index/undo2.xq	2012-04-23 08:44:52 +0000
+++ test/rbkt/Queries/zorba/index/undo2.xq	2012-07-12 16:38:27 +0000
@@ -28,7 +28,7 @@
 }}
 catch * 
 {
-  $err:code
+  <exception>{$err:code} : {$err:description}</exception>
 }
 ,
 

=== modified file 'test/rbkt/Queries/zorba/index/undo2.xqlib'
--- test/rbkt/Queries/zorba/index/undo2.xqlib	2012-04-22 21:55:56 +0000
+++ test/rbkt/Queries/zorba/index/undo2.xqlib	2012-07-12 16:38:27 +0000
@@ -12,18 +12,21 @@
 declare variable $auctions:auctions2 := xs:QName("auctions:auctions2");
 declare variable $auctions:PersonId2 := xs:QName("auctions:PersonId2");
 
+
 declare %an:ordered collection auctions:auctions1 as node()*;
 
 declare %an:automatic %an:value-equality index auctions:PersonId1
 on nodes dml:collection(xs:QName("auctions:auctions1"))
 by xs:string(./@key) as xs:string;
 
+
 declare %an:ordered collection auctions:auctions2 as node()*;
 
 declare %an:unique %an:automatic %an:value-range index auctions:PersonId2
 on nodes dml:collection(xs:QName("auctions:auctions2"))
 by xs:string(./@id) as xs:string;
 
+
 declare %an:sequential function auctions:create-db()
 {
   ddl:create($auctions:auctions1);

=== added file 'test/rbkt/Queries/zorba/index/undo4.xq'
--- test/rbkt/Queries/zorba/index/undo4.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/index/undo4.xq	2012-07-12 16:38:27 +0000
@@ -0,0 +1,145 @@
+
+import module namespace u = "http://www.zorba-xquery.com/unique-index"; at "undo4.xqlib";
+
+import module namespace dml = "http://www.zorba-xquery.com/modules/store/static/collections/dml";;
+import module namespace idml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";;
+
+declare namespace zerr = "http://www.zorba-xquery.com/errors";;
+declare namespace err = "http://www.w3.org/2005/xqt-errors";;
+
+u:create-db();
+
+
+dml:insert-nodes($u:c1, 
+<person id="1">
+<car make="honda"/><car make="vw"/>
+</person>);
+
+dml:insert-nodes($u:c1,
+<person id="2">
+<car make="vw"/>
+</person>);
+
+
+dml:insert-nodes($u:c2, 
+<person id="1">
+<car make="honda"/><car make="vw"/>
+</person>);
+
+
+idml:probe-index-point-general($u:PersonCars, "vw")
+,
+"
+
+TEST 0:
+
+"
+,
+try
+{
+  idml:probe-index-point-value($u:PersonCars, "vw")
+}
+catch * 
+{
+  <exception>{$err:code} : {$err:description}</exception>
+}
+,
+"
+
+TEST 1:
+
+"
+,
+try
+{{
+  (
+    dml:insert-nodes($u:c1, <person id="3"><car make="vw"/></person>),
+
+    dml:insert-nodes($u:c2, <person id="1"/>)
+  );
+  ()
+}}
+catch * 
+{
+  <exception>{$err:code} : {$err:description}</exception>
+}
+,
+"
+"
+,
+idml:probe-index-point-general($u:PersonCars, "vw")
+,
+"
+
+TEST 2:
+
+"
+,
+try
+{{
+  (
+    dml:insert-nodes($u:c1, <person id="3"><car make="vw"/></person>),
+
+    dml:delete-node-first($u:c1),
+
+    dml:insert-nodes($u:c2, <person id="1"/>)
+  );
+  ()
+}}
+catch * 
+{
+  <exception>{$err:code} : {$err:description}</exception>
+}
+,
+"
+"
+,
+idml:probe-index-point-general($u:PersonCars, "vw")
+,
+"
+
+TEST 3:
+
+"
+,
+try
+{{
+  (
+    insert node <car make="BMW"/> into dml:collection($u:c1)[1],
+
+    dml:insert-nodes($u:c1, <person id="3"><car make="vw"/></person>),
+
+    dml:delete-node-first($u:c1),
+
+    delete nodes dml:collection($u:c1)[2]/car,
+
+    dml:insert-nodes($u:c2, <person id="1"/>)
+  );
+  ()
+}}
+catch * 
+{
+  <exception>{$err:code} : {$err:description}</exception>
+}
+,
+"
+"
+,
+idml:probe-index-point-general($u:PersonCars, ("vw", "BMW"))
+,
+"
+
+TEST 4:
+
+"
+,
+{
+delete nodes dml:collection($u:c1)[1]/car[1];
+
+idml:probe-index-point-value($u:PersonCars, "vw")
+}
+,
+"
+"
+
+

=== added file 'test/rbkt/Queries/zorba/index/undo4.xqlib'
--- test/rbkt/Queries/zorba/index/undo4.xqlib	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/index/undo4.xqlib	2012-07-12 16:38:27 +0000
@@ -0,0 +1,43 @@
+module namespace f = "http://www.zorba-xquery.com/unique-index";;
+
+import module namespace ddl = "http://www.zorba-xquery.com/modules/store/static/collections/ddl";;
+import module namespace iddl = "http://www.zorba-xquery.com/modules/store/static/indexes/ddl";;
+import module namespace dml = "http://www.zorba-xquery.com/modules/store/static/collections/dml";;
+import module namespace idml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";;
+
+declare namespace an = "http://www.zorba-xquery.com/annotations";;
+
+
+
+declare variable $f:c1 := xs:QName("f:c1");
+declare variable $f:PersonCars := xs:QName("f:PersonCars");
+
+declare %an:ordered collection f:c1 as node()*;
+
+declare %an:automatic %an:general-equality index f:PersonCars
+on nodes dml:collection(xs:QName("f:c1"))
+by (for $x in ./car return xs:string($x/@make)) as xs:string*;
+
+
+
+declare variable $f:c2 := xs:QName("f:c2");
+declare variable $f:PersonId := xs:QName("f:PersonId");
+
+declare %an:ordered collection f:c2 as node()*;
+
+declare %an:unique %an:automatic %an:value-range index f:PersonId
+on nodes dml:collection(xs:QName("f:c2"))
+by xs:string(./@id) as xs:string;
+
+
+
+declare %an:sequential function f:create-db()
+{
+  ddl:create($f:c1);
+
+  ddl:create($f:c2);
+
+  iddl:create($f:PersonCars);
+
+  iddl:create($f:PersonId);
+};


Follow ups