1 /* Copyright (C) 2014 InfiniDB, Inc.
2 Copyright (C) 2019 MariaDB Corporation
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; version 2 of
7 the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301, USA. */
18
19 /***********************************************************************
20 * $Id: predicateoperator.cpp 9306 2013-03-12 15:49:11Z rdempsey $
21 *
22 *
23 ***********************************************************************/
24
25 #include <iostream>
26
27 #include "bytestream.h"
28 #include "predicateoperator.h"
29 #include "objectreader.h"
30
31 #include "liboamcpp.h"
32
33 #include "collation.h"
34
35 using namespace oam;
36
37 using namespace std;
38
39 namespace execplan
40 {
41
42 /**
43 * Constructors/Destructors
44 */
PredicateOperator()45 PredicateOperator::PredicateOperator() :
46 cs(NULL)
47 {
48 }
49
PredicateOperator(const string & operatorName)50 PredicateOperator::PredicateOperator(const string& operatorName) :
51 cs(NULL)
52 {
53 data(operatorName);
54 }
55
PredicateOperator(const PredicateOperator & rhs)56 PredicateOperator::PredicateOperator(const PredicateOperator& rhs) : Operator(rhs)
57 {
58 data(rhs.data());
59 cs = rhs.getCharset();
60 }
61
~PredicateOperator()62 PredicateOperator:: ~PredicateOperator()
63 {
64 }
65
66 /**
67 * Operations
68 */
69
70 /**
71 * friend function
72 */
operator <<(ostream & output,const PredicateOperator & rhs)73 ostream& operator<<(ostream& output, const PredicateOperator& rhs)
74 {
75 output << rhs.toString() << endl;
76 output << "OpType=" << rhs.operationType().colDataType << endl;
77 return output;
78 }
79
80 /**
81 * The serialization interface
82 */
serialize(messageqcpp::ByteStream & b) const83 void PredicateOperator::serialize(messageqcpp::ByteStream& b) const
84 {
85 b << (ObjectReader::id_t) ObjectReader::PREDICATEOPERATOR;
86 //b << fData;
87 Operator::serialize(b);
88 }
89
unserialize(messageqcpp::ByteStream & b)90 void PredicateOperator::unserialize(messageqcpp::ByteStream& b)
91 {
92 ObjectReader::checkType(b, ObjectReader::PREDICATEOPERATOR);
93 //b >> fData;
94 Operator::unserialize(b);
95 cs = & datatypes::Charset(fOperationType.charsetNumber).getCharset();
96 }
97
operator ==(const PredicateOperator & t) const98 bool PredicateOperator::operator==(const PredicateOperator& t) const
99 {
100 if (data() == t.data())
101 return true;
102
103 return false;
104 }
105
operator ==(const TreeNode * t) const106 bool PredicateOperator::operator==(const TreeNode* t) const
107 {
108 const PredicateOperator* o;
109
110 o = dynamic_cast<const PredicateOperator*>(t);
111
112 if (o == NULL)
113 return false;
114
115 return *this == *o;
116 }
117
operator !=(const PredicateOperator & t) const118 bool PredicateOperator::operator!=(const PredicateOperator& t) const
119 {
120 return (!(*this == t));
121 }
122
operator !=(const TreeNode * t) const123 bool PredicateOperator::operator!=(const TreeNode* t) const
124 {
125 return (!(*this == t));
126 }
127
128 //FIXME: VARBINARY???
setOpType(Type & l,Type & r)129 void PredicateOperator::setOpType(Type& l, Type& r)
130 {
131 fOperationType = l; // Default to left side. Modify as needed.
132 if ( l.colDataType == execplan::CalpontSystemCatalog::DATETIME ||
133 l.colDataType == execplan::CalpontSystemCatalog::TIME ||
134 l.colDataType == execplan::CalpontSystemCatalog::TIMESTAMP ||
135 l.colDataType == execplan::CalpontSystemCatalog::DATE )
136 {
137 switch (r.colDataType)
138 {
139 case execplan::CalpontSystemCatalog::CHAR:
140 case execplan::CalpontSystemCatalog::VARCHAR:
141 fOperationType.charsetNumber = r.charsetNumber;
142 break;
143
144 case execplan::CalpontSystemCatalog::DATETIME:
145 fOperationType.colDataType = execplan::CalpontSystemCatalog::DATETIME;
146 fOperationType.colWidth = 8;
147 break;
148
149 case execplan::CalpontSystemCatalog::TIMESTAMP:
150 fOperationType.colDataType = execplan::CalpontSystemCatalog::TIMESTAMP;
151 fOperationType.colWidth = 8;
152 break;
153
154 case execplan::CalpontSystemCatalog::TIME:
155 fOperationType.colDataType = execplan::CalpontSystemCatalog::TIME;
156 fOperationType.colWidth = 8;
157 break;
158
159 case execplan::CalpontSystemCatalog::DATE:
160 fOperationType = l;
161 break;
162
163 default:
164 fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE;
165 fOperationType.colWidth = 8;
166 break;
167 }
168 }
169 else if ( r.colDataType == execplan::CalpontSystemCatalog::DATETIME ||
170 r.colDataType == execplan::CalpontSystemCatalog::TIME ||
171 r.colDataType == execplan::CalpontSystemCatalog::TIMESTAMP ||
172 r.colDataType == execplan::CalpontSystemCatalog::DATE )
173 {
174 switch (l.colDataType)
175 {
176 case execplan::CalpontSystemCatalog::CHAR:
177 case execplan::CalpontSystemCatalog::VARCHAR:
178 fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR;
179 fOperationType.colWidth = 255;
180 break;
181
182 case execplan::CalpontSystemCatalog::DATETIME:
183 fOperationType.colDataType = execplan::CalpontSystemCatalog::DATETIME;
184 fOperationType.colWidth = 8;
185 break;
186
187 case execplan::CalpontSystemCatalog::TIMESTAMP:
188 fOperationType.colDataType = execplan::CalpontSystemCatalog::TIMESTAMP;
189 fOperationType.colWidth = 8;
190 break;
191
192 case execplan::CalpontSystemCatalog::TIME:
193 fOperationType.colDataType = execplan::CalpontSystemCatalog::TIME;
194 fOperationType.colWidth = 8;
195 break;
196
197 case execplan::CalpontSystemCatalog::DATE:
198 fOperationType = r;
199 break;
200
201 default:
202 fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE;
203 fOperationType.colWidth = 8;
204 break;
205 }
206 }
207 else if (l.colDataType == execplan::CalpontSystemCatalog::DECIMAL ||
208 l.colDataType == execplan::CalpontSystemCatalog::UDECIMAL)
209 {
210 switch (r.colDataType)
211 {
212 case execplan::CalpontSystemCatalog::DECIMAL:
213 case execplan::CalpontSystemCatalog::UDECIMAL:
214 {
215 // should following the result type that MySQL gives
216 fOperationType = l;
217 fOperationType.scale = (l.scale > r.scale ? l.scale : r.scale);
218 break;
219 }
220
221 case execplan::CalpontSystemCatalog::INT:
222 case execplan::CalpontSystemCatalog::MEDINT:
223 case execplan::CalpontSystemCatalog::TINYINT:
224 case execplan::CalpontSystemCatalog::BIGINT:
225 case execplan::CalpontSystemCatalog::UINT:
226 case execplan::CalpontSystemCatalog::UMEDINT:
227 case execplan::CalpontSystemCatalog::UTINYINT:
228 case execplan::CalpontSystemCatalog::UBIGINT:
229 fOperationType.colDataType = execplan::CalpontSystemCatalog::DECIMAL;
230 fOperationType.scale = l.scale;
231 fOperationType.colWidth = 8;
232 break;
233
234 default:
235 fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE;
236 fOperationType.colWidth = 8;
237 }
238 }
239 else if (r.colDataType == execplan::CalpontSystemCatalog::DECIMAL ||
240 r.colDataType == execplan::CalpontSystemCatalog::UDECIMAL)
241 {
242 switch (l.colDataType)
243 {
244 case execplan::CalpontSystemCatalog::DECIMAL:
245 case execplan::CalpontSystemCatalog::UDECIMAL:
246 {
247 // should following the result type that MySQL gives based on the following logic?
248 // @NOTE is this trustable?
249 fOperationType = fResultType;
250 break;
251 }
252
253 case execplan::CalpontSystemCatalog::INT:
254 case execplan::CalpontSystemCatalog::MEDINT:
255 case execplan::CalpontSystemCatalog::TINYINT:
256 case execplan::CalpontSystemCatalog::BIGINT:
257 case execplan::CalpontSystemCatalog::UINT:
258 case execplan::CalpontSystemCatalog::UMEDINT:
259 case execplan::CalpontSystemCatalog::UTINYINT:
260 case execplan::CalpontSystemCatalog::UBIGINT:
261 fOperationType.colDataType = execplan::CalpontSystemCatalog::DECIMAL;
262 fOperationType.scale = r.scale;
263 fOperationType.colWidth = 8;
264 break;
265
266 case execplan::CalpontSystemCatalog::LONGDOUBLE:
267 fOperationType.colDataType = execplan::CalpontSystemCatalog::LONGDOUBLE;
268 fOperationType.colWidth = sizeof(long double);
269 break;
270 default:
271 fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE;
272 fOperationType.colWidth = 8;
273 }
274 }
275 // If both sides are unsigned, use UBIGINT as result type, otherwise
276 // "promote" to BIGINT.
277 else if (isUnsigned(l.colDataType) && isUnsigned(r.colDataType))
278 {
279 fOperationType.colDataType = execplan::CalpontSystemCatalog::UBIGINT;
280 fOperationType.colWidth = 8;
281 }
282 else if ((isSignedInteger(l.colDataType) && isUnsigned(r.colDataType)) ||
283 (isUnsigned(l.colDataType) && isSignedInteger(r.colDataType)) ||
284 (isSignedInteger(l.colDataType) && isSignedInteger(r.colDataType)))
285 {
286 fOperationType.colDataType = execplan::CalpontSystemCatalog::BIGINT;
287 fOperationType.colWidth = 8;
288 }
289 else if ((l.colDataType == execplan::CalpontSystemCatalog::CHAR ||
290 l.colDataType == execplan::CalpontSystemCatalog::VARCHAR ||
291 l.colDataType == execplan::CalpontSystemCatalog::TEXT) &&
292 (r.colDataType == execplan::CalpontSystemCatalog::CHAR ||
293 r.colDataType == execplan::CalpontSystemCatalog::VARCHAR ||
294 r.colDataType == execplan::CalpontSystemCatalog::TEXT))
295 {
296 #if 0
297 // Currently, STRINT isn't properly implemented everywhere
298 // For short strings, we can get a faster execution for charset that fit in one byte.
299 if ( ( (l.colDataType == execplan::CalpontSystemCatalog::CHAR && l.colWidth <= 8) ||
300 (l.colDataType == execplan::CalpontSystemCatalog::VARCHAR && l.colWidth < 8) ) &&
301 ( (r.colDataType == execplan::CalpontSystemCatalog::CHAR && r.colWidth <= 8) ||
302 (r.colDataType == execplan::CalpontSystemCatalog::VARCHAR && r.colWidth < 8) ) )
303 {
304 switch (fOperationType.charsetNumber)
305 {
306 case 8: // latin1_swedish_ci
307 case 9: // latin2_general_ci
308 case 11: // ascii_general_ci
309 case 47: // latin1_bin
310 case 48: // latin1_general_ci
311 case 49: // latin1_general_cs
312 case 65: // ascii_bin
313 case 77: // latin2_bin
314 // char[] as network order int for fast comparison.
315 fOperationType.colDataType = execplan::CalpontSystemCatalog::BIGINT;
316 fOperationType.scale = 0;
317 fOperationType.colWidth = 8;
318 l.colDataType = execplan::CalpontSystemCatalog::STRINT;
319 r.colDataType = execplan::CalpontSystemCatalog::STRINT;
320 default:
321 fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR;
322 fOperationType.colWidth = 255;
323 }
324 }
325 else
326 #endif
327 {
328 fOperationType.colDataType = execplan::CalpontSystemCatalog::VARCHAR;
329 fOperationType.colWidth = 255;
330 }
331 }
332 else if (l.colDataType == execplan::CalpontSystemCatalog::LONGDOUBLE ||
333 r.colDataType == execplan::CalpontSystemCatalog::LONGDOUBLE)
334 {
335 fOperationType.colDataType = execplan::CalpontSystemCatalog::LONGDOUBLE;
336 fOperationType.colWidth = sizeof(long double);
337 }
338 else
339 {
340 fOperationType.colDataType = execplan::CalpontSystemCatalog::DOUBLE;
341 fOperationType.colWidth = 8;
342 }
343
344 cs = & datatypes::Charset(fOperationType.charsetNumber).getCharset();
345 }
346
strTrimCompare(const std::string & op1,const std::string & op2)347 inline bool PredicateOperator::strTrimCompare(const std::string& op1, const std::string& op2)
348 {
349 int r1 = cs->strnncollsp(op1.c_str(), op1.length(), op2.c_str(), op2.length());
350 switch (fOp)
351 {
352 case OP_EQ:
353 return r1 == 0;
354
355 case OP_NE:
356 return r1 != 0;
357
358 case OP_GT:
359 return r1 > 0;
360
361 case OP_GE:
362 return r1 >= 0;
363
364 case OP_LT:
365 return r1 < 0;
366
367 case OP_LE:
368 return r1 <= 0;
369
370 default:
371 {
372 std::ostringstream oss;
373 oss << "Unsupported predicate operation: " << fOp;
374 throw logging::InvalidOperationExcept(oss.str());
375 }
376 }
377 }
378
getBoolVal(rowgroup::Row & row,bool & isNull,ReturnedColumn * lop,ReturnedColumn * rop)379 bool PredicateOperator::getBoolVal(rowgroup::Row& row, bool& isNull, ReturnedColumn* lop, ReturnedColumn* rop)
380 {
381 // like operator. both sides are string.
382 if (fOp == OP_LIKE || fOp == OP_NOTLIKE)
383 {
384 const std::string & subject = lop->getStrVal(row, isNull);
385 if (isNull)
386 return false;
387 const std::string & pattern = rop->getStrVal(row, isNull);
388 if (isNull)
389 return false;
390 return datatypes::Charset(cs).like(fOp == OP_NOTLIKE,
391 utils::ConstString(subject),
392 utils::ConstString(pattern));
393 }
394
395 // fOpType should have already been set on the connector during parsing
396 switch (fOperationType.colDataType)
397 {
398 case execplan::CalpontSystemCatalog::BIGINT:
399 case execplan::CalpontSystemCatalog::INT:
400 case execplan::CalpontSystemCatalog::MEDINT:
401 case execplan::CalpontSystemCatalog::TINYINT:
402 case execplan::CalpontSystemCatalog::SMALLINT:
403 {
404 if (fOp == OP_ISNULL)
405 {
406 lop->getIntVal(row, isNull);
407 bool ret = isNull;
408 isNull = false;
409 return ret;
410 }
411
412 if (fOp == OP_ISNOTNULL)
413 {
414 lop->getIntVal(row, isNull);
415 bool ret = isNull;
416 isNull = false;
417 return !ret;
418 }
419
420 if (isNull)
421 return false;
422
423 int64_t val1 = lop->getIntVal(row, isNull);
424
425 if (isNull)
426 return false;
427
428 return numericCompare(val1, rop->getIntVal(row, isNull)) && !isNull;
429 }
430
431 case execplan::CalpontSystemCatalog::UBIGINT:
432 case execplan::CalpontSystemCatalog::UINT:
433 case execplan::CalpontSystemCatalog::UMEDINT:
434 case execplan::CalpontSystemCatalog::UTINYINT:
435 case execplan::CalpontSystemCatalog::USMALLINT:
436 {
437 if (fOp == OP_ISNULL)
438 {
439 lop->getUintVal(row, isNull);
440 bool ret = isNull;
441 isNull = false;
442 return ret;
443 }
444
445 if (fOp == OP_ISNOTNULL)
446 {
447 lop->getUintVal(row, isNull);
448 bool ret = isNull;
449 isNull = false;
450 return !ret;
451 }
452
453 if (isNull)
454 return false;
455
456 uint64_t val1 = lop->getUintVal(row, isNull);
457
458 if (isNull)
459 return false;
460
461 return numericCompare(val1, rop->getUintVal(row, isNull)) && !isNull;
462 }
463
464 case execplan::CalpontSystemCatalog::FLOAT:
465 case execplan::CalpontSystemCatalog::UFLOAT:
466 case execplan::CalpontSystemCatalog::DOUBLE:
467 case execplan::CalpontSystemCatalog::UDOUBLE:
468 {
469 if (fOp == OP_ISNULL)
470 {
471 lop->getDoubleVal(row, isNull);
472 bool ret = isNull;
473 isNull = false;
474 return ret;
475 }
476
477 if (fOp == OP_ISNOTNULL)
478 {
479 lop->getDoubleVal(row, isNull);
480 bool ret = isNull;
481 isNull = false;
482 return !ret;
483 }
484
485 if (isNull)
486 return false;
487
488 double val1 = lop->getDoubleVal(row, isNull);
489
490 if (isNull)
491 return false;
492
493 return numericCompare(val1, rop->getDoubleVal(row, isNull)) && !isNull;
494 }
495
496 case execplan::CalpontSystemCatalog::LONGDOUBLE:
497 {
498 if (fOp == OP_ISNULL)
499 {
500 lop->getLongDoubleVal(row, isNull);
501 bool ret = isNull;
502 isNull = false;
503 return ret;
504 }
505
506 if (fOp == OP_ISNOTNULL)
507 {
508 lop->getLongDoubleVal(row, isNull);
509 bool ret = isNull;
510 isNull = false;
511 return !ret;
512 }
513
514 if (isNull)
515 return false;
516
517 long double val1 = lop->getLongDoubleVal(row, isNull);
518 if (isNull)
519 return false;
520
521 long double val2 = rop->getLongDoubleVal(row, isNull);
522 if (isNull)
523 return false;
524
525 // In many case, rounding error will prevent an eq compare to work
526 // In these cases, use the largest scale of the two items.
527 if (fOp == execplan::OP_EQ)
528 {
529 // In case a val is a representation of a very large integer,
530 // we won't want to just multiply by scale, as it may move
531 // significant digits out of scope. So we break them apart
532 // and compare each separately
533 int64_t scale = std::max(lop->resultType().scale, rop->resultType().scale);
534 if (scale)
535 {
536 long double intpart1;
537 long double fract1 = modfl(val1, &intpart1);
538 long double intpart2;
539 long double fract2 = modfl(val2, &intpart2);
540 if (numericCompare(intpart1, intpart2))
541 {
542 double factor = pow(10.0, (double)scale);
543 fract1 = roundl(fract1 * factor);
544 fract2 = roundl(fract2 * factor);
545 return numericCompare(fract1, fract2);
546 }
547 else
548 {
549 return false;
550 }
551 }
552 }
553 return numericCompare(val1, val2);
554 }
555
556 case execplan::CalpontSystemCatalog::DECIMAL:
557 case execplan::CalpontSystemCatalog::UDECIMAL:
558 {
559 if (fOp == OP_ISNULL)
560 {
561 lop->getDecimalVal(row, isNull);
562 bool ret = isNull;
563 isNull = false;
564 return ret;
565 }
566
567 if (fOp == OP_ISNOTNULL)
568 {
569 lop->getDecimalVal(row, isNull);
570 bool ret = isNull;
571 isNull = false;
572 return !ret;
573 }
574
575 if (isNull)
576 return false;
577
578 IDB_Decimal val1 = lop->getDecimalVal(row, isNull);
579
580 if (isNull)
581 return false;
582
583 return numericCompare(val1, rop->getDecimalVal(row, isNull)) && !isNull;
584 }
585
586 case execplan::CalpontSystemCatalog::DATE:
587 {
588 if (fOp == OP_ISNULL)
589 {
590 lop->getDateIntVal(row, isNull);
591 bool ret = isNull;
592 isNull = false;
593 return ret;
594 }
595
596 if (fOp == OP_ISNOTNULL)
597 {
598 lop->getDateIntVal(row, isNull);
599 bool ret = isNull;
600 isNull = false;
601 return !ret;
602 }
603
604 if (isNull)
605 return false;
606
607 int64_t val1 = lop->getDateIntVal(row, isNull);
608
609 if (isNull)
610 return false;
611
612 return numericCompare(val1, (int64_t)rop->getDateIntVal(row, isNull)) && !isNull;
613 }
614
615 case execplan::CalpontSystemCatalog::DATETIME:
616 {
617 if (fOp == OP_ISNULL)
618 {
619 lop->getDatetimeIntVal(row, isNull);
620 bool ret = isNull;
621 isNull = false;
622 return ret;
623 }
624
625 if (fOp == OP_ISNOTNULL)
626 {
627 lop->getDatetimeIntVal(row, isNull);
628 bool ret = isNull;
629 isNull = false;
630 return !ret;
631 }
632
633 if (isNull)
634 return false;
635
636 int64_t val1 = lop->getDatetimeIntVal(row, isNull);
637
638 if (isNull)
639 return false;
640
641 return numericCompare(val1, rop->getDatetimeIntVal(row, isNull)) && !isNull;
642 }
643
644 case execplan::CalpontSystemCatalog::TIMESTAMP:
645 {
646 if (fOp == OP_ISNULL)
647 {
648 lop->getTimestampIntVal(row, isNull);
649 bool ret = isNull;
650 isNull = false;
651 return ret;
652 }
653
654 if (fOp == OP_ISNOTNULL)
655 {
656 lop->getTimestampIntVal(row, isNull);
657 bool ret = isNull;
658 isNull = false;
659 return !ret;
660 }
661
662 if (isNull)
663 return false;
664
665 int64_t val1 = lop->getTimestampIntVal(row, isNull);
666
667 if (isNull)
668 return false;
669
670 return numericCompare(val1, rop->getTimestampIntVal(row, isNull)) && !isNull;
671 }
672
673 case execplan::CalpontSystemCatalog::TIME:
674 {
675 if (fOp == OP_ISNULL)
676 {
677 lop->getTimeIntVal(row, isNull);
678 bool ret = isNull;
679 isNull = false;
680 return ret;
681 }
682
683 if (fOp == OP_ISNOTNULL)
684 {
685 lop->getTimeIntVal(row, isNull);
686 bool ret = isNull;
687 isNull = false;
688 return !ret;
689 }
690
691 if (isNull)
692 return false;
693
694 int64_t val1 = lop->getTimeIntVal(row, isNull);
695
696 if (isNull)
697 return false;
698
699 return numericCompare(val1, rop->getTimeIntVal(row, isNull)) && !isNull;
700 }
701
702
703
704 case execplan::CalpontSystemCatalog::VARCHAR:
705 case execplan::CalpontSystemCatalog::CHAR:
706 case execplan::CalpontSystemCatalog::TEXT:
707 {
708 if (fOp == OP_ISNULL)
709 {
710 lop->getStrVal(row, isNull);
711 bool ret = isNull;
712 isNull = false;
713 return ret;
714 }
715
716 if (fOp == OP_ISNOTNULL)
717 {
718 lop->getStrVal(row, isNull);
719 bool ret = isNull;
720 isNull = false;
721 return !ret;
722 }
723
724 if (isNull)
725 return false;
726
727 const std::string& val1 = lop->getStrVal(row, isNull);
728 if (isNull)
729 return false;
730
731 return strTrimCompare(val1, rop->getStrVal(row, isNull)) && !isNull;
732 }
733
734 //FIXME: ???
735 case execplan::CalpontSystemCatalog::VARBINARY:
736 case execplan::CalpontSystemCatalog::BLOB:
737 return false;
738 break;
739
740 default:
741 {
742 std::ostringstream oss;
743 oss << "invalid predicate operation type: " << fOperationType.colDataType;
744 throw logging::InvalidOperationExcept(oss.str());
745 }
746 }
747
748 return false;
749 }
750
751 } // namespace
752