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 // $Id: jlf_subquery.cpp 6419 2010-03-30 04:28:32Z xlou $
20
21
22 #include <iostream>
23 #include <stack>
24 #include <iterator>
25 //#define NDEBUG
26 #include <cassert>
27 #include <vector>
28 using namespace std;
29
30 #include <boost/shared_ptr.hpp>
31 using namespace boost;
32
33 #include "calpontsystemcatalog.h"
34 #include "logicoperator.h"
35 #include "constantcolumn.h"
36 #include "existsfilter.h"
37 #include "predicateoperator.h"
38 #include "pseudocolumn.h"
39 #include "selectfilter.h"
40 #include "simplefilter.h"
41 #include "simplescalarfilter.h"
42 #include "windowfunctioncolumn.h"
43 using namespace execplan;
44
45 #include "rowgroup.h"
46 using namespace rowgroup;
47
48 #include "idberrorinfo.h"
49 #include "errorids.h"
50 #include "exceptclasses.h"
51 #include "dataconvert.h"
52 using namespace logging;
53
54 #include "elementtype.h"
55 #include "jobstep.h"
56 #include "jlf_common.h"
57 #include "jlf_execplantojoblist.h"
58 #include "expressionstep.h"
59 #include "tupleconstantstep.h"
60 #include "tuplehashjoin.h"
61 #include "subquerystep.h"
62 #include "subquerytransformer.h"
63 #include "jlf_subquery.h"
64 using namespace joblist;
65
66
67 namespace
68 {
69
getColumnValue(ConstantColumn ** cc,uint64_t i,const Row & row,const string & timeZone)70 void getColumnValue(ConstantColumn** cc, uint64_t i, const Row& row, const string& timeZone)
71 {
72 ostringstream oss;
73 int64_t data = 0;
74
75 switch (row.getColTypes()[i])
76 {
77 case CalpontSystemCatalog::TINYINT:
78 case CalpontSystemCatalog::SMALLINT:
79 case CalpontSystemCatalog::MEDINT:
80 case CalpontSystemCatalog::INT:
81 case CalpontSystemCatalog::BIGINT:
82 if (row.getScale(i) == 0)
83 {
84 oss << row.getIntField(i);
85 *cc = new ConstantColumn(oss.str(), row.getIntField(i));
86 break;
87 }
88 /* fall through */
89 /* else > 0 */
90
91 case CalpontSystemCatalog::DECIMAL:
92 case CalpontSystemCatalog::UDECIMAL:
93 data = row.getIntField(i);
94 oss << (data / IDB_pow[row.getScale(i)]);
95
96 if (row.getScale(i) > 0)
97 {
98 if (data > 0)
99 oss << "." << (data % IDB_pow[row.getScale(i)]);
100 else if (data < 0)
101 oss << "." << (-data % IDB_pow[row.getScale(i)]);
102 }
103
104 *cc = new ConstantColumn(oss.str(),
105 IDB_Decimal(data, row.getScale(i), row.getPrecision(i)));
106 break;
107
108 case CalpontSystemCatalog::UTINYINT:
109 case CalpontSystemCatalog::USMALLINT:
110 case CalpontSystemCatalog::UMEDINT:
111 case CalpontSystemCatalog::UINT:
112 case CalpontSystemCatalog::UBIGINT:
113 oss << row.getUintField(i);
114 *cc = new ConstantColumn(oss.str(), row.getUintField(i));
115 break;
116
117 case CalpontSystemCatalog::FLOAT:
118 case CalpontSystemCatalog::UFLOAT:
119 oss << fixed << row.getFloatField(i);
120 *cc = new ConstantColumn(oss.str(), (double) row.getFloatField(i));
121 break;
122 break;
123
124 case CalpontSystemCatalog::DOUBLE:
125 oss << fixed << row.getDoubleField(i);
126 *cc = new ConstantColumn(oss.str(), row.getDoubleField(i));
127 break;
128
129 case CalpontSystemCatalog::LONGDOUBLE:
130 oss << fixed << row.getLongDoubleField(i);
131 *cc = new ConstantColumn(oss.str(), row.getLongDoubleField(i));
132 break;
133
134 case CalpontSystemCatalog::DATE:
135 oss << dataconvert::DataConvert::dateToString(row.getUintField<4>(i));
136 *cc = new ConstantColumn(oss.str());
137 break;
138
139 case CalpontSystemCatalog::DATETIME:
140 oss << dataconvert::DataConvert::datetimeToString(row.getUintField<8>(i));
141 *cc = new ConstantColumn(oss.str());
142 break;
143
144 case CalpontSystemCatalog::TIMESTAMP:
145 oss << dataconvert::DataConvert::timestampToString(row.getUintField<8>(i), timeZone);
146 *cc = new ConstantColumn(oss.str());
147 break;
148
149 case CalpontSystemCatalog::TIME:
150 oss << dataconvert::DataConvert::timeToString(row.getUintField<8>(i));
151 *cc = new ConstantColumn(oss.str());
152 break;
153
154 case CalpontSystemCatalog::CHAR:
155 case CalpontSystemCatalog::VARCHAR:
156 case CalpontSystemCatalog::TEXT:
157 case CalpontSystemCatalog::BLOB:
158 oss << (char*) (row.getStringField(i).c_str());
159 *cc = new ConstantColumn(oss.str());
160 break;
161
162 default:
163 oss << "Unsupported data type: " << row.getColTypes()[i];
164 throw QueryDataExcept(oss.str(), dataTypeErr);
165 }
166 }
167
168
sfInHaving(ParseTree * pt,void *)169 void sfInHaving(ParseTree* pt, void*)
170 {
171 SelectFilter* sf = dynamic_cast<SelectFilter*>(pt->data());
172
173 if (sf != NULL)
174 throw IDBExcept(ERR_NON_SUPPORT_HAVING);
175 }
176
177
ssfInHaving(ParseTree * pt,void * obj)178 void ssfInHaving(ParseTree* pt, void* obj)
179 {
180 JobInfo* jobInfo = reinterpret_cast<JobInfo*>(obj);
181 SimpleScalarFilter* ssf = dynamic_cast<SimpleScalarFilter*>(pt->data());
182
183 if (ssf != NULL)
184 {
185 ParseTree* parseTree = NULL;
186
187 if (simpleScalarFilterToParseTree(ssf, parseTree, *jobInfo))
188 {
189 // replace simple scalar filter with simple filters
190 delete pt->data();
191 pt->left(parseTree->left());
192 pt->right(parseTree->right());
193 pt->data(parseTree->data());
194
195 jobInfo->dynamicParseTreeVec.push_back(parseTree);
196 // don't delete the parseTree, it has been placed in the plan.
197 // Instead, we use the dynamicParseTreeVec above for deletion
198 // in ~csep() or csep.unserialize().
199 // delete parseTree;
200 }
201 else
202 {
203 // not a scalar result
204 // replace simple scalar filter with simple filters
205 delete pt->data();
206 pt->data(NULL);
207 delete parseTree;
208 jobInfo->constantFalse = true;
209 }
210 }
211 }
212
213
getCorrelatedFilters(ParseTree * pt,void * obj)214 void getCorrelatedFilters(ParseTree* pt, void* obj)
215 {
216 SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->data());
217
218 if (sf != NULL)
219 {
220 ReturnedColumn* rc1 = dynamic_cast<ReturnedColumn*>(sf->lhs());
221 ReturnedColumn* rc2 = dynamic_cast<ReturnedColumn*>(sf->rhs());
222
223 bool correlated = false;
224
225 if (rc1 != NULL && rc1->joinInfo() != 0)
226 correlated = true;
227
228 if (rc2 != NULL && rc2->joinInfo() != 0)
229 correlated = true;
230
231 if (correlated)
232 {
233 ParseTree** correlatedFilters = reinterpret_cast<ParseTree**>(obj);
234
235 if (*correlatedFilters == NULL)
236 {
237 *correlatedFilters = new ParseTree(sf);
238 }
239 else
240 {
241 ParseTree* left = *correlatedFilters;
242 *correlatedFilters = new ParseTree(new LogicOperator("and"));
243 (*correlatedFilters)->left(left);
244 (*correlatedFilters)->right(new ParseTree(sf));
245 }
246
247 pt->data(NULL);
248 }
249 }
250 }
251
252
trim(ParseTree * & pt)253 ParseTree* trim(ParseTree*& pt)
254 {
255 ParseTree* lhs = pt->left();
256
257 if (lhs)
258 pt->left(trim(lhs));
259
260 ParseTree* rhs = pt->right();
261
262 if (rhs)
263 pt->right(trim(rhs));
264
265 if ((lhs == NULL) && (rhs == NULL) && (pt->data() == NULL))
266 {
267 delete pt;
268 pt = NULL;
269 }
270 else if ((lhs == NULL || rhs == NULL) && dynamic_cast<LogicOperator*>(pt->data()))
271 {
272 idbassert(dynamic_cast<LogicOperator*>(pt->data())->data() == "and");
273 ParseTree* br = pt;
274 ParseTree* nl = NULL; // the left()/right() are overloaded
275
276 if (lhs == NULL && rhs != NULL)
277 pt = rhs;
278 else if (lhs != NULL && rhs == NULL)
279 pt = lhs;
280 else
281 pt = NULL;
282
283 br->left(nl);
284 br->right(nl);
285 delete br;
286 }
287
288 return pt;
289 }
290
291
handleNotIn(JobStepVector & jsv,JobInfo * jobInfo)292 void handleNotIn(JobStepVector& jsv, JobInfo* jobInfo)
293 {
294 // convert CORRELATED join (but not MATCHNULLS) to expression.
295 for (JobStepVector::iterator i = jsv.begin(); i != jsv.end(); i++)
296 {
297 TupleHashJoinStep* thjs = dynamic_cast<TupleHashJoinStep*>(i->get());
298
299 if (!thjs || !(thjs->getJoinType() & CORRELATED) || (thjs->getJoinType() & MATCHNULLS) )
300 continue;
301
302 ReturnedColumn* lhs = thjs->column1()->clone();
303 ReturnedColumn* rhs = thjs->column2()->clone();
304
305 SOP sop(new PredicateOperator("="));
306 sop->setOpType(lhs->resultType(), rhs->resultType());
307 sop->resultType(sop->operationType());
308 SimpleFilter* sf = new SimpleFilter(sop, lhs, rhs);
309
310 ExpressionStep* es = new ExpressionStep(*jobInfo);
311
312 if (es == NULL)
313 throw runtime_error("Failed to create ExpressionStep 2");
314
315 es->expressionFilter(sf, *jobInfo);
316 es->resetJoinInfo(); // Not to be done as join
317 i->reset(es);
318
319 delete sf;
320 }
321 }
322
323
isNotInSubquery(JobStepVector & jsv)324 bool isNotInSubquery(JobStepVector& jsv)
325 {
326 // use MATCHNULLS(execplan::JOIN_NULL_MATCH) to identify NOT IN and NOT EXIST
327 bool notIn = false;
328
329 for (JobStepVector::iterator i = jsv.begin(); i != jsv.end(); i++)
330 {
331 TupleHashJoinStep* thjs = dynamic_cast<TupleHashJoinStep*>(i->get());
332
333 if (thjs)
334 {
335 if (thjs->getJoinType() & MATCHNULLS)
336 {
337 // only NOT IN will be specially treated.
338 notIn = true;
339 break;
340 }
341 }
342 }
343
344 return notIn;
345 }
346
347 // This fcn is currently unused. Will keep it in the code for now.
348 #if 0
349 void alterCsepInExistsFilter(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
350 {
351 // This is for window function in IN/EXISTS sub-query.
352 // Replace an expression of window functions with indivisual window functions.
353 RetColsVector& retCols = csep->returnedCols();
354 RetColsVector wcs;
355
356 for (RetColsVector::iterator i = retCols.begin(); i < retCols.end(); i++)
357 {
358 const vector<WindowFunctionColumn*>& wcList = (*i)->windowfunctionColumnList();
359
360 if (!wcList.empty())
361 {
362 vector<WindowFunctionColumn*>::const_iterator j = wcList.begin();
363
364 while (j != wcList.end())
365 wcs.push_back(SRCP((*j++)->clone()));
366
367 // a little optimization, eliminate the expression in select clause
368 // replace the window function expression with the 1st windowfunction
369 (*i) = wcs[0];
370 }
371 }
372
373 if (wcs.size() > 1)
374 retCols.insert(retCols.end(), wcs.begin() + 1, wcs.end());
375 }
376 #endif
377
doCorrelatedExists(const ExistsFilter * ef,JobInfo & jobInfo)378 void doCorrelatedExists(const ExistsFilter* ef, JobInfo& jobInfo)
379 {
380 // Transformer sub to a subquery step.
381 SErrorInfo errorInfo(jobInfo.errorInfo);
382 SubQueryTransformer transformer(&jobInfo, errorInfo);
383 CalpontSelectExecutionPlan* csep = ef->sub().get();
384 //alterCsepInExistsFilter(csep, jobInfo);
385 SJSTEP subQueryStep = transformer.makeSubQueryStep(csep);
386
387 // @bug3524, special handling of not in.
388 JobStepVector& jsv = transformer.correlatedSteps();
389
390 if (isNotInSubquery(jsv) == true)
391 handleNotIn(jsv, transformer.subJobInfo());
392
393 transformer.updateCorrelateInfo();
394 jsv.push_back(subQueryStep);
395 JLF_ExecPlanToJobList::addJobSteps(jsv, jobInfo, false);
396 }
397
398
doNonCorrelatedExists(const ExistsFilter * ef,JobInfo & jobInfo)399 void doNonCorrelatedExists(const ExistsFilter* ef, JobInfo& jobInfo)
400 {
401 // Assume: exists-subquery without a from clause, like exists (select 1)
402 // always evalustes to true
403 bool noFrom = (ef->sub()->tableList().size() == 0);
404 bool exists = !ef->notExists();
405
406 if (!noFrom)
407 {
408 // Transformer sub to a scalar result set.
409 SErrorInfo errorInfo(new ErrorInfo());
410 SimpleScalarTransformer transformer(&jobInfo, errorInfo, true);
411 transformer.makeSubQueryStep(ef->sub().get());
412
413 // @bug 2839. error out in-relelvant correlated column case
414 if (!transformer.correlatedSteps().empty())
415 {
416 JobStepVector::const_iterator it = transformer.correlatedSteps().begin();
417 string tn;
418
419 for (; it != transformer.correlatedSteps().end(); ++it)
420 {
421 // 1. if tuplehashjoin, check alias1 and alias2; otherwise, check alias
422 // 2. alias start with "$sub_"
423 TupleHashJoinStep* thjs = dynamic_cast<TupleHashJoinStep*>(it->get());
424
425 if (thjs)
426 {
427 if (thjs->alias1().empty() || thjs->alias1().compare(0, 5, "$sub_"))
428 tn = thjs->alias2();
429 else
430 tn = thjs->alias1();
431 }
432 else
433 {
434 tn = it->get()->alias();
435 }
436 }
437
438 Message::Args args;
439
440 if (tn.empty() || tn.compare(0, 5, "$sub_"))
441 tn = "sub-query";
442
443 args.add(tn);
444 throw IDBExcept(ERR_MISS_JOIN_IN_SUB, args);
445 }
446
447 // Catch more_than_1_row exception only
448 try
449 {
450 transformer.run();
451 }
452 catch (MoreThan1RowExcept&)
453 {
454 // no-op
455 };
456
457 // Check if the exists condition is satisfied.
458 //((!transformer.emptyResultSet() && !ef->notExists()) ||
459 // ( transformer.emptyResultSet() && ef->notExists()))
460 exists = (transformer.emptyResultSet() == ef->notExists());
461 }
462
463 JobStepVector jsv;
464 SJSTEP tcs(new TupleConstantBooleanStep(jobInfo, exists));
465 jsv.push_back(tcs);
466 JLF_ExecPlanToJobList::addJobSteps(jsv, jobInfo, false);
467 }
468
469
doSelectSubquery(CalpontExecutionPlan * ep,SRCP & sc,JobInfo & jobInfo)470 const SRCP doSelectSubquery(CalpontExecutionPlan* ep, SRCP& sc, JobInfo& jobInfo)
471 {
472 CalpontSelectExecutionPlan* csep = dynamic_cast<CalpontSelectExecutionPlan*>(ep);
473 SRCP rc;
474 SErrorInfo errorInfo(jobInfo.errorInfo);
475 string subView = dynamic_cast<SimpleColumn*>(sc.get())->viewName();
476 SubQueryTransformer transformer(&jobInfo, errorInfo, subView);
477 transformer.setVarbinaryOK();
478 SJSTEP subQueryStep = transformer.makeSubQueryStep(csep);
479
480 if (transformer.correlatedSteps().size() > 0)
481 {
482 transformer.updateCorrelateInfo();
483 JobStepVector jsv = transformer.correlatedSteps();
484 jsv.push_back(subQueryStep);
485 jobInfo.selectAndFromSubs.insert(jobInfo.selectAndFromSubs.end(), jsv.begin(), jsv.end());
486 const RetColsVector& retCol = csep->returnedCols();
487
488 for (uint64_t i = 0; i < retCol.size(); i++)
489 {
490 if (retCol[i]->colSource() == 0)
491 {
492 rc = transformer.virtualTable().columns()[i];
493 break;
494 }
495 }
496 }
497 else
498 {
499 // Non-correlated subquery
500 // Do not catch exceptions here, let caller handle them.
501 SimpleScalarTransformer simpleTransformer(transformer);
502 simpleTransformer.run();
503
504 // Costruct a simple column based on the scalar result.
505 ConstantColumn* cc = NULL;
506
507 if (simpleTransformer.emptyResultSet() == false)
508 {
509 // set value for cc
510 const Row& row = simpleTransformer.resultRow();
511
512 if (!row.isNullValue(0))
513 getColumnValue(&cc, 0, row, jobInfo.timeZone);
514 }
515
516 // Empty set or null value
517 if (cc == NULL)
518 {
519 cc = new ConstantColumn("");
520 cc->type(ConstantColumn::NULLDATA);
521 }
522
523 rc.reset(cc);
524 }
525
526 return rc;
527 }
528
529
530 }
531
532
533 namespace joblist
534 {
535
simpleScalarFilterToParseTree(SimpleScalarFilter * sf,ParseTree * & pt,JobInfo & jobInfo)536 bool simpleScalarFilterToParseTree(SimpleScalarFilter* sf, ParseTree*& pt, JobInfo& jobInfo)
537 {
538 const vector<SRCP>& cols = sf->cols();
539 CalpontSelectExecutionPlan* csep = sf->sub().get();
540 SOP sop = sf->op();
541
542 // For row construct, supports only =, <> in Release 1.1.
543 // Other operators are errored out by connector.
544 string lop("and");
545
546 if ((cols.size() > 1) && (sop->data() == "<>"))
547 lop = "or";
548
549 // Transformer sub to a scalar result.
550 SErrorInfo errorInfo(jobInfo.errorInfo);
551 SimpleScalarTransformer transformer(&jobInfo, errorInfo, false);
552 transformer.makeSubQueryStep(csep);
553
554 // Do not catch exceptions here, let caller handle them.
555 transformer.run();
556
557 // if subquery errored out
558 if (errorInfo->errCode)
559 {
560 ostringstream oss;
561 oss << "Sub-query failed: ";
562
563 if (errorInfo->errMsg.empty())
564 {
565 oss << "error code " << errorInfo->errCode;
566 errorInfo->errMsg = oss.str();
567 }
568
569 throw runtime_error(errorInfo->errMsg);
570 }
571
572 // Construct simple filters based on the scalar result.
573 bool isScalar = false;
574
575 if (transformer.emptyResultSet() == false)
576 {
577 const Row& row = transformer.resultRow();
578 uint64_t i = 0;
579
580 for (; i < cols.size(); i++)
581 {
582 // = null is always false
583 if (row.isNullValue(i) == true)
584 break;
585
586 // set fResult for cc
587 ConstantColumn* cc = NULL;
588 getColumnValue(&cc, i, row, jobInfo.timeZone);
589 sop->setOpType(cols[i]->resultType(), cc->resultType());
590
591 SimpleFilter* sf = new SimpleFilter(sop, cols[i]->clone(), cc);
592
593 if (i == 0)
594 {
595 pt = new ParseTree(sf);
596 }
597 else
598 {
599 ParseTree* left = pt;
600 pt = new ParseTree(new LogicOperator(lop));
601 pt->left(left);
602 pt->right(new ParseTree(sf));
603 }
604 }
605
606 if (i >= cols.size())
607 isScalar = true;
608 }
609
610 return isScalar;
611 }
612
613
doSimpleScalarFilter(ParseTree * p,JobInfo & jobInfo)614 void doSimpleScalarFilter(ParseTree* p, JobInfo& jobInfo)
615 {
616 SimpleScalarFilter* sf = dynamic_cast<SimpleScalarFilter*>(p->data());
617 idbassert(sf != NULL);
618 ParseTree* parseTree = NULL;
619
620 // Parse filters to job step.
621 if (simpleScalarFilterToParseTree(sf, parseTree, jobInfo))
622 {
623 // update the plan for supporting OR in future.
624 ParseTree* ccp = (p);
625 delete ccp->data();
626 ccp->left(parseTree->left());
627 ccp->right(parseTree->right());
628 ccp->data(parseTree->data());
629
630 // create job steps for each simple filter
631 JLF_ExecPlanToJobList::walkTree(parseTree, jobInfo);
632
633 jobInfo.dynamicParseTreeVec.push_back(parseTree);
634 // don't delete the parseTree, it has been placed in the plan.
635 // Instead, we use the dynamicParseTreeVec above for deletion
636 // in ~csep() or csep.unserialize().
637 // delete parseTree;
638 }
639 else
640 {
641 // not a scalar result
642 delete parseTree;
643 JobStepVector jsv;
644 SJSTEP tcs(new TupleConstantBooleanStep(jobInfo, false));
645 jsv.push_back(tcs);
646 JLF_ExecPlanToJobList::addJobSteps(jsv, jobInfo, false);
647 }
648 }
649
650
doExistsFilter(const ParseTree * p,JobInfo & jobInfo)651 void doExistsFilter(const ParseTree* p, JobInfo& jobInfo)
652 {
653 const ExistsFilter* ef = dynamic_cast<const ExistsFilter*>(p->data());
654 idbassert(ef != NULL);
655
656 if (ef->correlated())
657 doCorrelatedExists(ef, jobInfo);
658 else
659 doNonCorrelatedExists(ef, jobInfo);
660 }
661
662
doSelectFilter(const ParseTree * p,JobInfo & jobInfo)663 void doSelectFilter(const ParseTree* p, JobInfo& jobInfo)
664 {
665 const SelectFilter* sf = dynamic_cast<const SelectFilter*>(p->data());
666 idbassert(sf != NULL);
667
668 SErrorInfo errorInfo(jobInfo.errorInfo);
669 SubQueryTransformer transformer(&jobInfo, errorInfo);
670 SJSTEP subQueryStep = transformer.makeSubQueryStep(sf->sub().get());
671 transformer.updateCorrelateInfo();
672 JobStepVector jsv = transformer.correlatedSteps();
673
674 jsv.push_back(subQueryStep);
675
676 const vector<SRCP>& cols = sf->cols();
677 SOP sop = sf->op();
678
679 // For row construct, supports only =, <> in Release 1.1.
680 // Other operators are errored out by connector.
681 string lop("and");
682
683 if ((cols.size() > 1) && (sop->data() == "<>"))
684 lop = "or";
685
686 // @bug3780, select filters are not additional comparison, but fe2.
687 // When parsing the sub query, correlated columns may be added as group by column,
688 // s is the start position of the original selected columns.
689 uint64_t s = sf->returnedColPos();
690 ParseTree* pt = NULL;
691 const VirtualTable& vt = transformer.virtualTable();
692
693 for (uint64_t i = 0; i < cols.size(); i++)
694 {
695 ReturnedColumn* lhs = cols[i].get()->clone();
696 ReturnedColumn* rhs = vt.columns()[s + i].get()->clone();
697 sop->setOpType(lhs->resultType(), rhs->resultType());
698
699 if (i == 0)
700 {
701 pt = new ParseTree(new SimpleFilter(sop, lhs, rhs));
702 }
703 else
704 {
705 ParseTree* left = pt;
706 pt = new ParseTree(new LogicOperator(lop));
707 pt->left(left);
708 pt->right(new ParseTree(new SimpleFilter(sop, lhs, rhs)));
709 }
710 }
711
712 if (pt != NULL)
713 {
714 ExpressionStep* es = new ExpressionStep(jobInfo);
715 es->expressionFilter(pt, jobInfo);
716 es->selectFilter(true);
717 delete pt;
718
719 jsv.push_back(SJSTEP(es));
720 }
721
722 JLF_ExecPlanToJobList::addJobSteps(jsv, jobInfo, false);
723 }
724
725
preprocessHavingClause(CalpontSelectExecutionPlan * csep,JobInfo & jobInfo)726 void preprocessHavingClause(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
727 {
728 ParseTree* havings = (csep->having());
729 idbassert(havings != NULL); // check having exists before calling this function.
730
731 // check select filter in having
732 havings->walk(sfInHaving, &jobInfo);
733
734 // check simple scalar filters in having
735 havings->walk(ssfInHaving, &jobInfo);
736
737 // check correlated columns in having
738 ParseTree* correlatedFilters = NULL;
739 havings->walk(getCorrelatedFilters, &correlatedFilters);
740 trim(havings);
741
742 if (havings == NULL)
743 {
744 csep->having(NULL);
745 }
746
747 if (correlatedFilters != NULL)
748 {
749 ParseTree* newFilters = new ParseTree(new LogicOperator("and"));
750 newFilters->left(csep->filters());
751 newFilters->right(correlatedFilters);
752
753 csep->filters(newFilters);
754 csep->having(havings);
755 }
756 }
757
758
doFromSubquery(CalpontExecutionPlan * ep,const string & alias,const string & view,JobInfo & jobInfo)759 int doFromSubquery(CalpontExecutionPlan* ep, const string& alias, const string& view, JobInfo& jobInfo)
760 {
761 CalpontSelectExecutionPlan* csep = dynamic_cast<CalpontSelectExecutionPlan*>(ep);
762 SErrorInfo errorInfo(jobInfo.errorInfo);
763 SubQueryTransformer transformer(&jobInfo, errorInfo, alias, view);
764 transformer.setVarbinaryOK();
765 SJSTEP subQueryStep = transformer.makeSubQueryStep(csep, true);
766 subQueryStep->view(view);
767 SJSTEP subAd(new SubAdapterStep(subQueryStep, jobInfo));
768 jobInfo.selectAndFromSubs.push_back(subAd);
769
770 return CNX_VTABLE_ID;
771 }
772
773
addOrderByAndLimit(CalpontSelectExecutionPlan * csep,JobInfo & jobInfo)774 void addOrderByAndLimit(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
775 {
776 jobInfo.limitStart = csep->limitStart();
777 jobInfo.limitCount = csep->limitNum();
778 jobInfo.orderByThreads = csep->orderByThreads();
779
780 CalpontSelectExecutionPlan::OrderByColumnList& orderByCols = csep->orderByCols();
781
782 for (uint64_t i = 0; i < orderByCols.size(); i++)
783 {
784 // skip constant columns
785 if (dynamic_cast<ConstantColumn*>(orderByCols[i].get()) != NULL)
786 continue;
787
788 uint32_t tupleKey = -1;
789 SimpleColumn* sc = dynamic_cast<SimpleColumn*>(orderByCols[i].get());
790
791 if (sc != NULL)
792 {
793 CalpontSystemCatalog::OID oid = sc->oid();
794 CalpontSystemCatalog::OID tblOid = tableOid(sc, jobInfo.csc);
795 CalpontSystemCatalog::OID dictOid = 0;
796 CalpontSystemCatalog::ColType ct;
797 string alias(extractTableAlias(sc));
798 string view(sc->viewName());
799 string schema(sc->schemaName());
800
801 // string name(sc->columnName());
802 if (!sc->schemaName().empty())
803 {
804 ct = sc->colType();
805
806 //XXX use this before connector sets colType in sc correctly.
807 // type of pseudo column is set by connector
808 if (sc->isColumnStore() && !(dynamic_cast<PseudoColumn*>(sc)))
809 {
810 ct = jobInfo.csc->colType(sc->oid());
811 ct.charsetNumber =sc->colType().charsetNumber;
812 }
813 //X
814 dictOid = isDictCol(ct);
815 }
816 else
817 {
818 if (sc->colPosition() == -1)
819 {
820 sc = dynamic_cast<SimpleColumn*>(jobInfo.deliveredCols[sc->orderPos()].get());
821
822 // If sc is NULL it's most likely a scaler subquery
823 if (sc == NULL)
824 {
825 const ReturnedColumn* rc = dynamic_cast<const ReturnedColumn*>(orderByCols[i].get());
826 uint32_t eid = rc->expressionId();
827 // If eid is -1, then there's no corresponding
828 // entry in tupleKeyMap and it will assert down the line
829 // Don't add the order by. It won't work and ordering on
830 // a singleton is a waste anyway.
831 if ((int32_t)eid == -1)
832 continue;
833 CalpontSystemCatalog::ColType ct = rc->resultType();
834 tupleKey = getExpTupleKey(jobInfo, eid);
835 jobInfo.orderByColVec.push_back(make_pair(tupleKey, orderByCols[i]->asc()));
836 continue;
837 }
838 }
839 else
840 {
841 sc->oid((tblOid + 1) + sc->colPosition());
842 }
843
844 oid = sc->oid();
845 ct = jobInfo.vtableColTypes[UniqId(oid, alias, "", "")];
846 }
847
848 tupleKey = getTupleKey(jobInfo, sc);
849
850 // for dictionary columns, replace the token oid with string oid
851 if (dictOid > 0)
852 {
853 tupleKey = jobInfo.keyInfo->dictKeyMap[tupleKey];
854 }
855 }
856 else
857 {
858 const ReturnedColumn* rc = dynamic_cast<const ReturnedColumn*>(orderByCols[i].get());
859 uint64_t eid = rc->expressionId();
860 CalpontSystemCatalog::ColType ct = rc->resultType();
861 tupleKey = getExpTupleKey(jobInfo, eid);
862 }
863
864 jobInfo.orderByColVec.push_back(make_pair(tupleKey, orderByCols[i]->asc()));
865 }
866 }
867
868
preprocessSelectSubquery(CalpontSelectExecutionPlan * csep,JobInfo & jobInfo)869 void preprocessSelectSubquery(CalpontSelectExecutionPlan* csep, JobInfo& jobInfo)
870 {
871 RetColsVector& retCols = (csep->returnedCols());
872 CalpontSelectExecutionPlan::SelectList::const_iterator sub = csep->selectSubList().begin();
873
874 for (RetColsVector::iterator i = retCols.begin(); i != retCols.end(); i++)
875 {
876 if ((*i)->colSource() == execplan::SELECT_SUB)
877 {
878 (*i) = doSelectSubquery(sub->get(), *i, jobInfo);
879 sub++;
880 }
881 }
882 }
883
884
doUnionSub(CalpontExecutionPlan * ep,JobInfo & jobInfo)885 SJSTEP doUnionSub(CalpontExecutionPlan* ep, JobInfo& jobInfo)
886 {
887 CalpontSelectExecutionPlan* csep = dynamic_cast<CalpontSelectExecutionPlan*>(ep);
888 SErrorInfo errorInfo(jobInfo.errorInfo);
889 SubQueryTransformer transformer(&jobInfo, errorInfo);
890 transformer.setVarbinaryOK();
891 SJSTEP subQueryStep = transformer.makeSubQueryStep(csep, false);
892 SJSTEP subAd(new SubAdapterStep(subQueryStep, jobInfo));
893 return subAd;
894 }
895
896
897 }
898 // vim:ts=4 sw=4:
899
900