You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-30 07:25:34 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1525 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1525 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2014 InfiniDB, Inc.
 | |
|    Copyright (C) 2016 MariaDB Corporation
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or
 | |
|    modify it under the terms of the GNU General Public License
 | |
|    as published by the Free Software Foundation; version 2 of
 | |
|    the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 | |
|    MA 02110-1301, USA. */
 | |
| 
 | |
| #include <string>
 | |
| #include <stdexcept>
 | |
| #include <typeinfo>
 | |
| using namespace std;
 | |
| 
 | |
| #include <cppunit/extensions/HelperMacros.h>
 | |
| 
 | |
| #include <sstream>
 | |
| #include <exception>
 | |
| #include <iostream>
 | |
| #include <unistd.h>
 | |
| #include <cstdlib>
 | |
| #include <pthread.h>
 | |
| #include <values.h>
 | |
| #include <signal.h>
 | |
| #include <errno.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/ipc.h>
 | |
| #include <sys/sem.h>
 | |
| #include <sys/shm.h>
 | |
| 
 | |
| #include "configcpp.h"
 | |
| using namespace config;
 | |
| 
 | |
| #include "messagequeue.h"
 | |
| #include "bytestream.h"
 | |
| using namespace messageqcpp;
 | |
| 
 | |
| #include "calpontselectexecutionplan.h"
 | |
| #include "simplefilter.h"
 | |
| #include "simplecolumn.h"
 | |
| #include "expressionparser.h"
 | |
| #include "constantcolumn.h"
 | |
| #include "treenode.h"
 | |
| #include "operator.h"
 | |
| #include "arithmeticcolumn.h"
 | |
| #include "aggregatecolumn.h"
 | |
| #include "existsfilter.h"
 | |
| #include "functioncolumn.h"
 | |
| #include "selectfilter.h"
 | |
| #include "objectreader.h"
 | |
| #include "objectidmanager.h"
 | |
| #include "sessionmanager.h"
 | |
| #include "sessionmonitor.h"
 | |
| #include "treenodeimpl.h"
 | |
| 
 | |
| using namespace execplan;
 | |
| 
 | |
| const char* OIDBitmapFilename = NULL;
 | |
| int maxNewTxns = 1000;
 | |
| 
 | |
| class ExecPlanTest : public CppUnit::TestFixture
 | |
| {
 | |
|   CPPUNIT_TEST_SUITE(ExecPlanTest);
 | |
| 
 | |
|   CPPUNIT_TEST(selectExecutionPlan_1);
 | |
|   CPPUNIT_TEST(selectExecutionPlan_2);
 | |
|   CPPUNIT_TEST(expressionParser_1);
 | |
|   CPPUNIT_TEST(expressionParser_2);
 | |
|   CPPUNIT_TEST(aggregatecolumn_1);
 | |
|   CPPUNIT_TEST(arithmeticExpression_1);
 | |
|   CPPUNIT_TEST(arithmeticExpression_2);
 | |
|   CPPUNIT_TEST(arithmeticExpression_3);
 | |
|   CPPUNIT_TEST(copyTree);
 | |
|   CPPUNIT_TEST(treeNodeImpl);
 | |
|   CPPUNIT_TEST(serializeSimpleColumn);
 | |
|   CPPUNIT_TEST(serializeAggregateColumn);
 | |
|   CPPUNIT_TEST(serializeOperator);
 | |
|   CPPUNIT_TEST(serializeFilter);
 | |
|   CPPUNIT_TEST(serializeFunctionColumn);
 | |
|   CPPUNIT_TEST(serializeConstantColumn);
 | |
|   CPPUNIT_TEST(serializeParseTree);
 | |
|   CPPUNIT_TEST(serializeArithmeticColumn);
 | |
|   CPPUNIT_TEST(serializeSimpleFilter);
 | |
|   CPPUNIT_TEST(serializeCSEP);
 | |
|   CPPUNIT_TEST(serializeSelectFilter);
 | |
|   CPPUNIT_TEST(serializeExistsFilter);
 | |
| 
 | |
|   CPPUNIT_TEST(sessionManager_1);
 | |
|   CPPUNIT_TEST(sessionManager_2);
 | |
|   CPPUNIT_TEST(sessionManager_3);
 | |
|   CPPUNIT_TEST(sessionManager_4);
 | |
| 
 | |
|   unlink("/tmp/CalpontSessionMonitorShm");
 | |
|   // CPPUNIT_TEST( MonitorTestPlan_1 );
 | |
|   // CPPUNIT_TEST( MonitorTestPlan_1 );
 | |
|   unlink("/tmp/CalpontSessionMonitorShm");
 | |
|   CPPUNIT_TEST(objectIDManager_1);
 | |
| 
 | |
|   if (OIDBitmapFilename != NULL)
 | |
|     unlink(OIDBitmapFilename);
 | |
| 
 | |
|   CPPUNIT_TEST_SUITE_END();
 | |
| 
 | |
|  private:
 | |
|   boost::shared_ptr<CalpontSystemCatalog> csc;
 | |
| 
 | |
|  public:
 | |
|   static void walkfnString(const ParseTree* n)
 | |
|   {
 | |
|     cout << *(n->data()) << endl;
 | |
|   }
 | |
| 
 | |
|   static void walkfnInt(const ExpressionTree<int>* n)
 | |
|   {
 | |
|     cout << n->data() << endl;
 | |
|   }
 | |
| 
 | |
|   void setUp()
 | |
|   {
 | |
|     csc = CalpontSystemCatalog::makeCalpontSystemCatalog(0);
 | |
|     csc->identity(CalpontSystemCatalog::FE);
 | |
|   }
 | |
| 
 | |
|   void tearDown()
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   void selectExecutionPlan_1()
 | |
|   {
 | |
|     cout << "SQL: select region.r_regionkey from region, nation where nation.n_regionkey = "
 | |
|             "region.r_regionkey and nation.n_regionkey != 3;"
 | |
|          << endl;
 | |
| 
 | |
|     CalpontSelectExecutionPlan csep;
 | |
|     CPPUNIT_ASSERT(csep.location() == CalpontSelectExecutionPlan::MAIN);
 | |
|     CPPUNIT_ASSERT(csep.dependent() == false);
 | |
|     CPPUNIT_ASSERT(csep.subSelects().size() == 0);
 | |
| 
 | |
|     // returned columns
 | |
|     CalpontSelectExecutionPlan::ReturnedColumnList colList;
 | |
|     SimpleColumn* sc = new SimpleColumn("tpch.region.r_regionkey", 0);
 | |
|     colList.push_back(sc);
 | |
|     ArithmeticColumn* ac = new ArithmeticColumn("a+sum(r_regionkey)", 0);
 | |
|     colList.push_back(ac);
 | |
|     csep.returnedCols(colList);
 | |
|     CPPUNIT_ASSERT(csep.returnedCols().size() == 2);
 | |
| 
 | |
|     // filters
 | |
|     CalpontSelectExecutionPlan::FilterTokenList filterTokenList;
 | |
| 
 | |
|     SimpleFilter* sf = new SimpleFilter();
 | |
|     SimpleColumn* lhs = new SimpleColumn();
 | |
|     *lhs = *sc;
 | |
|     SimpleColumn* rhs = new SimpleColumn("tpch.nation.n_regionkey", 0);
 | |
|     CPPUNIT_ASSERT(*lhs == *sc);
 | |
|     CPPUNIT_ASSERT(*rhs != *lhs);
 | |
|     Operator* op = new Operator("=");
 | |
| 
 | |
|     sf->op(op);
 | |
|     sf->lhs(lhs);
 | |
|     sf->rhs(rhs);
 | |
|     filterTokenList.push_back(sf);
 | |
| 
 | |
|     filterTokenList.push_back(new Operator("And"));
 | |
|     SimpleFilter* sf1 = new SimpleFilter(new Operator("="), sc->clone(), ac->clone());
 | |
| 
 | |
|     filterTokenList.push_back(sf1);
 | |
| 
 | |
|     csep.filterTokenList(filterTokenList);
 | |
|     ParseTree* filterList = const_cast<ParseTree*>(csep.filters());
 | |
| 
 | |
|     // draw filterList tree
 | |
|     filterList->drawTree("selectExecutionPlan_1.dot");
 | |
|     csep.filters(filterList);
 | |
| 
 | |
|     // Group by
 | |
|     CalpontSelectExecutionPlan::GroupByColumnList groupByList;
 | |
|     groupByList.push_back(sc->clone());
 | |
|     csep.groupByCols(groupByList);
 | |
|     CPPUNIT_ASSERT(csep.groupByCols().size() == 1);
 | |
| 
 | |
|     // Having
 | |
|     CalpontSelectExecutionPlan::FilterTokenList havingTokenList;
 | |
|     SimpleFilter* having =
 | |
|         new SimpleFilter(new Operator("="), new ArithmeticColumn("sum(volumn)", 0), new ConstantColumn(8));
 | |
|     havingTokenList.push_back(having);
 | |
|     csep.havingTokenList(havingTokenList);
 | |
|     CPPUNIT_ASSERT(*sf1 != *having);
 | |
|     CPPUNIT_ASSERT(csep.havingTokenList().size() == 1);
 | |
| 
 | |
|     // Order by
 | |
|     CalpontSelectExecutionPlan::OrderByColumnList orderByList;
 | |
|     ArithmeticColumn* o1 = new ArithmeticColumn(*ac);
 | |
|     o1->asc(false);
 | |
|     orderByList.push_back(o1);
 | |
|     csep.orderByCols(orderByList);
 | |
|     CPPUNIT_ASSERT(csep.orderByCols().size() == 1);
 | |
| 
 | |
|     // another csep
 | |
|     CalpontSelectExecutionPlan* newcsep = new CalpontSelectExecutionPlan(CalpontSelectExecutionPlan::FROM);
 | |
|     CalpontSelectExecutionPlan::ReturnedColumnList ncolList;
 | |
|     SimpleColumn* newsc = new SimpleColumn("tpch.region.r_regionkey", 0);
 | |
|     ncolList.push_back(newsc);
 | |
|     newcsep->returnedCols(ncolList);
 | |
|     CalpontSelectExecutionPlan::FilterTokenList nfilterTokenList;
 | |
|     SimpleFilter* newsf = new SimpleFilter(new Operator(">"), sc->clone(), newsc->clone());
 | |
|     nfilterTokenList.push_back(newsf);
 | |
|     newcsep->filterTokenList(nfilterTokenList);
 | |
|     CalpontSelectExecutionPlan::FilterTokenList nhavingTokenList;
 | |
|     SimpleFilter* newhaving = new SimpleFilter(new Operator(">"), sc->clone(), newsc->clone());
 | |
|     CPPUNIT_ASSERT(*newsf == *newhaving);
 | |
|     nhavingTokenList.push_back(newhaving);
 | |
|     newcsep->havingTokenList(nhavingTokenList);
 | |
|     CPPUNIT_ASSERT(*newcsep != csep);
 | |
|     CPPUNIT_ASSERT(*newcsep->filters() == *newcsep->having());
 | |
|     ByteStream b;
 | |
|     csep.serialize(b);
 | |
|     newcsep->unserialize(b);
 | |
|     CPPUNIT_ASSERT(csep == *newcsep);
 | |
|     CalpontSelectExecutionPlan::SelectList selectList;
 | |
|     selectList.push_back(newcsep);
 | |
|     csep.subSelects(selectList);
 | |
|     cout << "\nCalpont Execution Plan:" << endl;
 | |
|     cout << csep;
 | |
|     cout << " --- end of test 1 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void selectExecutionPlan_2()
 | |
|   {
 | |
|     CalpontSelectExecutionPlan cep;
 | |
| 
 | |
|     // select filter
 | |
|     CalpontSelectExecutionPlan* subselect = new CalpontSelectExecutionPlan;
 | |
|     subselect->location(CalpontSelectExecutionPlan::WHERE);
 | |
|     subselect->dependent(false);
 | |
|     CPPUNIT_ASSERT(subselect->location() == CalpontSelectExecutionPlan::WHERE);
 | |
|     CPPUNIT_ASSERT(subselect->dependent() == false);
 | |
|     ByteStream selb;
 | |
|     subselect->serialize(selb);
 | |
|     CalpontSelectExecutionPlan* subselect1 = new CalpontSelectExecutionPlan;
 | |
|     subselect->location(CalpontSelectExecutionPlan::WHERE);
 | |
|     subselect1->unserialize(selb);
 | |
| 
 | |
|     SelectFilter* sef =
 | |
|         new SelectFilter(new SimpleColumn("tpch.region.r_regionkey", 0), new Operator(">="), subselect);
 | |
|     cout << *sef;
 | |
|     ByteStream b;
 | |
|     sef->serialize(b);
 | |
|     SelectFilter* newsef =
 | |
|         new SelectFilter(new SimpleColumn("tpch.nation.n_regionke", 0), new Operator("<="), subselect1);
 | |
|     newsef->unserialize(b);
 | |
|     CPPUNIT_ASSERT(*sef == *newsef);
 | |
|     delete sef;
 | |
|     delete newsef;
 | |
| 
 | |
|     // simple filter
 | |
|     Filter* sf = new SimpleFilter(new Operator("="), new SimpleColumn("tpch.nation.n_regionke", 0),
 | |
|                                   new SimpleColumn("tpch.region.r_regionkey", 0));
 | |
|     cout << *sf;
 | |
| 
 | |
|     ByteStream sfb;
 | |
|     SimpleFilter* sf2 = new SimpleFilter();
 | |
|     sf2->serialize(sfb);
 | |
|     sf->unserialize(sfb);
 | |
|     CPPUNIT_ASSERT(*sf == *sf2);
 | |
|     delete sf2;
 | |
|     delete sf;
 | |
| 
 | |
|     // exist filter
 | |
|     CalpontSelectExecutionPlan* cep1 = new CalpontSelectExecutionPlan();
 | |
|     ExistsFilter* filter = new ExistsFilter();
 | |
|     delete filter;
 | |
|     filter = new ExistsFilter(cep1);
 | |
|     filter->exists(cep1);
 | |
|     const CalpontSelectExecutionPlan* cep2 = filter->exists();
 | |
|     cout << *filter;
 | |
|     CPPUNIT_ASSERT(*cep1 == *cep2);
 | |
|     CalpontSelectExecutionPlan::Parser parser;
 | |
|     std::vector<Token> tokens;
 | |
|     Token t;
 | |
|     t.value = filter;
 | |
|     tokens.push_back(t);
 | |
|     cep.filters(parser.parse(tokens.begin(), tokens.end()));
 | |
|     cout << cep;
 | |
| 
 | |
|     cout << " --- end of test 2 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void expressionParser_1()
 | |
|   {
 | |
|     cout << "\nPost order of int expression tree(pointer):" << endl;
 | |
|     ExpressionTree<int>* et = new ExpressionTree<int>(3);
 | |
|     ExpressionTree<int>* et1 = new ExpressionTree<int>(5);
 | |
|     ExpressionTree<int>* et2 = new ExpressionTree<int>(6);
 | |
|     et->left(et1);
 | |
|     et->right(et2);
 | |
|     et->walk(walkfnInt);
 | |
|     et->destroyTree(et);
 | |
|     cout << " --- end of test 3 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void expressionParser_2()
 | |
|   {
 | |
|     cout << "\nPost order of int expression tree (reference):" << endl;
 | |
|     ExpressionTree<int> et(3);
 | |
|     ExpressionTree<int> et1(5);
 | |
|     ExpressionTree<int> et2(6);
 | |
|     et.left(&et1);
 | |
|     et.right(&et2);
 | |
|     et.walk(walkfnInt);
 | |
|     cout << " --- end of test 4 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void aggregatecolumn_1()
 | |
|   {
 | |
|     cout << "\naggregate column: " << endl;
 | |
|     AggregateColumn a;
 | |
|     cout << a;
 | |
|     cout << "\nsum(p_type)" << endl;
 | |
|     AggregateColumn d("sum", "p_type");
 | |
|     cout << d;
 | |
|     a.functionName("avg");
 | |
|     ArithmeticColumn* b = new ArithmeticColumn("a-(b-c)");
 | |
|     a.functionParms(b);
 | |
|     CPPUNIT_ASSERT(a.functionName() == "avg");
 | |
|     cout << *const_cast<ReturnedColumn*>(a.functionParms());
 | |
|     cout << " --- end of test 5 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void arithmeticExpression_1()
 | |
|   {
 | |
|     cout << "\narithmetic expression: " << endl;
 | |
|     string exp(
 | |
|         "substr(a)+ 100.00 * sum(tpch.part.p_type) / sum(tpch.lineitem.l_extendedprice "
 | |
|         "*(1-tpch.lineitem.l_discount))");
 | |
|     cout << exp << endl;
 | |
|     ArithmeticColumn a(exp, 0);
 | |
|     ParseTree* pt = const_cast<ParseTree*>(a.expression());
 | |
| 
 | |
|     if (pt != NULL)
 | |
|     {
 | |
|       pt->walk(walkfnString);
 | |
|       pt->drawTree("arithmeticExpression_1.dot");
 | |
|     }
 | |
| 
 | |
|     cout << " --- end of test 6 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void copyTree()
 | |
|   {
 | |
|     // cout << "\narithmetic expression: " << endl;
 | |
|     string exp(
 | |
|         "substr(a)+ 100.00 * sum(tpch.part.p_type) / sum(tpch.lineitem.l_extendedprice "
 | |
|         "*(1-tpch.lineitem.l_discount))");
 | |
|     ArithmeticColumn a(exp);
 | |
|     ParseTree* pt = const_cast<ParseTree*>(a.expression());
 | |
| 
 | |
|     ParseTree* newTree = new ParseTree();
 | |
| 
 | |
|     // copy 1st time
 | |
|     newTree->copyTree(*pt);
 | |
| 
 | |
|     // copy 2nd time, see if the existing tree is deleted.
 | |
|     newTree->copyTree(*pt);
 | |
| 
 | |
|     // explicitly delete the 2nd copied tree
 | |
|     delete newTree;
 | |
|   }
 | |
| 
 | |
|   void arithmeticExpression_2()
 | |
|   {
 | |
|     cout << "\nbuild arithmetic column by using accessing methods:" << endl;
 | |
|     CalpontSelectExecutionPlan::Parser parser;
 | |
|     std::vector<Token> tokens;
 | |
|     Token t;
 | |
| 
 | |
|     ArithmeticColumn b;
 | |
|     cout << b;
 | |
| 
 | |
|     ConstantColumn* c1 = new ConstantColumn();
 | |
|     c1->constval("'ASIA'");
 | |
|     c1->type(ConstantColumn::LITERAL);
 | |
|     // CPPUNIT_ASSERT (c1->data() == "'ASIA'(l)");
 | |
| 
 | |
|     t.value = c1;
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     t.value = new Operator("/");
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     ConstantColumn* c2 = new ConstantColumn(5);
 | |
|     CPPUNIT_ASSERT(c2->type() == ConstantColumn::NUM);
 | |
|     t.value = c2;
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     ParseTree* tree = parser.parse(tokens.begin(), tokens.end());
 | |
|     b.expression(tree);
 | |
| 
 | |
|     cout << b;
 | |
|     cout << " --- end of test 7 ---" << endl;
 | |
|   }
 | |
| 
 | |
|   void arithmeticExpression_3()
 | |
|   {
 | |
|     // invalid expression test
 | |
|     try
 | |
|     {
 | |
|       ArithmeticColumn a("-a+b", 0);
 | |
|       ArithmeticColumn d("a* b-", 0);
 | |
|     }
 | |
|     catch (const runtime_error& e)
 | |
|     {
 | |
|       cerr << e.what() << endl;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       ArithmeticColumn e("a+substr (c from 1 4", 0);
 | |
|     }
 | |
|     catch (const runtime_error& e)
 | |
|     {
 | |
|       cerr << e.what() << endl;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       ArithmeticColumn f("a + b c", 0);
 | |
|     }
 | |
|     catch (const runtime_error& e)
 | |
|     {
 | |
|       cerr << e.what() << endl;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       ArithmeticColumn b("a + ((b+ c -e)", 0);
 | |
|     }
 | |
|     catch (const runtime_error& e)
 | |
|     {
 | |
|       cerr << e.what() << endl;
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       ArithmeticColumn g("a ++ b", 0);  // valid
 | |
|     }
 | |
|     catch (const runtime_error& e)
 | |
|     {
 | |
|       cerr << e.what() << endl;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void treeNodeImpl()
 | |
|   {
 | |
|     TreeNodeImpl* node1 = new TreeNodeImpl();
 | |
|     TreeNodeImpl* node2 = new TreeNodeImpl("node2");
 | |
|     CPPUNIT_ASSERT(node2->data() == "node2");
 | |
|     CPPUNIT_ASSERT(*node1 != *node2);
 | |
| 
 | |
|     ByteStream b;
 | |
|     node2->serialize(b);
 | |
|     node1->unserialize(b);
 | |
|     CPPUNIT_ASSERT(*node1 == *node2);
 | |
| 
 | |
|     node2->data("node3");
 | |
|     cout << *node2;
 | |
| 
 | |
|     TreeNodeImpl* node4 = node2->clone();
 | |
|     CPPUNIT_ASSERT(*node2 == node4);
 | |
| 
 | |
|     delete node1;
 | |
|     delete node2;
 | |
|     delete node4;
 | |
|   }
 | |
| 
 | |
|   void serializeSimpleColumn()
 | |
|   {
 | |
|     SimpleColumn s1, s2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &s2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(s1 == s2);
 | |
|     CPPUNIT_ASSERT(!(s1 != s2));
 | |
|     CPPUNIT_ASSERT(s1 == t);
 | |
|     CPPUNIT_ASSERT(!(s1 != t));
 | |
| 
 | |
|     s1.schemaName("Schema Name 1");
 | |
|     s1.tableName("Table Name 1");
 | |
|     s1.columnName("Column Name 1");
 | |
|     // s1.tcn(5);
 | |
|     s1.data("sc1");
 | |
| 
 | |
|     s1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(s2.schemaName() == "");
 | |
|     CPPUNIT_ASSERT(s2.tableName() == "");
 | |
|     CPPUNIT_ASSERT(s2.columnName() == "");
 | |
|     // CPPUNIT_ASSERT(s2.tcn() == 0);
 | |
| 
 | |
|     CPPUNIT_ASSERT(s1 != s2);
 | |
|     CPPUNIT_ASSERT(s1 == s1);
 | |
|     CPPUNIT_ASSERT(s1 != t);
 | |
|     CPPUNIT_ASSERT(!(s1 == t));
 | |
| 
 | |
|     s2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
| 
 | |
|     CPPUNIT_ASSERT(s2.schemaName() == "Schema Name 1");
 | |
|     CPPUNIT_ASSERT(s2.tableName() == "Table Name 1");
 | |
|     CPPUNIT_ASSERT(s2.columnName() == "Column Name 1");
 | |
|     // CPPUNIT_ASSERT(s2.tcn() == 5);
 | |
|     CPPUNIT_ASSERT(s2.data() == "sc1");
 | |
| 
 | |
|     CPPUNIT_ASSERT(s1 == s2);
 | |
|     CPPUNIT_ASSERT(!(s1 != s2));
 | |
|     CPPUNIT_ASSERT(s1 == t);
 | |
|     CPPUNIT_ASSERT(!(s1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeAggregateColumn()
 | |
|   {
 | |
|     AggregateColumn a1, a2;
 | |
|     SimpleColumn* s1;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &a2;
 | |
| 
 | |
|     s1 = new SimpleColumn();
 | |
| 
 | |
|     CPPUNIT_ASSERT(a1 == a2);
 | |
|     CPPUNIT_ASSERT(!(a1 != a2));
 | |
|     CPPUNIT_ASSERT(a1 == t);
 | |
|     CPPUNIT_ASSERT(!(a1 != t));
 | |
| 
 | |
|     a1.functionName("AggregateColumn test");
 | |
|     a1.data("agg1");
 | |
|     a1.functionParms(s1);
 | |
| 
 | |
|     a1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(a2.functionName() == "");
 | |
|     CPPUNIT_ASSERT(a2.data() == "");
 | |
|     CPPUNIT_ASSERT(a2.functionParms() == NULL);
 | |
| 
 | |
|     CPPUNIT_ASSERT(a1 != a2);
 | |
|     CPPUNIT_ASSERT(!(a1 == a2));
 | |
|     CPPUNIT_ASSERT(a1 != t);
 | |
|     CPPUNIT_ASSERT(!(a1 == t));
 | |
| 
 | |
|     a2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
| 
 | |
|     CPPUNIT_ASSERT(a2.functionName() == "AggregateColumn test");
 | |
|     CPPUNIT_ASSERT(a2.data() == "agg1");
 | |
|     CPPUNIT_ASSERT(a2.functionParms() != NULL);
 | |
|     CPPUNIT_ASSERT(*(a2.functionParms()) == s1);
 | |
| 
 | |
|     CPPUNIT_ASSERT(a1 == a2);
 | |
|     CPPUNIT_ASSERT(!(a1 != a2));
 | |
|     CPPUNIT_ASSERT(a1 == t);
 | |
|     CPPUNIT_ASSERT(!(a1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeOperator()
 | |
|   {
 | |
|     Operator o1, o2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &o2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(o1 == o2);
 | |
|     CPPUNIT_ASSERT(!(o1 != o2));
 | |
|     CPPUNIT_ASSERT(o1 == t);
 | |
|     CPPUNIT_ASSERT(!(o1 != t));
 | |
| 
 | |
|     o1.data("=");
 | |
| 
 | |
|     CPPUNIT_ASSERT(o1 != o2);
 | |
|     CPPUNIT_ASSERT(!(o1 == o2));
 | |
|     CPPUNIT_ASSERT(o1 != t);
 | |
|     CPPUNIT_ASSERT(!(o1 == t));
 | |
| 
 | |
|     o1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(o2.data() == "");
 | |
|     o2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(o2.data() == "=");
 | |
| 
 | |
|     CPPUNIT_ASSERT(o1 == o2);
 | |
|     CPPUNIT_ASSERT(!(o1 != o2));
 | |
|     CPPUNIT_ASSERT(o1 == t);
 | |
|     CPPUNIT_ASSERT(!(o1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeFilter()
 | |
|   {
 | |
|     Filter f1, f2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &f2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(f1 == f2);
 | |
|     CPPUNIT_ASSERT(!(f1 != f2));
 | |
|     CPPUNIT_ASSERT(f1 == t);
 | |
|     CPPUNIT_ASSERT(!(f1 != t));
 | |
| 
 | |
|     f1.data("Filter test");
 | |
| 
 | |
|     CPPUNIT_ASSERT(f1 != f2);
 | |
|     CPPUNIT_ASSERT(!(f1 == f2));
 | |
|     CPPUNIT_ASSERT(f1 != t);
 | |
|     CPPUNIT_ASSERT(!(f1 == t));
 | |
| 
 | |
|     f1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(f2.data() == "");
 | |
|     f2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(f2.data() == "Filter test");
 | |
| 
 | |
|     CPPUNIT_ASSERT(f1 == f2);
 | |
|     CPPUNIT_ASSERT(!(f1 != f2));
 | |
|     CPPUNIT_ASSERT(f1 == t);
 | |
|     CPPUNIT_ASSERT(!(f1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeFunctionColumn()
 | |
|   {
 | |
|     FunctionColumn fc1, fc2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &fc2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(fc1 == fc2);
 | |
|     CPPUNIT_ASSERT(!(fc1 != fc2));
 | |
|     CPPUNIT_ASSERT(fc1 == t);
 | |
|     CPPUNIT_ASSERT(!(fc1 != t));
 | |
| 
 | |
|     /* FunctionColumn */
 | |
|     fc1.sessionID(0);
 | |
|     fc1.functionName("FunctionColumn test");
 | |
|     fc1.functionParms("tpch.region.r_regionkey, tpch.nation.n_nationkey");
 | |
|     fc1.data("fc1");
 | |
| 
 | |
|     CPPUNIT_ASSERT(fc1 != fc2);
 | |
|     CPPUNIT_ASSERT(!(fc1 == fc2));
 | |
|     CPPUNIT_ASSERT(fc1 != t);
 | |
|     CPPUNIT_ASSERT(!(fc1 == t));
 | |
| 
 | |
|     FunctionColumn::FunctionParm functionParms;
 | |
|     functionParms = fc1.functionParms();
 | |
|     CPPUNIT_ASSERT(functionParms.size() == 2);
 | |
| 
 | |
|     fc1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(fc2.functionName() == "");
 | |
|     CPPUNIT_ASSERT(fc2.functionParms().size() == 0);
 | |
| 
 | |
|     fc2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(fc2.functionName() == "FunctionColumn test");
 | |
|     CPPUNIT_ASSERT(fc2.functionParms().size() == 2);
 | |
|     functionParms = fc2.functionParms();
 | |
|     CPPUNIT_ASSERT(functionParms.size() == 2);
 | |
| 
 | |
|     CPPUNIT_ASSERT(fc1 == fc2);
 | |
|     CPPUNIT_ASSERT(!(fc1 != fc2));
 | |
|     CPPUNIT_ASSERT(fc1 == t);
 | |
|     CPPUNIT_ASSERT(!(fc1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeConstantColumn()
 | |
|   {
 | |
|     ConstantColumn c1, c2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &c2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(c1 == c2);
 | |
|     CPPUNIT_ASSERT(!(c1 != c2));
 | |
|     CPPUNIT_ASSERT(c1 == t);
 | |
|     CPPUNIT_ASSERT(!(c1 != t));
 | |
| 
 | |
|     c1.type(5);
 | |
|     c1.constval("ConstantColumn test");
 | |
|     c1.data("c1");
 | |
| 
 | |
|     CPPUNIT_ASSERT(c1 != c2);
 | |
|     CPPUNIT_ASSERT(!(c1 == c2));
 | |
|     CPPUNIT_ASSERT(c1 != t);
 | |
|     CPPUNIT_ASSERT(!(c1 == t));
 | |
| 
 | |
|     c1.serialize(b);
 | |
|     CPPUNIT_ASSERT(c2.constval() == "");
 | |
|     c2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(c2.type() == 5);
 | |
|     CPPUNIT_ASSERT(c2.constval() == "ConstantColumn test");
 | |
| 
 | |
|     CPPUNIT_ASSERT(c1 == c2);
 | |
|     CPPUNIT_ASSERT(!(c1 != c2));
 | |
|     CPPUNIT_ASSERT(c1 == t);
 | |
|     CPPUNIT_ASSERT(!(c1 != t));
 | |
|   }
 | |
| 
 | |
|   ParseTree* makeParseTree()
 | |
|   {
 | |
|     ParseTree* t[5];
 | |
|     SimpleColumn* s[5];
 | |
|     int i;
 | |
| 
 | |
|     /* ParseTree (ExpressionTree<TreeNode*>) */
 | |
| 
 | |
|     /*
 | |
|                    t0(s0)
 | |
|                     /  \
 | |
|                   s1   s2
 | |
|                   /      \
 | |
|                 s3       s4
 | |
|     */
 | |
| 
 | |
|     for (i = 0; i < 5; i++)
 | |
|     {
 | |
|       t[i] = new ParseTree(NULL);
 | |
|       s[i] = new SimpleColumn();
 | |
|       t[i]->data(s[i]);
 | |
|     }
 | |
| 
 | |
|     s[0]->schemaName("Schema Name 0");
 | |
|     s[1]->schemaName("Schema Name 1");
 | |
|     s[2]->schemaName("Schema Name 2");
 | |
|     s[3]->schemaName("Schema Name 3");
 | |
|     s[4]->schemaName("Schema Name 4");
 | |
| 
 | |
|     t[0]->left(t[1]);
 | |
|     t[0]->right(t[2]);
 | |
|     t[1]->left(t[3]);
 | |
|     t[2]->right(t[4]);
 | |
| 
 | |
|     return t[0];
 | |
|   }
 | |
| 
 | |
|   void verifyParseTree(const ParseTree* t)
 | |
|   {
 | |
|     const ParseTree *ct, *ct2;
 | |
|     SimpleColumn* s;
 | |
| 
 | |
|     CPPUNIT_ASSERT(t != NULL);
 | |
|     s = dynamic_cast<SimpleColumn*>(t->data());
 | |
|     CPPUNIT_ASSERT(s != NULL);
 | |
|     CPPUNIT_ASSERT(s->schemaName() == "Schema Name 0");
 | |
|     ct = t->left();
 | |
|     CPPUNIT_ASSERT(ct != NULL);
 | |
|     s = dynamic_cast<SimpleColumn*>(ct->data());
 | |
|     CPPUNIT_ASSERT(s != NULL);
 | |
|     CPPUNIT_ASSERT(s->schemaName() == "Schema Name 1");
 | |
|     ct2 = ct->left();
 | |
|     CPPUNIT_ASSERT(ct2 != NULL);
 | |
|     s = dynamic_cast<SimpleColumn*>(ct2->data());
 | |
|     CPPUNIT_ASSERT(s != NULL);
 | |
|     CPPUNIT_ASSERT(s->schemaName() == "Schema Name 3");
 | |
|     CPPUNIT_ASSERT(ct->right() == NULL);
 | |
|     CPPUNIT_ASSERT(ct2->left() == NULL);
 | |
|     CPPUNIT_ASSERT(ct2->right() == NULL);
 | |
|     ct = t->right();
 | |
|     CPPUNIT_ASSERT(ct != NULL);
 | |
|     s = dynamic_cast<SimpleColumn*>(ct->data());
 | |
|     CPPUNIT_ASSERT(s != NULL);
 | |
|     CPPUNIT_ASSERT(s->schemaName() == "Schema Name 2");
 | |
|     ct2 = ct->right();
 | |
|     CPPUNIT_ASSERT(ct2 != NULL);
 | |
|     s = dynamic_cast<SimpleColumn*>(ct2->data());
 | |
|     CPPUNIT_ASSERT(s != NULL);
 | |
|     CPPUNIT_ASSERT(s->schemaName() == "Schema Name 4");
 | |
|     CPPUNIT_ASSERT(ct->left() == NULL);
 | |
|     CPPUNIT_ASSERT(ct2->left() == NULL);
 | |
|     CPPUNIT_ASSERT(ct2->right() == NULL);
 | |
|   }
 | |
| 
 | |
|   void serializeParseTree()
 | |
|   {
 | |
|     ByteStream b;
 | |
|     ParseTree *t, *tmodel;
 | |
| 
 | |
|     t = makeParseTree();
 | |
|     tmodel = makeParseTree();
 | |
|     verifyParseTree(t);  // sanity check on the test itself
 | |
| 
 | |
|     CPPUNIT_ASSERT(*t == *tmodel);
 | |
|     CPPUNIT_ASSERT(!(*t != *tmodel));
 | |
| 
 | |
|     ObjectReader::writeParseTree(t, b);
 | |
| 
 | |
|     delete t;
 | |
| 
 | |
|     t = ObjectReader::createParseTree(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(t != NULL);
 | |
|     verifyParseTree(t);
 | |
| 
 | |
|     CPPUNIT_ASSERT(*t == *tmodel);
 | |
|     CPPUNIT_ASSERT(!(*t != *tmodel));
 | |
| 
 | |
|     delete t;
 | |
|     delete tmodel;
 | |
|   }
 | |
| 
 | |
|   ArithmeticColumn* makeArithmeticColumn()
 | |
|   {
 | |
|     ArithmeticColumn* ret;
 | |
|     ParseTree* t;
 | |
| 
 | |
|     t = makeParseTree();
 | |
|     ret = new ArithmeticColumn();
 | |
|     ret->expression(t);
 | |
|     ret->alias("ArithmeticColumn");
 | |
|     ret->data("AD");
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   void serializeArithmeticColumn()
 | |
|   {
 | |
|     ParseTree* t;
 | |
|     const ParseTree* ct;
 | |
|     ArithmeticColumn ac, ac2;
 | |
|     TreeNode* tn;
 | |
|     ByteStream b;
 | |
| 
 | |
|     tn = &ac2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(ac == ac2);
 | |
|     CPPUNIT_ASSERT(!(ac != ac2));
 | |
|     CPPUNIT_ASSERT(ac == tn);
 | |
|     CPPUNIT_ASSERT(!(ac != tn));
 | |
| 
 | |
|     t = makeParseTree();
 | |
| 
 | |
|     ac.expression(t);
 | |
|     ac.alias("ArithmeticColumn");
 | |
|     ac.data("AD");
 | |
| 
 | |
|     CPPUNIT_ASSERT(ac != ac2);
 | |
|     CPPUNIT_ASSERT(!(ac == ac2));
 | |
|     CPPUNIT_ASSERT(ac != tn);
 | |
|     CPPUNIT_ASSERT(!(ac == tn));
 | |
| 
 | |
|     ac.serialize(b);
 | |
|     ac2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     ct = ac2.expression();
 | |
|     verifyParseTree(ct);
 | |
|     CPPUNIT_ASSERT(ac2.alias() == "ArithmeticColumn");
 | |
|     CPPUNIT_ASSERT(ac2.data() == "AD");
 | |
| 
 | |
|     CPPUNIT_ASSERT(ac == ac2);
 | |
|     CPPUNIT_ASSERT(!(ac != ac2));
 | |
|     CPPUNIT_ASSERT(ac == tn);
 | |
|     CPPUNIT_ASSERT(!(ac != tn));
 | |
|   }
 | |
| 
 | |
|   void serializeSimpleFilter()
 | |
|   {
 | |
|     ArithmeticColumn *pac1, *pac2;
 | |
|     const ArithmeticColumn *cpac1, *cpac2;
 | |
|     SimpleFilter sf1, sf2;
 | |
|     Operator* o1;
 | |
|     const Operator* co2;
 | |
|     TreeNode* t;
 | |
|     ByteStream b;
 | |
| 
 | |
|     t = &sf2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(sf1 == sf2);
 | |
|     CPPUNIT_ASSERT(!(sf1 != sf2));
 | |
|     CPPUNIT_ASSERT(sf1 == t);
 | |
|     CPPUNIT_ASSERT(!(sf1 != t));
 | |
| 
 | |
|     pac1 = makeArithmeticColumn();
 | |
|     pac2 = makeArithmeticColumn();
 | |
| 
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(pac1 != NULL);
 | |
|     CPPUNIT_ASSERT(pac2 != NULL);
 | |
| 
 | |
|     o1 = new Operator("=");
 | |
|     sf1.lhs(pac1);
 | |
|     sf1.rhs(pac2);
 | |
|     sf1.op(o1);
 | |
| 
 | |
|     sf1.serialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(sf1 != sf2);
 | |
|     CPPUNIT_ASSERT(!(sf1 == sf2));
 | |
|     CPPUNIT_ASSERT(sf1 != t);
 | |
|     CPPUNIT_ASSERT(!(sf1 == t));
 | |
| 
 | |
|     sf2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
| 
 | |
|     cpac1 = dynamic_cast<const ArithmeticColumn*>(sf2.lhs());
 | |
|     CPPUNIT_ASSERT(cpac1 != NULL);
 | |
|     verifyParseTree(cpac1->expression());
 | |
|     cpac2 = dynamic_cast<const ArithmeticColumn*>(sf2.rhs());
 | |
|     CPPUNIT_ASSERT(cpac2 != NULL);
 | |
|     verifyParseTree(cpac2->expression());
 | |
|     co2 = sf2.op();
 | |
|     CPPUNIT_ASSERT(co2 != NULL);
 | |
|     CPPUNIT_ASSERT(co2->data() == o1->data());
 | |
| 
 | |
|     CPPUNIT_ASSERT(sf1 == sf2);
 | |
|     CPPUNIT_ASSERT(!(sf1 != sf2));
 | |
|     CPPUNIT_ASSERT(sf1 == t);
 | |
|     CPPUNIT_ASSERT(!(sf1 != t));
 | |
|   }
 | |
| 
 | |
|   void serializeCSEP()
 | |
|   {
 | |
|     /*
 | |
|      * CalpontSelectExecutionPlan
 | |
|      * This is a large class; it makes more sense to write == operators
 | |
|      * for everything than to write a giant equivalance test here.
 | |
|      * For now this is mostly a regression test.
 | |
|      */
 | |
| 
 | |
|     CalpontSelectExecutionPlan csep1, csep2;
 | |
|     CalpontSelectExecutionPlan::ReturnedColumnList colList;
 | |
|     ParseTree* filterList;
 | |
|     CalpontExecutionPlan* cep;
 | |
|     ByteStream b;
 | |
| 
 | |
|     cep = &csep2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(csep1 == csep2);
 | |
|     CPPUNIT_ASSERT(!(csep1 != csep2));
 | |
|     CPPUNIT_ASSERT(csep1 == cep);
 | |
|     CPPUNIT_ASSERT(!(csep1 != cep));
 | |
| 
 | |
|     // returned columns
 | |
|     SimpleColumn* sc = new SimpleColumn("tpch.region.r_regionkey");
 | |
|     colList.push_back(sc);
 | |
| 
 | |
|     // filters
 | |
|     CalpontSelectExecutionPlan::Parser parser;
 | |
|     std::vector<Token> tokens;
 | |
|     Token t;
 | |
| 
 | |
|     SimpleFilter* sf = new SimpleFilter();
 | |
|     SimpleColumn* lhs = new SimpleColumn(*sc);
 | |
|     SimpleColumn* rhs = new SimpleColumn("tpch.nation.n_regionkey");
 | |
|     Operator* op = new Operator("=");
 | |
| 
 | |
|     sf->op(op);
 | |
|     sf->lhs(lhs);
 | |
|     sf->rhs(rhs);
 | |
| 
 | |
|     t.value = sf;
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     Operator* op1 = new Operator("and");
 | |
|     t.value = op1;
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     SimpleFilter* sf1 = new SimpleFilter();
 | |
|     SimpleColumn* lhs1 = new SimpleColumn(*rhs);
 | |
|     ConstantColumn* constCol = new ConstantColumn("3", ConstantColumn::NUM);
 | |
|     Operator* op2 = new Operator("!=");
 | |
| 
 | |
|     sf1->op(op2);
 | |
|     sf1->lhs(lhs1);
 | |
|     sf1->rhs(constCol);
 | |
| 
 | |
|     t.value = sf1;
 | |
|     tokens.push_back(t);
 | |
| 
 | |
|     filterList = parser.parse(tokens.begin(), tokens.end());
 | |
| 
 | |
|     // draw filterList tree
 | |
|     filterList->drawTree("selectExecutionPlan_1.dot");
 | |
| 
 | |
|     // calpont execution plan
 | |
|     csep1.returnedCols(colList);
 | |
|     csep1.filters(filterList);
 | |
| 
 | |
|     CPPUNIT_ASSERT(csep1 != csep2);
 | |
|     CPPUNIT_ASSERT(!(csep1 == csep2));
 | |
|     CPPUNIT_ASSERT(csep1 != cep);
 | |
|     CPPUNIT_ASSERT(!(csep1 == cep));
 | |
| 
 | |
|     csep1.serialize(b);
 | |
|     csep2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
| 
 | |
|     CPPUNIT_ASSERT(csep1 == csep2);
 | |
|     CPPUNIT_ASSERT(!(csep1 != csep2));
 | |
|     CPPUNIT_ASSERT(csep1 == cep);
 | |
|     CPPUNIT_ASSERT(!(csep1 != cep));
 | |
| 
 | |
|     CalpontSelectExecutionPlan csep3, csep4;
 | |
| 
 | |
|     // subselect
 | |
|     CalpontSelectExecutionPlan* subselect = new CalpontSelectExecutionPlan;
 | |
|     subselect->location(CalpontSelectExecutionPlan::WHERE);
 | |
|     subselect->dependent(false);
 | |
|     CPPUNIT_ASSERT(subselect->location() == CalpontSelectExecutionPlan::WHERE);
 | |
|     CPPUNIT_ASSERT(subselect->dependent() == false);
 | |
|     CalpontSelectExecutionPlan::SelectList selectList;
 | |
|     selectList.push_back(subselect);
 | |
|     csep3.subSelects(selectList);
 | |
| 
 | |
|     // exist filter
 | |
|     CalpontSelectExecutionPlan* cep1 = new CalpontSelectExecutionPlan();
 | |
|     ExistsFilter* filter = new ExistsFilter();
 | |
|     delete filter;
 | |
|     filter = new ExistsFilter(cep1);
 | |
|     filter->exists(cep1);
 | |
|     // CalpontSelectExecutionPlan* cep2 = const_cast<CalpontSelectExecutionPlan*>(filter->exists());
 | |
| 
 | |
|     CalpontSelectExecutionPlan::Parser parser1;
 | |
|     std::vector<Token> tokens1;
 | |
|     Token t1;
 | |
|     t1.value = filter;
 | |
|     tokens1.push_back(t1);
 | |
|     csep3.filters(parser1.parse(tokens1.begin(), tokens1.end()));
 | |
| 
 | |
|     csep3.serialize(b);
 | |
|     csep4.unserialize(b);
 | |
| 
 | |
|     CPPUNIT_ASSERT(csep3 == csep4);
 | |
|     CPPUNIT_ASSERT(!(csep3 != csep4));
 | |
|   }
 | |
| 
 | |
|   void serializeSelectFilter()
 | |
|   {
 | |
|     ByteStream b;
 | |
|     ArithmeticColumn* pac1;
 | |
|     Operator* o1;
 | |
|     const Operator* co2;
 | |
|     CalpontSelectExecutionPlan csep1;
 | |
|     SelectFilter sel1, sel2;
 | |
|     const ArithmeticColumn* cpac1;
 | |
|     const ParseTree* ct;
 | |
|     TreeNode* t;
 | |
| 
 | |
|     t = &sel2;
 | |
| 
 | |
|     CPPUNIT_ASSERT(sel1 == sel2);
 | |
|     CPPUNIT_ASSERT(!(sel1 != sel2));
 | |
|     CPPUNIT_ASSERT(sel1 == t);
 | |
|     CPPUNIT_ASSERT(!(sel1 != t));
 | |
| 
 | |
|     pac1 = makeArithmeticColumn();
 | |
|     o1 = new Operator("=");
 | |
|     sel1.lhs(pac1);
 | |
|     sel1.op(o1);
 | |
| 
 | |
|     CPPUNIT_ASSERT(sel1 != sel2);
 | |
|     CPPUNIT_ASSERT(!(sel1 == sel2));
 | |
|     CPPUNIT_ASSERT(sel1 != t);
 | |
|     CPPUNIT_ASSERT(!(sel1 == t));
 | |
| 
 | |
|     sel1.serialize(b);
 | |
|     sel2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
| 
 | |
|     CPPUNIT_ASSERT(sel1 == sel2);
 | |
|     CPPUNIT_ASSERT(!(sel1 != sel2));
 | |
|     CPPUNIT_ASSERT(sel1 == t);
 | |
|     CPPUNIT_ASSERT(!(sel1 != t));
 | |
| 
 | |
|     cpac1 = dynamic_cast<const ArithmeticColumn*>(sel2.lhs());
 | |
|     CPPUNIT_ASSERT(cpac1 != NULL);
 | |
|     ct = cpac1->expression();
 | |
|     verifyParseTree(ct);
 | |
|     co2 = sel2.op();
 | |
|     CPPUNIT_ASSERT(co2 != NULL);
 | |
|     CPPUNIT_ASSERT(co2->data() == o1->data());
 | |
|   }
 | |
| 
 | |
|   /* ExistFilters get tested as part of the CSEP test at the moment. */
 | |
|   void serializeExistsFilter()
 | |
|   {
 | |
|     ExistsFilter ef1, ef2;
 | |
|     ByteStream b;
 | |
| 
 | |
|     ef2.data("ExistsFilter test");
 | |
|     ef1.serialize(b);
 | |
|     ef2.unserialize(b);
 | |
|     CPPUNIT_ASSERT(b.length() == 0);
 | |
|     CPPUNIT_ASSERT(ef2.data() == "");
 | |
|   }
 | |
| 
 | |
|   void objectIDManager_1()
 | |
|   {
 | |
|     int oid, oidBase;
 | |
| 
 | |
|     // fake out the objmgr...
 | |
|     setenv("CALPONT_CONFIG_FILE", "/usr/local/mariadb/columnstore/etc/Columnstore.xml", 1);
 | |
|     Config* cf = Config::makeConfig();
 | |
|     cf->setConfig("OIDManager", "OIDBitmapFile", "./oidbitmap");
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       ObjectIDManager o;
 | |
| 
 | |
|       OIDBitmapFilename = strdup(o.getFilename().c_str());
 | |
|       oidBase = o.allocOID();
 | |
|       oid = o.allocOID();
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 1);
 | |
|       oid = o.allocOIDs(20);
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 2);
 | |
|       oid = o.allocOIDs(20);
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 22);
 | |
|       o.returnOID(oidBase + 5);
 | |
|       oid = o.allocOID();
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 5);
 | |
|       o.returnOID(oidBase + 5);
 | |
|       oid = o.allocOIDs(20);
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 42);
 | |
|       oid = o.allocOID();
 | |
|       CPPUNIT_ASSERT(oid == oidBase + 5);
 | |
|       o.returnOIDs(oidBase, oidBase + 61);
 | |
|       oid = o.allocOID();
 | |
|       CPPUNIT_ASSERT(oid == oidBase);
 | |
|       o.returnOID(0);
 | |
|     }
 | |
|     catch (...)
 | |
|     {
 | |
|       if (OIDBitmapFilename != NULL)
 | |
|         unlink(OIDBitmapFilename);  // XXXPAT: fix this when libstdc++ regains its sanity
 | |
| 
 | |
|       throw;
 | |
|     }
 | |
| 
 | |
|     unlink(OIDBitmapFilename);
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|    * destroySemaphores() and destroyShmseg() will print error messages
 | |
|    * if there are no objects to destroy.  That's OK.
 | |
|    */
 | |
|   void destroySemaphores()
 | |
|   {
 | |
|     key_t semkey;
 | |
|     int sems, err;
 | |
| 
 | |
|     semkey = SESSIONMANAGER_SYSVKEY;
 | |
|     sems = semget(semkey, 2, 0666);
 | |
| 
 | |
|     if (sems != -1)
 | |
|     {
 | |
|       err = semctl(sems, 0, IPC_RMID);
 | |
| 
 | |
|       if (err == -1)
 | |
|         perror("tdriver: semctl");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void destroyShmseg()
 | |
|   {
 | |
|     key_t shmkey;
 | |
|     int shms, err;
 | |
| 
 | |
|     shmkey = SESSIONMANAGER_SYSVKEY;
 | |
|     shms = shmget(shmkey, 0, 0666);
 | |
| 
 | |
|     if (shms != -1)
 | |
|     {
 | |
|       err = shmctl(shms, IPC_RMID, NULL);
 | |
| 
 | |
|       if (err == -1 && errno != EINVAL)
 | |
|       {
 | |
|         perror("tdriver: shmctl");
 | |
|         return;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void sessionManager_1()
 | |
|   {
 | |
|     SessionManager* sm = NULL;
 | |
|     SessionManager::TxnID txn;
 | |
|     const SessionManager::SIDTIDEntry* activeTxns;
 | |
|     int len;
 | |
|     string filename;
 | |
| 
 | |
|     // 		destroySemaphores();
 | |
|     // 		destroyShmseg();
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       sm = new SessionManager();
 | |
|       // CPPUNIT_ASSERT(sm->verID() == 0);
 | |
|       filename = sm->getTxnIDFilename();
 | |
|       delete sm;
 | |
|       sm = new SessionManager();
 | |
|       txn = sm->newTxnID(0);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 1);
 | |
|       // 			CPPUNIT_ASSERT(sm->verID() == 1);
 | |
|       txn = sm->newTxnID(1);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 2);
 | |
|       // 			CPPUNIT_ASSERT(sm->verID() == 2);
 | |
|       activeTxns = sm->SIDTIDMap(len);
 | |
|       CPPUNIT_ASSERT(activeTxns != NULL);
 | |
|       CPPUNIT_ASSERT(len == 2);
 | |
|       txn = sm->getTxnID(0);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 1);
 | |
|       CPPUNIT_ASSERT(txn.valid == activeTxns[0].txnid.valid);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == activeTxns[0].txnid.id);
 | |
|       txn = sm->getTxnID(1);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 2);
 | |
|       CPPUNIT_ASSERT(txn.valid == activeTxns[1].txnid.valid);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == activeTxns[1].txnid.id);
 | |
|       delete[] activeTxns;
 | |
| 
 | |
|       // make sure it's consistent across invocations
 | |
|       delete sm;
 | |
|       sm = new SessionManager();
 | |
|       activeTxns = sm->SIDTIDMap(len);
 | |
|       CPPUNIT_ASSERT(activeTxns != NULL);
 | |
|       CPPUNIT_ASSERT(len == 2);
 | |
|       txn = sm->getTxnID(0);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 1);
 | |
|       CPPUNIT_ASSERT(txn.valid == activeTxns[0].txnid.valid);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == activeTxns[0].txnid.id);
 | |
|       txn = sm->getTxnID(1);
 | |
|       CPPUNIT_ASSERT(txn.valid == true);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == 2);
 | |
|       CPPUNIT_ASSERT(txn.valid == activeTxns[1].txnid.valid);
 | |
|       // 			CPPUNIT_ASSERT(txn.id == activeTxns[1].txnid.id);
 | |
|       sm->rolledback(txn);
 | |
|       CPPUNIT_ASSERT(txn.valid == false);
 | |
|       txn = sm->getTxnID(0);
 | |
|       sm->committed(txn);
 | |
|       CPPUNIT_ASSERT(txn.valid == false);
 | |
|       delete[] activeTxns;
 | |
|       activeTxns = sm->SIDTIDMap(len);
 | |
|       CPPUNIT_ASSERT(len == 0);
 | |
|       delete[] activeTxns;
 | |
|     }
 | |
|     catch (runtime_error& e)
 | |
|     {
 | |
|       cout << "caught runtime_error (why doesn't cppunit notice these?): " << e.what() << endl;
 | |
| 
 | |
|       if (sm != NULL)
 | |
|         delete sm;
 | |
| 
 | |
|       // 			destroySemaphores();
 | |
|       // 			destroyShmseg();
 | |
|       throw logic_error("Hey!  Stop!");
 | |
|     }
 | |
|     catch (exception& e)
 | |
|     {
 | |
|       cout << "caught exception: " << e.what() << endl;
 | |
| 
 | |
|       if (sm != NULL)
 | |
|         delete sm;
 | |
| 
 | |
|       // 			destroySemaphores();
 | |
|       // 			destroyShmseg();
 | |
|       throw;
 | |
|     }
 | |
| 
 | |
|     delete sm;
 | |
|     // 		destroySemaphores();
 | |
|     // 		destroyShmseg();
 | |
|   }
 | |
| 
 | |
|   /** Verifies that we can only have MaxTxns (1000 right now) active transactions at
 | |
|   any given time */
 | |
|   void sessionManager_2()
 | |
|   {
 | |
|     int i;
 | |
|     SessionManager* sm;
 | |
|     SessionManager::TxnID txns[1001];
 | |
|     string filename;
 | |
| 
 | |
|     // 		destroySemaphores();
 | |
|     // 		destroyShmseg();
 | |
| 
 | |
|     sm = new SessionManager();
 | |
|     filename = sm->getTxnIDFilename();
 | |
|     delete sm;
 | |
|     sm = new SessionManager();
 | |
| 
 | |
|     for (i = 0; i < 1000; i++)
 | |
|     {
 | |
|       txns[i] = sm->newTxnID(i, false);
 | |
|       CPPUNIT_ASSERT(txns[i].valid == true);
 | |
|       // CPPUNIT_ASSERT(sm->verID() == txns[i].id);
 | |
|     }
 | |
| 
 | |
|     txns[1000] = sm->newTxnID(i, false);
 | |
|     CPPUNIT_ASSERT(txns[1000].valid == false);
 | |
| 
 | |
|     for (i = 999; i >= 0; i--)
 | |
|     {
 | |
|       SessionManager::TxnID tmp = sm->getTxnID(i);
 | |
|       CPPUNIT_ASSERT(tmp.valid == txns[i].valid == true);
 | |
|       CPPUNIT_ASSERT(tmp.id == txns[i].id);
 | |
|       sm->committed(txns[i]);
 | |
|       tmp = sm->getTxnID(i);
 | |
|       CPPUNIT_ASSERT(tmp.valid == false);
 | |
|       CPPUNIT_ASSERT(txns[i].valid == false);
 | |
|     }
 | |
| 
 | |
|     try
 | |
|     {
 | |
|       sm->committed(txns[1000]);
 | |
|     }
 | |
|     // expected exception
 | |
|     catch (invalid_argument& e)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     delete sm;
 | |
|     // 		destroySemaphores();
 | |
|     // 		destroyShmseg();
 | |
|   }
 | |
| 
 | |
|   /** Verifies that transaction IDs get saved and restored correctly across "reboots" */
 | |
|   void sessionManager_3()
 | |
|   {
 | |
|     SessionManager* sm;
 | |
|     string filename;
 | |
|     SessionManager::TxnID txnid;
 | |
| 
 | |
|     // scrub env
 | |
|     sm = new SessionManager();
 | |
|     filename = sm->getTxnIDFilename();
 | |
|     delete sm;
 | |
|     // 		destroyShmseg();
 | |
|     // 		destroySemaphores();
 | |
| 
 | |
|     sm = new SessionManager();
 | |
| 
 | |
|     txnid = sm->newTxnID(0);
 | |
|     //   		CPPUNIT_ASSERT(txnid.id == 1);
 | |
| 
 | |
|     delete sm;
 | |
|     // 		destroyShmseg();
 | |
|     // 		destroySemaphores();
 | |
| 
 | |
|     sm = new SessionManager();
 | |
|     sm->committed(txnid);
 | |
|     txnid = sm->newTxnID(1);
 | |
|     //   		CPPUNIT_ASSERT(txnid.id == 2);
 | |
| 
 | |
|     delete sm;
 | |
|     sm = new SessionManager();
 | |
|     sm->committed(txnid);
 | |
| 
 | |
|     // 		destroyShmseg();
 | |
|     // 		destroySemaphores();
 | |
|   }
 | |
| 
 | |
|   void sessionManager_4()
 | |
|   {
 | |
|     char* buf;
 | |
|     int len;
 | |
|     SessionManager sm;
 | |
| 
 | |
|     buf = sm.getShmContents(len);
 | |
|     CPPUNIT_ASSERT(len > 0);
 | |
|     CPPUNIT_ASSERT(buf != NULL);
 | |
|     delete[] buf;
 | |
|   }
 | |
| 
 | |
|   SessionManager* manager;
 | |
|   SessionManager::TxnID managerTxns[1000];
 | |
| 
 | |
|   int createTxns(const int& start, const int& end)
 | |
|   {
 | |
|     const int first = start;
 | |
|     const int last = end;
 | |
|     int newTxns = 0;
 | |
|     int verifyLen = 0;
 | |
| 
 | |
|     verifyLen = manager->verifySize();
 | |
| 
 | |
|     for (int idx = first; idx < last && verifyLen < maxNewTxns; idx++)
 | |
|     {
 | |
|       managerTxns[idx] = manager->newTxnID((uint32_t)idx + 1000);
 | |
|       CPPUNIT_ASSERT(managerTxns[idx].id > 0);
 | |
|       CPPUNIT_ASSERT(managerTxns[idx].valid == true);
 | |
|       verifyLen = manager->verifySize();
 | |
|       newTxns++;
 | |
|     }
 | |
| 
 | |
|     CPPUNIT_ASSERT(newTxns == last - first);
 | |
|     return newTxns;
 | |
|   }
 | |
| 
 | |
|   int closeTxns(const int& start, const int& end)
 | |
|   {
 | |
|     int first = start;
 | |
|     int last = end;
 | |
|     int totalClosed = 0;
 | |
| 
 | |
|     for (int idx = first; idx < last; idx++)
 | |
|     {
 | |
|       try
 | |
|       {
 | |
|         SessionManager::TxnID tmp = manager->getTxnID(idx + 1000);
 | |
| 
 | |
|         if (tmp.valid == true)
 | |
|         {
 | |
|           manager->committed(tmp);
 | |
|           CPPUNIT_ASSERT(tmp.valid == false);
 | |
|           totalClosed++;
 | |
|         }
 | |
|       }
 | |
|       catch (exception& e)
 | |
|       {
 | |
|         cerr << e.what() << endl;
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return totalClosed;
 | |
| 
 | |
|   }  // closeTxns
 | |
| 
 | |
|   void MonitorTestPlan_1()
 | |
|   {
 | |
|     int currStartTxn = 0;
 | |
|     int currEndTxn = 5;
 | |
|     int txnCntIncr = 5;
 | |
|     const int sleepTime = 11;
 | |
|     const int iterMax = 1;
 | |
|     vector<SessionMonitor::MonSIDTIDEntry*> toTxns;
 | |
| 
 | |
|     destroySemaphores();
 | |
|     destroyShmseg();
 | |
| 
 | |
|     manager = new SessionManager();
 | |
|     manager->reset();
 | |
|     CPPUNIT_ASSERT(manager->verifySize() == 0);
 | |
| 
 | |
|     SessionMonitor* monitor = NULL;
 | |
| 
 | |
|     for (int jdx = 0; jdx < iterMax; jdx++)
 | |
|     {
 | |
|       // store the current state of the SessionManager
 | |
|       monitor = new SessionMonitor();
 | |
|       delete monitor;
 | |
|       int idx = 0;
 | |
|       int grpStart = currStartTxn;
 | |
| 
 | |
|       for (idx = 0; idx < 3; idx++)
 | |
|       {
 | |
|         createTxns(currStartTxn, currEndTxn);
 | |
|         CPPUNIT_ASSERT(manager->verifySize() == (idx + 1) * txnCntIncr);
 | |
| 
 | |
|         currStartTxn += txnCntIncr;
 | |
|         currEndTxn += txnCntIncr;
 | |
|         sleep(sleepTime);  // make sessions time out
 | |
| 
 | |
|         monitor = new SessionMonitor();  // read Monitor data
 | |
|         toTxns.clear();
 | |
|         toTxns = monitor->timedOutTxns();  // get timed out txns
 | |
|         CPPUNIT_ASSERT(toTxns.size() == (uint32_t)txnCntIncr * idx);
 | |
| 
 | |
|         delete monitor;
 | |
|       }
 | |
| 
 | |
|       int grpEnd = currEndTxn;
 | |
|       monitor = new SessionMonitor();
 | |
|       closeTxns(grpStart, grpEnd);  // close this iteration of txns
 | |
|       CPPUNIT_ASSERT(manager->verifySize() == 0);
 | |
|       toTxns = monitor->timedOutTxns();  // get timed out txns
 | |
|       CPPUNIT_ASSERT(toTxns.size() == 0);
 | |
| 
 | |
|       delete monitor;
 | |
|     }
 | |
| 
 | |
|     monitor = new SessionMonitor();  // readload Monitor data
 | |
| 
 | |
|     toTxns.clear();
 | |
|     toTxns = monitor->timedOutTxns();  // get timed out txns
 | |
|     CPPUNIT_ASSERT(toTxns.size() == 0);
 | |
|     delete monitor;
 | |
| 
 | |
|     CPPUNIT_ASSERT(manager->verifySize() == 0);
 | |
| 
 | |
|     if (manager)
 | |
|       delete manager;
 | |
|   }
 | |
| };
 | |
| 
 | |
| CPPUNIT_TEST_SUITE_REGISTRATION(ExecPlanTest);
 | |
| 
 | |
| #include <cppunit/extensions/TestFactoryRegistry.h>
 | |
| #include <cppunit/ui/text/TestRunner.h>
 | |
| 
 | |
| int main(int argc, char** argv)
 | |
| {
 | |
|   CppUnit::TextUi::TestRunner runner;
 | |
|   CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
 | |
|   runner.addTest(registry.makeTest());
 | |
|   bool wasSuccessful = runner.run("", false);
 | |
|   return (wasSuccessful ? 0 : 1);
 | |
| }
 |