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