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