1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "stdafx.h"
17 
18 #include <algorithm>
19 
20 #include "diagnostics/xquery_diagnostics.h"
21 #include "diagnostics/util_macros.h"
22 
23 #include "store_defs.h"
24 #include "simple_store.h"
25 #include "collection.h"
26 #include "simple_index_value.h"
27 #include "simple_index_general.h"
28 #include "simple_pul.h"
29 #include "pul_primitives.h"
30 #include "node_items.h"
31 #ifdef ZORBA_WITH_JSON
32 #  include "json_items.h"
33 #endif
34 #include "atomic_items.h"
35 #include "pul_primitive_factory.h"
36 #include "node_factory.h"
37 
38 #include "store/api/iterator.h"
39 #include "store/api/item_factory.h"
40 #include "store/api/validator.h"
41 #include "store/api/ic.h"
42 
43 
44 namespace zorba {
45 namespace simplestore {
46 
47 
48 /*******************************************************************************
49 
50 ********************************************************************************/
cleanList(std::vector<UpdatePrimitive * > & aVector)51 void cleanList(std::vector<UpdatePrimitive*>& aVector)
52 {
53   std::vector<UpdatePrimitive*>::iterator ite = aVector.begin();
54   std::vector<UpdatePrimitive*>::iterator end = aVector.end();
55 
56   for (; ite != end; ++ite)
57   {
58     delete (*ite);
59   }
60 }
61 
62 
63 /*******************************************************************************
64 
65 ********************************************************************************/
applyList(std::vector<UpdatePrimitive * > & list)66 void applyList(std::vector<UpdatePrimitive*>& list)
67 {
68   std::vector<UpdatePrimitive*>::iterator iter = list.begin();
69   std::vector<UpdatePrimitive*>::iterator end = list.end();
70 
71   for (; iter != end; ++iter)
72   {
73     (*iter)->apply();
74   }
75 }
76 
77 
78 /*******************************************************************************
79 
80 ********************************************************************************/
undoList(std::vector<UpdatePrimitive * > & list)81 void undoList(std::vector<UpdatePrimitive*>& list)
82 {
83   csize size = list.size();
84 
85   for (csize i = size; i > 0; --i)
86   {
87     if (list[i-1]->isApplied())
88       list[i-1]->undo();
89   }
90 }
91 
92 
93 /*******************************************************************************
94 
95 ********************************************************************************/
~NodeToUpdatesMap()96 NodeToUpdatesMap::~NodeToUpdatesMap()
97 {
98   NodeToUpdatesMap::iterator ite = theMap.begin();
99   NodeToUpdatesMap::iterator end = theMap.end();
100 
101   for (; ite != end; ++ite)
102   {
103     delete (*ite).second;
104   }
105 }
106 
107 
108 /*******************************************************************************
109 
110 ********************************************************************************/
PULImpl()111 PULImpl::PULImpl()
112   :
113   PUL(),
114   theNoCollectionPul(NULL),
115   theLastPul(NULL),
116   theLastCollection(NULL),
117   theValidator(NULL),
118   theInheritNSBindings(false)
119 {
120 }
121 
122 
123 /*******************************************************************************
124 
125 ********************************************************************************/
~PULImpl()126 PULImpl::~PULImpl()
127 {
128   cleanList(thePutList);
129 
130   cleanList(theCreateIndexList);
131   cleanList(theRefreshIndexList);
132   cleanList(theDeleteIndexList);
133 
134   cleanList(theValidationList);
135 
136   CollectionPuls::iterator ite = theCollectionPuls.begin();
137   CollectionPuls::iterator end = theCollectionPuls.end();
138 
139   for (; ite != end; ++ite)
140   {
141     delete (*ite);
142   }
143 
144   cleanList(theICActivationList);
145   cleanList(theCreateDocumentList);
146   cleanList(theDeleteDocumentList);
147 
148   cleanList(theCreateHashMapList);
149   cleanList(theDestroyHashMapList);
150   cleanList(theInsertIntoHashMapList);
151   cleanList(theRemoveFromHashMapList);
152 }
153 
154 
155 /*******************************************************************************
156 
157 ********************************************************************************/
setValidator(store::SchemaValidator * validator)158 void PULImpl::setValidator(store::SchemaValidator* validator)
159 {
160   theValidator = validator;
161 }
162 
163 
164 /*******************************************************************************
165 
166 ********************************************************************************/
getCollectionPul(const store::Item * target)167 CollectionPul* PULImpl::getCollectionPul(const store::Item* target)
168 {
169   const QNameItem* collName;
170 
171 #ifdef ZORBA_WITH_JSON
172   assert(target->isNode()
173       || target->isJSONObject()
174       || target->isJSONArray());
175 #else
176   assert(target->isNode());
177 #endif
178 
179   const store::Collection* lCollection;
180 
181   if (target->isNode())
182   {
183     assert(dynamic_cast<const XmlNode*>(target));
184     const XmlNode* lNode = static_cast<const XmlNode*>(target);
185     lCollection = lNode->getCollection();
186 #ifdef ZORBA_WITH_JSON
187   }
188   else if (target->isJSONItem())
189   {
190     assert(dynamic_cast<const json::JSONItem*>(target));
191     const json::JSONItem* lJSONItem = static_cast<const json::JSONItem*>(target);
192     lCollection = lJSONItem->getCollection();
193 #endif
194   }
195 
196   if (lCollection != NULL)
197   {
198     collName = static_cast<const QNameItem*>(lCollection->getName())->getNormalized();
199 
200     if (collName == theLastCollection)
201       return theLastPul;
202 
203     return getCollectionPulByName(collName, lCollection->isDynamic());
204   }
205   else if (theNoCollectionPul != NULL)
206   {
207     return theNoCollectionPul;
208   }
209   else
210   {
211     theNoCollectionPul = new CollectionPul(this, NULL);
212     theCollectionPuls.push_back(theNoCollectionPul);
213     theCollectionPulsMap[NULL] = theCollectionPuls.size() - 1;
214     return theNoCollectionPul;
215   }
216 }
217 
218 
getCollectionPulByName(const store::Item * name,bool isDynamic)219 CollectionPul* PULImpl::getCollectionPulByName(
220     const store::Item* name,
221     bool isDynamic)
222 {
223   const QNameItem* collName = static_cast<const QNameItem*>(name)->getNormalized();
224 
225   assert(name->isAtomic());
226 
227   // "name" is the name of a collection.
228   if (name == theLastCollection)
229     return theLastPul;
230 
231   CollectionPulMap::iterator ite = theCollectionPulsMap.find(collName);
232 
233   theLastCollection = collName;
234 
235   if (ite != theCollectionPulsMap.end())
236   {
237     theLastPul = theCollectionPuls[ite->second];
238   }
239   else
240   {
241     Collection* collection = static_cast<Collection*>
242     (GET_STORE().getCollection(collName, isDynamic).getp());
243 
244     theLastPul = new CollectionPul(this, collection);
245 
246     theCollectionPuls.push_back(theLastPul);
247 
248     theCollectionPulsMap[collName] = theCollectionPuls.size() - 1;
249   }
250 
251   return theLastPul;
252 }
253 
254 
255 
256 /*******************************************************************************
257   Create a delete primitive in "this" pul for the given node, if another delete
258   for the same node does not exist already.
259 ********************************************************************************/
addDelete(const QueryLoc * aQueryLoc,store::Item_t & target)260 void PULImpl::addDelete(const QueryLoc* aQueryLoc, store::Item_t& target)
261 {
262   CollectionPul* pul = getCollectionPul(target.getp());
263 
264   XmlNode* n = BASE_NODE(target);
265 
266   NodeUpdates* updates = NULL;
267   bool found = pul->theNodeToUpdatesMap.get(n, updates);
268 
269   if (!found)
270   {
271     UpdDelete* upd = GET_PUL_FACTORY().createUpdDelete(pul, aQueryLoc, target);
272     pul->theDeleteList.push_back(upd);
273 
274     updates = new NodeUpdates(1);
275     (*updates)[0] = upd;
276     pul->theNodeToUpdatesMap.insert(n, updates);
277   }
278   else
279   {
280     csize numUpdates = updates->size();
281     for (csize i = 0; i < numUpdates; ++i)
282     {
283       if ((*updates)[i]->getKind() == store::UpdateConsts::UP_DELETE)
284         return;
285     }
286 
287     UpdDelete* upd = GET_PUL_FACTORY().createUpdDelete(pul,  aQueryLoc,target);
288     pul->theDeleteList.push_back(upd);
289     updates->push_back(upd);
290   }
291 }
292 
293 
294 /*******************************************************************************
295 
296 ********************************************************************************/
addInsertInto(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & children)297 void PULImpl::addInsertInto(
298     const QueryLoc* aQueryLoc,
299     store::Item_t& target,
300     std::vector<store::Item_t>& children)
301 {
302   store::Item_t sibling;
303   addInsertChildren(aQueryLoc,
304                     store::UpdateConsts::UP_INSERT_INTO,
305                     target,
306                     sibling,
307                     children);
308 }
309 
310 
addInsertFirst(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & children)311 void PULImpl::addInsertFirst(
312     const QueryLoc* aQueryLoc,
313     store::Item_t& target,
314     std::vector<store::Item_t>& children)
315 {
316   store::Item_t sibling;
317   addInsertChildren(aQueryLoc,
318                     store::UpdateConsts::UP_INSERT_INTO_FIRST,
319                     target,
320                     sibling,
321                     children);
322 }
323 
324 
addInsertLast(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & children)325 void PULImpl::addInsertLast(
326     const QueryLoc* aQueryLoc,
327     store::Item_t& target,
328     std::vector<store::Item_t>& children)
329 {
330   store::Item_t sibling;
331   addInsertChildren(aQueryLoc, store::UpdateConsts::UP_INSERT_INTO_LAST,
332                     target, sibling, children);
333 }
334 
335 
addInsertBefore(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & siblings)336 void PULImpl::addInsertBefore(
337     const QueryLoc* aQueryLoc,
338     store::Item_t& target,
339     std::vector<store::Item_t>& siblings)
340 {
341   store::Item_t p = target->getParent();
342   addInsertChildren(aQueryLoc, store::UpdateConsts::UP_INSERT_BEFORE, p, target, siblings);
343 }
344 
345 
addInsertAfter(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & siblings)346 void PULImpl::addInsertAfter(
347     const QueryLoc* aQueryLoc,
348     store::Item_t& target,
349     std::vector<store::Item_t>& siblings)
350 {
351   store::Item_t p = target->getParent();
352   addInsertChildren(aQueryLoc, store::UpdateConsts::UP_INSERT_AFTER, p, target, siblings);
353 }
354 
355 
addInsertChildren(const QueryLoc * aQueryLoc,store::UpdateConsts::UpdPrimKind kind,store::Item_t & target,store::Item_t & sibling,std::vector<store::Item_t> & children)356 void PULImpl::addInsertChildren(
357     const QueryLoc* aQueryLoc,
358     store::UpdateConsts::UpdPrimKind kind,
359     store::Item_t& target,
360     store::Item_t& sibling,
361     std::vector<store::Item_t>& children)
362 {
363   CollectionPul* pul = getCollectionPul(target.getp());
364 
365   XmlNode* n = BASE_NODE(target);
366 
367   NodeUpdates* updates = 0;
368   bool found = pul->theNodeToUpdatesMap.get(n, updates);
369 
370   UpdInsertChildren* upd = GET_PUL_FACTORY().
371   createUpdInsertChildren(pul, aQueryLoc, kind, target, sibling, children);
372 
373   if (kind == store::UpdateConsts::UP_INSERT_INTO)
374     pul->theDoFirstList.push_back(upd);
375   else
376     pul->theInsertList.push_back(upd);
377 
378   if (!found)
379   {
380     updates = new NodeUpdates(1);
381     (*updates)[0] = upd;
382     pul->theNodeToUpdatesMap.insert(n, updates);
383   }
384   else
385   {
386     updates->push_back(upd);
387   }
388 }
389 
390 
391 /*******************************************************************************
392 
393 ********************************************************************************/
addInsertAttributes(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & attrs)394 void PULImpl::addInsertAttributes(
395     const QueryLoc* aQueryLoc,
396     store::Item_t& target,
397     std::vector<store::Item_t>& attrs)
398 {
399   CollectionPul* pul = getCollectionPul(target.getp());
400 
401   ElementNode* n = ELEM_NODE(target);
402 
403   csize numAttrs = attrs.size();
404   for (csize i = 0; i < numAttrs; i++)
405   {
406     n->checkNamespaceConflict(attrs[i]->getNodeName(), err::XUDY0023);
407   }
408 
409   NodeUpdates* updates = 0;
410   bool found = pul->theNodeToUpdatesMap.get(n, updates);
411 
412   UpdInsertAttributes* upd = GET_PUL_FACTORY().
413   createUpdInsertAttributes(pul, aQueryLoc, target, attrs);
414 
415   pul->theDoFirstList.push_back(upd);
416 
417   if (!found)
418   {
419     updates = new NodeUpdates(1);
420     (*updates)[0] = upd;
421     pul->theNodeToUpdatesMap.insert(n, updates);
422   }
423   else
424   {
425     updates->push_back(upd);
426   }
427 }
428 
429 
430 /*******************************************************************************
431 
432 ********************************************************************************/
addReplaceNode(const QueryLoc * aQueryLoc,store::Item_t & target,std::vector<store::Item_t> & newNodes)433 void PULImpl::addReplaceNode(
434     const QueryLoc* aQueryLoc,
435     store::Item_t& target,
436     std::vector<store::Item_t>& newNodes)
437 {
438   CollectionPul* pul = getCollectionPul(target.getp());
439 
440   XmlNode* n = BASE_NODE(target);
441 
442   store::Item_t parent = target->getParent();
443 
444   NodeUpdates* updates = 0;
445   bool found = pul->theNodeToUpdatesMap.get(n, updates);
446 
447   UpdatePrimitive* upd;
448   store::UpdateConsts::UpdPrimKind kind;
449 
450   if (target->getNodeKind() == store::StoreConsts::attributeNode)
451   {
452     ElementNode* elemParent = static_cast<ElementNode*>(n->theParent);
453 
454     if (elemParent != NULL)
455     {
456       csize numNewAttrs = newNodes.size();
457       for (csize i = 0; i < numNewAttrs; ++i)
458       {
459         elemParent->checkNamespaceConflict(newNodes[i]->getNodeName(), err::XUDY0023);
460       }
461     }
462 
463     upd = GET_PUL_FACTORY().
464           createUpdReplaceAttribute(pul, aQueryLoc, parent, target, newNodes);
465 
466     kind = store::UpdateConsts::UP_REPLACE_ATTRIBUTE;
467   }
468   else
469   {
470     upd = GET_PUL_FACTORY().
471           createUpdReplaceChild(pul, aQueryLoc, parent, target, newNodes);
472 
473     kind = store::UpdateConsts::UP_REPLACE_CHILD;
474   }
475 
476   if (!found)
477   {
478      updates = new NodeUpdates(1);
479     (*updates)[0] = upd;
480     pul->theNodeToUpdatesMap.insert(n, updates);
481   }
482   else
483   {
484     csize numUpdates = updates->size();
485     for (csize i = 0; i < numUpdates; ++i)
486     {
487       if ((*updates)[i]->getKind() == kind)
488       {
489         const QueryLoc* lLoc = upd->theLoc;
490         delete upd;
491         throw XQUERY_EXCEPTION(err::XUDY0016, ERROR_LOC(*lLoc));
492       }
493     }
494 
495     updates->push_back(upd);
496   }
497 
498    pul->theReplaceNodeList.push_back(upd);
499 }
500 
501 
502 /*******************************************************************************
503 
504 ********************************************************************************/
addReplaceContent(const QueryLoc * aQueryLoc,store::Item_t & target,store::Item_t & newChild)505 void PULImpl::addReplaceContent(
506     const QueryLoc* aQueryLoc,
507     store::Item_t& target,
508     store::Item_t& newChild)
509 {
510   CollectionPul* pul = getCollectionPul(target.getp());
511 
512   XmlNode* n = BASE_NODE(target);
513 
514   NodeUpdates* updates = NULL;
515   bool found = pul->theNodeToUpdatesMap.get(n, updates);
516 
517   if (!found)
518   {
519     UpdatePrimitive* upd = GET_PUL_FACTORY().
520     createUpdReplaceElemContent(pul, aQueryLoc, target, newChild);
521 
522     pul->theReplaceContentList.push_back(upd);
523 
524     updates = new NodeUpdates(1);
525     (*updates)[0] = upd;
526     pul->theNodeToUpdatesMap.insert(n, updates);
527   }
528   else
529   {
530     csize numUpdates = updates->size();
531     for (csize i = 0; i < numUpdates; ++i)
532     {
533       if ((*updates)[i]->getKind() == store::UpdateConsts::UP_REPLACE_CONTENT)
534         throw XQUERY_EXCEPTION(err::XUDY0017);
535     }
536 
537     UpdatePrimitive* upd = GET_PUL_FACTORY().
538     createUpdReplaceElemContent(pul, aQueryLoc, target, newChild);
539 
540     pul->theReplaceContentList.push_back(upd);
541     updates->push_back(upd);
542   }
543 }
544 
545 
546 /*******************************************************************************
547 
548 ********************************************************************************/
addReplaceValue(const QueryLoc * aQueryLoc,store::Item_t & target,zstring & newValue)549 void PULImpl::addReplaceValue(
550     const QueryLoc* aQueryLoc,
551     store::Item_t& target,
552     zstring& newValue)
553 {
554   CollectionPul* pul = getCollectionPul(target.getp());
555 
556   XmlNode* n = BASE_NODE(target);
557   store::StoreConsts::NodeKind targetKind = n->getNodeKind();
558 
559   NodeUpdates* updates = NULL;
560   bool found = pul->theNodeToUpdatesMap.get(n, updates);
561 
562   UpdatePrimitive* upd;
563   switch (targetKind)
564   {
565   case store::StoreConsts::attributeNode:
566   {
567     upd = GET_PUL_FACTORY().
568     createUpdReplaceAttrValue(pul, aQueryLoc, target, newValue);
569     break;
570   }
571   case store::StoreConsts::textNode:
572     upd = GET_PUL_FACTORY().
573     createUpdReplaceTextValue(pul, aQueryLoc, target, newValue);
574     break;
575   case store::StoreConsts::piNode:
576     upd = GET_PUL_FACTORY().
577     createUpdReplacePiValue(pul, aQueryLoc, target, newValue);
578     break;
579   case store::StoreConsts::commentNode:
580     upd = GET_PUL_FACTORY().
581     createUpdReplaceCommentValue(pul, aQueryLoc, target, newValue);
582     break;
583   default:
584     ZORBA_FATAL(0, "");
585   }
586 
587   if (!found)
588   {
589     pul->theDoFirstList.push_back(upd);
590 
591     updates = new NodeUpdates(1);
592     (*updates)[0] = upd;
593     pul->theNodeToUpdatesMap.insert(n, updates);
594   }
595   else
596   {
597     csize numUpdates = updates->size();
598     for (csize i = 0; i < numUpdates; i++)
599     {
600       if (store::UpdateConsts::isReplaceValue((*updates)[i]->getKind()))
601       {
602         delete upd;
603         throw XQUERY_EXCEPTION(err::XUDY0017);
604       }
605     }
606 
607     pul->theDoFirstList.push_back(upd);
608     updates->push_back(upd);
609   }
610 }
611 
612 
613 /*******************************************************************************
614 
615 ********************************************************************************/
addRename(const QueryLoc * aQueryLoc,store::Item_t & target,store::Item_t & newName)616 void PULImpl::addRename(
617     const QueryLoc* aQueryLoc,
618     store::Item_t& target,
619     store::Item_t& newName)
620 {
621   CollectionPul* pul = getCollectionPul(target.getp());
622 
623   XmlNode* n = BASE_NODE(target);
624   store::StoreConsts::NodeKind targetKind = n->getNodeKind();
625 
626   NodeUpdates* updates = NULL;
627   bool found = pul->theNodeToUpdatesMap.get(n, updates);
628 
629   UpdatePrimitive* upd;
630   switch (targetKind)
631   {
632   case store::StoreConsts::elementNode:
633   {
634     ElementNode* elemTarget = ELEM_NODE(target);
635     elemTarget->checkNamespaceConflict(newName.getp(), err::XUDY0023);
636 
637     upd = GET_PUL_FACTORY().
638     createUpdRenameElem(pul, aQueryLoc, target, newName);
639     break;
640   }
641   case store::StoreConsts::attributeNode:
642   {
643     ElementNode* elemParent = reinterpret_cast<ElementNode*>(n->theParent);
644 
645     if (elemParent != NULL)
646       elemParent->checkNamespaceConflict(newName.getp(), err::XUDY0023);
647 
648     upd = GET_PUL_FACTORY().createUpdRenameAttr(pul, aQueryLoc, target, newName);
649     break;
650   }
651   case store::StoreConsts::piNode:
652   {
653     zstring tmp;
654     newName->getStringValue2(tmp);
655     upd = GET_PUL_FACTORY().createUpdRenamePi(pul, aQueryLoc, target, tmp);
656     break;
657   }
658   default:
659     ZORBA_FATAL(0, "");
660   }
661 
662   if (!found)
663   {
664     pul->theDoFirstList.push_back(upd);
665 
666     updates = new NodeUpdates(1);
667     (*updates)[0] = upd;
668     pul->theNodeToUpdatesMap.insert(n, updates);
669   }
670   else
671   {
672     csize numUpdates = updates->size();
673     for (csize i = 0; i < numUpdates; i++)
674     {
675       if (store::UpdateConsts::isRename((*updates)[i]->getKind()))
676       {
677         delete upd;
678         throw XQUERY_EXCEPTION(err::XUDY0015);
679       }
680     }
681 
682     pul->theDoFirstList.push_back(upd);
683     updates->push_back(upd);
684   }
685 }
686 
687 
688 /*******************************************************************************
689 
690 ********************************************************************************/
addPut(const QueryLoc * aQueryLoc,store::Item_t & target,store::Item_t & uri)691 void PULImpl::addPut(
692     const QueryLoc* aQueryLoc,
693     store::Item_t& target,
694     store::Item_t& uri)
695 {
696   csize numPuts = thePutList.size();
697 
698   for (csize i = 0; i < numPuts; ++i)
699   {
700     UpdPut* upd = static_cast<UpdPut*>(thePutList[i]);
701 
702     if (upd->theTargetUri == uri)
703     {
704       throw XQUERY_EXCEPTION(err::XUDY0031, ERROR_PARAMS( uri->getStringValue()));
705     }
706   }
707 
708   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdPut(this, aQueryLoc, target, uri);
709 
710   thePutList.push_back(upd);
711 }
712 
713 
714 /*******************************************************************************
715 
716 ********************************************************************************/
addSetElementType(const QueryLoc * aQueryLoc,store::Item_t & target,store::Item_t & typeName,store::Item_t & value,bool haveValue,bool haveEmptyValue,bool haveTypedValue,bool isInSubstitutionGroup)717 void PULImpl::addSetElementType(
718     const QueryLoc* aQueryLoc,
719     store::Item_t& target,
720     store::Item_t& typeName,
721     store::Item_t& value,
722     bool haveValue,
723     bool haveEmptyValue,
724     bool haveTypedValue,
725     bool isInSubstitutionGroup)
726 {
727   UpdatePrimitive* upd = GET_PUL_FACTORY().
728   createUpdSetElementType(this,
729                           aQueryLoc,
730                           target,
731                           typeName,
732                           value,
733                           haveValue,
734                           haveEmptyValue,
735                           haveTypedValue,
736                           false,
737                           isInSubstitutionGroup);
738 
739   theValidationList.push_back(upd);
740 }
741 
742 
addSetElementType(const QueryLoc * aQueryLoc,store::Item_t & target,store::Item_t & typeName,std::vector<store::Item_t> & valueV,bool haveValue,bool haveEmptyValue,bool haveTypedValue,bool isInSubstitutionGroup)743 void PULImpl::addSetElementType(
744     const QueryLoc* aQueryLoc,
745     store::Item_t& target,
746     store::Item_t& typeName,
747     std::vector<store::Item_t>& valueV,
748     bool haveValue,
749     bool haveEmptyValue,
750     bool haveTypedValue,
751     bool isInSubstitutionGroup)
752 {
753   store::Item_t typedValue = new ItemVector(valueV);
754 
755   UpdatePrimitive* upd = GET_PUL_FACTORY().
756   createUpdSetElementType(this,
757                           aQueryLoc,
758                           target,
759                           typeName,
760                           typedValue,
761                           haveValue,
762                           haveEmptyValue,
763                           haveTypedValue,
764                           true,
765                           isInSubstitutionGroup);
766 
767   theValidationList.push_back(upd);
768 }
769 
770 
addSetAttributeType(const QueryLoc * loc,store::Item_t & target,store::Item_t & typeName,store::Item_t & typedValue)771 void PULImpl::addSetAttributeType(
772     const QueryLoc* loc,
773     store::Item_t& target,
774     store::Item_t& typeName,
775     store::Item_t& typedValue)
776 {
777   UpdatePrimitive* upd = GET_PUL_FACTORY().
778   createUpdSetAttributeType(this, loc, target, typeName, typedValue, false);
779 
780   theValidationList.push_back(upd);
781 }
782 
783 
addSetAttributeType(const QueryLoc * loc,store::Item_t & target,store::Item_t & typeName,std::vector<store::Item_t> & typedValueV)784 void PULImpl::addSetAttributeType(
785     const QueryLoc* loc,
786     store::Item_t&  target,
787     store::Item_t&  typeName,
788     std::vector<store::Item_t>& typedValueV)
789 {
790   store::Item_t typedValue = new ItemVector(typedValueV);
791 
792   UpdatePrimitive* upd = GET_PUL_FACTORY().
793   createUpdSetAttributeType(this, loc, target, typeName, typedValue, true);
794 
795   theValidationList.push_back(upd);
796 }
797 
798 
addRevalidate(const QueryLoc * aQueryLoc,store::Item_t & target)799 void PULImpl::addRevalidate(
800     const QueryLoc* aQueryLoc,
801     store::Item_t& target)
802 {
803   CollectionPul* pul = getCollectionPul(target.getp());
804 
805   XmlNode* n = BASE_NODE(target);
806 
807   NodeUpdates* updates = 0;
808   bool found = pul->theNodeToUpdatesMap.get(n, updates);
809 
810   UpdRevalidate* upd = GET_PUL_FACTORY().
811   createUpdRevalidate(this, aQueryLoc, target);
812 
813   pul->theRevalidateList.push_back(upd);
814 
815   if (!found)
816   {
817     updates = new NodeUpdates(1);
818     (*updates)[0] = upd;
819     pul->theNodeToUpdatesMap.insert(n, updates);
820   }
821   else
822   {
823     updates->push_back(upd);
824   }
825 }
826 
827 
828 /*******************************************************************************
829  Collection primitives
830 ********************************************************************************/
addCreateCollection(const QueryLoc * loc,store::Item_t & name,const std::vector<store::Annotation_t> & annotations,const store::Item_t & nodeType,bool isDynamic)831 void PULImpl::addCreateCollection(
832     const QueryLoc* loc,
833     store::Item_t& name,
834     const std::vector<store::Annotation_t>& annotations,
835     const store::Item_t& nodeType,
836     bool isDynamic)
837 {
838   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
839 
840   pul->theCreateCollectionList.push_back(GET_PUL_FACTORY().
841   createUpdCreateCollection(pul, loc, name, annotations, nodeType, isDynamic));
842 }
843 
844 
addDeleteCollection(const QueryLoc * loc,store::Item_t & name,bool isDynamic)845 void PULImpl::addDeleteCollection(
846     const QueryLoc* loc,
847     store::Item_t& name,
848     bool isDynamic)
849 {
850   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
851 
852   pul->theDeleteCollectionList.push_back(GET_PUL_FACTORY().
853   createUpdDeleteCollection(pul, loc, name, isDynamic));
854 }
855 
856 
addInsertIntoCollection(const QueryLoc * loc,store::Item_t & name,std::vector<store::Item_t> & nodes,bool isDynamic)857 void PULImpl::addInsertIntoCollection(
858     const QueryLoc* loc,
859     store::Item_t& name,
860     std::vector<store::Item_t>& nodes,
861     bool isDynamic)
862 {
863   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
864 
865   pul->theInsertIntoCollectionList.push_back(GET_PUL_FACTORY().
866   createUpdInsertIntoCollection(pul, loc, name, nodes, isDynamic));
867 }
868 
869 
addInsertFirstIntoCollection(const QueryLoc * loc,store::Item_t & name,std::vector<store::Item_t> & nodes,bool isDynamic)870 void PULImpl::addInsertFirstIntoCollection(
871     const QueryLoc* loc,
872     store::Item_t& name,
873     std::vector<store::Item_t>& nodes,
874     bool isDynamic)
875 {
876   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
877 
878   pul->theInsertIntoCollectionList.push_back(GET_PUL_FACTORY().
879   createUpdInsertFirstIntoCollection(pul, loc, name, nodes, isDynamic));
880 }
881 
882 
addInsertLastIntoCollection(const QueryLoc * loc,store::Item_t & name,std::vector<store::Item_t> & nodes,bool isDynamic)883 void PULImpl::addInsertLastIntoCollection(
884     const QueryLoc* loc,
885     store::Item_t& name,
886     std::vector<store::Item_t>& nodes,
887     bool isDynamic)
888 {
889   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
890 
891   pul->theInsertIntoCollectionList.push_back(GET_PUL_FACTORY().
892   createUpdInsertLastIntoCollection(pul, loc, name, nodes, isDynamic));
893 }
894 
895 
addInsertBeforeIntoCollection(const QueryLoc * loc,store::Item_t & name,store::Item_t & target,std::vector<store::Item_t> & nodes,bool isDynamic)896 void PULImpl::addInsertBeforeIntoCollection(
897     const QueryLoc* loc,
898     store::Item_t& name,
899     store::Item_t& target,
900     std::vector<store::Item_t>& nodes,
901     bool isDynamic)
902 {
903   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
904 
905   pul->theInsertIntoCollectionList.push_back(GET_PUL_FACTORY().
906   createUpdInsertBeforeIntoCollection(pul, loc, name, target, nodes, isDynamic));
907 }
908 
909 
addInsertAfterIntoCollection(const QueryLoc * loc,store::Item_t & name,store::Item_t & target,std::vector<store::Item_t> & nodes,bool isDynamic)910 void PULImpl::addInsertAfterIntoCollection(
911     const QueryLoc* loc,
912     store::Item_t& name,
913     store::Item_t& target,
914     std::vector<store::Item_t>& nodes,
915     bool isDynamic)
916 {
917   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
918 
919   pul->theInsertIntoCollectionList.push_back(GET_PUL_FACTORY().
920   createUpdInsertAfterIntoCollection(pul, loc, name, target, nodes, isDynamic));
921 }
922 
923 
addDeleteFromCollection(const QueryLoc * loc,store::Item_t & name,std::vector<store::Item_t> & nodes,bool isLast,bool isDynamic)924 void PULImpl::addDeleteFromCollection(
925     const QueryLoc* loc,
926     store::Item_t& name,
927     std::vector<store::Item_t>& nodes,
928     bool isLast,
929     bool isDynamic)
930 {
931   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
932 
933   pul->theDeleteFromCollectionList.push_back(GET_PUL_FACTORY().
934   createUpdDeleteNodesFromCollection(pul, loc, name, nodes, isLast, isDynamic));
935 }
936 
937 
addTruncateCollection(const QueryLoc * aQueryLoc,store::Item_t & name,bool isDynamic)938 void PULImpl::addTruncateCollection(
939     const QueryLoc* aQueryLoc,
940     store::Item_t& name,
941     bool isDynamic)
942 {
943   CollectionPul* pul = getCollectionPulByName(name.getp(), isDynamic);
944 
945   pul->theTruncateCollectionList.push_back(GET_PUL_FACTORY().
946   createUpdTruncateCollection(pul, aQueryLoc, name, isDynamic));
947 }
948 
949 
950 /*******************************************************************************
951   Index primitives
952 ********************************************************************************/
addCreateIndex(const QueryLoc * loc,const store::Item_t & qname,const store::IndexSpecification & spec,store::Iterator * sourceIter)953 void PULImpl::addCreateIndex(
954     const QueryLoc* loc,
955     const store::Item_t& qname,
956     const store::IndexSpecification& spec,
957     store::Iterator* sourceIter)
958 {
959   UpdatePrimitive* upd = GET_PUL_FACTORY().
960   createUpdCreateIndex(this, loc,  qname, spec, sourceIter);
961 
962   theCreateIndexList.push_back(upd);
963 }
964 
965 
addDeleteIndex(const QueryLoc * loc,const store::Item_t & qname)966 void PULImpl::addDeleteIndex(
967     const QueryLoc* loc,
968     const store::Item_t& qname)
969 {
970   UpdatePrimitive* upd = GET_PUL_FACTORY().
971   createUpdDeleteIndex(this, loc, qname);
972 
973   theDeleteIndexList.push_back(upd);
974 }
975 
976 
addRefreshIndex(const QueryLoc * loc,const store::Item_t & qname,store::Iterator * sourceIter)977 void PULImpl::addRefreshIndex(
978     const QueryLoc* loc,
979     const store::Item_t& qname,
980     store::Iterator* sourceIter)
981 {
982   UpdatePrimitive* upd = GET_PUL_FACTORY().
983   createUpdRefreshIndex(this, loc,  qname, sourceIter);
984 
985   theRefreshIndexList.push_back(upd);
986 }
987 
988 
989 /*******************************************************************************
990   Integrity Constraint Primitives
991 ********************************************************************************/
addActivateIC(const QueryLoc * loc,const store::Item_t & qname,const store::Item_t & aCollectionName)992 void PULImpl::addActivateIC(
993     const QueryLoc* loc,
994       const store::Item_t& qname,
995       const store::Item_t& aCollectionName)
996 {
997   UpdatePrimitive* upd =
998   GET_PUL_FACTORY().createUpdActivateIC(this, loc, qname, aCollectionName);
999 
1000   theICActivationList.push_back(upd);
1001 }
1002 
addActivateForeignKeyIC(const QueryLoc * loc,const store::Item_t & qname,const store::Item_t & aFromCollectionName,const store::Item_t & aToCollectionName)1003 void PULImpl::addActivateForeignKeyIC(
1004     const QueryLoc* loc,
1005       const store::Item_t& qname,
1006       const store::Item_t& aFromCollectionName,
1007       const store::Item_t& aToCollectionName)
1008 {
1009   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdActivateForeignKeyIC(this,
1010       loc,
1011       qname,
1012       aFromCollectionName,
1013       aToCollectionName);
1014 
1015   theICActivationList.push_back(upd);
1016 }
1017 
addDeActivateIC(const QueryLoc * loc,const store::Item_t & qname)1018 void PULImpl::addDeActivateIC(
1019     const QueryLoc* loc,
1020       const store::Item_t& qname)
1021 {
1022   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdDeActivateIC(this, loc, qname);
1023 
1024   theICActivationList.push_back(upd);
1025 }
1026 
1027 
1028 /*******************************************************************************
1029   Document PULs
1030 ********************************************************************************/
addCreateDocument(const QueryLoc * loc,const store::Item_t & uri,store::Item_t & doc)1031 void PULImpl::addCreateDocument(
1032     const QueryLoc* loc,
1033     const store::Item_t& uri,
1034     store::Item_t& doc)
1035 {
1036   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdCreateDocument(
1037       this, loc, uri, doc);
1038   theCreateDocumentList.push_back(upd);
1039 }
1040 
1041 
addDeleteDocument(const QueryLoc * loc,const store::Item_t & uri)1042 void PULImpl::addDeleteDocument(
1043     const QueryLoc* loc,
1044     const store::Item_t& uri)
1045 {
1046   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdDeleteDocument(
1047       this, loc, uri);
1048   theDeleteDocumentList.push_back(upd);
1049 }
1050 
1051 
1052 /*******************************************************************************
1053   HashMap PULs
1054 ********************************************************************************/
addCreateHashMap(const QueryLoc * loc,const store::Item_t & aQName,const std::vector<store::Item_t> & aKeyTypes,const std::vector<zstring> & aCollations,long aTimezone)1055 void PULImpl::addCreateHashMap(
1056     const QueryLoc* loc,
1057     const store::Item_t& aQName,
1058     const std::vector<store::Item_t>& aKeyTypes,
1059     const std::vector<zstring>& aCollations,
1060     long  aTimezone)
1061 {
1062   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdCreateHashMap(
1063       this, loc, aQName, aKeyTypes, aCollations, aTimezone);
1064 
1065   theCreateHashMapList.push_back(upd);
1066 }
1067 
addDestroyHashMap(const QueryLoc * loc,const store::Item_t & aQName)1068 void PULImpl::addDestroyHashMap(
1069     const QueryLoc* loc,
1070     const store::Item_t& aQName)
1071 {
1072   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdDestroyHashMap(
1073       this, loc, aQName);
1074 
1075   theDestroyHashMapList.push_back(upd);
1076 }
1077 
addInsertIntoHashMap(const QueryLoc * loc,const store::Item_t & aQName,const std::vector<store::Item_t> & aKey,const store::Iterator_t & aValue)1078 void PULImpl::addInsertIntoHashMap(
1079     const QueryLoc* loc,
1080     const store::Item_t& aQName,
1081     const std::vector<store::Item_t>& aKey,
1082     const store::Iterator_t& aValue)
1083 {
1084   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdInsertIntoHashMap(
1085       this, loc, aQName, aKey, aValue);
1086 
1087   theInsertIntoHashMapList.push_back(upd);
1088 }
1089 
addRemoveFromHashMap(const QueryLoc * loc,const store::Item_t & aQName,const std::vector<store::Item_t> & aKey)1090 void PULImpl::addRemoveFromHashMap(
1091     const QueryLoc* loc,
1092       const store::Item_t& aQName,
1093       const std::vector<store::Item_t>& aKey)
1094 {
1095   UpdatePrimitive* upd = GET_PUL_FACTORY().createUpdRemoveFromHashMap(
1096       this, loc, aQName, aKey);
1097 
1098   theRemoveFromHashMapList.push_back(upd);
1099 }
1100 
1101 
1102 #ifdef ZORBA_WITH_JSON
1103 /*******************************************************************************
1104 
1105 ********************************************************************************/
addJSONObjectInsert(const QueryLoc * loc,store::Item_t & target,store::Item_t & content)1106 void PULImpl::addJSONObjectInsert(
1107      const QueryLoc* loc,
1108      store::Item_t& target,
1109      store::Item_t& content)
1110 {
1111   assert(content->isJSONObject());
1112   assert(dynamic_cast<json::JSONObject*>(content.getp()));
1113   json::JSONObject* lObject = static_cast<json::JSONObject*>(content.getp());
1114   store::Iterator_t lIterator = lObject->getObjectKeys();
1115   lIterator->open();
1116   store::Item_t lKey;
1117   std::vector<store::Item_t> lKeys;
1118   std::vector<store::Item_t> lValues;
1119   while(lIterator->next(lKey))
1120   {
1121     lKeys.push_back(lKey);
1122     lValues.push_back(lObject->getObjectValue(lKey));
1123   }
1124   lIterator->close();
1125   this->addJSONObjectInsert(loc, target, lKeys, lValues);
1126 }
1127 
1128 /*******************************************************************************
1129 
1130 ********************************************************************************/
addJSONObjectInsert(const QueryLoc * loc,store::Item_t & target,std::vector<store::Item_t> & names,std::vector<store::Item_t> & values)1131 void PULImpl::addJSONObjectInsert(
1132      const QueryLoc* loc,
1133      store::Item_t& target,
1134      std::vector<store::Item_t>& names,
1135      std::vector<store::Item_t>& values)
1136 {
1137   CollectionPul* pul = getCollectionPul(target.getp());
1138 
1139   json::JSONObject* obj = static_cast<json::JSONObject*>(target.getp());
1140 
1141   csize numPairs = names.size();
1142 
1143   for (csize i = 0; i < numPairs; ++i)
1144   {
1145     if (obj->getObjectValue(names[i]) != NULL)
1146     {
1147       RAISE_ERROR(jerr::JNUP0006, loc, ERROR_PARAMS(names[i]->getStringValue()));
1148     }
1149 
1150     for (csize j = 0; j < i; ++j)
1151     {
1152       if (names[j]->equals(names[i]))
1153       {
1154         RAISE_ERROR(jerr::JNUP0005, loc, ERROR_PARAMS(names[i]->getStringValue()));
1155       }
1156     }
1157   }
1158 
1159   NodeUpdates* updates = 0;
1160   bool found = pul->theNodeToUpdatesMap.get(obj, updates);
1161 
1162   // merge object-insert primitives and raise error if duplicate names
1163   if (found)
1164   {
1165     NodeUpdates::iterator ite = updates->begin();
1166     NodeUpdates::iterator end = updates->end();
1167 
1168     for (; ite != end; ++ite)
1169     {
1170       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_OBJECT_INSERT)
1171         continue;
1172 
1173       UpdJSONObjectInsert* upd = static_cast<UpdJSONObjectInsert*>(*ite);
1174 
1175       csize numPairs1 = upd->theNames.size();
1176       csize numPairs2 = names.size();
1177       csize numPairs = numPairs1;
1178 
1179       upd->theNames.resize(numPairs1 + numPairs2);
1180       upd->theValues.resize(numPairs1 + numPairs2);
1181 
1182       for (csize i = 0; i < numPairs2; ++i, ++numPairs)
1183       {
1184         for (csize j = 0; j < numPairs1; ++j)
1185         {
1186           if (names[i]->equals(upd->theNames[j]))
1187             RAISE_ERROR(jerr::JNUP0005, loc, ERROR_PARAMS(names[i]->getStringValue()));
1188         }
1189 
1190         upd->theNames[numPairs].transfer(names[i]);
1191         upd->theValues[numPairs].transfer(values[i]);
1192       }
1193 
1194       return;
1195     }
1196 
1197     UpdatePrimitive* upd =  GET_PUL_FACTORY().
1198     createUpdJSONObjectInsert(pul, loc, target, names, values);
1199 
1200     pul->theJSONObjectInsertList.push_back(upd);
1201 
1202     updates->push_back(upd);
1203   }
1204   else
1205   {
1206     UpdatePrimitive* upd =  GET_PUL_FACTORY().
1207     createUpdJSONObjectInsert(pul, loc, target, names, values);
1208 
1209     pul->theJSONObjectInsertList.push_back(upd);
1210 
1211     updates = new NodeUpdates(1);
1212     (*updates)[0] = upd;
1213     pul->theNodeToUpdatesMap.insert(obj, updates);
1214   }
1215 }
1216 
1217 
1218 /*******************************************************************************
1219 
1220 ********************************************************************************/
addJSONObjectDelete(const QueryLoc * loc,store::Item_t & target,store::Item_t & name)1221 void PULImpl::addJSONObjectDelete(
1222    const QueryLoc* loc,
1223    store::Item_t& target,
1224    store::Item_t& name)
1225 {
1226   CollectionPul* pul = getCollectionPul(target.getp());
1227 
1228   json::JSONObject* obj = static_cast<json::JSONObject*>(target.getp());
1229 
1230   if (obj->getObjectValue(name) == NULL)
1231   {
1232     RAISE_ERROR(jerr::JNUP0016, loc,
1233     ERROR_PARAMS(ZED(JNUP0016_Object), name->getStringValue()));
1234   }
1235 
1236   NodeUpdates* updates = 0;
1237   bool found = pul->theNodeToUpdatesMap.get(obj, updates);
1238 
1239   // skip deletions with duplicate names
1240   if (found)
1241   {
1242     NodeUpdates::iterator ite = updates->begin();
1243     NodeUpdates::iterator end = updates->end();
1244 
1245     for (; ite != end; ++ite)
1246     {
1247       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_OBJECT_DELETE)
1248         continue;
1249 
1250       UpdJSONObjectDelete* upd = static_cast<UpdJSONObjectDelete*>(*ite);
1251 
1252       if (upd->theName->equals(name))
1253         return;
1254     }
1255 
1256     UpdatePrimitive* upd = GET_PUL_FACTORY().
1257     createUpdJSONObjectDelete(pul, loc, target, name);
1258 
1259     pul->theJSONObjectDeleteList.push_back(upd);
1260 
1261     updates->push_back(upd);
1262   }
1263   else
1264   {
1265     UpdatePrimitive* upd = GET_PUL_FACTORY().
1266     createUpdJSONObjectDelete(pul, loc, target, name);
1267 
1268     pul->theJSONObjectDeleteList.push_back(upd);
1269 
1270     updates = new NodeUpdates(1);
1271     (*updates)[0] = upd;
1272     pul->theNodeToUpdatesMap.insert(obj, updates);
1273   }
1274 }
1275 
1276 
1277 /*******************************************************************************
1278 
1279 ********************************************************************************/
addJSONObjectReplaceValue(const QueryLoc * loc,store::Item_t & target,store::Item_t & name,store::Item_t & newValue)1280 void PULImpl::addJSONObjectReplaceValue(
1281      const QueryLoc* loc,
1282      store::Item_t& target,
1283      store::Item_t& name,
1284      store::Item_t& newValue)
1285 {
1286   CollectionPul* pul = getCollectionPul(target.getp());
1287 
1288   json::JSONObject* obj = static_cast<json::JSONObject*>(target.getp());
1289 
1290   if (obj->getObjectValue(name) == NULL)
1291   {
1292     RAISE_ERROR(jerr::JNUP0016, loc,
1293     ERROR_PARAMS(ZED(JNUP0016_Object), name->getStringValue()));
1294   }
1295 
1296   NodeUpdates* updates = 0;
1297   bool found = pul->theNodeToUpdatesMap.get(obj, updates);
1298 
1299   // raise error if duplicate names
1300   if (found)
1301   {
1302     NodeUpdates::iterator ite = updates->begin();
1303     NodeUpdates::iterator end = updates->end();
1304 
1305     for (; ite != end; ++ite)
1306     {
1307       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_OBJECT_REPLACE_VALUE)
1308         continue;
1309 
1310       UpdJSONObjectReplaceValue* upd = static_cast<UpdJSONObjectReplaceValue*>(*ite);
1311 
1312       if (name->equals(upd->theName))
1313         RAISE_ERROR(jerr::JNUP0009, loc, ERROR_PARAMS(name->getStringValue()));
1314     }
1315 
1316     UpdatePrimitive* upd = GET_PUL_FACTORY().
1317     createUpdJSONObjectReplaceValue(pul, loc, target, name, newValue);
1318 
1319     pul->theJSONObjectReplaceValueList.push_back(upd);
1320 
1321     updates->push_back(upd);
1322   }
1323   else
1324   {
1325     UpdatePrimitive* upd = GET_PUL_FACTORY().
1326     createUpdJSONObjectReplaceValue(pul, loc, target, name, newValue);
1327 
1328     pul->theJSONObjectReplaceValueList.push_back(upd);
1329 
1330     updates = new NodeUpdates(1);
1331     (*updates)[0] = upd;
1332     pul->theNodeToUpdatesMap.insert(obj, updates);
1333   }
1334 }
1335 
1336 
1337 /*******************************************************************************
1338 
1339 ********************************************************************************/
addJSONObjectRename(const QueryLoc * loc,store::Item_t & target,store::Item_t & name,store::Item_t & newName)1340 void PULImpl::addJSONObjectRename(
1341      const QueryLoc* loc,
1342      store::Item_t& target,
1343      store::Item_t& name,
1344      store::Item_t& newName)
1345 {
1346   CollectionPul* pul = getCollectionPul(target.getp());
1347 
1348   json::JSONObject* obj = static_cast<json::JSONObject*>(target.getp());
1349 
1350   if (obj->getObjectValue(name) == NULL)
1351   {
1352     RAISE_ERROR(jerr::JNUP0016, loc,
1353     ERROR_PARAMS(ZED(JNUP0016_Object), name->getStringValue()));
1354   }
1355 
1356   if (obj->getObjectValue(newName) != NULL)
1357   {
1358     RAISE_ERROR(jerr::JNUP0006, loc, ERROR_PARAMS(newName->getStringValue()));
1359   }
1360 
1361   NodeUpdates* updates = 0;
1362   bool found = pul->theNodeToUpdatesMap.get(obj, updates);
1363 
1364   // raise error if duplicate names
1365   if (found)
1366   {
1367     NodeUpdates::iterator ite = updates->begin();
1368     NodeUpdates::iterator end = updates->end();
1369 
1370     for (; ite != end; ++ite)
1371     {
1372       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_OBJECT_RENAME)
1373         continue;
1374 
1375       UpdJSONObjectRename* upd = static_cast<UpdJSONObjectRename*>(*ite);
1376 
1377       if (name->equals(upd->theName))
1378         RAISE_ERROR(jerr::JNUP0010, loc, ERROR_PARAMS(name->getStringValue()));
1379     }
1380 
1381     UpdatePrimitive* upd = GET_PUL_FACTORY().
1382     createUpdJSONObjectRename(pul, loc, target, name, newName);
1383 
1384     pul->theJSONObjectRenameList.push_back(upd);
1385 
1386     updates->push_back(upd);
1387   }
1388   else
1389   {
1390     UpdatePrimitive* upd = GET_PUL_FACTORY().
1391     createUpdJSONObjectRename(pul, loc, target, name, newName);
1392 
1393     pul->theJSONObjectRenameList.push_back(upd);
1394 
1395     updates = new NodeUpdates(1);
1396     (*updates)[0] = upd;
1397     pul->theNodeToUpdatesMap.insert(obj, updates);
1398   }
1399 }
1400 
1401 
1402 /*******************************************************************************
1403 
1404 ********************************************************************************/
addJSONArrayInsert(const QueryLoc * loc,store::Item_t & target,store::Item_t & position,std::vector<store::Item_t> & members)1405 void PULImpl::addJSONArrayInsert(
1406      const QueryLoc* loc,
1407      store::Item_t& target,
1408      store::Item_t& position,
1409      std::vector<store::Item_t>& members)
1410 {
1411   CollectionPul* pul = getCollectionPul(target.getp());
1412 
1413   json::JSONArray* arr = static_cast<json::JSONArray*>(target.getp());
1414 
1415   xs_integer pos = position->getIntegerValue();
1416 
1417   if (pos <= xs_integer::zero() ||
1418       arr->getArraySize() + 1 < pos)
1419   {
1420     RAISE_ERROR(jerr::JNUP0016, loc,
1421     ERROR_PARAMS(ZED(JNUP0016_Array), position->getStringValue()));
1422   }
1423 
1424   NodeUpdates* updates = 0;
1425   bool found = pul->theNodeToUpdatesMap.get(arr, updates);
1426 
1427   // merge array-insert primitives
1428   if (found)
1429   {
1430     NodeUpdates::iterator ite = updates->begin();
1431     NodeUpdates::iterator end = updates->end();
1432 
1433     for (; ite != end; ++ite)
1434     {
1435       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_INSERT)
1436         continue;
1437 
1438       UpdJSONArrayInsert* upd = static_cast<UpdJSONArrayInsert*>(*ite);
1439 
1440       if (upd->thePosition != pos)
1441         continue;
1442 
1443       csize numMembers1 = upd->theMembers.size();
1444       csize numMembers2 = members.size();
1445       csize numMembers = numMembers1;
1446 
1447       upd->theMembers.resize(numMembers1 + numMembers2);
1448 
1449       for (csize i = 0; i < numMembers2; ++i, ++numMembers)
1450       {
1451         upd->theMembers[numMembers].transfer(members[i]);
1452       }
1453 
1454       return;
1455     }
1456 
1457     UpdatePrimitive* upd = GET_PUL_FACTORY().
1458     createUpdJSONArrayInsert(pul, loc, target, pos, members);
1459 
1460     pul->theJSONArrayInsertList.push_back(upd);
1461 
1462     updates->push_back(upd);
1463   }
1464   else
1465   {
1466     UpdatePrimitive* upd = GET_PUL_FACTORY().
1467     createUpdJSONArrayInsert(pul, loc, target, pos, members);
1468 
1469     pul->theJSONArrayInsertList.push_back(upd);
1470 
1471     updates = new NodeUpdates(1);
1472     (*updates)[0] = upd;
1473     pul->theNodeToUpdatesMap.insert(arr, updates);
1474   }
1475 }
1476 
1477 
1478 /*******************************************************************************
1479 
1480 ********************************************************************************/
addJSONArrayAppend(const QueryLoc * loc,store::Item_t & target,std::vector<store::Item_t> & members)1481 void PULImpl::addJSONArrayAppend(
1482      const QueryLoc* loc,
1483      store::Item_t& target,
1484      std::vector<store::Item_t>& members)
1485 {
1486   CollectionPul* pul = getCollectionPul(target.getp());
1487 
1488   json::JSONArray* arr = static_cast<json::JSONArray*>(target.getp());
1489 
1490   NodeUpdates* updates = 0;
1491   bool found = pul->theNodeToUpdatesMap.get(arr, updates);
1492 
1493   // merge array-append primitives
1494   if (found)
1495   {
1496     NodeUpdates::iterator ite = updates->begin();
1497     NodeUpdates::iterator end = updates->end();
1498 
1499     for (; ite != end; ++ite)
1500     {
1501       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_INSERT)
1502         continue;
1503 
1504       UpdJSONArrayAppend* upd = static_cast<UpdJSONArrayAppend*>(*ite);
1505 
1506       csize numMembers1 = upd->theMembers.size();
1507       csize numMembers2 = members.size();
1508       csize numMembers = numMembers1;
1509 
1510       upd->theMembers.resize(numMembers1 + numMembers2);
1511 
1512       for (csize i = 0; i < numMembers2; ++i, ++numMembers)
1513       {
1514         upd->theMembers[numMembers].transfer(members[i]);
1515       }
1516 
1517       return;
1518     }
1519 
1520     UpdatePrimitive* upd = GET_PUL_FACTORY().
1521     createUpdJSONArrayAppend(pul, loc, target, members);
1522 
1523     pul->theJSONArrayAppendList.push_back(upd);
1524 
1525     updates->push_back(upd);
1526   }
1527   else
1528   {
1529     UpdatePrimitive* upd = GET_PUL_FACTORY().
1530     createUpdJSONArrayAppend(pul, loc, target, members);
1531 
1532     pul->theJSONArrayAppendList.push_back(upd);
1533 
1534     updates = new NodeUpdates(1);
1535     (*updates)[0] = upd;
1536     pul->theNodeToUpdatesMap.insert(arr, updates);
1537   }
1538 }
1539 
1540 
1541 /*******************************************************************************
1542 
1543 ********************************************************************************/
addJSONArrayDelete(const QueryLoc * loc,store::Item_t & target,store::Item_t & position)1544 void PULImpl::addJSONArrayDelete(
1545    const QueryLoc* loc,
1546    store::Item_t& target,
1547    store::Item_t& position)
1548 {
1549   CollectionPul* pul = getCollectionPul(target.getp());
1550 
1551   json::JSONArray* arr = static_cast<json::JSONArray*>(target.getp());
1552 
1553   xs_integer pos = position->getIntegerValue();
1554 
1555   if (pos <= xs_integer::zero() ||
1556       arr->getArraySize() < pos)
1557   {
1558     RAISE_ERROR(jerr::JNUP0016, loc,
1559     ERROR_PARAMS(ZED(JNUP0016_Array), position->getStringValue()));
1560   }
1561 
1562   NodeUpdates* updates = 0;
1563   bool found = pul->theNodeToUpdatesMap.get(arr, updates);
1564 
1565   // skip duplicate deletes
1566   if (found)
1567   {
1568     NodeUpdates::iterator ite = updates->begin();
1569     NodeUpdates::iterator end = updates->end();
1570 
1571     for (; ite != end; ++ite)
1572     {
1573       if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_DELETE &&
1574           (*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_REPLACE_VALUE)
1575         continue;
1576 
1577       UpdJSONArrayUpdate* upd = static_cast<UpdJSONArrayUpdate*>(*ite);
1578 
1579       if (upd->thePosition == pos)
1580       {
1581         return;
1582       }
1583     }
1584 
1585     UpdatePrimitive* upd = GET_PUL_FACTORY().
1586     createUpdJSONArrayDelete(pul, loc, target, pos);
1587 
1588     pul->theJSONArrayDeleteList.push_back(upd);
1589 
1590     updates->push_back(upd);
1591   }
1592   else
1593   {
1594     UpdatePrimitive* upd = GET_PUL_FACTORY().
1595     createUpdJSONArrayDelete(pul, loc, target, pos);
1596 
1597     pul->theJSONArrayDeleteList.push_back(upd);
1598 
1599     updates = new NodeUpdates(1);
1600     (*updates)[0] = upd;
1601     pul->theNodeToUpdatesMap.insert(arr, updates);
1602   }
1603 }
1604 
1605 
1606 /*******************************************************************************
1607 
1608 ********************************************************************************/
addJSONArrayReplaceValue(const QueryLoc * loc,store::Item_t & target,store::Item_t & position,store::Item_t & newValue)1609 void PULImpl::addJSONArrayReplaceValue(
1610      const QueryLoc* loc,
1611      store::Item_t& target,
1612      store::Item_t& position,
1613      store::Item_t& newValue)
1614 {
1615   CollectionPul* pul = getCollectionPul(target.getp());
1616 
1617   json::JSONArray* arr = static_cast<json::JSONArray*>(target.getp());
1618 
1619   xs_integer pos = position->getIntegerValue();
1620 
1621   if (pos <= xs_integer::zero() ||
1622       arr->getArraySize() < pos)
1623   {
1624     RAISE_ERROR(jerr::JNUP0016, loc,
1625     ERROR_PARAMS(ZED(JNUP0016_Array), position->getStringValue()));
1626   }
1627 
1628   NodeUpdates* updates = 0;
1629   bool found = pul->theNodeToUpdatesMap.get(arr, updates);
1630 
1631   // raise error if duplicate positions and skip if same position as delete
1632   if (found)
1633   {
1634     NodeUpdates::iterator ite = updates->begin();
1635     NodeUpdates::iterator end = updates->end();
1636 
1637     for (; ite != end; ++ite)
1638     {
1639       if ((*ite)->getKind() == store::UpdateConsts::UP_JSON_ARRAY_REPLACE_VALUE)
1640       {
1641         UpdJSONArrayUpdate* upd = static_cast<UpdJSONArrayUpdate*>(*ite);
1642 
1643         if (upd->thePosition == pos)
1644         {
1645           RAISE_ERROR(jerr::JNUP0009, loc, ERROR_PARAMS(pos.toString()));
1646         }
1647       }
1648       else if ((*ite)->getKind() == store::UpdateConsts::UP_JSON_ARRAY_DELETE)
1649       {
1650         UpdJSONArrayUpdate* upd = static_cast<UpdJSONArrayUpdate*>(*ite);
1651 
1652         if (upd->thePosition == pos)
1653         {
1654           ite = updates->erase(ite);
1655         }
1656       }
1657     }
1658 
1659     UpdatePrimitive* upd = GET_PUL_FACTORY().
1660     createUpdJSONArrayReplaceValue(pul, loc, target, pos, newValue);
1661 
1662     pul->theJSONArrayReplaceValueList.push_back(upd);
1663 
1664     updates->push_back(upd);
1665   }
1666   else
1667   {
1668     UpdatePrimitive* upd = GET_PUL_FACTORY().
1669     createUpdJSONArrayReplaceValue(pul, loc, target, pos, newValue);
1670 
1671     pul->theJSONArrayReplaceValueList.push_back(upd);
1672 
1673     updates = new NodeUpdates(1);
1674     (*updates)[0] = upd;
1675     pul->theNodeToUpdatesMap.insert(arr, updates);
1676   }
1677 }
1678 
1679 #endif // ZORBA_WITH_JSON
1680 
1681 
1682 /*******************************************************************************
1683   Merge PULs
1684 ********************************************************************************/
mergeUpdates(store::Item * other)1685 void PULImpl::mergeUpdates(store::Item* other)
1686 {
1687   PULImpl* otherp = reinterpret_cast<PULImpl*>(other);
1688 
1689   // Merge collection-specific primitives
1690   CollectionPulMap::iterator thisIte = theCollectionPulsMap.begin();
1691   CollectionPulMap::iterator thisEnd = theCollectionPulsMap.end();
1692   CollectionPulMap::iterator otherIte = otherp->theCollectionPulsMap.begin();
1693   CollectionPulMap::iterator otherEnd = otherp->theCollectionPulsMap.end();
1694 
1695   while (thisIte != thisEnd && otherIte != otherEnd)
1696   {
1697     if (thisIte->first == otherIte->first)
1698     {
1699       CollectionPul* thisPul = theCollectionPuls[thisIte->second];
1700       CollectionPul* otherPul = otherp->theCollectionPuls[otherIte->second];
1701 
1702       // Merge XQUF primitives
1703       mergeTargetedUpdateLists(thisPul,
1704                                thisPul->theDoFirstList,
1705                                otherPul->theDoFirstList);
1706 
1707       mergeTargetedUpdateLists(thisPul,
1708                                thisPul->theInsertList,
1709                                otherPul->theInsertList);
1710 
1711       mergeTargetedUpdateLists(thisPul,
1712                                thisPul->theReplaceNodeList,
1713                                otherPul->theReplaceNodeList);
1714 
1715       mergeTargetedUpdateLists(thisPul,
1716                                thisPul->theReplaceContentList,
1717                                otherPul->theReplaceContentList);
1718 
1719       mergeTargetedUpdateLists(thisPul,
1720                                thisPul->theDeleteList,
1721                                otherPul->theDeleteList);
1722 
1723       // Merge revalidation primitives
1724       mergeCollectionUpdateLists(thisPul,
1725                                  thisPul->theRevalidateList,
1726                                  otherPul->theRevalidateList);
1727 
1728       // Merge collection primitives
1729       mergeCollectionUpdateLists(thisPul,
1730                                  thisPul->theCreateCollectionList,
1731                                  otherPul->theCreateCollectionList);
1732 
1733       mergeCollectionUpdateLists(thisPul,
1734                                  thisPul->theInsertIntoCollectionList,
1735                                  otherPul->theInsertIntoCollectionList);
1736 
1737       mergeCollectionUpdateLists(thisPul,
1738                                  thisPul->theDeleteFromCollectionList,
1739                                  otherPul->theDeleteFromCollectionList);
1740 
1741       mergeCollectionUpdateLists(thisPul,
1742                                  thisPul->theTruncateCollectionList,
1743                                  otherPul->theTruncateCollectionList);
1744 
1745       mergeCollectionUpdateLists(thisPul,
1746                                  thisPul->theDeleteCollectionList,
1747                                  otherPul->theDeleteCollectionList);
1748 
1749 #ifdef ZORBA_WITH_JSON
1750       // merge jsoniq primitives
1751       mergeTargetedUpdateLists(thisPul,
1752                                thisPul->theJSONObjectInsertList,
1753                                otherPul->theJSONObjectInsertList);
1754 
1755       mergeTargetedUpdateLists(thisPul,
1756                                thisPul->theJSONObjectDeleteList,
1757                                otherPul->theJSONObjectDeleteList);
1758 
1759       mergeTargetedUpdateLists(thisPul,
1760                                thisPul->theJSONObjectReplaceValueList,
1761                                otherPul->theJSONObjectReplaceValueList);
1762 
1763       mergeTargetedUpdateLists(thisPul,
1764                                thisPul->theJSONObjectRenameList,
1765                                otherPul->theJSONObjectRenameList);
1766 
1767       mergeTargetedUpdateLists(thisPul,
1768                                thisPul->theJSONArrayInsertList,
1769                                otherPul->theJSONArrayInsertList);
1770 
1771       mergeTargetedUpdateLists(thisPul,
1772                                thisPul->theJSONArrayDeleteList,
1773                                otherPul->theJSONArrayDeleteList);
1774 
1775       mergeTargetedUpdateLists(thisPul,
1776                                thisPul->theJSONArrayReplaceValueList,
1777                                otherPul->theJSONArrayReplaceValueList);
1778 
1779       mergeTargetedUpdateLists(thisPul,
1780                                thisPul->theJSONArrayAppendList,
1781                                otherPul->theJSONArrayAppendList);
1782 #endif
1783 
1784       ++thisIte;
1785       ++otherIte;
1786     }
1787     else if (thisIte->first < otherIte->first)
1788     {
1789       ++thisIte;
1790     }
1791     else
1792     {
1793       CollectionPul* otherPul = otherp->theCollectionPuls[otherIte->second];
1794       otherp->theCollectionPuls[otherIte->second] = NULL;
1795 
1796       theCollectionPuls.push_back(otherPul);
1797       theCollectionPulsMap[otherIte->first] = theCollectionPuls.size() - 1;
1798 
1799       otherPul->switchPul(this);
1800       ++otherIte;
1801     }
1802   }
1803 
1804   while (otherIte != otherEnd)
1805   {
1806     CollectionPul* otherPul = otherp->theCollectionPuls[otherIte->second];
1807     otherp->theCollectionPuls[otherIte->second] = NULL;
1808 
1809     theCollectionPuls.push_back(otherPul);
1810     theCollectionPulsMap[otherIte->first] = theCollectionPuls.size() - 1;
1811 
1812     otherPul->switchPul(this);
1813 
1814     ++otherIte;
1815   }
1816 
1817   // Merge fn:put primitives
1818   mergeSimpleUpdateLists(thePutList, otherp->thePutList);
1819 
1820   // merge index and IC primitives
1821   mergeSimpleUpdateLists(theCreateIndexList, otherp->theCreateIndexList);
1822 
1823   mergeSimpleUpdateLists(theDeleteIndexList, otherp->theDeleteIndexList);
1824 
1825   mergeSimpleUpdateLists(theRefreshIndexList, otherp->theRefreshIndexList);
1826 
1827   mergeSimpleUpdateLists(theICActivationList, otherp->theICActivationList);
1828 
1829   // merge document primitives
1830   mergeSimpleUpdateLists(theCreateDocumentList, otherp->theCreateDocumentList);
1831 
1832   mergeSimpleUpdateLists(theDeleteDocumentList, otherp->theDeleteDocumentList);
1833 
1834   // merge hashmap primitives
1835   mergeSimpleUpdateLists(theCreateHashMapList, otherp->theCreateHashMapList);
1836 
1837   mergeSimpleUpdateLists(theDestroyHashMapList, otherp->theDestroyHashMapList);
1838 
1839   mergeSimpleUpdateLists(theInsertIntoHashMapList, otherp->theInsertIntoHashMapList);
1840 
1841   mergeSimpleUpdateLists(theRemoveFromHashMapList, otherp->theRemoveFromHashMapList);
1842 
1843   // merge validation primitives
1844   mergeSimpleUpdateLists(theValidationList, otherp->theValidationList);
1845 }
1846 
1847 
1848 /*******************************************************************************
1849 
1850 ********************************************************************************/
mergeSimpleUpdateLists(std::vector<UpdatePrimitive * > & myList,std::vector<UpdatePrimitive * > & otherList)1851 void PULImpl::mergeSimpleUpdateLists(
1852     std::vector<UpdatePrimitive*>& myList,
1853     std::vector<UpdatePrimitive*>& otherList)
1854 {
1855   csize numUpdates = myList.size();
1856   csize numOtherUpdates = otherList.size();
1857 
1858   myList.reserve(numUpdates + numOtherUpdates);
1859 
1860   for (csize i = 0; i < numOtherUpdates; ++i)
1861   {
1862     UpdatePrimitive* otherUpd = otherList[i];
1863     otherUpd->thePul = this;
1864 
1865     myList.push_back(otherUpd);
1866     otherList[i] = NULL;
1867 
1868     store::UpdateConsts::UpdPrimKind otherUpdKind = otherUpd->getKind();
1869 
1870     switch (otherUpdKind)
1871     {
1872     case store::UpdateConsts::UP_CREATE_INDEX:
1873     {
1874       UpdCreateIndex* otherUpd2 = static_cast<UpdCreateIndex*>(otherUpd);
1875 
1876       for (csize j = 0; j < numUpdates; ++j)
1877       {
1878         UpdCreateIndex* myUpd = static_cast<UpdCreateIndex*>(myList[j]);
1879 
1880         if (myUpd->getName()->equals(otherUpd2->getName()))
1881         {
1882           RAISE_ERROR(zerr::ZDDY0027_INDEX_MULTIPLE_CREATES, otherUpd->theLoc,
1883           ERROR_PARAMS(myUpd->getName()->getStringValue()));
1884         }
1885       }
1886     }
1887     case store::UpdateConsts::UP_PUT:
1888     {
1889       UpdPut* otherUpd2 = static_cast<UpdPut*>(otherUpd);
1890 
1891       for (csize j = 0; j < numUpdates; ++j)
1892       {
1893         UpdPut* myUpd = static_cast<UpdPut*>(myList[j]);
1894 
1895       if (myUpd->theTargetUri->equals(otherUpd2->theTargetUri))
1896       {
1897         RAISE_ERROR(err::XUDY0031, otherUpd->theLoc,
1898         ERROR_PARAMS(myUpd->theTargetUri->getStringValue()));
1899       }
1900     }
1901     }
1902     default:
1903       break;
1904     }
1905   }
1906 
1907   otherList.clear();
1908 }
1909 
1910 
1911 /*******************************************************************************
1912 
1913 ********************************************************************************/
mergeTargetedUpdateLists(CollectionPul * myPul,std::vector<UpdatePrimitive * > & myList,std::vector<UpdatePrimitive * > & otherList)1914 void PULImpl::mergeTargetedUpdateLists(
1915     CollectionPul* myPul,
1916     std::vector<UpdatePrimitive*>& myList,
1917     std::vector<UpdatePrimitive*>& otherList)
1918 {
1919   csize numUpdates = myList.size();
1920   csize numOtherUpdates = otherList.size();
1921 
1922   myList.reserve(numUpdates + numOtherUpdates);
1923 
1924   for (csize i = 0; i < numOtherUpdates; ++i)
1925   {
1926     UpdatePrimitive* otherUpd = otherList[i];
1927     otherUpd->thePul = this;
1928     otherUpd->theCollectionPul = myPul;
1929 
1930     myList.push_back(otherUpd);
1931     otherList[i] = NULL;
1932 
1933     store::UpdateConsts::UpdPrimKind otherUpdKind = otherUpd->getKind();
1934 
1935     // Get the target and see if myPul has any other updates on the same target
1936     store::Item* target = otherUpd->theTarget.getp();
1937 
1938     if (otherUpdKind == store::UpdateConsts::UP_REPLACE_CHILD)
1939       target = static_cast<UpdReplaceChild*>(otherUpd)->theChild.getp();
1940     else if (otherUpdKind == store::UpdateConsts::UP_REPLACE_ATTRIBUTE)
1941       target = static_cast<UpdReplaceAttribute*>(otherUpd)->theAttr.getp();
1942 
1943     NodeUpdates* targetUpdates = NULL;
1944     bool found = myPul->theNodeToUpdatesMap.get(target, targetUpdates);
1945 
1946     if (!found)
1947     {
1948       targetUpdates = new NodeUpdates(1);
1949       (*targetUpdates)[0] = otherUpd;
1950 
1951       myPul->theNodeToUpdatesMap.insert(target, targetUpdates);
1952     }
1953     else
1954     {
1955       bool merged = false;
1956 
1957       switch (otherUpdKind)
1958       {
1959       case store::UpdateConsts::UP_RENAME_ELEM:
1960       case store::UpdateConsts::UP_RENAME_ATTR:
1961       case store::UpdateConsts::UP_RENAME_PI:
1962 
1963       case store::UpdateConsts::UP_REPLACE_CHILD:
1964       case store::UpdateConsts::UP_REPLACE_ATTRIBUTE:
1965 
1966       case store::UpdateConsts::UP_REPLACE_ATTR_VALUE:
1967       case store::UpdateConsts::UP_REPLACE_TEXT_VALUE:
1968       case store::UpdateConsts::UP_REPLACE_PI_VALUE:
1969       case store::UpdateConsts::UP_REPLACE_COMMENT_VALUE:
1970 
1971       case store::UpdateConsts::UP_REPLACE_CONTENT:
1972       {
1973         NodeUpdates::iterator ite = targetUpdates->begin();
1974         NodeUpdates::iterator end = targetUpdates->end();
1975 
1976         for (; ite != end; ++ite)
1977         {
1978           if ((*ite)->getKind() == otherUpdKind)
1979           {
1980             if (store::UpdateConsts::isRename(otherUpdKind))
1981               RAISE_ERROR_NO_PARAMS(err::XUDY0015, otherUpd->theLoc);
1982 
1983             else if (store::UpdateConsts::isReplaceNode(otherUpdKind))
1984               RAISE_ERROR_NO_PARAMS(err::XUDY0016, otherUpd->theLoc);
1985 
1986             else
1987               RAISE_ERROR_NO_PARAMS(err::XUDY0017, otherUpd->theLoc);
1988           }
1989         }
1990 
1991         break;
1992       }
1993 
1994       case store::UpdateConsts::UP_DELETE:
1995       {
1996         NodeUpdates::iterator ite = targetUpdates->begin();
1997         NodeUpdates::iterator end = targetUpdates->end();
1998 
1999         for (; ite != end; ++ite)
2000         {
2001           if ((*ite)->getKind() == otherUpdKind)
2002           {
2003             merged = true;
2004             break;
2005           }
2006         }
2007 
2008         break;
2009       }
2010 
2011 #ifdef ZORBA_WITH_JSON
2012       // merge object-insert primitives and raise error if duplicate names
2013       case store::UpdateConsts::UP_JSON_OBJECT_INSERT:
2014       {
2015         UpdJSONObjectInsert* otherUpd2 = static_cast<UpdJSONObjectInsert*>(otherUpd);
2016 
2017         NodeUpdates::iterator ite = targetUpdates->begin();
2018         NodeUpdates::iterator end = targetUpdates->end();
2019 
2020         for (; ite != end; ++ite)
2021         {
2022           if ((*ite)->getKind() != otherUpdKind)
2023             continue;
2024 
2025           UpdJSONObjectInsert* myUpd = static_cast<UpdJSONObjectInsert*>(*ite);
2026 
2027           csize numMyPairs = myUpd->theNames.size();
2028           csize numOtherPairs = otherUpd2->theNames.size();
2029           csize numPairs = numMyPairs;
2030 
2031           myUpd->theNames.resize(numMyPairs + numOtherPairs);
2032           myUpd->theValues.resize(numMyPairs + numOtherPairs);
2033 
2034           for (csize i = 0; i < numOtherPairs; ++i, ++numPairs)
2035           {
2036             for (csize j = 0; j < numMyPairs; ++j)
2037             {
2038               if (otherUpd2->theNames[i]->equals(myUpd->theNames[j]))
2039                 RAISE_ERROR(jerr::JNUP0005, otherUpd->theLoc,
2040                 ERROR_PARAMS(myUpd->theNames[j]->getStringValue()));
2041             }
2042 
2043             myUpd->theNames[numPairs].transfer(otherUpd2->theNames[i]);
2044             myUpd->theValues[numPairs].transfer(otherUpd2->theValues[i]);
2045           }
2046 
2047           merged = true;
2048           break;
2049         }
2050 
2051         break;
2052       }
2053 
2054       // skip deletions with duplicate names
2055       case store::UpdateConsts::UP_JSON_OBJECT_DELETE:
2056       {
2057         UpdJSONObjectDelete* otherUpd2 = static_cast<UpdJSONObjectDelete*>(otherUpd);
2058 
2059         NodeUpdates::iterator ite = targetUpdates->begin();
2060         NodeUpdates::iterator end = targetUpdates->end();
2061 
2062         for (; ite != end; ++ite)
2063         {
2064           if ((*ite)->getKind() != otherUpdKind)
2065             continue;
2066 
2067           UpdJSONObjectDelete* myUpd = static_cast<UpdJSONObjectDelete*>(*ite);
2068 
2069           if (myUpd->theName->equals(otherUpd2->theName))
2070           {
2071             merged = true;
2072             break;
2073           }
2074         }
2075 
2076         break;
2077       }
2078 
2079       // raise error if duplicate names
2080       case store::UpdateConsts::UP_JSON_OBJECT_REPLACE_VALUE:
2081       {
2082         UpdJSONObjectReplaceValue* otherUpd2 =
2083         static_cast<UpdJSONObjectReplaceValue*>(otherUpd);
2084 
2085         NodeUpdates::iterator ite = targetUpdates->begin();
2086         NodeUpdates::iterator end = targetUpdates->end();
2087 
2088         for (; ite != end; ++ite)
2089         {
2090           if ((*ite)->getKind() != otherUpdKind)
2091             continue;
2092 
2093           UpdJSONObjectReplaceValue* myUpd =
2094           static_cast<UpdJSONObjectReplaceValue*>(*ite);
2095 
2096           if (myUpd->theName->equals(otherUpd2->theName))
2097           {
2098             RAISE_ERROR(jerr::JNUP0009, otherUpd->theLoc,
2099             ERROR_PARAMS(myUpd->theName->getStringValue()));
2100           }
2101         }
2102 
2103         break;
2104       }
2105 
2106       // raise error if duplicate names
2107       case store::UpdateConsts::UP_JSON_OBJECT_RENAME:
2108       {
2109         UpdJSONObjectRename* otherUpd2 = static_cast<UpdJSONObjectRename*>(otherUpd);
2110 
2111         NodeUpdates::iterator ite = targetUpdates->begin();
2112         NodeUpdates::iterator end = targetUpdates->end();
2113 
2114         for (; ite != end; ++ite)
2115         {
2116           if ((*ite)->getKind() != otherUpdKind)
2117             continue;
2118 
2119           UpdJSONObjectRename* myUpd = static_cast<UpdJSONObjectRename*>(*ite);
2120 
2121           if (myUpd->theName->equals(otherUpd2->theName))
2122           {
2123             RAISE_ERROR(jerr::JNUP0010, otherUpd->theLoc,
2124             ERROR_PARAMS(myUpd->theName->getStringValue()));
2125           }
2126         }
2127 
2128         break;
2129       }
2130 
2131       // skip duplicate deletes
2132       case store::UpdateConsts::UP_JSON_ARRAY_DELETE:
2133       {
2134         UpdJSONArrayUpdate* otherUpd2 = static_cast<UpdJSONArrayUpdate*>(otherUpd);
2135 
2136         NodeUpdates::iterator ite = targetUpdates->begin();
2137         NodeUpdates::iterator end = targetUpdates->end();
2138 
2139         for (; ite != end; ++ite)
2140         {
2141           if ((*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_DELETE &&
2142               (*ite)->getKind() != store::UpdateConsts::UP_JSON_ARRAY_REPLACE_VALUE)
2143             continue;
2144 
2145           UpdJSONArrayUpdate* myUpd = static_cast<UpdJSONArrayUpdate*>(*ite);
2146 
2147           if (myUpd->thePosition == otherUpd2->thePosition)
2148           {
2149             merged = true;
2150             break;
2151           }
2152         }
2153 
2154         break;
2155       }
2156 
2157       // raise error if duplicate positions and skip if same position as delete
2158       case store::UpdateConsts::UP_JSON_ARRAY_REPLACE_VALUE:
2159       {
2160         UpdJSONArrayUpdate* otherUpd2 = static_cast<UpdJSONArrayUpdate*>(otherUpd);
2161 
2162         NodeUpdates::iterator ite = targetUpdates->begin();
2163         NodeUpdates::iterator end = targetUpdates->end();
2164 
2165         for (; ite != end; ++ite)
2166         {
2167           UpdJSONArrayUpdate* myUpd = static_cast<UpdJSONArrayUpdate*>(*ite);
2168 
2169           if ((*ite)->getKind() == store::UpdateConsts::UP_JSON_ARRAY_REPLACE_VALUE)
2170           {
2171             if (myUpd->thePosition == otherUpd2->thePosition)
2172             {
2173               RAISE_ERROR(jerr::JNUP0009, otherUpd->theLoc,
2174               ERROR_PARAMS(myUpd->thePosition.toString()));
2175             }
2176           }
2177           else if ((*ite)->getKind() == store::UpdateConsts::UP_JSON_ARRAY_DELETE)
2178           {
2179             if (myUpd->thePosition == otherUpd2->thePosition)
2180             {
2181               ite = targetUpdates->erase(ite);
2182             }
2183           }
2184         }
2185 
2186         break;
2187       }
2188 
2189 #endif
2190 
2191       default:
2192         break;
2193       }
2194 
2195       if (merged)
2196       {
2197         delete otherUpd;
2198         myList.pop_back();
2199       }
2200       else
2201       {
2202         targetUpdates->push_back(otherUpd);
2203       }
2204     } // target has other updates in this pul
2205   } // for each primitive in other list
2206 
2207   otherList.clear();
2208 }
2209 
2210 
2211 /*******************************************************************************
2212 
2213 ********************************************************************************/
mergeCollectionUpdateLists(CollectionPul * myPul,std::vector<UpdatePrimitive * > & myList,std::vector<UpdatePrimitive * > & otherList)2214 void PULImpl::mergeCollectionUpdateLists(
2215     CollectionPul* myPul,
2216     std::vector<UpdatePrimitive*>& myList,
2217     std::vector<UpdatePrimitive*>& otherList)
2218 {
2219   csize numUpdates = myList.size();
2220   csize numOtherUpdates = otherList.size();
2221 
2222   myList.reserve(numUpdates + numOtherUpdates);
2223 
2224   for (csize i = 0; i < numOtherUpdates; ++i)
2225   {
2226     UpdatePrimitive* otherUpd = otherList[i];
2227     otherUpd->thePul = this;
2228     otherUpd->theCollectionPul = myPul;
2229 
2230     myList.push_back(otherUpd);
2231     otherList[i] = NULL;
2232 
2233     store::UpdateConsts::UpdPrimKind otherUpdKind = otherUpd->getKind();
2234 
2235     if (otherUpdKind == store::UpdateConsts::UP_CREATE_COLLECTION)
2236     {
2237       UpdCreateCollection* otherUpd2 = static_cast<UpdCreateCollection*>(otherUpd);
2238 
2239       for (csize j = 0; j < numUpdates; ++j)
2240       {
2241         UpdCreateCollection* myUpd = static_cast<UpdCreateCollection*>(myList[j]);
2242 
2243         if (myUpd->getName()->equals(otherUpd2->getName()))
2244         {
2245           RAISE_ERROR(zerr::ZDDY0016_COLLECTION_MULTIPLE_CREATES, otherUpd->theLoc,
2246           ERROR_PARAMS(myUpd->getName()->getStringValue()));
2247         }
2248       }
2249     }
2250   }
2251 
2252   otherList.clear();
2253 }
2254 
2255 
2256 /*******************************************************************************
2257   Check that each target node of this pul is inside one of the trees rooted at
2258   the given root nodes (the root nodes are the copies of the nodes produced by
2259   the source expr of a transform expr).
2260 ********************************************************************************/
checkTransformUpdates(const std::vector<store::Item * > & rootNodes) const2261 void PULImpl::checkTransformUpdates(const std::vector<store::Item*>& rootNodes) const
2262 {
2263   csize numRoots = rootNodes.size();
2264 
2265   std::vector<CollectionPul*>::const_iterator collIte = theCollectionPuls.begin();
2266   std::vector<CollectionPul*>::const_iterator collEnd = theCollectionPuls.end();
2267 
2268   for (; collIte != collEnd; ++collIte)
2269   {
2270     CollectionPul* pul = *collIte;
2271 
2272     NodeToUpdatesMap::iterator it = pul->theNodeToUpdatesMap.begin();
2273     NodeToUpdatesMap::iterator end = pul->theNodeToUpdatesMap.end();
2274 
2275     bool found = false;
2276 
2277     for (; it != end; ++it)
2278     {
2279       zorba::store::Item* lItem = (*it).first;
2280       if (lItem->isNode())
2281       {
2282         assert(dynamic_cast<const XmlNode*>(lItem));
2283         const XmlNode* lNode = static_cast<const XmlNode*>(lItem);
2284         for (csize i = 0; i < numRoots; i++)
2285         {
2286           if (rootNodes[i]->isNode())
2287           {
2288             assert(dynamic_cast<const XmlNode*>(rootNodes[i]));
2289             XmlNode* lRootNode = static_cast<XmlNode*>(rootNodes[i]);
2290 
2291             if (lNode->getTree() == lRootNode->getTree())
2292             {
2293               found = true;
2294               break;
2295             }
2296           }
2297         }
2298 #ifdef ZORBA_WITH_JSON
2299       }
2300       else if (lItem->isJSONItem())
2301       {
2302         assert(dynamic_cast<const json::JSONItem*>(lItem));
2303         const json::JSONItem* lJSONItem = static_cast<const json::JSONItem*>(lItem);
2304         for (csize i = 0; i < numRoots; i++)
2305         {
2306           if (rootNodes[i]->isJSONItem())
2307           {
2308             assert(dynamic_cast<const json::JSONItem*>(rootNodes[i]));
2309             json::JSONItem* lRootJSONItem = static_cast<json::JSONItem*>(rootNodes[i]);
2310 
2311             if (lJSONItem->getTree() == lRootJSONItem->getTree())
2312             {
2313               found = true;
2314               break;
2315             }
2316           }
2317         }
2318 #endif
2319       }
2320 
2321       if (!found)
2322         throw XQUERY_EXCEPTION(err::XUDY0014);
2323     }
2324   }
2325 }
2326 
2327 
2328 /*******************************************************************************
2329   Find all the indices that may require maintenance. A index is a candidate for
2330   maintenance if it references at least one collection that has been modified
2331   (either by adding/removing docs to/from it, or by modifying at least one of
2332   the docs that belong to that collection already).
2333 
2334   As a side-effect, the method will also collect in theModifiedDocs all the
2335   exisiting collection docs that are modified by this pul.
2336 
2337   This method is invoked by the ApplyIterator before any of the pul primitives
2338   is applied.
2339 ********************************************************************************/
getIndicesToRefresh(std::vector<store::Index * > & indices,std::vector<store::Index * > & truncate_indices)2340 void PULImpl::getIndicesToRefresh(
2341     std::vector<store::Index*>& indices,
2342     std::vector<store::Index*>& truncate_indices)
2343 {
2344   Store* store = &GET_STORE();
2345 
2346   if (store->getIndices().empty())
2347     return;
2348 
2349   // First, find all the collections that are modified. We also gather all the
2350   // modified/inserted/deleted collection docs, because they will be need later
2351   // to maintain indices.
2352   std::set<store::Collection*> collections;
2353   std::set<store::Collection*> truncated_collections;
2354 
2355   CollectionPuls::iterator collIte = theCollectionPuls.begin();
2356   CollectionPuls::iterator collEnd = theCollectionPuls.end();
2357 
2358   for (; collIte != collEnd; ++collIte)
2359   {
2360     store::Collection* collection = (*collIte)->theCollection;
2361 
2362     // The collection may not be created yet.
2363     if (collection == NULL)
2364       continue;
2365 
2366     collections.insert(collection);
2367 
2368     CollectionPul* pul = *collIte;
2369 
2370     if (pul->theTruncateCollectionList.size() > 0)
2371     {
2372       truncated_collections.insert(collection);
2373       continue;
2374     }
2375 
2376     NodeToUpdatesMap::iterator ite = pul->theNodeToUpdatesMap.begin();
2377     NodeToUpdatesMap::iterator end = pul->theNodeToUpdatesMap.end();
2378     for (; ite != end; ++ite)
2379     {
2380       store::Item* lItem = (*ite).first;
2381 #ifdef ZORBA_WITH_JSON
2382       ZORBA_ASSERT(lItem->isNode() || lItem->isJSONItem());
2383 
2384       if (lItem->isJSONItem())
2385       {
2386         json::JSONItem* lJSONItem = dynamic_cast<json::JSONItem*>(lItem);
2387         ZORBA_ASSERT(lJSONItem != NULL);
2388         pul->theModifiedDocs.insert(const_cast<json::JSONItem*>(lJSONItem->getRoot()));
2389         continue;
2390       }
2391 #endif
2392       ZORBA_ASSERT(lItem->isNode());
2393       XmlNode* node = dynamic_cast<XmlNode*>((*ite).first);
2394       ZORBA_ASSERT(node != NULL);
2395       pul->theModifiedDocs.insert(node->getRoot());
2396       continue;
2397     }
2398 
2399     csize numCollUpdates = pul->theInsertIntoCollectionList.size();
2400 
2401     for (csize i = 0; i < numCollUpdates; ++i)
2402     {
2403       UpdCollection* upd = static_cast<UpdCollection*>
2404                            (pul->theInsertIntoCollectionList[i]);
2405 
2406       csize numDocs = upd->numNodes();
2407 
2408       for (csize j = 0; j < numDocs; ++j)
2409         pul->theInsertedDocs.push_back(upd->getNode(j));
2410     }
2411 
2412     numCollUpdates = pul->theDeleteFromCollectionList.size();
2413 
2414     for (csize i = 0; i < numCollUpdates; ++i)
2415     {
2416       UpdCollection* upd = static_cast<UpdCollection*>
2417                            (pul->theDeleteFromCollectionList[i]);
2418 
2419       csize numDocs = upd->numNodes();
2420 
2421       for (csize j = 0; j < numDocs; ++j)
2422         pul->theDeletedDocs.push_back(upd->getNode(j));
2423     }
2424   }
2425 
2426   // Now go through each index, and check if its sources intersect with the
2427   // modified collections.
2428   IndexSet::iterator idxIte = store->getIndices().begin();
2429   IndexSet::iterator idxEnd = store->getIndices().end();
2430 
2431   for (; idxIte != idxEnd; ++idxIte)
2432   {
2433     IndexImpl* index = static_cast<IndexImpl*>((*idxIte).second.getp());
2434     const store::IndexSpecification& indexSpec = index->getSpecification();
2435 
2436     if (!indexSpec.theIsAutomatic)
2437       continue;
2438 
2439     const std::vector<store::Item_t>& indexSources = indexSpec.theSources;
2440     csize numIndexSources = indexSources.size();
2441 
2442     for (csize i = 0; i < numIndexSources; ++i)
2443     {
2444       std::set<store::Collection*>::const_iterator colIte = collections.begin();
2445       std::set<store::Collection*>::const_iterator colEnd = collections.end();
2446 
2447       for (; colIte != colEnd; ++colIte)
2448       {
2449         if (indexSources[i]->equals((*colIte)->getName()))
2450         {
2451           indices.push_back(index);
2452           break;
2453         }
2454       }
2455 
2456       if (colIte != colEnd)
2457         break;
2458     }
2459 
2460     for (csize i = 0; i < numIndexSources; ++i)
2461     {
2462       std::set<store::Collection*>::const_iterator colIte = truncated_collections.begin();
2463       std::set<store::Collection*>::const_iterator colEnd = truncated_collections.end();
2464 
2465       for (; colIte != colEnd; ++colIte)
2466       {
2467         if (indexSources[i]->equals((*colIte)->getName()))
2468         {
2469           truncate_indices.push_back(index);
2470           break;
2471         }
2472       }
2473     }
2474   }
2475 }
2476 
2477 
2478 /*******************************************************************************
2479 
2480 ********************************************************************************/
addIndexEntryCreator(const store::Item * collectionName,store::Index * idx,store::IndexEntryCreator * creator)2481 void PULImpl::addIndexEntryCreator(
2482     const store::Item* collectionName,
2483     store::Index* idx,
2484     store::IndexEntryCreator* creator)
2485 {
2486   CollectionPul* pul = getCollectionPulByName(collectionName, false);
2487 
2488   pul->theIncrementalIndices.push_back(static_cast<IndexImpl*>(idx));
2489   pul->theIndexEntryCreators.push_back(creator);
2490 }
2491 
2492 
2493 /*******************************************************************************
2494 
2495 ********************************************************************************/
addIndexTruncator(const store::Item * collectionName,store::Index * idx)2496 void PULImpl::addIndexTruncator(
2497     const store::Item* collectionName,
2498     store::Index* idx)
2499 {
2500   CollectionPul* pul = getCollectionPulByName(collectionName, false);
2501   pul->theTruncatedIndices.push_back(static_cast<IndexImpl*>(idx));
2502 }
2503 
2504 
2505 /*******************************************************************************
2506 
2507 ********************************************************************************/
setICChecker(store::ICChecker * icChecker)2508 void PULImpl::setICChecker(store::ICChecker* icChecker)
2509 {
2510   theICChecker = icChecker;
2511 }
2512 
2513 
2514 /*******************************************************************************
2515 
2516 ********************************************************************************/
checkIC(const store::Item * collName)2517 void PULImpl::checkIC(const store::Item* collName)
2518 {
2519   theICChecker->check(collName);
2520 }
2521 
2522 
2523 /*******************************************************************************
2524 
2525 ********************************************************************************/
applyUpdates(bool inheritNSBindings)2526 void PULImpl::applyUpdates(bool inheritNSBindings)
2527 {
2528   CollectionPuls::iterator collIte = theCollectionPuls.begin();
2529   CollectionPuls::iterator collEnd = theCollectionPuls.end();
2530 
2531   theInheritNSBindings = inheritNSBindings;
2532 
2533   try
2534   {
2535     // For each collection C, apply XQUF and collection primitives (except
2536     // delete primitives). Also, refresh any indexes that can be
2537     // maintained incrementally w.r.t. updates in C.
2538     for (; collIte != collEnd; ++collIte)
2539     {
2540       CollectionPul* pul = *collIte;
2541       pul->applyUpdates();
2542     }
2543 
2544     // apply fn:put primitives
2545     applyList(thePutList);
2546 
2547     // Apply index primitives
2548     applyList(theRefreshIndexList);
2549     applyList(theCreateIndexList);
2550     applyList(theDeleteIndexList);
2551 
2552     // Apply document primitives
2553     applyList(theCreateDocumentList);
2554     applyList(theDeleteDocumentList);
2555 
2556     // Apply hashmap primitives
2557     applyList(theCreateHashMapList);
2558     applyList(theDestroyHashMapList);
2559     applyList(theInsertIntoHashMapList);
2560     applyList(theRemoveFromHashMapList);
2561 
2562     // check integrity constraints for involved collections
2563     for (collIte = theCollectionPuls.begin(); collIte != collEnd; ++collIte)
2564     {
2565       CollectionPul* pul = *collIte;
2566 
2567       if (pul->theCollection != NULL)
2568       {
2569         const store::Item* collName = pul->theCollection->getName();
2570 
2571         if ( collName && theICChecker )
2572         {
2573           // throws error if IC not met
2574           checkIC(collName);
2575         }
2576       }
2577     }
2578 
2579     // Apply delete-collection primitives
2580     for (collIte = theCollectionPuls.begin(); collIte != collEnd; ++collIte)
2581     {
2582       CollectionPul* pul = *collIte;
2583       applyList(pul->theDeleteCollectionList);
2584     }
2585 
2586     // Refresh each incrementally maintained index. We need to do this here
2587     // because refreshIndices can raise an error (e.g. if the unique constraint
2588     // of an index is violated).
2589     for (collIte = theCollectionPuls.begin(); collIte != collEnd; ++collIte)
2590     {
2591       CollectionPul* pul = *collIte;
2592       pul->refreshIndexes();
2593     }
2594   }
2595   catch (...)
2596   {
2597     undoUpdates();
2598     throw;
2599   }
2600 
2601   // Perform actions that are not expected to raise any errors
2602   for (collIte = theCollectionPuls.begin(); collIte != collEnd; ++collIte)
2603   {
2604     CollectionPul* pul = *collIte;
2605     pul->finalizeUpdates();
2606   }
2607 
2608   // Apply validation primitives, if this is a revalidation pul.
2609   try
2610   {
2611     applyList(theValidationList);
2612   }
2613   catch (...)
2614   {
2615     ZORBA_FATAL(0, "Unexpected error during application of revalidation PUL");
2616   }
2617 
2618   try
2619   {
2620     applyList(theICActivationList);
2621   }
2622   catch (...)
2623   {
2624     ZORBA_FATAL(0, "Unexpected error during application of integrity constraint PUL");
2625   }
2626 }
2627 
2628 
2629 /*******************************************************************************
2630 
2631 ********************************************************************************/
undoUpdates()2632 void PULImpl::undoUpdates()
2633 {
2634   try
2635   {
2636     undoList(theValidationList);
2637 
2638     CollectionPuls::iterator collIte = theCollectionPuls.begin();
2639     CollectionPuls::iterator collEnd = theCollectionPuls.end();
2640 
2641     for (; collIte != collEnd; ++collIte)
2642     {
2643       CollectionPul* pul = *collIte;
2644       undoList(pul->theDeleteCollectionList);
2645     }
2646 
2647     undoList(theDeleteIndexList);
2648     undoList(theCreateIndexList);
2649     undoList(theRefreshIndexList);
2650 
2651     undoList(thePutList);
2652 
2653     for (collIte = theCollectionPuls.begin(); collIte != collEnd; ++collIte)
2654     {
2655       CollectionPul* pul = *collIte;
2656       pul->undoUpdates();
2657     }
2658 
2659     undoList(theICActivationList);
2660   }
2661   catch (...)
2662   {
2663     ZORBA_FATAL(0, "Unexpected error during pul undo");
2664   }
2665 }
2666 
2667 
2668 /*******************************************************************************
2669 
2670 ********************************************************************************/
CollectionPul(PULImpl * pul,Collection * collection)2671 CollectionPul::CollectionPul(PULImpl* pul, Collection* collection)
2672   :
2673   theCollection(collection),
2674   thePul(pul),
2675   theAdjustTreePositions(false),
2676   theIsApplied(false)
2677 {
2678 }
2679 
2680 
2681 /*******************************************************************************
2682 
2683 ********************************************************************************/
~CollectionPul()2684 CollectionPul::~CollectionPul()
2685 {
2686   cleanList(theDoFirstList);
2687   cleanList(theInsertList);
2688   cleanList(theReplaceNodeList);
2689   cleanList(theReplaceContentList);
2690   cleanList(theDeleteList);
2691   cleanList(theRevalidateList);
2692 
2693   cleanList(theCreateCollectionList);
2694   cleanList(theInsertIntoCollectionList);
2695   cleanList(theDeleteFromCollectionList);
2696   cleanList(theTruncateCollectionList);
2697   cleanList(theDeleteCollectionList);
2698 
2699 #ifdef ZORBA_WITH_JSON
2700   cleanList(theJSONObjectInsertList);
2701   cleanList(theJSONObjectDeleteList);
2702   cleanList(theJSONObjectReplaceValueList);
2703   cleanList(theJSONObjectRenameList);
2704   cleanList(theJSONArrayInsertList);
2705   cleanList(theJSONArrayDeleteList);
2706   cleanList(theJSONArrayReplaceValueList);
2707   cleanList(theJSONArrayAppendList);
2708 #endif
2709 
2710   cleanIndexDeltas();
2711 }
2712 
2713 
2714 /*******************************************************************************
2715 
2716 ********************************************************************************/
switchPul(PULImpl * pul)2717 void CollectionPul::switchPul(PULImpl* pul)
2718 {
2719   thePul = pul;
2720 
2721   switchPulInPrimitivesList(theDoFirstList);
2722   switchPulInPrimitivesList(theInsertList);
2723   switchPulInPrimitivesList(theReplaceNodeList);
2724   switchPulInPrimitivesList(theReplaceContentList);
2725   switchPulInPrimitivesList(theDeleteList);
2726   switchPulInPrimitivesList(theRevalidateList);
2727 
2728 #ifdef ZORBA_WITH_JSON
2729   switchPulInPrimitivesList(theJSONObjectInsertList);
2730   switchPulInPrimitivesList(theJSONObjectDeleteList);
2731   switchPulInPrimitivesList(theJSONObjectReplaceValueList);
2732   switchPulInPrimitivesList(theJSONObjectRenameList);
2733   switchPulInPrimitivesList(theJSONArrayInsertList);
2734   switchPulInPrimitivesList(theJSONArrayDeleteList);
2735   switchPulInPrimitivesList(theJSONArrayReplaceValueList);
2736   switchPulInPrimitivesList(theJSONArrayAppendList);
2737 #endif
2738 
2739   switchPulInPrimitivesList(theCreateCollectionList);
2740   switchPulInPrimitivesList(theInsertIntoCollectionList);
2741   switchPulInPrimitivesList(theDeleteFromCollectionList);
2742   switchPulInPrimitivesList(theTruncateCollectionList);
2743   switchPulInPrimitivesList(theDeleteCollectionList);
2744 }
2745 
2746 
switchPulInPrimitivesList(std::vector<UpdatePrimitive * > & list)2747 void CollectionPul::switchPulInPrimitivesList(std::vector<UpdatePrimitive*>& list)
2748 {
2749   std::vector<UpdatePrimitive*>::iterator ite = list.begin();
2750   std::vector<UpdatePrimitive*>::iterator end = list.end();
2751   for (; ite != end; ++ite)
2752   {
2753     (*ite)->thePul = thePul;
2754   }
2755 }
2756 
2757 
2758 /*******************************************************************************
2759   For each incrementally-maintained index associated with this collection,
2760   compute the index contents on the modified and deleted docs, before any
2761   modifications are actually applied.
2762 
2763   Note 1: If any docs are deleted, we have to remove from the before and after
2764   deltas any entries for nodes belonging to the deleted docs. This is required
2765   for the undo to work properly. For example, let E = [N, K] be an after-delta
2766   entry, and let N be a node in a doc D that is going to be removed from the
2767   collection. Then, during undo, the key pointer in E may be a dangling pointer.
2768 
2769   Note 2: Given note 1, we actually have to compute the delete-docs deltas
2770   *before* any modification are actually applied.
2771 ********************************************************************************/
computeIndexBeforeDeltas()2772 void CollectionPul::computeIndexBeforeDeltas()
2773 {
2774   csize numIncrementalIndices = theIncrementalIndices.size();
2775 
2776   if (numIncrementalIndices == 0)
2777     return;
2778 
2779   std::vector<store::Item*>::const_iterator docIte = theDeletedDocs.begin();
2780   std::vector<store::Item*>::const_iterator docEnd = theDeletedDocs.end();
2781 
2782   for (; docIte != docEnd; ++docIte)
2783   {
2784     theModifiedDocs.erase(*docIte);
2785 
2786     for (csize i = 0; i < numIncrementalIndices; ++i)
2787     {
2788       store::IndexEntryCreator* docIndexer = theIndexEntryCreators[i].getp();
2789       store::IndexDelta& indexDelta = theDeletedDocsIndexDeltas[i];
2790 
2791       docIndexer->createIndexEntries((*docIte), indexDelta);
2792     }
2793   }
2794 
2795   computeIndexDeltas(theBeforeIndexDeltas);
2796 }
2797 
2798 
2799 /*******************************************************************************
2800   Compute the index contents on the modified docs, after the modifications
2801   are actually applied. Also, compute the index contents on the newly inserted
2802   and the deleted docs.
2803 ********************************************************************************/
computeIndexAfterDeltas()2804 void CollectionPul::computeIndexAfterDeltas()
2805 {
2806   csize numIncrementalIndices = theIncrementalIndices.size();
2807 
2808   if (numIncrementalIndices == 0)
2809     return;
2810 
2811   computeIndexDeltas(theAfterIndexDeltas);
2812 
2813   std::vector<store::Item*>::const_iterator docIte = theInsertedDocs.begin();
2814   std::vector<store::Item*>::const_iterator docEnd = theInsertedDocs.end();
2815 
2816   for (; docIte != docEnd; ++docIte)
2817   {
2818     for (csize i = 0; i < numIncrementalIndices; ++i)
2819     {
2820       store::IndexEntryCreator* docIndexer = theIndexEntryCreators[i].getp();
2821       store::IndexDelta& indexDelta = theInsertedDocsIndexDeltas[i];
2822 
2823       docIndexer->createIndexEntries((*docIte), indexDelta);
2824     }
2825   }
2826 }
2827 
2828 
2829 /*******************************************************************************
2830   For each incrementally maintained index I and each collection doc D that is
2831   modified by this pul, compute the index entries for I and D, and insert them
2832   into the given deltas vector
2833 ********************************************************************************/
computeIndexDeltas(std::vector<IndexDeltaImpl> & deltas)2834 void CollectionPul::computeIndexDeltas(std::vector<IndexDeltaImpl>& deltas)
2835 {
2836   csize numIncrementalIndices = theIncrementalIndices.size();
2837 
2838   std::set<store::Item*>::const_iterator docIte = theModifiedDocs.begin();
2839   std::set<store::Item*>::const_iterator docEnd = theModifiedDocs.end();
2840 
2841   for (; docIte != docEnd; ++docIte)
2842   {
2843     for (csize i = 0; i < numIncrementalIndices; ++i)
2844     {
2845       store::IndexEntryCreator* docIndexer = theIndexEntryCreators[i].getp();
2846       store::IndexDelta& indexDelta = deltas[i];
2847 
2848       docIndexer->createIndexEntries((*docIte), indexDelta);
2849     }
2850   }
2851 }
2852 
2853 
2854 /*******************************************************************************
2855 
2856 ********************************************************************************/
cleanIndexDeltas()2857 void CollectionPul::cleanIndexDeltas()
2858 {
2859   csize numIncrementalIndices = theIncrementalIndices.size();
2860 
2861   for (csize idx = 0; idx < numIncrementalIndices; ++idx)
2862   {
2863     if (theIncrementalIndices[idx]->isGeneral())
2864     {
2865       ;
2866     }
2867     else
2868     {
2869       IndexDeltaImpl::ValueIterator ite;
2870       IndexDeltaImpl::ValueIterator end;
2871       store::IndexDelta::ValueDelta* delta;
2872       csize numApplied;
2873 
2874       delta = &theInsertedDocsIndexDeltas[idx].getValueDelta();
2875       numApplied = theNumInsertedDocsIndexDeltasApplied[idx];
2876       ite = delta->begin() + numApplied;
2877       end = delta->end();
2878       for (; ite != end; ++ite)
2879       {
2880         delete (*ite).second;
2881       }
2882 
2883       delta = &theAfterIndexDeltas[idx].getValueDelta();
2884       numApplied = theNumAfterIndexDeltasApplied[idx];
2885       ite = delta->begin() + numApplied;
2886       end = delta->end();
2887       for (; ite != end; ++ite)
2888       {
2889         delete (*ite).second;
2890       }
2891 
2892       theDeletedDocsIndexDeltas[idx].clear();
2893 
2894       theBeforeIndexDeltas[idx].clear();
2895     }
2896   }
2897 }
2898 
2899 
2900 /*******************************************************************************
2901   Refresh the incrementally maintained indexes.
2902 ********************************************************************************/
refreshIndexes()2903 void CollectionPul::refreshIndexes()
2904 {
2905   csize numIncrementalIndices = theIncrementalIndices.size();
2906 
2907   if (numIncrementalIndices > 0)
2908   {
2909     assert(theCollection);
2910 
2911     STORE_TRACE1("Refreshing indexes for collection "
2912                  << theCollection->getName()->getStringValue().c_str());
2913 
2914     for (csize idx = 0; idx < numIncrementalIndices; ++idx)
2915     {
2916       if (theIncrementalIndices[idx]->isGeneral())
2917         refreshGeneralIndex(idx);
2918       else
2919         refreshValueIndex(idx);
2920     }
2921 
2922     STORE_TRACE1("Refreshed indexes for collection "
2923                  << theCollection->getName()->getStringValue().c_str()
2924                  << std::endl);
2925   }
2926 }
2927 
2928 
2929 
2930 /*******************************************************************************
2931 
2932 ********************************************************************************/
refreshValueIndex(csize idx)2933 void CollectionPul::refreshValueIndex(csize idx)
2934 {
2935   ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
2936 
2937   STORE_TRACE2("Index size before do = " << index->size());
2938 
2939   store::IndexDelta::ValueDelta&
2940   beforeDelta = theBeforeIndexDeltas[idx].getValueDelta();
2941   store::IndexDelta::ValueDelta&
2942   afterDelta = theAfterIndexDeltas[idx].getValueDelta();
2943   store::IndexDelta::ValueDelta&
2944   deletedDelta = theDeletedDocsIndexDeltas[idx].getValueDelta();
2945   store::IndexDelta::ValueDelta&
2946   insertedDelta = theInsertedDocsIndexDeltas[idx].getValueDelta();
2947 
2948   csize& numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
2949   csize& numAfterApplied = theNumAfterIndexDeltasApplied[idx];
2950   csize& numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
2951   csize& numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
2952 
2953   store::IndexKey* key;
2954   store::Item_t node;
2955 
2956   IndexDeltaImpl::ValueIterator ite;
2957   IndexDeltaImpl::ValueIterator end;
2958 
2959   ite = beforeDelta.begin();
2960   end = beforeDelta.end();
2961   for (; ite != end; ++ite, ++numBeforeApplied)
2962   {
2963     index->remove((*ite).second, (*ite).first, false);
2964   }
2965 
2966   ite = afterDelta.begin();
2967   end = afterDelta.end();
2968   for (; ite != end; ++ite, ++numAfterApplied)
2969   {
2970     node = (*ite).first;
2971     key = (*ite).second;
2972 
2973     // If the index had its own key obj already, delete the key obj that was
2974     // allocated during the delta creation.
2975     if (index->insert((*ite).second, node))
2976     {
2977       assert(key != (*ite).second);
2978       delete key;
2979     }
2980   }
2981 
2982   STORE_TRACE2("deleted-delta size = " << deletedDelta.size());
2983 
2984   ite = deletedDelta.begin();
2985   end = deletedDelta.end();
2986   for (; ite != end; ++ite, ++numDeletedApplied)
2987   {
2988     index->remove((*ite).second, (*ite).first, false);
2989   }
2990 
2991   STORE_TRACE2("inserted-delta size = " << insertedDelta.size());
2992 
2993   ite = insertedDelta.begin();
2994   end = insertedDelta.end();
2995   for (; ite != end; ++ite, ++numInsertedApplied)
2996   {
2997     node = (*ite).first;
2998     key = (*ite).second;
2999 
3000     if (index->insert((*ite).second, node))
3001     {
3002       assert(key != (*ite).second);
3003       delete key;
3004     }
3005   }
3006 
3007   STORE_TRACE2("Index size after do = " << index->size());
3008 }
3009 
3010 
3011 /*******************************************************************************
3012 
3013 ********************************************************************************/
refreshGeneralIndex(csize idx)3014 void CollectionPul::refreshGeneralIndex(csize idx)
3015 {
3016   GeneralIndex* index = static_cast<GeneralIndex*>(theIncrementalIndices[idx]);
3017 
3018   store::IndexDelta::GeneralDelta&
3019   beforeDelta = theBeforeIndexDeltas[idx].getGeneralDelta();
3020   store::IndexDelta::GeneralDelta&
3021   afterDelta = theAfterIndexDeltas[idx].getGeneralDelta();
3022   store::IndexDelta::GeneralDelta&
3023   deletedDelta = theDeletedDocsIndexDeltas[idx].getGeneralDelta();
3024   store::IndexDelta::GeneralDelta&
3025   insertedDelta = theInsertedDocsIndexDeltas[idx].getGeneralDelta();
3026 
3027   csize& numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
3028   csize& numAfterApplied = theNumAfterIndexDeltasApplied[idx];
3029   csize& numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
3030   csize& numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
3031 
3032   store::Item_t key;
3033   store::Item_t node;
3034 
3035   IndexDeltaImpl::GeneralIterator ite;
3036   IndexDeltaImpl::GeneralIterator end;
3037   std::vector<store::Item_t>::iterator keyIte;
3038   std::vector<store::Item_t>::iterator keyEnd;
3039 
3040   STORE_TRACE2("before-delta size = " << beforeDelta.size());
3041 
3042   ite = beforeDelta.begin();
3043   end = beforeDelta.end();
3044 
3045   while (ite != end)
3046   {
3047     store::Item* nodep = (*ite).first.getp();
3048 
3049     index->remove((*ite).second, (*ite).first);
3050     ++numBeforeApplied;
3051     ++ite;
3052 
3053     if (ite != end && (*ite).first.getp() == nodep)
3054     {
3055       index->remove((*ite).second, (*ite).first);
3056       ++numDeletedApplied;
3057       ++ite;
3058 
3059       // Call removeMultiKey() after removing the 2nd key for the same node.
3060       // We do this to make undo easier.
3061       index->removeMultiKey();
3062 
3063       while (ite != end && (*ite).first.getp() == nodep)
3064       {
3065         index->remove((*ite).second, (*ite).first);
3066         ++numBeforeApplied;
3067         ++ite;
3068       }
3069     }
3070   }
3071 
3072   STORE_TRACE2("after-delta size = " << afterDelta.size());
3073 
3074   ite = afterDelta.begin();
3075   end = afterDelta.end();
3076 
3077   while (ite != end)
3078   {
3079     node = (*ite).first;
3080     key = (*ite).second;
3081     store::Item* nodep = node.getp();
3082 
3083     index->insert(key, node);
3084     ++numAfterApplied;
3085     ++ite;
3086 
3087     if (ite != end && (*ite).first.getp() == nodep)
3088     {
3089       node = (*ite).first;
3090       key = (*ite).second;
3091 
3092       index->insert(key, node);
3093       ++numAfterApplied;
3094       ++ite;
3095 
3096       index->addMultiKey();
3097 
3098       while (ite != end && (*ite).first.getp() == nodep)
3099       {
3100         node = (*ite).first;
3101         key = (*ite).second;
3102 
3103         index->insert(key, node);
3104         ++numAfterApplied;
3105         ++ite;
3106       }
3107     }
3108   }
3109 
3110   STORE_TRACE2("deleted-delta size = " << deletedDelta.size());
3111 
3112   ite = deletedDelta.begin();
3113   end = deletedDelta.end();
3114 
3115   while (ite != end)
3116   {
3117     store::Item* nodep = (*ite).first.getp();
3118 
3119     index->remove((*ite).second, (*ite).first);
3120     ++numDeletedApplied;
3121     ++ite;
3122 
3123     if (ite != end && (*ite).first.getp() == nodep)
3124     {
3125       index->remove((*ite).second, (*ite).first);
3126       ++numDeletedApplied;
3127       ++ite;
3128 
3129       // Call removeMultiKey() after removing the 2nd key for the same node.
3130       // We do this to make undo easier.
3131       index->removeMultiKey();
3132 
3133       while (ite != end && (*ite).first.getp() == nodep)
3134       {
3135         index->remove((*ite).second, (*ite).first);
3136         ++numDeletedApplied;
3137         ++ite;
3138       }
3139     }
3140   }
3141 
3142   STORE_TRACE2("inserted-delta size = " << insertedDelta.size());
3143 
3144   ite = insertedDelta.begin();
3145   end = insertedDelta.end();
3146 
3147   while (ite != end)
3148   {
3149     node = (*ite).first;
3150     key = (*ite).second;
3151     store::Item* nodep = node.getp();
3152 
3153     index->insert(key, node);
3154     ++numInsertedApplied;
3155     ++ite;
3156 
3157     if (ite != end && (*ite).first.getp() == nodep)
3158     {
3159       node = (*ite).first;
3160       key = (*ite).second;
3161 
3162       index->insert(key, node);
3163       ++numInsertedApplied;
3164       ++ite;
3165 
3166       index->addMultiKey();
3167 
3168       while (ite != end && (*ite).first.getp() == nodep)
3169       {
3170         node = (*ite).first;
3171         key = (*ite).second;
3172 
3173         index->insert(key, node);
3174         ++numInsertedApplied;
3175         ++ite;
3176       }
3177     }
3178   }
3179 }
3180 
3181 
3182 /*******************************************************************************
3183 
3184 ********************************************************************************/
undoRefreshIndexes()3185 void CollectionPul::undoRefreshIndexes()
3186 {
3187   csize numIncrementalIndices = theIncrementalIndices.size();
3188 
3189   STORE_TRACE1("Reverting indexes for collection "
3190                << (theCollection ?
3191                    theCollection->getName()->getStringValue().c_str() :
3192                    "NULL")
3193                << std::endl);
3194 
3195   for (csize idx = 0; idx < numIncrementalIndices; ++idx)
3196   {
3197     if (theIncrementalIndices[idx]->isGeneral())
3198       undoGeneralIndexRefresh(idx);
3199     else
3200       undoValueIndexRefresh(idx);
3201   }
3202 
3203   STORE_TRACE1("Reverted indexes for collection "
3204                << (theCollection ?
3205                    theCollection->getName()->getStringValue().c_str() :
3206                    "NULL")
3207                << std::endl);
3208 }
3209 
3210 
3211 /*******************************************************************************
3212 
3213 ********************************************************************************/
undoValueIndexRefresh(csize idx)3214 void CollectionPul::undoValueIndexRefresh(csize idx)
3215 {
3216   ValueIndex* index = static_cast<ValueIndex*>(theIncrementalIndices[idx]);
3217 
3218   STORE_TRACE2("Index size before undo = " << index->size());
3219 
3220   store::IndexDelta::ValueDelta&
3221   beforeDelta = theBeforeIndexDeltas[idx].getValueDelta();
3222   store::IndexDelta::ValueDelta&
3223   afterDelta = theAfterIndexDeltas[idx].getValueDelta();
3224   store::IndexDelta::ValueDelta&
3225   insertedDelta = theInsertedDocsIndexDeltas[idx].getValueDelta();
3226   store::IndexDelta::ValueDelta&
3227   deletedDelta = theDeletedDocsIndexDeltas[idx].getValueDelta();
3228 
3229   csize numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
3230   csize numAfterApplied = theNumAfterIndexDeltasApplied[idx];
3231   csize numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
3232   csize numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
3233 
3234   IndexDeltaImpl::ReverseValueIterator ite;
3235   IndexDeltaImpl::ReverseValueIterator end;
3236 
3237   ite = insertedDelta.rbegin() + (insertedDelta.size() - numInsertedApplied);
3238   end = insertedDelta.rend();
3239   for (; ite != end; ++ite)
3240   {
3241     index->remove((*ite).second, (*ite).first, false);
3242   }
3243 
3244   ite = deletedDelta.rbegin() + (deletedDelta.size() - numDeletedApplied);
3245   end = deletedDelta.rend();
3246   for (; ite != end; ++ite)
3247   {
3248     store::IndexKey* key = (*ite).second;
3249 
3250     // If the index takes ownership of the key obj, set the key ptr to null
3251     // so that the key obj will not be deleted during cleanIndexDeltas().
3252     if (!index->insert(key, (*ite).first))
3253     {
3254       assert(key == (*ite).second);
3255       (*ite).second = NULL;
3256     }
3257   }
3258 
3259   ite = afterDelta.rbegin() + (afterDelta.size() - numAfterApplied);
3260   end = afterDelta.rend();
3261   for (; ite != end; ++ite)
3262   {
3263     index->remove((*ite).second, (*ite).first, false);
3264   }
3265 
3266   ite = beforeDelta.rbegin() + (beforeDelta.size() - numBeforeApplied);
3267   end = beforeDelta.rend();
3268   for (; ite != end; ++ite)
3269   {
3270     store::IndexKey* key = (*ite).second;
3271 
3272     // If the index takes ownership of the key obj, set the key ptr to null
3273     // so that the key obj will not be deleted during cleanIndexDeltas().
3274     if (!index->insert(key, (*ite).first))
3275     {
3276       assert(key == (*ite).second);
3277       (*ite).second = NULL;
3278     }
3279   }
3280 
3281   STORE_TRACE2("Index size after undo = " << index->size());
3282 }
3283 
3284 
3285 /*******************************************************************************
3286 
3287 ********************************************************************************/
undoGeneralIndexRefresh(csize idx)3288 void CollectionPul::undoGeneralIndexRefresh(csize idx)
3289 {
3290   GeneralIndex* index = static_cast<GeneralIndex*>(theIncrementalIndices[idx]);
3291 
3292   store::IndexDelta::GeneralDelta&
3293   beforeDelta = theBeforeIndexDeltas[idx].getGeneralDelta();
3294   store::IndexDelta::GeneralDelta&
3295   afterDelta = theAfterIndexDeltas[idx].getGeneralDelta();
3296   store::IndexDelta::GeneralDelta&
3297   insertedDelta = theInsertedDocsIndexDeltas[idx].getGeneralDelta();
3298   store::IndexDelta::GeneralDelta&
3299   deletedDelta = theDeletedDocsIndexDeltas[idx].getGeneralDelta();
3300 
3301   csize numBeforeApplied = theNumBeforeIndexDeltasApplied[idx];
3302   csize numAfterApplied = theNumAfterIndexDeltasApplied[idx];
3303   csize numDeletedApplied = theNumDeletedDocsIndexDeltasApplied[idx];
3304   csize numInsertedApplied = theNumInsertedDocsIndexDeltasApplied[idx];
3305 
3306   IndexDeltaImpl::ReverseGeneralIterator ite;
3307   IndexDeltaImpl::ReverseGeneralIterator end;
3308   std::vector<store::Item_t>::reverse_iterator keyIte;
3309   std::vector<store::Item_t>::reverse_iterator keyEnd;
3310 
3311   // Inserted delta
3312 
3313   ite = insertedDelta.rbegin() + (insertedDelta.size() - numInsertedApplied);
3314   end = insertedDelta.rend();
3315 
3316   while (ite != end)
3317   {
3318     store::Item* nodep = (*ite).first.getp();
3319 
3320     index->remove((*ite).second, (*ite).first);
3321     ++ite;
3322 
3323     if (ite != end && (*ite).first.getp() == nodep)
3324     {
3325       index->removeMultiKey();
3326 
3327       do
3328       {
3329         index->remove((*ite).second, (*ite).first);
3330         ++ite;
3331       }
3332       while (ite != end && (*ite).first.getp() == nodep);
3333     }
3334   }
3335 
3336   // Deleted delta
3337 
3338   ite = deletedDelta.rbegin() + (deletedDelta.size() - numDeletedApplied);
3339   end = deletedDelta.rend();
3340 
3341   while (ite != end)
3342   {
3343     store::Item* nodep = (*ite).first.getp();
3344 
3345     index->insert((*ite).second, (*ite).first);
3346     ++ite;
3347 
3348     if (ite != end && (*ite).first.getp() == nodep)
3349     {
3350       index->addMultiKey();
3351 
3352       do
3353       {
3354         index->insert((*ite).second, (*ite).first);
3355         ++ite;
3356       }
3357       while (ite != end && (*ite).first.getp() == nodep);
3358     }
3359   }
3360 
3361   // After delta
3362 
3363   ite = afterDelta.rbegin() + (afterDelta.size() - numAfterApplied);
3364   end = afterDelta.rend();
3365 
3366   while (ite != end)
3367   {
3368     store::Item* nodep = (*ite).first.getp();
3369 
3370     index->remove((*ite).second, (*ite).first);
3371     ++ite;
3372 
3373     if (ite != end && (*ite).first.getp() == nodep)
3374     {
3375       index->removeMultiKey();
3376 
3377       do
3378       {
3379         index->remove((*ite).second, (*ite).first);
3380         ++ite;
3381       }
3382       while (ite != end && (*ite).first.getp() == nodep);
3383     }
3384   }
3385 
3386   // Before delta
3387 
3388   ite = beforeDelta.rbegin() + (beforeDelta.size() - numBeforeApplied);
3389   end = beforeDelta.rend();
3390 
3391   while (ite != end)
3392   {
3393     store::Item* nodep = (*ite).first.getp();
3394 
3395     index->insert((*ite).second, (*ite).first);
3396     ++ite;
3397 
3398     if (ite != end && (*ite).first.getp() == nodep)
3399     {
3400       index->addMultiKey();
3401 
3402       do
3403       {
3404         index->insert((*ite).second, (*ite).first);
3405         ++ite;
3406       }
3407       while (ite != end && (*ite).first.getp() == nodep);
3408     }
3409   }
3410 }
3411 
3412 
3413 /*******************************************************************************
3414   The method is called from CollectionPul::finalizeUpdates()
3415 ********************************************************************************/
truncateIndexes()3416 void CollectionPul::truncateIndexes()
3417 {
3418   csize numTruncatedIndices = theTruncatedIndices.size();
3419 
3420   for (csize idx = 0; idx < numTruncatedIndices; ++idx)
3421   {
3422     ValueIndex* index = static_cast<ValueIndex*>(theTruncatedIndices[idx]);
3423     index->clear();
3424   }
3425 }
3426 
3427 
3428 /*******************************************************************************
3429 
3430 ********************************************************************************/
applyUpdates()3431 void CollectionPul::applyUpdates()
3432 {
3433   csize numIncrementalIndices = theIncrementalIndices.size();
3434 
3435 #if 0
3436   if (theCollection != NULL)
3437   {
3438     std::cout << "applying PUL for collection "
3439               << theCollection->getName()->getStringValue() << std::endl;
3440   }
3441 #endif
3442 
3443   if (numIncrementalIndices > 0)
3444   {
3445     theBeforeIndexDeltas.resize(numIncrementalIndices);
3446     theAfterIndexDeltas.resize(numIncrementalIndices);
3447     theDeletedDocsIndexDeltas.resize(numIncrementalIndices);
3448     theInsertedDocsIndexDeltas.resize(numIncrementalIndices);
3449 
3450     theNumBeforeIndexDeltasApplied.resize(numIncrementalIndices);
3451     theNumAfterIndexDeltasApplied.resize(numIncrementalIndices);
3452     theNumInsertedDocsIndexDeltasApplied.resize(numIncrementalIndices);
3453     theNumDeletedDocsIndexDeltasApplied.resize(numIncrementalIndices);
3454 
3455     for (csize idx = 0; idx < numIncrementalIndices; ++idx)
3456     {
3457       theNumBeforeIndexDeltasApplied[idx] = 0;
3458       theNumAfterIndexDeltasApplied[idx] = 0;
3459       theNumInsertedDocsIndexDeltasApplied[idx] = 0;
3460       theNumDeletedDocsIndexDeltasApplied[idx] = 0;
3461     }
3462   }
3463 
3464   // Don't apply anything if the collection is going to be deleted.
3465   if (!theDeleteCollectionList.empty())
3466     return;
3467 
3468   // if the collection is truncated, no other primitive needs to be applied
3469   if (!theTruncateCollectionList.empty())
3470   {
3471     applyList(theTruncateCollectionList);
3472     theIsApplied = true;
3473     return;
3474   }
3475 
3476   try
3477   {
3478     // Compute the before-delta for each incrementally maintained index.
3479     computeIndexBeforeDeltas();
3480 
3481     theIsApplied = true;
3482 
3483     // Apply all the XQUF update primitives
3484     applyList(theDoFirstList);
3485     applyList(theInsertList);
3486     applyList(theReplaceNodeList);
3487     applyList(theReplaceContentList);
3488     applyList(theDeleteList);
3489 
3490 #ifdef ZORBA_WITH_JSON
3491     applyList(theJSONObjectDeleteList);
3492     applyList(theJSONObjectReplaceValueList);
3493     applyList(theJSONObjectRenameList);
3494     applyList(theJSONObjectInsertList);
3495 
3496     if (!theJSONArrayDeleteList.empty() ||
3497         !theJSONArrayInsertList.empty() ||
3498         !theJSONArrayReplaceValueList.empty() ||
3499         !theJSONArrayAppendList.empty())
3500     {
3501       NodeToUpdatesMap::iterator ite = theNodeToUpdatesMap.begin();
3502       NodeToUpdatesMap::iterator end = theNodeToUpdatesMap.end();
3503       for (; ite != end; ++ite)
3504       {
3505         if (!(*ite).first->isJSONArray())
3506           continue;
3507 
3508         NodeUpdates* updates = (*ite).second;
3509 
3510         std::sort(updates->begin(), updates->end(), UpdJSONArrayUpdate::Comparator());
3511 
3512         NodeUpdates::iterator updIte = updates->begin();
3513         NodeUpdates::iterator updEnd = updates->end();
3514         for (; updIte != updEnd; ++updIte)
3515         {
3516           (*updIte)->apply();
3517         }
3518       }
3519     }
3520 #endif
3521 
3522     // Check if any inconsistencies that were detected during the application
3523     // of XQUF primitives were only temporary and have been resolved by now.
3524     // If not, an exception will be raised, and the updates will be undone
3525     // in the "catch" clause below.
3526     csize numToRecheck = thePrimitivesToRecheck.size();
3527     for (csize i = 0; i < numToRecheck; ++i)
3528       thePrimitivesToRecheck[i]->check();
3529 
3530     // Check if any text node merging has to be performed
3531     std::set<InternalNode*>::iterator it = theMergeToCheckSet.begin();
3532     std::set<InternalNode*>::iterator end = theMergeToCheckSet.end();
3533     for (; it != end; ++it)
3534     {
3535       InternalNode* node = (*it);
3536 
3537       for (csize i = 0; i < node->numChildren()-1; ++i)
3538       {
3539         if (node->getChild(i)->getNodeKind() == store::StoreConsts::textNode &&
3540             node->getChild(i+1)->getNodeKind() == store::StoreConsts::textNode)
3541         {
3542           TextNode* mergedNode = reinterpret_cast<TextNode*>(node->getChild(i));
3543 
3544           TextNodeMerge mergeInfo(node, i);
3545           mergeInfo.theMergedNodes.push_back(mergedNode);
3546           node->removeChild(i);
3547 
3548           zstring newContent = mergedNode->getText();
3549           csize j = i;
3550 
3551           while (j < node->numChildren() &&
3552                  node->getChild(j)->getNodeKind() == store::StoreConsts::textNode)
3553           {
3554             TextNode* mergedNode = reinterpret_cast<TextNode*>(node->getChild(j));
3555             newContent += mergedNode->getText();
3556             node->removeChild(j);
3557             mergeInfo.theMergedNodes.push_back(mergedNode);
3558           }
3559 
3560           theMergeList.push_back(mergeInfo);
3561 
3562           (void)GET_NODE_FACTORY().createTextNode(node->getTree(),
3563                                                   node,
3564                                                   false,
3565                                                   i,
3566                                                   newContent);
3567         }
3568       }
3569     }
3570 
3571 #ifndef ZORBA_NO_XMLSCHEMA
3572     // Revalidate the updated docs
3573     if (thePul->theValidator != NULL && !theValidationNodes.empty())
3574     {
3575       theValidationPul = GET_STORE().getItemFactory()->createPendingUpdateList();
3576 
3577       thePul->theValidator->validate(theValidationNodes, *theValidationPul.getp());
3578 
3579       try
3580       {
3581         theValidationPul->applyUpdates(false);
3582       }
3583       catch (...)
3584       {
3585         ZORBA_FATAL(0, "Error during the application of the validation PUL");
3586       }
3587     }
3588 
3589     if (thePul->theValidator != NULL)
3590     {
3591       applyList(theRevalidateList);
3592     }
3593 #endif
3594 
3595     // Apply collection primitives, except delete primitives
3596     applyList(theCreateCollectionList);
3597     applyList(theInsertIntoCollectionList);
3598     applyList(theDeleteFromCollectionList);
3599 
3600     // Compute the after-delta for each incrementally maintained index.
3601     computeIndexAfterDeltas();
3602   }
3603   catch (const std::exception& e)
3604   {
3605     //std::cerr << "Exception thrown during pul::applyUpdates: " << e.what() << std::endl;
3606     throw;
3607   }
3608   catch (...)
3609   {
3610     //std::cerr << "Exception thrown during pul::applyUpdates " << std::endl;
3611     throw;
3612   }
3613 
3614 #if 0
3615   if (theCollection != NULL)
3616   {
3617     std::cout << "applied PUL for collection "
3618               << theCollection->getName()->getStringValue() << std::endl << std::endl;
3619   }
3620 #endif
3621 }
3622 
3623 
3624 /*******************************************************************************
3625 
3626 ********************************************************************************/
undoUpdates()3627 void CollectionPul::undoUpdates()
3628 {
3629   if (!theIsApplied)
3630     return;
3631 
3632   try
3633   {
3634     undoList(theTruncateCollectionList);
3635     undoList(theDeleteFromCollectionList);
3636     undoList(theInsertIntoCollectionList);
3637     undoList(theCreateCollectionList);
3638 
3639 #ifndef ZORBA_NO_XMLSCHEMA
3640     // Undo validate-in-place validation
3641     undoList(theRevalidateList);
3642 
3643     // Undo apply-updates caused validation
3644     if (theValidationPul)
3645     {
3646       undoList(static_cast<PULImpl *>(theValidationPul.getp())->theValidationList);
3647     }
3648 #endif
3649 
3650     // Undo text node merging
3651     std::vector<TextNodeMerge>::reverse_iterator rit = theMergeList.rbegin();
3652     std::vector<TextNodeMerge>::reverse_iterator rend = theMergeList.rend();
3653     for (; rit != rend; ++rit)
3654     {
3655       TextNodeMerge merge = (*rit);
3656       XmlNode* newTextNode = merge.theParent->getChild(merge.thePos);
3657       ZORBA_ASSERT(newTextNode->getNodeKind()== store::StoreConsts::textNode);
3658 
3659       newTextNode->detach();
3660 
3661       for (csize j = 0; j < merge.theMergedNodes.size(); ++j)
3662         merge.theMergedNodes[j]->connect(merge.theParent, merge.thePos + j);
3663     }
3664     theMergeList.clear();
3665 
3666 #ifdef ZORBA_WITH_JSON
3667     undoList(theJSONObjectInsertList);
3668     undoList(theJSONObjectRenameList);
3669     undoList(theJSONObjectReplaceValueList);
3670     undoList(theJSONObjectDeleteList);
3671 
3672     if (!theJSONArrayDeleteList.empty() ||
3673         !theJSONArrayInsertList.empty() ||
3674         !theJSONArrayReplaceValueList.empty() ||
3675         !theJSONArrayAppendList.empty())
3676     {
3677       NodeToUpdatesMap::iterator ite = theNodeToUpdatesMap.begin();
3678       NodeToUpdatesMap::iterator end = theNodeToUpdatesMap.end();
3679       for (; ite != end; ++ite)
3680       {
3681         if (!(*ite).first->isJSONArray())
3682           continue;
3683 
3684         NodeUpdates* updates = (*ite).second;
3685 
3686         NodeUpdates::reverse_iterator updIte = updates->rbegin();
3687         NodeUpdates::reverse_iterator updEnd = updates->rend();
3688         for (; updIte != updEnd; ++updIte)
3689         {
3690           (*updIte)->undo();
3691         }
3692       }
3693     }
3694 #endif
3695 
3696     undoList(theDeleteList);
3697     undoList(theReplaceContentList);
3698     undoList(theReplaceNodeList);
3699     undoList(theInsertList);
3700     undoList(theDoFirstList);
3701 
3702     undoRefreshIndexes();
3703   }
3704   catch (...)
3705   {
3706     ZORBA_FATAL(0, "Unexpected error during pul undo");
3707   }
3708 }
3709 
3710 
3711 /*******************************************************************************
3712   Actions performed in this method are not expected to raise any error, and
3713   the method itself is called after all other actions that may raise errors
3714   have been executed already. This separation of actions into ones that may
3715   raise errors and other that never raise errors makes it easier to implement
3716   the undo actions for certain operations.
3717 ********************************************************************************/
finalizeUpdates()3718 void CollectionPul::finalizeUpdates()
3719 {
3720   try
3721   {
3722     truncateIndexes();
3723 
3724     // If necessary, adjust the position of trees inside this collection.
3725     if (theAdjustTreePositions)
3726     {
3727       assert(theCollection);
3728       theCollection->adjustTreePositions();
3729     }
3730 
3731     // Detach nodes that were deleted from their trees due to replace-node,
3732     // replace-content, or delete-node XQUF primitives.
3733     csize numUpdates = theReplaceNodeList.size();
3734 
3735     for (csize i = 0; i < numUpdates; ++i)
3736     {
3737       UpdatePrimitive* upd = theReplaceNodeList[i];
3738 
3739       if (!upd->theIsApplied)
3740         continue;
3741 
3742       if (upd->getKind() == store::UpdateConsts::UP_REPLACE_CHILD)
3743       {
3744         UpdReplaceChild* upd2 = static_cast<UpdReplaceChild*>(upd);
3745 
3746         XmlNode* node = BASE_NODE(upd2->theChild);
3747 
3748         // To make the detach() method work properly, we must set the node's
3749         // parent back to what it used to be.
3750         node->theParent = INTERNAL_NODE(upd->theTarget);
3751         node->detach();
3752       }
3753       else
3754       {
3755         XmlNode* node = BASE_NODE(static_cast<UpdReplaceAttribute*>(upd)->theAttr);
3756 
3757         // To make the detach() method work properly, we must set the node's
3758         // parent back to what it used to be.
3759         node->theParent = INTERNAL_NODE(upd->theTarget);
3760         node->detach();
3761       }
3762     }
3763 
3764     numUpdates = theReplaceContentList.size();
3765     for (csize i = 0; i < numUpdates; ++i)
3766     {
3767       UpdReplaceElemContent* upd;
3768       upd = static_cast<UpdReplaceElemContent*>(theReplaceContentList[i]);
3769 
3770       csize numChildren = upd->theOldChildren.size();
3771       for (csize j = 0; j < numChildren; ++j)
3772       {
3773         XmlNode* node = upd->theOldChildren[j];
3774         node->theParent = INTERNAL_NODE(upd->theTarget);
3775         node->detach();
3776       }
3777     }
3778 
3779     numUpdates = theDeleteList.size();
3780     for (csize i = 0; i < numUpdates; ++i)
3781     {
3782       UpdDelete* upd = static_cast<UpdDelete*>(theDeleteList[i]);
3783 
3784       if (upd->theIsApplied)
3785       {
3786         XmlNode* target = BASE_NODE(upd->theTarget);
3787         target->theParent = upd->theParent;
3788         target->detach();
3789       }
3790     }
3791 
3792     numUpdates = theMergeList.size();
3793     for (csize i = 0; i < numUpdates; ++i)
3794     {
3795       for (csize j = 0; j < theMergeList[i].theMergedNodes.size(); ++j)
3796       {
3797         theMergeList[i].theMergedNodes[j]->theParent= theMergeList[i].theParent;
3798         theMergeList[i].theMergedNodes[j]->detach();
3799       }
3800     }
3801   }
3802   catch (...)
3803   {
3804     ZORBA_FATAL(0, "Unexpected error during pul apply");
3805   }
3806 }
3807 
3808 
3809 } // namespace simplestore
3810 } // namespace zorba
3811 /* vim:set et sw=2 ts=2: */
3812