1 /* Copyright (C) 2014 InfiniDB, Inc.
2 
3    This program is free software; you can redistribute it and/or
4    modify it under the terms of the GNU General Public License
5    as published by the Free Software Foundation; version 2 of
6    the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16    MA 02110-1301, USA. */
17 
18 #include <string>
19 #include <stdexcept>
20 #include <typeinfo>
21 using namespace std;
22 
23 #include <cppunit/extensions/HelperMacros.h>
24 
25 #include<sstream>
26 #include<exception>
27 #include<iostream>
28 #include <unistd.h>
29 
30 #include "messagequeue.h"
31 #include "bytestream.h"
32 using namespace messageqcpp;
33 
34 #include "calpontselectexecutionplan.h"
35 #include "simplefilter.h"
36 #include "simplecolumn.h"
37 #include "expressionparser.h"
38 #include "constantcolumn.h"
39 #include "treenode.h"
40 #include "operator.h"
41 #include "arithmeticcolumn.h"
42 #include "aggregatecolumn.h"
43 
44 extern "C" char* cplus_demangle_with_style(const char*, int, int);
45 extern "C" void init_demangler(int, int, int);
46 
47 using namespace execplan;
48 
49 class ExecPlanTest : public CppUnit::TestFixture
50 {
51 
52     CPPUNIT_TEST_SUITE( ExecPlanTest );
53 
54     CPPUNIT_TEST( selectExecutionPlan_12 );
55 
56     CPPUNIT_TEST_SUITE_END();
57 
58 private:
59 public:
60 
walkfnString(const ParseTree * n)61     static void walkfnString(const ParseTree* n)
62     {
63         char* r;
64         static bool is_init = false;
65         const char* mname = typeid(*(n->data())).name();
66 
67         if (!is_init)
68         {
69             ::init_demangler(0, 0, 0);
70             is_init = true;
71         }
72 
73         r = ::cplus_demangle_with_style(mname, 7, 27);
74 
75         if (r != 0)
76         {
77             //cout << "mangle: " << mname << " demangle: " << r << endl;
78             ::free(r);
79         }
80 
81         if (typeid(*(n->data())) == typeid(SimpleFilter))
82         {
83             cout << "SimpleFilter: " << endl;
84             const SimpleFilter* sf = dynamic_cast<SimpleFilter*>(n->data());
85             const ReturnedColumn* lhs = sf->lhs();
86             const ReturnedColumn* rhs = sf->rhs();
87             const Operator* op = sf->op();
88             cout << '\t' << lhs->data() << ' ' << op->data() << ' ' << rhs->data();
89             cout << endl << "\t\t";
90 
91             if (typeid(*lhs) == typeid(SimpleColumn))
92             {
93                 cout << "SimpleColumn: " << lhs->data() << " / ";
94             }
95             else if (typeid(*lhs) == typeid(ConstantColumn))
96             {
97                 cout << "ConstantColumn: " << lhs->data() << " / ";
98             }
99             else
100             {
101                 cout << "UNK: " << lhs->data() << " / ";
102             }
103 
104             cout << "Operator: " << op->data() << " / ";
105 
106             if (typeid(*rhs) == typeid(SimpleColumn))
107             {
108                 cout << "SimpleColumn: " << rhs->data();
109             }
110             else if (typeid(*rhs) == typeid(ConstantColumn))
111             {
112                 cout << "ConstantColumn: " << rhs->data();
113             }
114             else
115             {
116                 cout << "UNK: " << rhs->data();
117             }
118         }
119         else if (typeid(*(n->data())) == typeid(Operator))
120         {
121             cout << "Operator: ";
122             const Operator* op = dynamic_cast<Operator*>(n->data());
123             cout << '\t' << op->data();
124         }
125         else
126         {
127             cout << mname << " -x-: ";
128         }
129 
130         cout << endl;
131     }
132 
setUp()133     void setUp()
134     {
135     }
136 
tearDown()137     void tearDown()
138     {
139     }
140 
selectExecutionPlan_12()141     void selectExecutionPlan_12()
142     {
143 
144 //        cout << "SQL: select r_regionkey from region, nation where n_regionkey = r_regionkey and n_regionkey = 2;" << endl;
145         cout <<
146              "SQL: select \
147  l_shipmode, \
148  sum(case \
149    when o_orderpriority = '1-URGENT' \
150      or o_orderpriority = '2-HIGH' \
151      then 1 \
152      else 0 \
153  end ) as high_line_count, \
154  sum(case \
155    when o_orderpriority <> '1-URGENT' \
156     and o_orderpriority <> '2-HIGH' \
157      then 1 \
158      else 0 \
159  end ) as low_line_count \
160 from \
161   orders, \
162   lineitem \
163 where \
164   o_orderkey = l_orderkey \
165   and l_shipmode in (':1', ':2') \
166   and l_commitdate < l_reciptdate \
167   and l_shipdate < l_commitdate \
168   and l_receiptdate >= date ':3' \
169   and l_receiptdate < date ':3' + interval '1' year' \
170 group by \
171   l_shipmode \
172 order by \
173   l_shipmode;" << endl;
174 
175 
176         CalpontSelectExecutionPlan csep;
177         CalpontSelectExecutionPlan::ReturnedColumnList colList;
178         CalpontSelectExecutionPlan::GroupByColumnList groupbyList;
179         CalpontSelectExecutionPlan::OrderByColumnList orderbyList;
180         ParseTree* filterList;
181 
182         // returned columns
183         SimpleColumn l_shipmode("tpch.lineitem.l_shipmode");
184         AggregateColumn* high_line_count = new AggregateColumn();
185         high_line_count->functionName("sum");
186         ArithmeticColumn* a1 = new ArithmeticColumn ("( CASE WHEN o_orderpriority = '1-URGENT' or o_orderpriority = '2-HIGH' THEN 1 ELSE 0  END )");
187         high_line_count->functionParms(a1);
188 
189         AggregateColumn* low_line_count = new AggregateColumn();
190         low_line_count->functionName("sum");
191         ArithmeticColumn* a2 = new ArithmeticColumn ("( CASE WHEN o_orderpriority <> '1-URGENT' and o_orderpriority <> '2-HIGH' THEN 1 ELSE 0  END )");
192         low_line_count->functionParms(a2);
193 
194 
195         // Create the Projection
196         colList.push_back(high_line_count);
197         colList.push_back(low_line_count);
198 
199         // Filter columns
200         SimpleColumn l_shipmode0("tpch.lineitem.l_shipmode");
201         SimpleColumn l_shipmode1("tpch.lineitem.l_shipmode");
202         SimpleColumn l_commitdate("tpch.lineitem.l_commitdate");
203         SimpleColumn l_receiptdate("tpch.lineitem.l_receiptdate");
204         SimpleColumn l_receiptdate1("tpch.lineitem.l_receiptdate");
205         SimpleColumn l_shipdate("tpch.lineitem.l_shipdate");
206 
207 
208         // filters
209         CalpontSelectExecutionPlan::Parser parser;
210         std::vector<Token> tokens;
211 
212         //tokens.push_back(Token(new Operator("(")));
213         //tokens.push_back(Token(new Operator(")")));
214 
215         tokens.push_back(Token(new SimpleFilter(new Operator("="),
216                                                 new SimpleColumn(l_shipmode),
217                                                 new ConstantColumn("1"))));
218 
219         tokens.push_back(Token(new Operator("and")));
220 
221         tokens.push_back(Token(new SimpleFilter(new Operator("="),
222                                                 new SimpleColumn(l_shipmode),
223                                                 new ConstantColumn("2"))));
224 
225         tokens.push_back(Token(new Operator("and")));
226 
227         tokens.push_back(Token(new SimpleFilter(new Operator("<"),
228                                                 new SimpleColumn(l_commitdate),
229                                                 new SimpleColumn(l_receiptdate))));
230 
231         tokens.push_back(Token(new Operator("and")));
232 
233         tokens.push_back(Token(new SimpleFilter(new Operator("<"),
234                                                 new SimpleColumn(l_shipdate),
235                                                 new SimpleColumn(l_commitdate))));
236 
237         tokens.push_back(Token(new Operator("and")));
238 
239         tokens.push_back(Token(new SimpleFilter(new Operator(">="),
240                                                 new SimpleColumn(l_receiptdate),
241                                                 new ConstantColumn("06/01/2005"))));
242 
243         tokens.push_back(Token(new Operator("and")));
244 
245         tokens.push_back(Token(new SimpleFilter(new Operator("<"),
246                                                 new SimpleColumn(l_receiptdate),
247                                                 new ConstantColumn("06/01/2006"))));
248 
249         // old below
250         filterList = parser.parse(tokens.begin(), tokens.end());
251 
252         // draw filterList tree
253         filterList->drawTree("selectExecutionPlan_12.dot");
254 
255         // Build Group By List
256         SimpleColumn* l_shipmode2 = new SimpleColumn("tpch.lineitem.l_shipmode");
257         groupbyList.push_back(l_shipmode2);
258 
259         // Build Order By List
260         // SimpleColumn *l_shipmode2 = new SimpleColumn("tpch.lineitem.l_shipmode");
261         orderbyList.push_back(l_shipmode2);
262 
263         // calpont execution plan
264         csep.returnedCols (colList);
265         csep.filters (filterList);
266         cout << "\nCalpont Execution Plan:" << endl;
267         cout << csep << endl;
268         cout << " --- end of test 12 ---" << endl;
269 
270         filterList->walk(walkfnString);
271 
272     }
273 
274 };
275 
276 CPPUNIT_TEST_SUITE_REGISTRATION( ExecPlanTest );
277 
278 #include <cppunit/extensions/TestFactoryRegistry.h>
279 #include <cppunit/ui/text/TestRunner.h>
280 
main(int argc,char ** argv)281 int main( int argc, char** argv)
282 {
283     CppUnit::TextUi::TestRunner runner;
284     CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
285     runner.addTest( registry.makeTest() );
286     bool wasSuccessful = runner.run( "", false );
287     return (wasSuccessful ? 0 : 1);
288 }
289 
290 
291