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 "diagnostics/xquery_diagnostics.h"
19 #include "diagnostics/util_macros.h"
20
21 #include "zorbatypes/collation_manager.h"
22 #include "zorbatypes/datetime.h"
23
24 #include "system/globalenv.h"
25
26 #include "types/casting.h"
27 #include "types/typeops.h"
28
29 #include "context/dynamic_context.h"
30 #include "context/static_context.h"
31
32 #include "compiler/api/compilercb.h"
33
34 #include "runtime/visitors/planiter_visitor.h"
35 #include "runtime/booleans/BooleanImpl.h"
36 #include "runtime/api/plan_iterator_wrapper.h"
37 #include "runtime/util/iterator_impl.h"
38
39 #include "store/api/temp_seq.h"
40 #include "store/api/item_factory.h"
41 #include "store/api/store.h"
42
43
44 namespace zorba {
45
46 SERIALIZABLE_CLASS_VERSIONS(FnBooleanIterator)
47
SERIALIZABLE_CLASS_VERSIONS(OrIterator)48 SERIALIZABLE_CLASS_VERSIONS(OrIterator)
49
50 SERIALIZABLE_CLASS_VERSIONS(AndIterator)
51
52 SERIALIZABLE_CLASS_VERSIONS(CompareIterator)
53
54 SERIALIZABLE_TEMPLATE_INSTANCE(TypedValueCompareIterator,
55 TypedValueCompareIterator<store::XS_DOUBLE>,
56 1)
57
58 SERIALIZABLE_TEMPLATE_INSTANCE(TypedValueCompareIterator,
59 TypedValueCompareIterator<store::XS_FLOAT>,
60 2)
61
62 SERIALIZABLE_TEMPLATE_INSTANCE(TypedValueCompareIterator,
63 TypedValueCompareIterator<store::XS_DECIMAL>,
64 3)
65
66 SERIALIZABLE_TEMPLATE_INSTANCE(TypedValueCompareIterator,
67 TypedValueCompareIterator<store::XS_INTEGER>,
68 4)
69
70 SERIALIZABLE_TEMPLATE_INSTANCE(TypedValueCompareIterator,
71 TypedValueCompareIterator<store::XS_STRING>,
72 5)
73
74 SERIALIZABLE_CLASS_VERSIONS(AtomicValuesEquivalenceIterator)
75
76
77 /*******************************************************************************
78 15.1.1 fn:boolean
79 ********************************************************************************/
80 FnBooleanIterator::FnBooleanIterator(
81 static_context* sctx,
82 const QueryLoc& loc,
83 PlanIter_t& aIter,
84 bool aNegate)
85 :
86 UnaryBaseIterator<FnBooleanIterator, PlanIteratorState>(sctx, loc, aIter),
87 theNegate(aNegate)
88 {
89 }
90
91
serialize(::zorba::serialization::Archiver & ar)92 void FnBooleanIterator::serialize(::zorba::serialization::Archiver& ar)
93 {
94 serialize_baseclass(ar,
95 (UnaryBaseIterator<FnBooleanIterator, PlanIteratorState>*)this);
96
97 ar & theNegate;
98 }
99
100
effectiveBooleanValue(const QueryLoc & loc,PlanState & planState,const PlanIterator * iter,bool negate)101 bool FnBooleanIterator::effectiveBooleanValue(
102 const QueryLoc& loc,
103 PlanState& planState,
104 const PlanIterator* iter,
105 bool negate)
106 {
107 store::Item_t item;
108 bool result;
109 bool is_sequence;
110
111 TypeManager* tm = iter->getStaticContext()->get_typemanager();
112
113 if (!consumeNext(item, iter, planState))
114 {
115 // empty sequence => false
116 result = negate ^ false;
117 }
118 else if (item->isNode())
119 {
120 // node => true
121 result = negate ^ true;
122 }
123 #ifdef ZORBA_WITH_JSON
124 else if (item->isJSONItem())
125 {
126 xqtref_t type = tm->create_value_type(item);
127
128 RAISE_ERROR(err::FORG0006, loc,
129 ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o), *type, "fn:boolean" ));
130 }
131 #endif
132 else
133 {
134 store::SchemaTypeCode type = item->getTypeCode();
135
136 store::Item_t item2;
137 is_sequence = consumeNext(item2, iter, planState);
138
139 if (!is_sequence
140 &&
141 (type == store::XS_BOOLEAN ||
142 TypeOps::is_subtype(type, store::XS_STRING) ||
143 TypeOps::is_subtype(type, store::XS_ANY_URI) ||
144 type == store::XS_UNTYPED_ATOMIC ||
145 type == store::JS_NULL ||
146 TypeOps::is_numeric(type)))
147 {
148 // atomic type xs_boolean, xs_string, xs_anyURI, xs_untypedAtomic
149 // => effective boolean value is defined in the items
150 bool temp = item->getEBV();
151 result = negate ? (negate ^ temp) : temp;
152 }
153 else
154 {
155 if (is_sequence)
156 {
157 xqtref_t type = tm->create_value_type(item);
158
159 RAISE_ERROR(err::FORG0006, loc,
160 ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o),
161 "", "fn:boolean",
162 ZED(EBVNotDefSeq_5),
163 *type));
164 }
165 else
166 {
167 RAISE_ERROR(err::FORG0006, loc,
168 ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o), "", "fn:boolean" ));
169 }
170 }
171 }
172
173 return result;
174 }
175
176
nextImpl(store::Item_t & result,PlanState & planState) const177 bool FnBooleanIterator::nextImpl(store::Item_t& result, PlanState& planState) const
178 {
179 PlanIteratorState* aState;
180 DEFAULT_STACK_INIT(PlanIteratorState, aState, planState);
181
182 GENV_ITEMFACTORY->
183 createBoolean(result,
184 FnBooleanIterator::effectiveBooleanValue(this->loc,
185 planState,
186 theChild,
187 theNegate));
188 STACK_PUSH(true, aState);
189 STACK_END(aState);
190 }
191
192
193 UNARY_ACCEPT(FnBooleanIterator);
194
195
196 /////////////////////////////////////////////////////////////////////////////////
197 // //
198 // OrIterator //
199 // //
200 /////////////////////////////////////////////////////////////////////////////////
201
202
OrIterator(static_context * sctx,const QueryLoc & loc,std::vector<PlanIter_t> & inChildren)203 OrIterator::OrIterator (
204 static_context* sctx,
205 const QueryLoc& loc,
206 std::vector<PlanIter_t>& inChildren)
207 :
208 NaryBaseIterator<OrIterator, PlanIteratorState>(sctx, loc, inChildren)
209 {
210 }
211
212
213 void
serialize(::zorba::serialization::Archiver & ar)214 OrIterator::serialize(::zorba::serialization::Archiver& ar)
215 {
216 serialize_baseclass(ar, (NaryBaseIterator<OrIterator, PlanIteratorState>*)this);
217 }
218
219
220 bool
nextImpl(store::Item_t & result,PlanState & planState) const221 OrIterator::nextImpl(store::Item_t& result, PlanState& planState) const
222 {
223 bool res = false;
224
225 PlanIteratorState* state;
226 DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
227
228 {
229 std::vector<PlanIter_t>::const_iterator ite = theChildren.begin();
230 std::vector<PlanIter_t>::const_iterator end = theChildren.end();
231 for (; res == false && ite != end; ++ite)
232 {
233 res = res ||
234 FnBooleanIterator::effectiveBooleanValue(loc, planState, (*ite));
235 }
236 }
237
238 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, res), state);
239 STACK_END(state);
240 }
241
242
243 NARY_ACCEPT(OrIterator);
244
245
246 /////////////////////////////////////////////////////////////////////////////////
247 // //
248 // AndIterator //
249 // //
250 /////////////////////////////////////////////////////////////////////////////////
251
AndIterator(static_context * sctx,const QueryLoc & loc,std::vector<PlanIter_t> & inChildren)252 AndIterator::AndIterator(
253 static_context* sctx,
254 const QueryLoc& loc,
255 std::vector<PlanIter_t>& inChildren)
256 :
257 NaryBaseIterator<AndIterator, PlanIteratorState>(sctx, loc, inChildren)
258 {
259 }
260
261
262 void
serialize(::zorba::serialization::Archiver & ar)263 AndIterator::serialize(::zorba::serialization::Archiver& ar)
264 {
265 serialize_baseclass(ar, (NaryBaseIterator<AndIterator, PlanIteratorState>*)this);
266 }
267
268
269 bool
nextImpl(store::Item_t & result,PlanState & planState) const270 AndIterator::nextImpl(store::Item_t& result, PlanState& planState) const
271 {
272 bool res = true;
273
274 PlanIteratorState* state;
275 DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
276
277 {
278 std::vector<PlanIter_t>::const_iterator ite = theChildren.begin();
279 std::vector<PlanIter_t>::const_iterator end = theChildren.end();
280 for (; res && ite != end; ++ite)
281 {
282 res = res &&
283 FnBooleanIterator::effectiveBooleanValue(loc, planState, (*ite));
284 }
285 }
286
287 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, res), state);
288 STACK_END(state);
289 }
290
291
292 NARY_ACCEPT(AndIterator);
293
294
295 /////////////////////////////////////////////////////////////////////////////////
296 // //
297 // CompareIterator //
298 // //
299 /////////////////////////////////////////////////////////////////////////////////
300
301
302 /*******************************************************************************
303
304 ********************************************************************************/
CompareIterator(static_context * sctx,const QueryLoc & loc,PlanIter_t aChild0,PlanIter_t aChild1,CompareConsts::CompareType aCompType)305 CompareIterator::CompareIterator(
306 static_context* sctx,
307 const QueryLoc& loc,
308 PlanIter_t aChild0,
309 PlanIter_t aChild1,
310 CompareConsts::CompareType aCompType)
311 :
312 BinaryBaseIterator<CompareIterator, PlanIteratorState> ( sctx, loc, aChild0, aChild1 ),
313 theCompType(aCompType),
314 theTypeManager(NULL),
315 theTimezone(0),
316 theCollation(NULL)
317 {
318 switch(theCompType)
319 {
320 case CompareConsts::GENERAL_EQUAL:
321 case CompareConsts::GENERAL_NOT_EQUAL:
322 case CompareConsts::GENERAL_LESS:
323 case CompareConsts::GENERAL_LESS_EQUAL:
324 case CompareConsts::GENERAL_GREATER:
325 case CompareConsts::GENERAL_GREATER_EQUAL:
326 theIsGeneralComparison = true;
327 break;
328 default:
329 theIsGeneralComparison = false;
330 break;
331 }
332 }
333
334
CompareIterator(::zorba::serialization::Archiver & ar)335 CompareIterator::CompareIterator(::zorba::serialization::Archiver& ar)
336 :
337 BinaryBaseIterator<CompareIterator, PlanIteratorState>(ar),
338 theTypeManager(NULL),
339 theTimezone(0),
340 theCollation(NULL)
341 {
342 }
343
344
serialize(::zorba::serialization::Archiver & ar)345 void CompareIterator::serialize(::zorba::serialization::Archiver& ar)
346 {
347 serialize_baseclass(ar,
348 (BinaryBaseIterator<CompareIterator, PlanIteratorState>*)this);
349
350 SERIALIZE_ENUM(CompareConsts::CompareType, theCompType)
351 ar & theIsGeneralComparison;
352 SERIALIZE_TYPEMANAGER(TypeManager, theTypeManager);
353 ar & theTimezone;
354 ar & theCollation;
355 }
356
357
358 BINARY_ACCEPT(CompareIterator);
359
360
361 /*******************************************************************************
362
363 ********************************************************************************/
openImpl(PlanState & planState,uint32_t & offset)364 void CompareIterator::openImpl(PlanState& planState, uint32_t& offset)
365 {
366 BinaryBaseIterator<CompareIterator, PlanIteratorState>::openImpl(planState, offset);
367
368 theTypeManager = theSctx->get_typemanager();
369 theCollation = theSctx->get_default_collator(loc);
370 theTimezone = planState.theLocalDynCtx->get_implicit_timezone();
371 }
372
373
374 /*******************************************************************************
375
376 ********************************************************************************/
nextImpl(store::Item_t & result,PlanState & planState) const377 bool CompareIterator::nextImpl(store::Item_t& result, PlanState& planState) const
378 {
379 store::Item_t item0, item1, tItem0, tItem1;
380 bool c0Done = false, c1Done = false, done = false, found = false;
381 std::vector<store::Item_t> seq0;
382 std::vector<store::Item_t> seq1;
383 store::TempSeq_t tSeq0, tSeq1;
384
385 PlanIteratorState* state;
386 DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
387
388 if (theIsGeneralComparison)
389 {
390 if (consumeNext(item0, theChild0.getp(), planState))
391 {
392 if (consumeNext(tItem0, theChild0.getp(), planState))
393 {
394 seq0.push_back(item0);
395 seq0.push_back(tItem0);
396 }
397 else
398 {
399 c0Done = true;
400 if (consumeNext(item1, theChild1.getp(), planState))
401 {
402 if (consumeNext(tItem1, theChild1.getp(), planState))
403 {
404 seq0.push_back(item0);
405 seq1.push_back(item1);
406 seq1.push_back(tItem1);
407 }
408 else
409 {
410 c1Done = true;
411 found = generalComparison(loc,
412 item0,
413 item1,
414 theCompType,
415 theTypeManager,
416 theTimezone,
417 theCollation);
418 done = true;
419 }
420 }
421 else
422 {
423 c1Done = true;
424 found = false;
425 done = true;
426 }
427 }
428 }
429 else
430 {
431 c0Done = true;
432 found = false;
433 done = true;
434 }
435
436 if (!done)
437 {
438 store::Iterator_t ite0;
439 store::Iterator_t ite1;
440 tSeq0 = GENV_STORE.createTempSeq(seq0);
441 tSeq1 = GENV_STORE.createTempSeq(seq1);
442
443 if (!c0Done)
444 {
445 ite0 = new PlanIteratorWrapper(theChild0, planState);
446 tSeq0->append(ite0);
447 }
448
449 if (!c1Done)
450 {
451 ite1 = new PlanIteratorWrapper(theChild1, planState);
452 tSeq1->append(ite1);
453 }
454
455 ite0 = tSeq0->getIterator();
456 ite1 = tSeq1->getIterator();
457 ite0->open();
458 ite1->open();
459
460 while (!found && ite0->next(item0))
461 {
462 while (!found && ite1->next(item1))
463 {
464 store::Item_t tmp = item0;
465
466 if (generalComparison(loc,
467 tmp,
468 item1,
469 theCompType,
470 theTypeManager,
471 theTimezone,
472 theCollation))
473 {
474 found = true;
475 break;
476 }
477 }
478
479 ite1->reset();
480 }
481 }
482
483 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, found), state);
484 }
485 else
486 {
487 // value comparison
488 if (consumeNext(item0, theChild0.getp(), planState) &&
489 consumeNext(item1, theChild1.getp(), planState))
490 {
491 if (item0->getTypeCode() != store::JS_NULL &&
492 item1->getTypeCode() != store::JS_NULL)
493 {
494 STACK_PUSH(GENV_ITEMFACTORY->
495 createBoolean(result,
496 CompareIterator::valueComparison(loc,
497 item0,
498 item1,
499 theCompType,
500 theTypeManager,
501 theTimezone,
502 theCollation)),
503 state);
504
505 assert(!consumeNext(item0, theChild0.getp(), planState) &&
506 !consumeNext(item1, theChild1.getp(), planState));
507 }
508 }
509 }
510
511 STACK_END (state);
512 }
513
514
515 /*******************************************************************************
516
517 ********************************************************************************/
valueComparison(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,CompareConsts::CompareType aCompType,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)518 bool CompareIterator::valueComparison(
519 const QueryLoc& loc,
520 store::Item_t& aItem0,
521 store::Item_t& aItem1,
522 CompareConsts::CompareType aCompType,
523 const TypeManager* typemgr,
524 long timezone,
525 XQPCollator* aCollation)
526 {
527 try
528 {
529 switch(aCompType)
530 {
531 case CompareConsts::VALUE_EQUAL:
532 {
533 return valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
534 }
535 case CompareConsts::VALUE_NOT_EQUAL:
536 {
537 return ! valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
538 }
539 case CompareConsts::VALUE_GREATER:
540 {
541 return valueCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) > 0;
542 }
543 case CompareConsts::VALUE_GREATER_EQUAL:
544 {
545 return valueCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) >= 0;
546 }
547 case CompareConsts::VALUE_LESS:
548 {
549 return valueCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) < 0;
550 }
551 case CompareConsts::VALUE_LESS_EQUAL:
552 {
553 return valueCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) <= 0;
554 }
555 default:
556 {
557 ZORBA_ASSERT(false);
558 }
559 }
560 }
561 catch (const ZorbaException& e)
562 {
563 if (e.diagnostic() == zerr::ZSTR0041_NAN_COMPARISON)
564 return false;
565
566 throw;
567 }
568 }
569
570
571 /*******************************************************************************
572 Compares two items for equality according to the rules of value comparison
573
574 @param item0
575 @param item1
576 @param tm The type manager to use to extract the type of the 2 items and
577 perform any necessary type checks and castings/promotions
578 @param timezone Optional timezone parameter used when comparing datetimes
579 @param aCollation optional collation parameter (passed as pointer to make
580 it possible to be set to 0)
581 @return True if the two item are equal; false otherwise.
582 @throw appropriate exception if any necesary casting/promotion fails.
583 @throw XPTY0004 if the two items are not equality comparable according to
584 the table in http://www.w3.org/TR/xquery/#mapping.
585 ********************************************************************************/
valueEqual(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)586 bool CompareIterator::valueEqual(
587 const QueryLoc& loc,
588 store::Item_t& aItem0,
589 store::Item_t& aItem1,
590 const TypeManager* typemgr,
591 long timezone,
592 XQPCollator* aCollation)
593 {
594 store::Item_t castItem0, castItem1;
595 valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
596 return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation);
597 }
598
599
600 /*******************************************************************************
601
602 ********************************************************************************/
valueCompare(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)603 long CompareIterator::valueCompare(
604 const QueryLoc& loc,
605 store::Item_t& aItem0,
606 store::Item_t& aItem1,
607 const TypeManager* typemgr,
608 long timezone,
609 XQPCollator* aCollation)
610 {
611 store::Item_t castItem0, castItem1;
612 valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
613 return compare(loc, castItem0, castItem1, typemgr, timezone, aCollation);
614 }
615
616
617 /*******************************************************************************
618
619 ********************************************************************************/
valueCasting(const QueryLoc & loc,const TypeManager * tm,store::Item_t & item0,store::Item_t & item1,store::Item_t & castItem0,store::Item_t & castItem1)620 void CompareIterator::valueCasting(
621 const QueryLoc& loc,
622 const TypeManager* tm,
623 store::Item_t& item0,
624 store::Item_t& item1,
625 store::Item_t& castItem0,
626 store::Item_t& castItem1)
627 {
628 store::SchemaTypeCode type0 = item0->getTypeCode();
629 store::SchemaTypeCode type1 = item1->getTypeCode();
630
631 // all untyped Atomics to String
632 if (TypeOps::is_subtype(type0, store::XS_UNTYPED_ATOMIC))
633 {
634 GenericCast::castToAtomic(castItem0, item0, store::XS_STRING, tm, NULL, loc);
635
636 if (TypeOps::is_subtype(type1, store::XS_UNTYPED_ATOMIC))
637 {
638 GenericCast::castToAtomic(castItem1, item1, store::XS_STRING, tm, NULL, loc);
639 }
640 else
641 {
642 if (!GenericCast::promote(castItem1, item1, store::XS_STRING, tm, loc))
643 castItem1.transfer(item1);
644 }
645 }
646 else if (TypeOps::is_subtype(type1, store::XS_UNTYPED_ATOMIC))
647 {
648 if (!GenericCast::promote(castItem0, item0, store::XS_STRING, tm, loc))
649 castItem0.transfer(item0);
650
651 GenericCast::castToAtomic(castItem1, item1, store::XS_STRING, tm, NULL, loc);
652 }
653 else
654 {
655 if (!GenericCast::promote(castItem0, item0, type1, tm, loc))
656 castItem0.transfer(item0);
657
658 if (!GenericCast::promote(castItem1, item1, type0, tm, loc))
659 castItem1.transfer(item1);
660 }
661 }
662
663
664 /*******************************************************************************
665 Compares two items for their relative order with respect to a general
666 comparison operator.
667
668 @param item0
669 @param item1
670 $param aCompType
671 @param tm The type manager to use to extract the type of the 2 items and
672 perform any necessary type checks and castings/promotions
673 @param timezone Optional timezone parameter used when comparing datetimes
674 @param aCollation optional collation parameter (passed as pointer to make
675 it possible to be set to 0)
676 @return True if the ordering between item0 and item1 satisfies the given
677 general comparison operator; false otherwise.
678 @throw appropriate exception if any necesary casting/promotion fails.
679 @throw XPTY0004 if the two items are not order comparable.
680 @throw ZSTR0041_NAN_COMPARISON if both the items are of type xs:double or
681 xs:float and at leat one of the items is NaN.
682 ********************************************************************************/
generalComparison(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,CompareConsts::CompareType aCompType,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)683 bool CompareIterator::generalComparison(
684 const QueryLoc& loc,
685 store::Item_t& aItem0,
686 store::Item_t& aItem1,
687 CompareConsts::CompareType aCompType,
688 const TypeManager* typemgr,
689 long timezone,
690 XQPCollator* aCollation)
691 {
692 if (aItem0->getTypeCode() == store::JS_NULL ||
693 aItem1->getTypeCode() == store::JS_NULL)
694 {
695 return false;
696 }
697 try
698 {
699 switch(aCompType)
700 {
701 case CompareConsts::GENERAL_EQUAL:
702 {
703 return generalEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
704 }
705 case CompareConsts::GENERAL_NOT_EQUAL:
706 {
707 return !generalEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
708 }
709 case CompareConsts::GENERAL_GREATER:
710 {
711 return generalCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) > 0;
712 }
713 case CompareConsts::GENERAL_GREATER_EQUAL:
714 {
715 return generalCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) >= 0;
716 }
717 case CompareConsts::GENERAL_LESS:
718 {
719 return generalCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) < 0;
720 }
721 case CompareConsts::GENERAL_LESS_EQUAL:
722 {
723 return generalCompare(loc, aItem0, aItem1, typemgr, timezone, aCollation) <= 0;
724 }
725 default:
726 {
727 ZORBA_ASSERT(false);
728 }
729 }
730 }
731 catch (const ZorbaException& e)
732 {
733 if (e.diagnostic() == zerr::ZSTR0041_NAN_COMPARISON)
734 return false;
735 throw;
736 }
737 }
738
739
740 /*******************************************************************************
741 Compares two items for equality according to the rules of general comparison
742
743 @param item0
744 @param item1
745 @param tm The type manager to use to extract the type of the 2 items and
746 perform any necessary type checks and castings/promotions
747 @param timezone Optional timezone parameter used when comparing datetimes
748 @param aCollation optional collation parameter (passed as pointer to make
749 it possible to be set to 0)
750 @return True if the two item are equal; false otherwise.
751 @throw appropriate exception if any necesary casting/promotion fails.
752 @throw XPTY0004 if the two items are not equality comparable.
753 ********************************************************************************/
generalEqual(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)754 bool CompareIterator::generalEqual(
755 const QueryLoc& loc,
756 store::Item_t& aItem0,
757 store::Item_t& aItem1,
758 const TypeManager* typemgr,
759 long timezone,
760 XQPCollator* aCollation)
761 {
762 store::Item_t castItem0, castItem1;
763 generalCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
764 return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation);
765 }
766
767
768 /*******************************************************************************
769 Compares two items for ordering according to the rules of general comparison
770
771 @param item0
772 @param item1
773 @param tm The type manager to use to extract the type of the 2 items and
774 perform any necessary type checks and castings/promotions
775 @param timezone Optional timezone parameter used when comparing datetimes
776 @param aCollation optional collation parameter (passed as pointer to make
777 it possible to be set to 0)
778 @return < 0 if item0 is less than item1, 0 if the two items are equal, or
779 > 0 if item0 is greater than item1.
780 @throw appropriate exception if any necesary casting/promotion fails.
781 @throw XPTY0004 if the two items are not order comparable.
782 @throw ZSTR0041_NAN_COMPARISON if both the items are of type xs:double or
783 xs:float and at leat one of the items is NaN.
784 ********************************************************************************/
generalCompare(const QueryLoc & loc,store::Item_t & aItem0,store::Item_t & aItem1,const TypeManager * typemgr,long timezone,XQPCollator * aCollation)785 long CompareIterator::generalCompare(
786 const QueryLoc& loc,
787 store::Item_t& aItem0,
788 store::Item_t& aItem1,
789 const TypeManager* typemgr,
790 long timezone,
791 XQPCollator* aCollation)
792 {
793 store::Item_t castItem0, castItem1;
794 generalCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
795 return compare(loc, castItem0, castItem1, typemgr, timezone, aCollation);
796 }
797
798
799 /*******************************************************************************
800
801 ********************************************************************************/
generalCasting(const QueryLoc & loc,const TypeManager * tm,store::Item_t & item0,store::Item_t & item1,store::Item_t & castItem0,store::Item_t & castItem1)802 void CompareIterator::generalCasting(
803 const QueryLoc& loc,
804 const TypeManager* tm,
805 store::Item_t& item0,
806 store::Item_t& item1,
807 store::Item_t& castItem0,
808 store::Item_t& castItem1)
809 {
810 store::SchemaTypeCode type0 = item0->getTypeCode();
811 store::SchemaTypeCode type1 = item1->getTypeCode();
812
813 if (TypeOps::is_subtype(type0, store::XS_UNTYPED_ATOMIC))
814 {
815 if (TypeOps::is_numeric(type1))
816 {
817 GenericCast::castToAtomic(castItem0, item0, store::XS_DOUBLE, tm, NULL, loc);
818
819 GenericCast::promote(castItem1, item1, store::XS_DOUBLE, tm, loc);
820 }
821 else if (TypeOps::is_subtype(type1, store::XS_UNTYPED_ATOMIC))
822 {
823 GenericCast::castToAtomic(castItem0, item0, store::XS_STRING, tm, NULL, loc);
824 GenericCast::castToAtomic(castItem1, item1, store::XS_STRING, tm, NULL, loc);
825 }
826 else if (TypeOps::is_subtype(type1, store::XS_STRING))
827 {
828 GenericCast::castToAtomic(castItem0, item0, store::XS_STRING, tm, NULL, loc);
829 castItem1.transfer(item1);
830 }
831 else
832 {
833 GenericCast::castToAtomic(castItem0, item0, type1, tm, NULL, loc);
834 castItem1.transfer(item1);
835 }
836 }
837 else if (TypeOps::is_subtype(type1, store::XS_UNTYPED_ATOMIC))
838 {
839 if (TypeOps::is_numeric(type0))
840 {
841 GenericCast::castToAtomic(castItem1, item1, store::XS_DOUBLE, tm, NULL, loc);
842 GenericCast::promote(castItem0, item0, store::XS_DOUBLE, tm, loc);
843 }
844 else if (TypeOps::is_subtype(type0, store::XS_STRING))
845 {
846 GenericCast::castToAtomic(castItem1, item1, store::XS_STRING, tm, NULL, loc);
847 castItem0.transfer(item0);
848 }
849 else
850 {
851 GenericCast::castToAtomic(castItem1, item1, type0, tm, NULL, loc);
852 castItem0.transfer(item0);
853 }
854 }
855 else
856 {
857 if (!GenericCast::promote(castItem0, item0, type1, tm, loc))
858 castItem0.transfer(item0);
859
860 if (!GenericCast::promote(castItem1, item1, type0, tm, loc))
861 castItem1.transfer(item1);
862 }
863 }
864
865
866 /*******************************************************************************
867 Checks if the two passed items contain the same value (without performing any
868 castings or promotions on the two items).
869
870 @param item0
871 @param item1
872 @param tm The type manager to use to extract the type of the 2 items
873 @param timezone Optional timezone parameter used when comparing datetimes
874 @param aCollation optional collation parameter (passed as pointer to make
875 it possible to be set to 0)
876 @return True if the two item are equal; false otherwise.
877 @throw XPTY0004 if the two items are not equality comparable according to
878 the table in http://www.w3.org/TR/xquery/#mapping.
879 ********************************************************************************/
equal(const QueryLoc & loc,const store::Item_t & item0,const store::Item_t & item1,const TypeManager * tm,long timezone,XQPCollator * collation)880 bool CompareIterator::equal(
881 const QueryLoc& loc,
882 const store::Item_t& item0,
883 const store::Item_t& item1,
884 const TypeManager* tm,
885 long timezone,
886 XQPCollator* collation)
887 {
888 store::SchemaTypeCode type0 = item0->getTypeCode();
889 store::SchemaTypeCode type1 = item1->getTypeCode();
890
891 if (TypeOps::is_subtype(type0, type1))
892 {
893 return item1->equals(item0, timezone, collation);
894 }
895 else if (TypeOps::is_subtype(type1, type0))
896 {
897 return item0->equals(item1, timezone, collation);
898 }
899 else
900 {
901 // There are 2 cases when two types are comparable without one being a
902 // subtype of the other: (a) they belong to different branches under of
903 // the type-inheritance subtree rooted at xs:integer, (b) they belong to
904 // different branches under of the type-inheritance subtree rooted at
905 // xs::duration (i.e. one is xs:yearMonthDuration and the other is
906 // xs:dayTimeDuration).
907 // The same case happens when there are two types derived from xs:NOTATION.
908 if (TypeOps::is_subtype(type0, store::XS_INTEGER) &&
909 TypeOps::is_subtype(type1, store::XS_INTEGER))
910 {
911 return (item0->getIntegerValue() == item1->getIntegerValue());
912 }
913 else if (TypeOps::is_subtype(type0, store::XS_DURATION) &&
914 TypeOps::is_subtype(type1, store::XS_DURATION))
915 {
916 return (item0->getDurationValue() == item1->getDurationValue());
917 }
918 else if (TypeOps::is_subtype(type0, store::XS_NOTATION) &&
919 TypeOps::is_subtype(type1, store::XS_NOTATION))
920 {
921 return item0->equals(item1);
922 }
923 else
924 {
925 xqtref_t type0 = tm->create_value_type(item0.getp());
926 xqtref_t type1 = tm->create_value_type(item1.getp());
927
928 RAISE_ERROR(err::XPTY0004, loc,
929 ERROR_PARAMS(ZED(BadType_23o), *type0, ZED(NoCompareWithType_4), *type1));
930 }
931 }
932 }
933
934
935 /*******************************************************************************
936 Performs an order-comparison between two given items (without performing any
937 castings or promotions on the two items).
938
939 @param item0
940 @param item1
941 @param tm The type manager to use to extract the type of the 2 items
942 @param timezone Optional timezone parameter used when comparing datetimes
943 @param aCollation optional collation parameter (passed as pointer to make
944 it possible to be set to 0)
945 @return < 0 if item0 is less than item1, 0 if the two items are equal, or
946 > 0 if item0 is greater than item1.
947 @throw XPTY0004 if the two items are not order comparable according to
948 the table in http://www.w3.org/TR/xquery/#mapping.
949 @throw ZSTR0041_NAN_COMPARISON if both the items are of type xs:double or
950 xs:float and at leat one of the items is NaN.
951 ********************************************************************************/
compare(const QueryLoc & loc,const store::Item_t & item0,const store::Item_t & item1,const TypeManager * tm,long timezone,XQPCollator * collation)952 long CompareIterator::compare(
953 const QueryLoc& loc,
954 const store::Item_t& item0,
955 const store::Item_t& item1,
956 const TypeManager* tm,
957 long timezone,
958 XQPCollator* collation)
959 {
960 store::SchemaTypeCode type0 = item0->getTypeCode();
961 store::SchemaTypeCode type1 = item1->getTypeCode();
962
963 try
964 {
965 if (TypeOps::is_subtype(type0, store::XS_DURATION) &&
966 TypeOps::is_subtype(type1, store::XS_DURATION))
967 {
968 if (type0 == type1 && type0 != store::XS_DURATION)
969 {
970 return item0->compare(item1, timezone, collation);
971 }
972 else
973 {
974 xqtref_t type0 = tm->create_value_type(item0.getp());
975 xqtref_t type1 = tm->create_value_type(item1.getp());
976
977 RAISE_ERROR(err::XPTY0004, loc,
978 ERROR_PARAMS(ZED(BadType_23o), *type0, ZED(NoCompareWithType_4), *type1));
979 }
980 }
981 else if (TypeOps::is_subtype(type1, type0))
982 {
983 return item0->compare(item1, timezone, collation);
984 }
985 else if (TypeOps::is_subtype(type0, type1))
986 {
987 return -item1->compare(item0, timezone, collation);
988 }
989 else
990 {
991 // There is 1 case when two types are order-comparable without one being a
992 // subtype of the other: they belong to different branches under of the
993 // type-inheritance subtree rooted at xs:integer.
994 if (TypeOps::is_subtype(type0, store::XS_INTEGER) &&
995 TypeOps::is_subtype(type1, store::XS_INTEGER))
996 {
997 return item0->getIntegerValue().compare(item1->getIntegerValue());
998 }
999 else
1000 {
1001 xqtref_t type0 = tm->create_value_type(item0.getp());
1002 xqtref_t type1 = tm->create_value_type(item1.getp());
1003
1004 RAISE_ERROR(err::XPTY0004, loc,
1005 ERROR_PARAMS(ZED(BadType_23o), *type0, ZED(NoCompareWithType_4), *type1));
1006 }
1007 }
1008 }
1009 catch(const ZorbaException& e)
1010 {
1011 // For example, two QName items do not have an order relationship.
1012 if (e.diagnostic() == zerr::ZSTR0040_TYPE_ERROR)
1013 {
1014 xqtref_t type0 = tm->create_value_type(item0.getp());
1015 xqtref_t type1 = tm->create_value_type(item1.getp());
1016
1017 RAISE_ERROR(err::XPTY0004, loc,
1018 ERROR_PARAMS(ZED(BadType_23o), *type0, ZED(NoCompareWithType_4), *type1));
1019 }
1020
1021 throw;
1022 }
1023 }
1024
1025
1026 /////////////////////////////////////////////////////////////////////////////////
1027 // //
1028 // TypedValueCompareIterator //
1029 // //
1030 /////////////////////////////////////////////////////////////////////////////////
1031
1032 template <store::SchemaTypeCode ATC>
serialize(::zorba::serialization::Archiver & ar)1033 void TypedValueCompareIterator<ATC>::serialize(::zorba::serialization::Archiver& ar)
1034 {
1035 serialize_baseclass(ar,
1036 (NaryBaseIterator<TypedValueCompareIterator<ATC>, PlanIteratorState>*)this);
1037
1038 SERIALIZE_ENUM(CompareConsts::CompareType, theCompType);
1039 ar & theTimezone;
1040 ar & theCollation;
1041 }
1042
1043
1044 template <store::SchemaTypeCode ATC>
accept(PlanIterVisitor & v) const1045 void TypedValueCompareIterator<ATC>::accept(PlanIterVisitor& v) const
1046 {
1047 v.beginVisit(*this);
1048
1049 std::vector<PlanIter_t>::const_iterator iter = this->theChildren.begin();
1050 std::vector<PlanIter_t>::const_iterator lEnd = this->theChildren.end();
1051 for ( ; iter != lEnd; ++iter )
1052 {
1053 (*iter)->accept(v);
1054 }
1055
1056 v.endVisit(*this);
1057 }
1058
1059
1060 template<store::SchemaTypeCode ATC>
openImpl(PlanState & planState,uint32_t & offset)1061 void TypedValueCompareIterator<ATC>::openImpl(PlanState& planState, uint32_t& offset)
1062 {
1063 NaryBaseIterator<TypedValueCompareIterator, PlanIteratorState>
1064 ::openImpl(planState, offset);
1065
1066 theTimezone = planState.theLocalDynCtx->get_implicit_timezone();
1067 theCollation = this->theSctx->get_default_collator(this->loc);
1068 }
1069
1070
1071 template<store::SchemaTypeCode ATC>
nextImpl(store::Item_t & result,PlanState & planState) const1072 bool TypedValueCompareIterator<ATC>::nextImpl(
1073 store::Item_t& result,
1074 PlanState& planState) const
1075 {
1076 store::Item_t lItem0, lItem1;
1077 bool bRes;
1078 bool neq = false;
1079 long cmp;
1080
1081 PlanIteratorState* state;
1082 DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
1083
1084 if (CONSUME(lItem0, 0) && CONSUME(lItem1, 1))
1085 {
1086 switch (theCompType)
1087 {
1088 case CompareConsts::VALUE_NOT_EQUAL:
1089 neq = true;
1090
1091 case CompareConsts::VALUE_EQUAL:
1092 {
1093 bRes = lItem0->equals(lItem1, theTimezone, theCollation);
1094 if (neq)
1095 bRes = ! bRes;
1096
1097 break;
1098 }
1099
1100 default:
1101 {
1102 try
1103 {
1104 cmp = lItem0->compare(lItem1, theTimezone, theCollation);
1105
1106 switch (theCompType)
1107 {
1108 case CompareConsts::VALUE_LESS:
1109 bRes = (cmp < 0);
1110 break;
1111 case CompareConsts::VALUE_GREATER:
1112 bRes = (cmp > 0);
1113 break;
1114 case CompareConsts::VALUE_LESS_EQUAL:
1115 bRes = (cmp <= 0);
1116 break;
1117 case CompareConsts::VALUE_GREATER_EQUAL:
1118 bRes = (cmp >= 0);
1119 break;
1120 default:
1121 ZORBA_ASSERT(false);
1122 } // switch (theCompType)
1123 }
1124 catch (const ZorbaException& e)
1125 {
1126 if (e.diagnostic() == zerr::ZSTR0041_NAN_COMPARISON)
1127 bRes = false;
1128 else
1129 throw;
1130 }
1131 } // default
1132 } // switch (theCompType)
1133
1134 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, bRes), state);
1135
1136 assert(!CONSUME(lItem0, 0) && !CONSUME(lItem1, 1));
1137 }
1138
1139 STACK_END(state);
1140 }
1141
1142
1143 template class TypedValueCompareIterator<store::XS_DOUBLE>;
1144 template class TypedValueCompareIterator<store::XS_FLOAT>;
1145 template class TypedValueCompareIterator<store::XS_DECIMAL>;
1146 template class TypedValueCompareIterator<store::XS_INTEGER>;
1147 template class TypedValueCompareIterator<store::XS_STRING>;
1148
1149
1150
1151 /////////////////////////////////////////////////////////////////////////////////
1152 // //
1153 // AtomicValuesEquivalenceIterator //
1154 // //
1155 // http://www.w3.org/TR/xquery-11/#dt-equivalence-two-atomic-values //
1156 // //
1157 /////////////////////////////////////////////////////////////////////////////////
1158
AtomicValuesEquivalenceIterator(static_context * sctx,const QueryLoc & loc,PlanIter_t aChild0,PlanIter_t aChild1)1159 AtomicValuesEquivalenceIterator::AtomicValuesEquivalenceIterator(
1160 static_context* sctx,
1161 const QueryLoc& loc,
1162 PlanIter_t aChild0,
1163 PlanIter_t aChild1)
1164 :
1165 BinaryBaseIterator<AtomicValuesEquivalenceIterator, PlanIteratorState>(sctx, loc, aChild0, aChild1),
1166 theTypeManager(NULL),
1167 theTimezone(0),
1168 theCollation(NULL)
1169 {
1170 }
1171
1172
AtomicValuesEquivalenceIterator(::zorba::serialization::Archiver & ar)1173 AtomicValuesEquivalenceIterator::AtomicValuesEquivalenceIterator(
1174 ::zorba::serialization::Archiver& ar)
1175 :
1176 BinaryBaseIterator<AtomicValuesEquivalenceIterator, PlanIteratorState>(ar),
1177 theTypeManager(NULL),
1178 theTimezone(0),
1179 theCollation(NULL)
1180 {
1181 }
1182
1183
serialize(::zorba::serialization::Archiver & ar)1184 void AtomicValuesEquivalenceIterator::serialize(::zorba::serialization::Archiver& ar)
1185 {
1186 serialize_baseclass(ar,
1187 (BinaryBaseIterator<AtomicValuesEquivalenceIterator, PlanIteratorState>*)this);
1188
1189 SERIALIZE_TYPEMANAGER(TypeManager, theTypeManager);
1190 ar & theTimezone;
1191 ar & theCollation;
1192 }
1193
1194
1195 BINARY_ACCEPT(AtomicValuesEquivalenceIterator);
1196
1197
openImpl(PlanState & planState,uint32_t & offset)1198 void AtomicValuesEquivalenceIterator::openImpl(PlanState& planState, uint32_t& offset)
1199 {
1200 BinaryBaseIterator<AtomicValuesEquivalenceIterator, PlanIteratorState>::
1201 openImpl(planState, offset);
1202
1203 theTypeManager = theSctx->get_typemanager();
1204 theCollation = theSctx->get_default_collator(loc);
1205 theTimezone = planState.theLocalDynCtx->get_implicit_timezone();
1206 }
1207
1208
nextImpl(store::Item_t & result,PlanState & planState) const1209 bool AtomicValuesEquivalenceIterator::nextImpl(
1210 store::Item_t& result,
1211 PlanState& planState) const
1212 {
1213 store::Item_t lItem0, lItem1, tItem0, tItem1;
1214 int count0, count1;
1215 xqtref_t type0, type1;
1216 bool are_equivalent;
1217
1218 RootTypeManager& rtm = GENV_TYPESYSTEM;
1219 TypeManager* tm = theSctx->get_typemanager();
1220
1221 PlanIteratorState* state;
1222 DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
1223
1224 count0 = 0;
1225 count1 = 0;
1226
1227 if (consumeNext(lItem0, theChild0.getp(), planState))
1228 count0 = 1;
1229
1230 if (count0 && consumeNext(tItem0, theChild0.getp(), planState))
1231 throw XQUERY_EXCEPTION(
1232 err::XPTY0004,
1233 ERROR_PARAMS( ZED( NoSeqTestedForAtomicEquiv ) ),
1234 ERROR_LOC( loc )
1235 );
1236
1237 if (consumeNext(lItem1, theChild1.getp(), planState))
1238 count1 = 1;
1239
1240 if (count1 && consumeNext(tItem1, theChild1.getp(), planState))
1241 throw XQUERY_EXCEPTION(
1242 err::XPTY0004,
1243 ERROR_PARAMS( ZED( NoSeqTestedForAtomicEquiv ) ),
1244 ERROR_LOC( loc )
1245 );
1246
1247 if (count0 == 0 && count1 == 0)
1248 {
1249 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, true), state);
1250 }
1251 else if ((count0 == 0 && count1 == 1) || (count0 == 1 && count1 == 0))
1252 {
1253 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, false), state);
1254 }
1255 else
1256 {
1257 type0 = theTypeManager->create_value_type(lItem0.getp());
1258 type1 = theTypeManager->create_value_type(lItem1.getp());
1259
1260 if ((TypeOps::is_subtype(tm, *type0, *rtm.FLOAT_TYPE_ONE) ||
1261 TypeOps::is_subtype(tm, *type0, *rtm.DOUBLE_TYPE_ONE))
1262 &&
1263 (TypeOps::is_subtype(tm, *type1, *rtm.FLOAT_TYPE_ONE) ||
1264 TypeOps::is_subtype(tm, *type1, *rtm.DOUBLE_TYPE_ONE))
1265 &&
1266 lItem0->isNaN() && lItem1->isNaN())
1267 {
1268 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, true), state);
1269 }
1270 else
1271 {
1272 try
1273 {
1274 are_equivalent = CompareIterator::valueEqual(loc,
1275 lItem0,
1276 lItem1,
1277 theTypeManager,
1278 theTimezone,
1279 theCollation);
1280 }
1281 catch (ZorbaException const& e)
1282 {
1283 if (e.diagnostic() == err::XPTY0004)
1284 are_equivalent = false;
1285 else
1286 throw;
1287 }
1288
1289 STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, are_equivalent),
1290 state);
1291 }
1292 }
1293
1294 STACK_END(state);
1295 }
1296
1297
1298 } // namespace zorba
1299 /* vim:set et sw=2 ts=2: */
1300