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