use of io.prestosql.spi.plan.ValuesNode in project hetu-core by openlookeng.
the class PruneValuesColumns method pushDownProjectOff.
@Override
protected Optional<PlanNode> pushDownProjectOff(PlanNodeIdAllocator idAllocator, ValuesNode valuesNode, Set<Symbol> referencedOutputs) {
List<Symbol> newOutputs = filteredCopy(valuesNode.getOutputSymbols(), referencedOutputs::contains);
// for each output of project, the corresponding column in the values node
int[] mapping = new int[newOutputs.size()];
for (int i = 0; i < mapping.length; i++) {
mapping[i] = valuesNode.getOutputSymbols().indexOf(newOutputs.get(i));
}
ImmutableList.Builder<List<RowExpression>> rowsBuilder = ImmutableList.builder();
for (List<RowExpression> row : valuesNode.getRows()) {
rowsBuilder.add(Arrays.stream(mapping).mapToObj(row::get).collect(Collectors.toList()));
}
return Optional.of(new ValuesNode(valuesNode.getId(), newOutputs, rowsBuilder.build()));
}
use of io.prestosql.spi.plan.ValuesNode in project hetu-core by openlookeng.
the class PushPredicateIntoTableScan method pushPredicateIntoTableScan.
/**
* For RowExpression {@param predicate}
*/
public static Optional<PlanNode> pushPredicateIntoTableScan(TableScanNode node, RowExpression predicate, boolean pruneWithPredicateExpression, Session session, PlanNodeIdAllocator idAllocator, PlanSymbolAllocator planSymbolAllocator, Metadata metadata, RowExpressionDomainTranslator domainTranslator, boolean pushPartitionsOnly) {
// don't include non-deterministic predicates
LogicalRowExpressions logicalRowExpressions = new LogicalRowExpressions(new RowExpressionDeterminismEvaluator(metadata), new FunctionResolution(metadata.getFunctionAndTypeManager()), metadata.getFunctionAndTypeManager());
RowExpression deterministicPredicate = logicalRowExpressions.filterDeterministicConjuncts(predicate);
RowExpressionDomainTranslator.ExtractionResult<VariableReferenceExpression> decomposedPredicate = domainTranslator.fromPredicate(session.toConnectorSession(), deterministicPredicate);
TupleDomain<ColumnHandle> newDomain = decomposedPredicate.getTupleDomain().transform(variableName -> node.getAssignments().get(new Symbol(variableName.getName()))).intersect(node.getEnforcedConstraint());
Map<ColumnHandle, Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse();
Set<ColumnHandle> allColumnHandles = new HashSet<>();
assignments.keySet().stream().forEach(allColumnHandles::add);
Constraint constraint;
List<Constraint> disjunctConstraints = ImmutableList.of();
if (!pushPartitionsOnly) {
List<RowExpression> orSet = LogicalRowExpressions.extractDisjuncts(decomposedPredicate.getRemainingExpression());
List<RowExpressionDomainTranslator.ExtractionResult<VariableReferenceExpression>> disjunctPredicates = orSet.stream().map(e -> domainTranslator.fromPredicate(session.toConnectorSession(), e)).collect(Collectors.toList());
/* Check if any Branch yeild all records; then no need to process OR branches */
if (!disjunctPredicates.stream().anyMatch(e -> e.getTupleDomain().isAll())) {
List<TupleDomain<ColumnHandle>> orDomains = disjunctPredicates.stream().map(er -> er.getTupleDomain().transform(variableName -> node.getAssignments().get(new Symbol(variableName.getName())))).collect(Collectors.toList());
disjunctConstraints = orDomains.stream().filter(d -> !d.isAll() && !d.isNone()).map(d -> new Constraint(d)).collect(Collectors.toList());
}
}
if (pruneWithPredicateExpression) {
LayoutConstraintEvaluatorForRowExpression evaluator = new LayoutConstraintEvaluatorForRowExpression(metadata, session, node.getAssignments(), logicalRowExpressions.combineConjuncts(deterministicPredicate, // which would be expensive to evaluate in the call to isCandidate below.
domainTranslator.toPredicate(newDomain.simplify().transform(column -> {
if (assignments.size() == 0 || assignments.getOrDefault(column, null) == null) {
return null;
} else {
return new VariableReferenceExpression(assignments.getOrDefault(column, null).getName(), planSymbolAllocator.getSymbols().get(assignments.getOrDefault(column, null)));
}
}))));
constraint = new Constraint(newDomain, evaluator::isCandidate);
} else {
// Currently, invoking the expression interpreter is very expensive.
// TODO invoke the interpreter unconditionally when the interpreter becomes cheap enough.
constraint = new Constraint(newDomain);
}
TableHandle newTable;
TupleDomain<ColumnHandle> remainingFilter;
if (!metadata.usesLegacyTableLayouts(session, node.getTable())) {
if (newDomain.isNone()) {
// to turn the subtree into a Values node
return Optional.of(new ValuesNode(idAllocator.getNextId(), node.getOutputSymbols(), ImmutableList.of()));
}
Optional<ConstraintApplicationResult<TableHandle>> result = metadata.applyFilter(session, node.getTable(), constraint, disjunctConstraints, allColumnHandles, pushPartitionsOnly);
if (!result.isPresent()) {
return Optional.empty();
}
newTable = result.get().getHandle();
if (metadata.getTableProperties(session, newTable).getPredicate().isNone()) {
return Optional.of(new ValuesNode(idAllocator.getNextId(), node.getOutputSymbols(), ImmutableList.of()));
}
remainingFilter = result.get().getRemainingFilter();
} else {
Optional<TableLayoutResult> layout = metadata.getLayout(session, node.getTable(), constraint, Optional.of(node.getOutputSymbols().stream().map(node.getAssignments()::get).collect(toImmutableSet())));
if (!layout.isPresent() || layout.get().getTableProperties().getPredicate().isNone()) {
return Optional.of(new ValuesNode(idAllocator.getNextId(), node.getOutputSymbols(), ImmutableList.of()));
}
newTable = layout.get().getNewTableHandle();
remainingFilter = layout.get().getUnenforcedConstraint();
}
TableScanNode tableScan = new TableScanNode(node.getId(), newTable, node.getOutputSymbols(), node.getAssignments(), computeEnforced(newDomain, remainingFilter), Optional.of(deterministicPredicate), node.getStrategy(), node.getReuseTableScanMappingId(), 0, node.isForDelete());
// The order of the arguments to combineConjuncts matters:
// * Unenforced constraints go first because they can only be simple column references,
// which are not prone to logic errors such as out-of-bound access, div-by-zero, etc.
// * Conjuncts in non-deterministic expressions and non-TupleDomain-expressible expressions should
// retain their original (maybe intermixed) order from the input predicate. However, this is not implemented yet.
// * Short of implementing the previous bullet point, the current order of non-deterministic expressions
// and non-TupleDomain-expressible expressions should be retained. Changing the order can lead
// to failures of previously successful queries.
RowExpression resultingPredicate;
if (remainingFilter.isAll() && newTable.getConnectorHandle().hasDisjunctFiltersPushdown()) {
resultingPredicate = logicalRowExpressions.combineConjuncts(domainTranslator.toPredicate(remainingFilter.transform(assignments::get), planSymbolAllocator.getSymbols()), logicalRowExpressions.filterNonDeterministicConjuncts(predicate));
} else {
resultingPredicate = logicalRowExpressions.combineConjuncts(domainTranslator.toPredicate(remainingFilter.transform(assignments::get), planSymbolAllocator.getSymbols()), logicalRowExpressions.filterNonDeterministicConjuncts(predicate), decomposedPredicate.getRemainingExpression());
}
if (!TRUE_CONSTANT.equals(resultingPredicate)) {
return Optional.of(new FilterNode(idAllocator.getNextId(), tableScan, resultingPredicate));
}
return Optional.of(tableScan);
}
use of io.prestosql.spi.plan.ValuesNode in project hetu-core by openlookeng.
the class PushAggregationThroughOuterJoin method createAggregationOverNull.
private Optional<MappedAggregationInfo> createAggregationOverNull(AggregationNode referenceAggregation, PlanSymbolAllocator planSymbolAllocator, PlanNodeIdAllocator idAllocator, Lookup lookup) {
// Create a values node that consists of a single row of nulls.
// Map the output symbols from the referenceAggregation's source
// to symbol references for the new values node.
ImmutableList.Builder<Symbol> nullSymbols = ImmutableList.builder();
ImmutableList.Builder<RowExpression> nullLiterals = ImmutableList.builder();
ImmutableMap.Builder<VariableReferenceExpression, VariableReferenceExpression> sourcesSymbolMappingBuilder = ImmutableMap.builder();
for (Symbol sourceSymbol : referenceAggregation.getSource().getOutputSymbols()) {
RowExpression nullLiteral = new ConstantExpression(null, planSymbolAllocator.getTypes().get(sourceSymbol));
nullLiterals.add(nullLiteral);
Symbol nullSymbol = planSymbolAllocator.newSymbol(nullLiteral);
nullSymbols.add(nullSymbol);
sourcesSymbolMappingBuilder.put(toVariableReference(sourceSymbol, planSymbolAllocator.getTypes().get(sourceSymbol)), toVariableReference(nullSymbol, nullLiteral.getType()));
}
ValuesNode nullRow = new ValuesNode(idAllocator.getNextId(), nullSymbols.build(), ImmutableList.of(nullLiterals.build()));
Map<VariableReferenceExpression, VariableReferenceExpression> sourcesSymbolMapping = sourcesSymbolMappingBuilder.build();
// For each aggregation function in the reference node, create a corresponding aggregation function
// that points to the nullRow. Map the symbols from the aggregations in referenceAggregation to the
// symbols in these new aggregations.
ImmutableMap.Builder<Symbol, Symbol> aggregationsSymbolMappingBuilder = ImmutableMap.builder();
ImmutableMap.Builder<Symbol, AggregationNode.Aggregation> aggregationsOverNullBuilder = ImmutableMap.builder();
for (Map.Entry<Symbol, AggregationNode.Aggregation> entry : referenceAggregation.getAggregations().entrySet()) {
Symbol aggregationSymbol = entry.getKey();
AggregationNode.Aggregation aggregation = entry.getValue();
if (!isUsingVariables(aggregation, sourcesSymbolMapping.keySet())) {
return Optional.empty();
}
Aggregation overNullAggregation = new Aggregation(new CallExpression(aggregation.getFunctionCall().getDisplayName(), aggregation.getFunctionCall().getFunctionHandle(), aggregation.getFunctionCall().getType(), aggregation.getArguments().stream().map(argument -> inlineVariables(sourcesSymbolMapping, argument)).collect(toImmutableList()), Optional.empty()), aggregation.getArguments().stream().map(argument -> inlineVariables(sourcesSymbolMapping, argument)).collect(toImmutableList()), aggregation.isDistinct(), aggregation.getFilter(), aggregation.getOrderingScheme(), aggregation.getMask());
Symbol overNullSymbol = planSymbolAllocator.newSymbol(overNullAggregation.getFunctionCall().getDisplayName(), planSymbolAllocator.getTypes().get(aggregationSymbol));
aggregationsOverNullBuilder.put(overNullSymbol, overNullAggregation);
aggregationsSymbolMappingBuilder.put(aggregationSymbol, overNullSymbol);
}
Map<Symbol, Symbol> aggregationsSymbolMapping = aggregationsSymbolMappingBuilder.build();
// create an aggregation node whose source is the null row.
AggregationNode aggregationOverNullRow = new AggregationNode(idAllocator.getNextId(), nullRow, aggregationsOverNullBuilder.build(), globalAggregation(), ImmutableList.of(), AggregationNode.Step.SINGLE, Optional.empty(), Optional.empty(), AggregationNode.AggregationType.HASH, Optional.empty());
return Optional.of(new MappedAggregationInfo(aggregationOverNullRow, aggregationsSymbolMapping));
}
use of io.prestosql.spi.plan.ValuesNode in project hetu-core by openlookeng.
the class TransformCorrelatedSingleRowSubqueryToProject method apply.
@Override
public Result apply(LateralJoinNode parent, Captures captures, Context context) {
List<ValuesNode> values = searchFrom(parent.getSubquery(), context.getLookup()).recurseOnlyWhen(ProjectNode.class::isInstance).where(ValuesNode.class::isInstance).findAll();
if (values.size() != 1 || !isSingleRowValuesWithNoColumns(values.get(0))) {
return Result.empty();
}
List<ProjectNode> subqueryProjections = searchFrom(parent.getSubquery(), context.getLookup()).where(node -> node instanceof ProjectNode && !node.getOutputSymbols().equals(parent.getCorrelation())).findAll();
if (subqueryProjections.size() == 0) {
return Result.ofPlanNode(parent.getInput());
}
if (subqueryProjections.size() == 1) {
Assignments assignments = Assignments.builder().putAll(AssignmentUtils.identityAsSymbolReferences(parent.getInput().getOutputSymbols())).putAll(subqueryProjections.get(0).getAssignments()).build();
return Result.ofPlanNode(projectNode(parent.getInput(), assignments, context));
}
return Result.empty();
}
use of io.prestosql.spi.plan.ValuesNode in project hetu-core by openlookeng.
the class RelationPlanner method visitUnnest.
@Override
protected RelationPlan visitUnnest(Unnest node, Void context) {
Scope scope = analysis.getScope(node);
ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder();
for (Field field : scope.getRelationType().getVisibleFields()) {
Symbol symbol = planSymbolAllocator.newSymbol(field);
outputSymbolsBuilder.add(symbol);
}
List<Symbol> unnestedSymbols = outputSymbolsBuilder.build();
// If we got here, then we must be unnesting a constant, and not be in a join (where there could be column references)
ImmutableList.Builder<Symbol> argumentSymbols = ImmutableList.builder();
ImmutableList.Builder<RowExpression> values = ImmutableList.builder();
ImmutableMap.Builder<Symbol, List<Symbol>> unnestSymbols = ImmutableMap.builder();
Iterator<Symbol> unnestedSymbolsIterator = unnestedSymbols.iterator();
for (Expression expression : node.getExpressions()) {
Type type = analysis.getType(expression);
Expression rewritten = Coercer.addCoercions(expression, analysis);
rewritten = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(analysis.getParameters(), analysis), rewritten);
values.add(castToRowExpression(rewritten));
Symbol inputSymbol = planSymbolAllocator.newSymbol(rewritten, type);
argumentSymbols.add(inputSymbol);
if (type instanceof ArrayType) {
Type elementType = ((ArrayType) type).getElementType();
if (elementType instanceof RowType) {
ImmutableList.Builder<Symbol> unnestSymbolBuilder = ImmutableList.builder();
for (int i = 0; i < ((RowType) elementType).getFields().size(); i++) {
unnestSymbolBuilder.add(unnestedSymbolsIterator.next());
}
unnestSymbols.put(inputSymbol, unnestSymbolBuilder.build());
} else {
unnestSymbols.put(inputSymbol, ImmutableList.of(unnestedSymbolsIterator.next()));
}
} else if (type instanceof MapType) {
unnestSymbols.put(inputSymbol, ImmutableList.of(unnestedSymbolsIterator.next(), unnestedSymbolsIterator.next()));
} else {
throw new IllegalArgumentException("Unsupported type for UNNEST: " + type);
}
}
Optional<Symbol> ordinalitySymbol = node.isWithOrdinality() ? Optional.of(unnestedSymbolsIterator.next()) : Optional.empty();
checkState(!unnestedSymbolsIterator.hasNext(), "Not all output symbols were matched with input symbols");
ValuesNode valuesNode = new ValuesNode(idAllocator.getNextId(), argumentSymbols.build(), ImmutableList.of(values.build()));
UnnestNode unnestNode = new UnnestNode(idAllocator.getNextId(), valuesNode, ImmutableList.of(), unnestSymbols.build(), ordinalitySymbol);
return new RelationPlan(unnestNode, scope, unnestedSymbols);
}
Aggregations