use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class StatementPartitioning method analyzeForMultiPartitionAccess.
/**
* Given the query's list of tables and its collection(s) of equality-filtered columns and their equivalents,
* determine whether all joins involving partitioned tables can be executed locally on a single partition.
* This is only the case when they include equality comparisons between partition key columns.
* VoltDB will reject joins of multiple partitioned tables unless all their partition keys are
* constrained to be equal to each other.
* Example: select * from T1, T2 where T1.ID = T2.ID
* Additionally, in this case, there may be a constant equality filter on any of the columns,
* which we want to extract as our SP partitioning parameter.
*
* @param tableAliasList The tables.
* @param valueEquivalence Their column equality filters
* @return the number of independently partitioned tables
* -- partitioned tables that aren't joined or filtered by the same value.
* The caller can raise an alarm if there is more than one.
*/
public void analyzeForMultiPartitionAccess(Collection<StmtTableScan> scans, HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence) {
//* enable to debug */ System.out.println("DEBUG: analyze4MPAccess w/ scans:" + scans.size() + " filters:" + valueEquivalence.size());
TupleValueExpression tokenPartitionKey = null;
Set<Set<AbstractExpression>> eqSets = new HashSet<Set<AbstractExpression>>();
int unfilteredPartitionKeyCount = 0;
// reset this flag to forget the last result of the multiple partition access path.
// AdHoc with parameters will call this function at least two times
// By default this flag should be true.
setJoinValid(true);
setJoinInvalidReason(null);
boolean subqueryHasReceiveNode = false;
boolean hasPartitionedTableJoin = false;
// Iterate over the tables to collect partition columns.
for (StmtTableScan tableScan : scans) {
// Replicated tables don't need filter coverage.
if (tableScan.getIsReplicated()) {
continue;
}
// The partition column can be null in an obscure edge case.
// The table is declared non-replicated yet specifies no partitioning column.
// This can occur legitimately when views based on partitioned tables neglect to group by the partition column.
// The interpretation of this edge case is that the table has "randomly distributed data".
// In such a case, the table is valid for use by MP queries only and can only be joined with replicated tables
// because it has no recognized partitioning join key.
List<SchemaColumn> columnsNeedingCoverage = tableScan.getPartitioningColumns();
if (tableScan instanceof StmtSubqueryScan) {
StmtSubqueryScan subScan = (StmtSubqueryScan) tableScan;
subScan.promoteSinglePartitionInfo(valueEquivalence, eqSets);
CompiledPlan subqueryPlan = subScan.getBestCostPlan();
if ((!subScan.canRunInOneFragment()) || ((subqueryPlan != null) && subqueryPlan.rootPlanGraph.hasAnyNodeOfClass(AbstractReceivePlanNode.class))) {
if (subqueryHasReceiveNode) {
// Has found another subquery with receive node on the same level
// Not going to support this kind of subquery join with 2 fragment plan.
setJoinValid(false);
setJoinInvalidReason("This multipartition query is not plannable. " + "It has a subquery which cannot be single partition.");
// Still needs to count the independent partition tables
break;
}
subqueryHasReceiveNode = true;
if (subScan.isTableAggregate()) {
// Any process based on this subquery should require 1 fragment only.
continue;
}
} else {
// this subquery partition table without receive node
hasPartitionedTableJoin = true;
}
} else {
// This table is a partition table
hasPartitionedTableJoin = true;
}
boolean unfiltered = true;
for (AbstractExpression candidateColumn : valueEquivalence.keySet()) {
if (!(candidateColumn instanceof TupleValueExpression)) {
continue;
}
TupleValueExpression candidatePartitionKey = (TupleValueExpression) candidateColumn;
if (!canCoverPartitioningColumn(candidatePartitionKey, columnsNeedingCoverage)) {
continue;
}
unfiltered = false;
if (tokenPartitionKey == null) {
tokenPartitionKey = candidatePartitionKey;
}
eqSets.add(valueEquivalence.get(candidatePartitionKey));
}
if (unfiltered) {
++unfilteredPartitionKeyCount;
}
}
// end for each table StmtTableScan in the collection
m_countOfIndependentlyPartitionedTables = eqSets.size() + unfilteredPartitionKeyCount;
//* enable to debug */ System.out.println("DEBUG: analyze4MPAccess found: " + m_countOfIndependentlyPartitionedTables + " = " + eqSets.size() + " + " + unfilteredPartitionKeyCount);
if (m_countOfIndependentlyPartitionedTables > 1) {
setJoinValid(false);
setJoinInvalidReason("This query is not plannable. " + "The planner cannot guarantee that all rows would be in a single partition.");
}
// on outer level. Not going to support this kind of join.
if (subqueryHasReceiveNode && hasPartitionedTableJoin) {
setJoinValid(false);
setJoinInvalidReason("This query is not plannable. It has a subquery which needs cross-partition access.");
}
if ((unfilteredPartitionKeyCount == 0) && (eqSets.size() == 1)) {
for (Set<AbstractExpression> partitioningValues : eqSets) {
for (AbstractExpression constExpr : partitioningValues) {
if (constExpr instanceof TupleValueExpression) {
continue;
}
VoltType valueType = tokenPartitionKey.getValueType();
addPartitioningExpression(tokenPartitionKey.getTableName() + '.' + tokenPartitionKey.getColumnName(), constExpr, valueType);
// Only need one constant value.
break;
}
}
}
}
use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class SubPlanAssembler method removeNotNullCoveredExpressions.
/**
* Remove NOT NULL expressions that are covered by the NULL-rejecting expressions. For example,
* 'COL IS NOT NULL' is covered by the 'COL > 0' NULL-rejecting comparison expression.
*
* @param tableScan
* @param coveringExprs
* @param exprsToCover
* @return List<AbstractExpression>
*/
private static List<AbstractExpression> removeNotNullCoveredExpressions(StmtTableScan tableScan, List<AbstractExpression> coveringExprs, List<AbstractExpression> exprsToCover) {
// Collect all TVEs from NULL-rejecting covering expressions
Set<TupleValueExpression> coveringTves = new HashSet<>();
for (AbstractExpression coveringExpr : coveringExprs) {
if (ExpressionUtil.isNullRejectingExpression(coveringExpr, tableScan.getTableAlias())) {
coveringTves.addAll(ExpressionUtil.getTupleValueExpressions(coveringExpr));
}
}
// For each NOT NULL expression to cover extract the TVE expressions. If all of them are also part
// of the covering NULL-rejecting collection then this NOT NULL expression is covered
Iterator<AbstractExpression> iter = exprsToCover.iterator();
while (iter.hasNext()) {
AbstractExpression filter = iter.next();
if (ExpressionType.OPERATOR_NOT == filter.getExpressionType()) {
assert (filter.getLeft() != null);
if (ExpressionType.OPERATOR_IS_NULL == filter.getLeft().getExpressionType()) {
assert (filter.getLeft().getLeft() != null);
List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(filter.getLeft().getLeft());
if (coveringTves.containsAll(tves)) {
iter.remove();
}
}
}
}
return exprsToCover;
}
use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class JoinNode method getTablesForExpression.
private static void getTablesForExpression(AbstractExpression expr, HashSet<String> tableAliasSet) {
List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(expr);
for (TupleValueExpression tupleExpr : tves) {
String tableAlias = tupleExpr.getTableAlias();
tableAliasSet.add(tableAlias);
}
}
use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class TestPlansSubQueries method testParameters.
public void testParameters() {
AbstractPlanNode pn = compile("select A1 FROM (SELECT A A1 FROM R1 WHERE A > ? LIMIT 10) TEMP WHERE A1 < ?");
pn = pn.getChild(0);
assertTrue(pn instanceof SeqScanPlanNode);
AbstractExpression p = ((SeqScanPlanNode) pn).getPredicate();
assertTrue(p != null);
assertTrue(p instanceof ComparisonExpression);
AbstractExpression cp = p.getLeft();
assertTrue(cp instanceof TupleValueExpression);
cp = p.getRight();
assertTrue(cp instanceof ParameterValueExpression);
assertEquals(1, ((ParameterValueExpression) cp).getParameterIndex().intValue());
assertTrue(pn.getChildCount() == 1);
assertTrue(pn.getChild(0) instanceof SeqScanPlanNode);
SeqScanPlanNode sc = (SeqScanPlanNode) pn.getChild(0);
assertTrue(sc.getPredicate() != null);
p = sc.getPredicate();
assertTrue(p instanceof ComparisonExpression);
cp = p.getRight();
assertTrue(cp instanceof ParameterValueExpression);
assertEquals(0, ((ParameterValueExpression) cp).getParameterIndex().intValue());
}
use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.
the class TestSelfJoins method testSelfJoin.
public void testSelfJoin() {
AbstractPlanNode pn = compile("select * FROM R1 A JOIN R1 B ON A.C = B.C WHERE B.A > 0 AND A.C < 3");
pn = pn.getChild(0).getChild(0);
assertTrue(pn instanceof NestLoopPlanNode);
assertEquals(4, pn.getOutputSchema().getColumns().size());
assertEquals(2, pn.getChildCount());
AbstractPlanNode c = pn.getChild(0);
assertTrue(c instanceof SeqScanPlanNode);
SeqScanPlanNode ss = (SeqScanPlanNode) c;
assertEquals("R1", ss.getTargetTableName());
assertEquals("A", ss.getTargetTableAlias());
assertEquals(ExpressionType.COMPARE_LESSTHAN, ss.getPredicate().getExpressionType());
c = pn.getChild(1);
assertTrue(c instanceof SeqScanPlanNode);
ss = (SeqScanPlanNode) c;
assertEquals("R1", ss.getTargetTableName());
assertEquals("B", ss.getTargetTableAlias());
assertEquals(ExpressionType.COMPARE_GREATERTHAN, ss.getPredicate().getExpressionType());
pn = compile("select * FROM R1 JOIN R1 B ON R1.C = B.C");
pn = pn.getChild(0).getChild(0);
assertTrue(pn instanceof NestLoopPlanNode);
assertEquals(4, pn.getOutputSchema().getColumns().size());
assertEquals(2, pn.getChildCount());
c = pn.getChild(0);
assertTrue(c instanceof SeqScanPlanNode);
ss = (SeqScanPlanNode) c;
assertEquals("R1", ss.getTargetTableName());
assertEquals("R1", ss.getTargetTableAlias());
c = pn.getChild(1);
assertTrue(c instanceof SeqScanPlanNode);
ss = (SeqScanPlanNode) c;
assertEquals("R1", ss.getTargetTableName());
assertEquals("B", ss.getTargetTableAlias());
pn = compile("select A.A, A.C, B.A, B.C FROM R1 A JOIN R1 B ON A.C = B.C");
pn = pn.getChild(0).getChild(0);
assertTrue(pn instanceof NestLoopPlanNode);
assertEquals(4, pn.getOutputSchema().getColumns().size());
pn = compile("select A,B.C FROM R1 A JOIN R2 B USING(A)");
pn = pn.getChild(0);
assertTrue(pn instanceof ProjectionPlanNode);
NodeSchema ns = pn.getOutputSchema();
for (SchemaColumn sc : ns.getColumns()) {
AbstractExpression e = sc.getExpression();
assertTrue(e instanceof TupleValueExpression);
TupleValueExpression tve = (TupleValueExpression) e;
assertNotSame(-1, tve.getColumnIndex());
}
}
Aggregations