use of org.voltdb.types.JoinType in project voltdb by VoltDB.
the class SelectSubPlanAssembler method generateJoinOrdersForTree.
private static List<JoinNode> generateJoinOrdersForTree(JoinNode subTree) {
if (subTree instanceof BranchNode) {
BranchNode branchSubTree = (BranchNode) subTree;
JoinType joinType = branchSubTree.getJoinType();
if (joinType == JoinType.INNER) {
return generateInnerJoinOrdersForTree(subTree);
} else if (joinType == JoinType.LEFT) {
return generateOuterJoinOrdersForTree(subTree);
} else if (joinType == JoinType.FULL) {
return generateFullJoinOrdersForTree(subTree);
} else {
// Shouldn't get there
assert (false);
return null;
}
} else {
// Single tables and subqueries
return generateInnerJoinOrdersForTree(subTree);
}
}
use of org.voltdb.types.JoinType in project voltdb by VoltDB.
the class SelectSubPlanAssembler method generateOuterAccessPaths.
/**
* Generate all possible access paths for an outer node in a join.
* The outer table and/or join can have the naive access path and possible index path(s)
* Optimizations - outer-table-only where expressions can be pushed down to the child node
* to pre-qualify the outer tuples before they enter the join.
* For inner joins outer-table-only join expressions can be pushed down as well
*
* @param parentNode A parent node to the node to generate paths to.
*/
private void generateOuterAccessPaths(BranchNode parentNode) {
JoinNode outerChildNode = parentNode.getLeftNode();
assert (outerChildNode != null);
JoinType joinType = parentNode.getJoinType();
// For LEFT and FULL join types, the outer join expressions are kept as a pre-join predicate
// at the join node to pre-qualify the outer rows
List<AbstractExpression> joinOuterList = (joinType == JoinType.INNER) ? parentNode.m_joinOuterList : null;
if (outerChildNode instanceof BranchNode) {
generateOuterAccessPaths((BranchNode) outerChildNode);
generateInnerAccessPaths((BranchNode) outerChildNode);
// The join node can have only sequential scan access
outerChildNode.m_accessPaths.add(getRelevantNaivePath(joinOuterList, parentNode.m_whereOuterList));
assert (outerChildNode.m_accessPaths.size() > 0);
return;
}
// WHERE Outer expressions must stay at the join node for the FULL joins
// They will be added later as part of the WHERE predicate of the join node
List<AbstractExpression> parentWhereList = null;
if (joinType != JoinType.FULL) {
parentWhereList = parentNode.m_whereOuterList;
}
outerChildNode.m_accessPaths.addAll(getRelevantAccessPathsForTable(outerChildNode.getTableScan(), joinOuterList, parentWhereList, null));
}
use of org.voltdb.types.JoinType in project voltdb by VoltDB.
the class BranchNode method pushDownExpressions.
/**
* Push down each WHERE expression on a given join node to the most specific child join
* or table the expression applies to.
* 1. The OUTER WHERE expressions can be pushed down to the outer (left) child for all joins
* (INNER and LEFT).
* 2. The INNER WHERE expressions can be pushed down to the inner (right) child for the INNER joins.
* 3. The WHERE expressions must be preserved for the FULL join type.
* @param joinNode JoinNode
*/
protected void pushDownExpressions(List<AbstractExpression> noneList) {
JoinType joinType = getJoinType();
if (joinType == JoinType.FULL) {
return;
}
JoinNode outerNode = getLeftNode();
if (outerNode instanceof BranchNode) {
((BranchNode) outerNode).pushDownExpressionsRecursively(m_whereOuterList, noneList);
}
JoinNode innerNode = getRightNode();
if (innerNode instanceof BranchNode && joinType == JoinType.INNER) {
((BranchNode) innerNode).pushDownExpressionsRecursively(m_whereInnerList, noneList);
}
}
use of org.voltdb.types.JoinType in project voltdb by VoltDB.
the class AbstractParsedStmt method parseTable.
/**
*
* @param tableNode
*/
private void parseTable(VoltXMLElement tableNode) {
String tableName = tableNode.attributes.get("table");
assert (tableName != null);
String tableAlias = tableNode.attributes.get("tablealias");
if (tableAlias == null) {
tableAlias = tableName;
}
// Hsql rejects name conflicts in a single query
m_tableAliasListAsJoinOrder.add(tableAlias);
VoltXMLElement subqueryElement = null;
// Possible sub-query
for (VoltXMLElement childNode : tableNode.children) {
if (!childNode.name.equals("tablesubquery")) {
continue;
}
if (childNode.children.isEmpty()) {
continue;
}
// sub-query FROM (SELECT ...)
subqueryElement = childNode.children.get(0);
break;
}
// add table to the query cache before processing the JOIN/WHERE expressions
// The order is important because processing sub-query expressions assumes that
// the sub-query is already registered
StmtTableScan tableScan = null;
Table table = null;
// In case of a subquery we need to preserve its filter expressions
AbstractExpression simplifiedSubqueryFilter = null;
if (subqueryElement == null) {
table = getTableFromDB(tableName);
assert (table != null);
tableScan = addTableToStmtCache(table, tableAlias);
m_tableList.add(table);
} else {
AbstractParsedStmt subquery = parseFromSubQuery(subqueryElement);
StmtSubqueryScan subqueryScan = addSubqueryToStmtCache(subquery, tableAlias);
tableScan = subqueryScan;
StmtTargetTableScan simpler = simplifierForSubquery(subquery);
if (simpler != null) {
tableScan = addSimplifiedSubqueryToStmtCache(subqueryScan, simpler);
table = simpler.getTargetTable();
// Extract subquery's filters
assert (subquery.m_joinTree != null);
// Adjust the table alias in all TVEs from the eliminated
// subquery expressions. Example:
// SELECT TA2.CA FROM (SELECT C CA FROM T TA1 WHERE C > 0) TA2
// The table alias TA1 from the original TVE (T)TA1.C from the
// subquery WHERE condition needs to be replaced with the alias
// TA2. The new TVE will be (T)TA2.C.
// The column alias does not require an adjustment.
simplifiedSubqueryFilter = subquery.m_joinTree.getAllFilters();
List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(simplifiedSubqueryFilter);
for (TupleValueExpression tve : tves) {
tve.setTableAlias(tableScan.getTableAlias());
tve.setOrigStmtId(m_stmtId);
}
}
}
AbstractExpression joinExpr = parseJoinCondition(tableNode);
AbstractExpression whereExpr = parseWhereCondition(tableNode);
if (simplifiedSubqueryFilter != null) {
// Add subqueruy's expressions as JOIN filters to make sure they will
// stay at the node level in case of an OUTER joins and won't affect
// the join simplification process:
// select * from T LEFT JOIN (select C FROM T1 WHERE C > 2) S ON T.C = S.C;
joinExpr = (joinExpr != null) ? ExpressionUtil.combine(joinExpr, simplifiedSubqueryFilter) : simplifiedSubqueryFilter;
}
// The join type of the leaf node is always INNER
// For a new tree its node's ids start with 0 and keep incrementing by 1
int nodeId = (m_joinTree == null) ? 0 : m_joinTree.getId() + 1;
JoinNode leafNode;
if (table != null) {
assert (tableScan instanceof StmtTargetTableScan);
leafNode = new TableLeafNode(nodeId, joinExpr, whereExpr, (StmtTargetTableScan) tableScan);
} else {
assert (tableScan instanceof StmtSubqueryScan);
leafNode = new SubqueryLeafNode(nodeId, joinExpr, whereExpr, (StmtSubqueryScan) tableScan);
leafNode.updateContentDeterminismMessage(((StmtSubqueryScan) tableScan).calculateContentDeterminismMessage());
}
if (m_joinTree == null) {
// this is the first table
m_joinTree = leafNode;
} else {
// Build the tree by attaching the next table always to the right
// The node's join type is determined by the type of its right node
JoinType joinType = JoinType.get(tableNode.attributes.get("jointype"));
assert (joinType != JoinType.INVALID);
JoinNode joinNode = new BranchNode(nodeId + 1, joinType, m_joinTree, leafNode);
m_joinTree = joinNode;
}
}
Aggregations