mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-05-08 15:01:34 +03:00
Create tables and schemas with lower case name only if the flag is set. During operations, convert to lowercase in plugin. Byt the time a query gets to ExeMgr, DDLProc etc., everything must be lower case if the flag is set, and undisturbed if not.
368 lines
12 KiB
C++
368 lines
12 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. */
|
|
|
|
/***********************************************************************
|
|
* $Id: ha_from_sub.cpp 6377 2010-03-22 20:18:47Z zzhu $
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
/** @file */
|
|
/** class FromSubSelect definition */
|
|
|
|
//#define NDEBUG
|
|
#include <my_config.h>
|
|
#include <cassert>
|
|
#include <map>
|
|
using namespace std;
|
|
|
|
#include "idb_mysql.h"
|
|
|
|
#include "parsetree.h"
|
|
#include "simplefilter.h"
|
|
#include "logicoperator.h"
|
|
#include "constantcolumn.h"
|
|
#include "simplecolumn.h"
|
|
using namespace execplan;
|
|
|
|
#include "ha_subquery.h"
|
|
|
|
namespace cal_impl_if
|
|
{
|
|
|
|
void derivedTableOptimization(THD* thd, SCSEP& csep)
|
|
{
|
|
// @bug5634. replace the unused column with ConstantColumn from derived table column list,
|
|
// ExeMgr will not project ConstantColumn. Only count for local derived column.
|
|
// subquery may carry main query derived table list for column reference, those
|
|
// derived tables are not checked for optimization in this scope.
|
|
CalpontSelectExecutionPlan::SelectList derivedTbList = csep->derivedTableList();
|
|
|
|
// @bug6156. Skip horizontal optimization for no table union.
|
|
bool horizontalOptimization = true;
|
|
|
|
for (uint i = 0; i < derivedTbList.size(); i++)
|
|
{
|
|
CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get());
|
|
CalpontSelectExecutionPlan::ReturnedColumnList cols = plan->returnedCols();
|
|
vector<CalpontSelectExecutionPlan::ReturnedColumnList> unionColVec;
|
|
|
|
// only do vertical optimization for union all
|
|
// @bug6134. Also skip the vertical optimization for select distinct
|
|
// because all columns need to be projected to check the distinctness.
|
|
bool verticalOptimization = false;
|
|
|
|
if (plan->distinctUnionNum() == 0 && !plan->distinct())
|
|
{
|
|
verticalOptimization = true;
|
|
|
|
for (uint j = 0; j < plan->unionVec().size(); j++)
|
|
{
|
|
unionColVec.push_back(
|
|
dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols());
|
|
}
|
|
}
|
|
|
|
if (plan->tableList().empty())
|
|
horizontalOptimization = false;
|
|
|
|
for (uint j = 0; j < plan->unionVec().size(); j++)
|
|
{
|
|
if (dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->tableList().empty())
|
|
{
|
|
horizontalOptimization = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (verticalOptimization)
|
|
{
|
|
int64_t val = 1;
|
|
|
|
for (uint i = 0; i < cols.size(); i++)
|
|
{
|
|
//if (cols[i]->derivedTable().empty())
|
|
if (cols[i]->refCount() == 0)
|
|
{
|
|
if (cols[i]->derivedRefCol())
|
|
cols[i]->derivedRefCol()->decRefCount();
|
|
|
|
cols[i].reset(new ConstantColumn(val));
|
|
(dynamic_cast<ConstantColumn*>(cols[i].get()))->timeZone(thd->variables.time_zone->get_name()->ptr());
|
|
|
|
for (uint j = 0; j < unionColVec.size(); j++)
|
|
{
|
|
unionColVec[j][i].reset(new ConstantColumn(val));
|
|
(dynamic_cast<ConstantColumn*>(unionColVec[j][i].get()))->timeZone(thd->variables.time_zone->get_name()->ptr());
|
|
}
|
|
}
|
|
}
|
|
|
|
// set back
|
|
plan->returnedCols(cols);
|
|
|
|
for (uint j = 0; j < unionColVec.size(); j++)
|
|
dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get())->returnedCols(unionColVec[j]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @bug5635. Move filters that only belongs to a derived table to inside the derived table.
|
|
* 1. parse tree walk to populate derivedTableFilterMap and set null candidate on the tree.
|
|
* 2. remove the null filters
|
|
* 3. and the filters of derivedTableFilterMap and append to the WHERE filter of the derived table
|
|
*
|
|
* Note:
|
|
* 1. Subquery filters is ignored because derived table can not be in subquery
|
|
* 2. While walking tree, whenever a single derive simplefilter is encountered,
|
|
* this filter is pushed to the corresponding stack
|
|
* 2. Whenever an OR operator is encountered, all the filter stack of
|
|
* that OR involving derived table are emptied and null candidate of each
|
|
* stacked filter needs to be reset (not null)
|
|
*/
|
|
ParseTree* pt = csep->filters();
|
|
map<string, ParseTree*> derivedTbFilterMap;
|
|
|
|
if (horizontalOptimization && pt)
|
|
{
|
|
pt->walk(setDerivedTable);
|
|
setDerivedFilter(thd, pt, derivedTbFilterMap, derivedTbList);
|
|
csep->filters(pt);
|
|
}
|
|
|
|
// AND the filters of individual stack to the derived table filter tree
|
|
// @todo union filters.
|
|
// @todo outer join complication
|
|
map<string, ParseTree*>::iterator mapIt;
|
|
|
|
for (uint i = 0; i < derivedTbList.size(); i++)
|
|
{
|
|
CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get());
|
|
CalpontSelectExecutionPlan::ReturnedColumnList derivedColList = plan->returnedCols();
|
|
mapIt = derivedTbFilterMap.find(plan->derivedTbAlias());
|
|
|
|
if (mapIt != derivedTbFilterMap.end())
|
|
{
|
|
// replace all derived column of this filter with real column from
|
|
// derived table projection list.
|
|
ParseTree* mainFilter = new ParseTree();
|
|
mainFilter->copyTree(*(mapIt->second));
|
|
replaceRefCol(mainFilter, derivedColList);
|
|
ParseTree* derivedFilter = plan->filters();
|
|
|
|
if (derivedFilter)
|
|
{
|
|
LogicOperator* op = new LogicOperator("and");
|
|
ParseTree* filter = new ParseTree(op);
|
|
filter->left(derivedFilter);
|
|
filter->right(mainFilter);
|
|
plan->filters(filter);
|
|
}
|
|
else
|
|
{
|
|
plan->filters(mainFilter);
|
|
}
|
|
|
|
// union filter handling
|
|
for (uint j = 0; j < plan->unionVec().size(); j++)
|
|
{
|
|
CalpontSelectExecutionPlan* unionPlan =
|
|
dynamic_cast<CalpontSelectExecutionPlan*>(plan->unionVec()[j].get());
|
|
CalpontSelectExecutionPlan::ReturnedColumnList unionColList = unionPlan->returnedCols();
|
|
ParseTree* mainFilterForUnion = new ParseTree();
|
|
mainFilterForUnion->copyTree(*(mapIt->second));
|
|
replaceRefCol(mainFilterForUnion, unionColList);
|
|
ParseTree* unionFilter = unionPlan->filters();
|
|
|
|
if (unionFilter)
|
|
{
|
|
LogicOperator* op = new LogicOperator("and");
|
|
ParseTree* filter = new ParseTree(op);
|
|
filter->left(unionFilter);
|
|
filter->right(mainFilterForUnion);
|
|
unionPlan->filters(filter);
|
|
}
|
|
else
|
|
{
|
|
unionPlan->filters(mainFilterForUnion);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean derivedTbFilterMap because all the filters are copied
|
|
for ( mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt )
|
|
delete (*mapIt).second;
|
|
|
|
// recursively process the nested derived table
|
|
for (uint i = 0; i < csep->subSelectList().size(); i++)
|
|
{
|
|
SCSEP subselect(boost::dynamic_pointer_cast<CalpontSelectExecutionPlan>(csep->subSelectList()[i]));
|
|
derivedTableOptimization(thd, subselect);
|
|
}
|
|
}
|
|
|
|
void setDerivedTable(execplan::ParseTree* n)
|
|
{
|
|
ParseTree* lhs = n->left();
|
|
ParseTree* rhs = n->right();
|
|
|
|
Operator* op = dynamic_cast<Operator*>(n->data());
|
|
|
|
// if logic operator then lhs and rhs can't be both null
|
|
if (op)
|
|
{
|
|
if (!lhs || lhs->derivedTable() == "*")
|
|
{
|
|
n->derivedTable(rhs ? rhs->derivedTable() : "*");
|
|
}
|
|
else if (!rhs || rhs->derivedTable() == "*")
|
|
{
|
|
n->derivedTable(lhs->derivedTable());
|
|
}
|
|
else if (lhs->derivedTable() == rhs->derivedTable())
|
|
{
|
|
n->derivedTable(lhs->derivedTable());
|
|
}
|
|
else
|
|
{
|
|
n->derivedTable("");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
n->data()->setDerivedTable();
|
|
n->derivedTable(n->data()->derivedTable());
|
|
}
|
|
}
|
|
|
|
ParseTree* setDerivedFilter(THD* thd, ParseTree*& n,
|
|
map<string, ParseTree*>& filterMap,
|
|
CalpontSelectExecutionPlan::SelectList& derivedTbList)
|
|
{
|
|
if (!(n->derivedTable().empty()))
|
|
{
|
|
// @todo replace virtual column of n to real column
|
|
// all simple columns should belong to the same derived table
|
|
CalpontSelectExecutionPlan* csep = NULL;
|
|
|
|
for (uint i = 0; i < derivedTbList.size(); i++)
|
|
{
|
|
CalpontSelectExecutionPlan* plan = dynamic_cast<CalpontSelectExecutionPlan*>(derivedTbList[i].get());
|
|
|
|
if (plan->derivedTbAlias() == n->derivedTable())
|
|
{
|
|
csep = plan;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// should never be null; if null then give up optimization.
|
|
if (!csep)
|
|
return n;
|
|
|
|
// 2. push the filter to the derived table filter stack, or 'and' with
|
|
// the filters in the stack
|
|
map<string, ParseTree*>::iterator mapIter = filterMap.find(n->derivedTable());
|
|
|
|
if ( mapIter == filterMap.end())
|
|
{
|
|
filterMap.insert(pair<string, ParseTree*>(n->derivedTable(), n));
|
|
}
|
|
else
|
|
{
|
|
ParseTree* pt = new ParseTree(new LogicOperator("and"));
|
|
pt->left(mapIter->second);
|
|
pt->right(n);
|
|
mapIter->second = pt;
|
|
}
|
|
|
|
int64_t val = 1;
|
|
n = new ParseTree(new ConstantColumn(val));
|
|
(dynamic_cast<ConstantColumn*>(n->data()))->timeZone(thd->variables.time_zone->get_name()->ptr());
|
|
}
|
|
else
|
|
{
|
|
Operator* op = dynamic_cast<Operator*>(n->data());
|
|
|
|
if (op && (op->op() == OP_OR || op->op() == OP_XOR))
|
|
{
|
|
return n;
|
|
}
|
|
else
|
|
{
|
|
ParseTree* lhs = n->left();
|
|
ParseTree* rhs = n->right();
|
|
|
|
if (lhs)
|
|
n->left(setDerivedFilter(thd, lhs, filterMap, derivedTbList));
|
|
|
|
if (rhs)
|
|
n->right(setDerivedFilter(thd, rhs, filterMap, derivedTbList));
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
FromSubQuery::FromSubQuery(gp_walk_info& gwip) : SubQuery(gwip)
|
|
{}
|
|
|
|
FromSubQuery::FromSubQuery(gp_walk_info& gwip,
|
|
SELECT_LEX* sub) :
|
|
SubQuery(gwip),
|
|
fFromSub(sub)
|
|
{}
|
|
|
|
FromSubQuery::~FromSubQuery()
|
|
{}
|
|
|
|
SCSEP FromSubQuery::transform()
|
|
{
|
|
assert (fFromSub);
|
|
SCSEP csep(new CalpontSelectExecutionPlan());
|
|
csep->sessionID(fGwip.sessionid);
|
|
csep->location(CalpontSelectExecutionPlan::FROM);
|
|
csep->subType (CalpontSelectExecutionPlan::FROM_SUBS);
|
|
|
|
// gwi for the sub query
|
|
gp_walk_info gwi;
|
|
gwi.thd = fGwip.thd;
|
|
gwi.subQuery = this;
|
|
gwi.viewName = fGwip.viewName;
|
|
csep->derivedTbAlias(fAlias); // always lower case
|
|
csep->derivedTbView(fGwip.viewName.alias, lower_case_table_names);
|
|
|
|
if (getSelectPlan(gwi, *fFromSub, csep, false) != 0)
|
|
{
|
|
fGwip.fatalParseError = true;
|
|
|
|
if (!gwi.parseErrorText.empty())
|
|
fGwip.parseErrorText = gwi.parseErrorText;
|
|
else
|
|
fGwip.parseErrorText = "Error occured in FromSubQuery::transform()";
|
|
|
|
csep.reset();
|
|
return csep;
|
|
}
|
|
|
|
fGwip.subselectList.push_back(csep);
|
|
return csep;
|
|
}
|
|
|
|
}
|