protected String joinPassExpressions(String on, List<Expression> expressions) { return Joiner.on(on).join(transform(expressions, new Function<Expression, Object>() { @Override public Object apply(Expression input) { if (input instanceof QualifiedNameReference) { // 20150709: enclose vero ident in () in case association matters return '(' + process(input, null) + ')'; } else { return process(input, null); } } })); }
public static Function<Expression, Expression> expressionOrNullSymbols(final Predicate<Symbol>... nullSymbolScopes) { return expression -> { ImmutableList.Builder<Expression> resultDisjunct = ImmutableList.builder(); resultDisjunct.add(expression); for (Predicate<Symbol> nullSymbolScope : nullSymbolScopes) { Iterable<Symbol> symbols = filter(DependencyExtractor.extractUnique(expression), nullSymbolScope); if (Iterables.isEmpty(symbols)) { continue; } ImmutableList.Builder<Expression> nullConjuncts = ImmutableList.builder(); for (Symbol symbol : symbols) { nullConjuncts.add(new IsNullPredicate(new QualifiedNameReference(symbol.toQualifiedName()))); } resultDisjunct.add(and(nullConjuncts.build())); } return or(resultDisjunct.build()); }; }
@Override public Void visitJoin(JoinNode node, Integer indent) { List<Expression> joinExpressions = new ArrayList<>(); for (JoinNode.EquiJoinClause clause : node.getCriteria()) { joinExpressions.add(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(clause.getLeft().toQualifiedName()), new QualifiedNameReference(clause.getRight().toQualifiedName()))); } print(indent, "- %s[%s] => [%s]", node.getType().getJoinLabel(), Joiner.on(" AND ").join(joinExpressions), formatOutputs(node.getOutputSymbols())); node.getLeft().accept(this, indent + 1); node.getRight().accept(this, indent + 1); return null; }
@Override public Void visitIndexJoin(IndexJoinNode node, Integer indent) { List<Expression> joinExpressions = new ArrayList<>(); for (IndexJoinNode.EquiJoinClause clause : node.getCriteria()) { joinExpressions.add(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(clause.getProbe().toQualifiedName()), new QualifiedNameReference(clause.getIndex().toQualifiedName()))); } print(indent, "- %sIndexJoin[%s] => [%s]", node.getType().getJoinLabel(), Joiner.on(" AND ").join(joinExpressions), formatOutputs(node.getOutputSymbols())); node.getProbeSource().accept(this, indent + 1); node.getIndexSource().accept(this, indent + 1); return null; }
public static boolean isCountConstant(ProjectNode projectNode, FunctionCall functionCall, Signature signature) { if (!"count".equals(signature.getName()) || signature.getArgumentTypes().size() != 1 || !signature.getReturnType().getBase().equals(StandardTypes.BIGINT)) { return false; } Expression argument = functionCall.getArguments().get(0); if (argument instanceof Literal && !(argument instanceof NullLiteral)) { return true; } if (argument instanceof QualifiedNameReference) { QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) argument; QualifiedName qualifiedName = qualifiedNameReference.getName(); Symbol argumentSymbol = Symbol.fromQualifiedName(qualifiedName); Expression argumentExpression = projectNode.getAssignments().get(argumentSymbol); return (argumentExpression instanceof Literal) && (!(argumentExpression instanceof NullLiteral)); } return false; }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Context> context) { // Rewrite the lookup symbols in terms of only the pre-projected symbols that have direct translations Set<Symbol> newLookupSymbols = context.get().getLookupSymbols().stream() .map(node.getAssignments()::get) .filter(QualifiedNameReference.class::isInstance) .map(IndexJoinOptimizer::referenceToSymbol) .collect(toImmutableSet()); if (newLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite(node, new Context(newLookupSymbols, context.get().getSuccess())); }
@Override public Map<Symbol, Symbol> visitProject(ProjectNode node, Set<Symbol> lookupSymbols) { // Map from output Symbols to source Symbols Map<Symbol, Symbol> directSymbolTranslationOutputMap = Maps.transformValues(Maps.filterValues(node.getAssignments(), QualifiedNameReference.class::isInstance), IndexJoinOptimizer::referenceToSymbol); Map<Symbol, Symbol> outputToSourceMap = FluentIterable.from(lookupSymbols) .filter(in(directSymbolTranslationOutputMap.keySet())) .toMap(Functions.forMap(directSymbolTranslationOutputMap)); checkState(!outputToSourceMap.isEmpty(), "No lookup symbols were able to pass through the projection"); // Map from source Symbols to underlying index source Symbols Map<Symbol, Symbol> sourceToIndexMap = node.getSource().accept(this, ImmutableSet.copyOf(outputToSourceMap.values())); // Generate the Map the connects lookup symbols to underlying index source symbols Map<Symbol, Symbol> outputToIndexMap = Maps.transformValues(Maps.filterValues(outputToSourceMap, in(sourceToIndexMap.keySet())), Functions.forMap(sourceToIndexMap)); return ImmutableMap.copyOf(outputToIndexMap); }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); if (node.getOutputSymbols().size() != source.getOutputSymbols().size()) { // Can't get rid of this projection. It constrains the output tuple from the underlying operator return replaceChildren(node, ImmutableList.of(source)); } boolean canElide = true; for (Map.Entry<Symbol, Expression> entry : node.getAssignments().entrySet()) { Expression expression = entry.getValue(); Symbol symbol = entry.getKey(); if (!(expression instanceof QualifiedNameReference && ((QualifiedNameReference) expression).getName().equals(symbol.toQualifiedName()))) { canElide = false; break; } } if (canElide) { return source; } return replaceChildren(node, ImmutableList.of(source)); }
private static Expression toPredicate(Domain domain, QualifiedNameReference reference) { if (domain.getValues().isNone()) { return domain.isNullAllowed() ? new IsNullPredicate(reference) : FALSE_LITERAL; } if (domain.getValues().isAll()) { return domain.isNullAllowed() ? TRUE_LITERAL : new NotExpression(new IsNullPredicate(reference)); } List<Expression> disjuncts = new ArrayList<>(); disjuncts.addAll(domain.getValues().getValuesProcessor().transform( ranges -> extractDisjuncts(domain.getType(), ranges, reference), discreteValues -> extractDisjuncts(domain.getType(), discreteValues, reference), allOrNone -> { throw new IllegalStateException("Case should not be reachable"); })); // Add nullability disjuncts if (domain.isNullAllowed()) { disjuncts.add(new IsNullPredicate(reference)); } return combineDisjunctsWithDefault(disjuncts, TRUE_LITERAL); }
@Override protected ExtractionResult visitInPredicate(InPredicate node, Boolean complement) { if (!(node.getValue() instanceof QualifiedNameReference) || !(node.getValueList() instanceof InListExpression)) { return super.visitInPredicate(node, complement); } InListExpression valueList = (InListExpression) node.getValueList(); checkState(!valueList.getValues().isEmpty(), "InListExpression should never be empty"); ImmutableList.Builder<Expression> disjuncts = ImmutableList.builder(); for (Expression expression : valueList.getValues()) { disjuncts.add(new ComparisonExpression(EQUAL, node.getValue(), expression)); } return process(or(disjuncts.build()), complement); }
@Override protected Type visitQualifiedNameReference(QualifiedNameReference node, StackableAstVisitorContext<AnalysisContext> context) { List<Field> matches = tupleDescriptor.resolveFields(node.getName()); if (matches.isEmpty()) { throw createMissingAttributeException(node); } if (matches.size() > 1) { throw new SemanticException(AMBIGUOUS_ATTRIBUTE, node, "Column '%s' is ambiguous", node.getName()); } Field field = Iterables.getOnlyElement(matches); int fieldIndex = tupleDescriptor.indexOf(field); resolvedNames.put(node, fieldIndex); expressionTypes.put(node, field.getType()); return field.getType(); }
@Override public Void visitProject(ProjectNode node, Void context) { StringBuilder builder = new StringBuilder(); for (Map.Entry<Symbol, Expression> entry : node.getAssignments().entrySet()) { if ((entry.getValue() instanceof QualifiedNameReference) && ((QualifiedNameReference) entry.getValue()).getName().equals(entry.getKey().toQualifiedName())) { // skip identity assignments continue; } builder.append(format("%s := %s\\n", entry.getKey(), entry.getValue())); } printNode(node, "Project", builder.toString(), NODE_COLORS.get(NodeType.PROJECT)); return node.getSource().accept(this, context); }
@Override public Void visitJoin(JoinNode node, Void context) { List<Expression> joinExpressions = new ArrayList<>(); for (JoinNode.EquiJoinClause clause : node.getCriteria()) { joinExpressions.add(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(clause.getLeft().toQualifiedName()), new QualifiedNameReference(clause.getRight().toQualifiedName()))); } String criteria = Joiner.on(" AND ").join(joinExpressions); printNode(node, node.getType().getJoinLabel(), criteria, NODE_COLORS.get(NodeType.JOIN)); node.getLeft().accept(this, context); node.getRight().accept(this, context); return null; }
@Override public Void visitIndexJoin(IndexJoinNode node, Void context) { List<Expression> joinExpressions = new ArrayList<>(); for (IndexJoinNode.EquiJoinClause clause : node.getCriteria()) { joinExpressions.add(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(clause.getProbe().toQualifiedName()), new QualifiedNameReference(clause.getIndex().toQualifiedName()))); } String criteria = Joiner.on(" AND ").join(joinExpressions); String joinLabel = format("%sIndexJoin", node.getType().getJoinLabel()); printNode(node, joinLabel, criteria, NODE_COLORS.get(NodeType.JOIN)); node.getProbeSource().accept(this, context); node.getIndexSource().accept(this, context); return null; }
@Test public void testUnnest() throws Exception { assertStatement("SELECT * FROM t CROSS JOIN UNNEST(a)", simpleQuery( selectList(new AllColumns()), new Join( Join.Type.CROSS, new Table(QualifiedName.of("t")), new Unnest(ImmutableList.of(new QualifiedNameReference(QualifiedName.of("a"))), false), Optional.empty()))); assertStatement("SELECT * FROM t CROSS JOIN UNNEST(a) WITH ORDINALITY", simpleQuery( selectList(new AllColumns()), new Join( Join.Type.CROSS, new Table(QualifiedName.of("t")), new Unnest(ImmutableList.of(new QualifiedNameReference(QualifiedName.of("a"))), true), Optional.empty()))); }
private Relation render(List<ForeignKey> keys) { if (keys.isEmpty()) { return QueryUtil.table(new QualifiedName(baseTable)); } ForeignKey key = keys.get(0); if (keys.size() == 1) { return new Join(Join.Type.INNER, QueryUtil.table(new QualifiedName(key.getSourceTable())), QueryUtil.table(new QualifiedName(key.getDestinationTable())), Optional.of(new JoinOn(new ComparisonExpression( ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of( key.getSourceTable(), key.getSourceColumn())), new QualifiedNameReference(QualifiedName.of( key.getDestinationTable(), key.getDestinationColumn())))))); } return new Join(Join.Type.INNER, render(keys.subList(1, keys.size())), QueryUtil.table(new QualifiedName(key.getDestinationTable())), Optional.of(new JoinOn(new ComparisonExpression( ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of( key.getSourceTable(), key.getSourceColumn())), new QualifiedNameReference(QualifiedName.of( key.getDestinationTable(), key.getDestinationColumn())))))); }
/** * extracts a variable name from the provided expression * @param e * @return */ private String getVariableName(Expression e){ if(e instanceof DereferenceExpression){ // parse columns like 'reference.field' return SelectParser.visitDereferenceExpression((DereferenceExpression)e); }else if (e instanceof QualifiedNameReference){ return ((QualifiedNameReference)e).getName().toString(); } else return e.toString(); }
@Override public Object getValue(Symbol symbol) { ColumnHandle column = assignments.get(symbol); checkArgument(column != null, "Missing column assignment for %s", symbol); if (!bindings.containsKey(column)) { return new QualifiedNameReference(symbol.toQualifiedName()); } return bindings.get(column).getValue(); }
@Override public Void visitProject(ProjectNode node, Integer indent) { print(indent, "- Project => [%s]", formatOutputs(node.getOutputSymbols())); for (Map.Entry<Symbol, Expression> entry : node.getAssignments().entrySet()) { if (entry.getValue() instanceof QualifiedNameReference && ((QualifiedNameReference) entry.getValue()).getName().equals(entry.getKey().toQualifiedName())) { // skip identity assignments continue; } print(indent + 2, "%s := %s", entry.getKey(), entry.getValue()); } return processChildren(node, indent + 1); }
@Override public Expression visitExchange(ExchangeNode node, Void context) { return deriveCommonPredicates(node, source -> { Map<Symbol, QualifiedNameReference> mappings = new HashMap<>(); for (int i = 0; i < node.getInputs().get(source).size(); i++) { mappings.put( node.getOutputSymbols().get(i), node.getInputs().get(source).get(i).toQualifiedNameReference()); } return mappings.entrySet(); }); }
private Expression deriveCommonPredicates(PlanNode node, Function<Integer, Collection<Map.Entry<Symbol, QualifiedNameReference>>> mapping) { // Find the predicates that can be pulled up from each source List<Set<Expression>> sourceOutputConjuncts = new ArrayList<>(); for (int i = 0; i < node.getSources().size(); i++) { Expression underlyingPredicate = node.getSources().get(i).accept(this, null); List<Expression> equalities = mapping.apply(i).stream() .filter(SYMBOL_MATCHES_EXPRESSION.negate()) .map(ENTRY_TO_EQUALITY) .collect(toImmutableList()); sourceOutputConjuncts.add(ImmutableSet.copyOf(extractConjuncts(pullExpressionThroughSymbols(combineConjuncts( ImmutableList.<Expression>builder() .addAll(equalities) .add(underlyingPredicate) .build()), node.getOutputSymbols())))); } // Find the intersection of predicates across all sources // TODO: use a more precise way to determine overlapping conjuncts (e.g. commutative predicates) Iterator<Set<Expression>> iterator = sourceOutputConjuncts.iterator(); Set<Expression> potentialOutputConjuncts = iterator.next(); while (iterator.hasNext()) { potentialOutputConjuncts = Sets.intersection(potentialOutputConjuncts, iterator.next()); } return combineConjuncts(potentialOutputConjuncts); }
@Override public Expression rewriteQualifiedNameReference(QualifiedNameReference node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { Expression expression = mappings.get(Symbol.fromQualifiedName(node.getName())); checkState(expression != null, "Cannot resolve symbol %s", node.getName()); return expression; }
private PlanBuilder explicitCoercionSymbols(PlanBuilder subPlan, Iterable<Symbol> alreadyCoerced, Iterable<? extends Expression> uncoerced) { TranslationMap translations = copyTranslations(subPlan); ImmutableMap.Builder<Symbol, Expression> projections = ImmutableMap.builder(); projections.putAll(coerce(uncoerced, subPlan, translations)); for (Symbol symbol : alreadyCoerced) { projections.put(symbol, new QualifiedNameReference(symbol.toQualifiedName())); } return new PlanBuilder(translations, new ProjectNode(idAllocator.getNextId(), subPlan.getRoot(), projections.build()), subPlan.getSampleWeight()); }
public Symbol newSymbol(Expression expression, Type type, String suffix) { String nameHint = "expr"; if (expression instanceof QualifiedNameReference) { nameHint = ((QualifiedNameReference) expression).getName().getSuffix(); } else if (expression instanceof FunctionCall) { nameHint = ((FunctionCall) expression).getName().getSuffix(); } return newSymbol(nameHint, type, suffix); }
private AccumulatorFactory buildAccumulatorFactory( PhysicalOperation source, Signature function, FunctionCall call, @Nullable Symbol mask, Optional<Integer> defaultMaskChannel, Optional<Symbol> sampleWeight, double confidence) { List<Integer> arguments = new ArrayList<>(); for (Expression argument : call.getArguments()) { Symbol argumentSymbol = Symbol.fromQualifiedName(((QualifiedNameReference) argument).getName()); arguments.add(source.getLayout().get(argumentSymbol)); } Optional<Integer> maskChannel = defaultMaskChannel; if (mask != null) { maskChannel = Optional.of(source.getLayout().get(mask)); } Optional<Integer> sampleWeightChannel = Optional.empty(); if (sampleWeight.isPresent()) { sampleWeightChannel = Optional.of(source.getLayout().get(sampleWeight.get())); } return metadata.getFunctionRegistry().getAggregateFunctionImplementation(function).bind(arguments, maskChannel, sampleWeightChannel, confidence); }
private static Expression oneIfNull(Optional<Symbol> symbol) { if (symbol.isPresent()) { return new CoalesceExpression(new QualifiedNameReference(symbol.get().toQualifiedName()), new LongLiteral("1")); } else { return new LongLiteral("1"); } }
private RelationPlan addConstantSampleWeight(RelationPlan subPlan) { ImmutableMap.Builder<Symbol, Expression> projections = ImmutableMap.builder(); for (Symbol symbol : subPlan.getOutputSymbols()) { Expression expression = new QualifiedNameReference(symbol.toQualifiedName()); projections.put(symbol, expression); } Expression one = new LongLiteral("1"); Symbol sampleWeightSymbol = symbolAllocator.newSymbol("$sampleWeight", BIGINT); projections.put(sampleWeightSymbol, one); ProjectNode projectNode = new ProjectNode(idAllocator.getNextId(), subPlan.getRoot(), projections.build()); return new RelationPlan(projectNode, subPlan.getDescriptor(), projectNode.getOutputSymbols(), Optional.of(sampleWeightSymbol)); }
@Override protected Object visitQualifiedNameReference(QualifiedNameReference node, Object context) { if (node.getName().getPrefix().isPresent()) { // not a symbol return node; } Symbol symbol = Symbol.fromQualifiedName(node.getName()); return ((SymbolResolver) context).getValue(symbol); }
@Override public PlanNode visitExchange(ExchangeNode node, RewriteContext<Expression> context) { boolean modified = false; ImmutableList.Builder<PlanNode> builder = ImmutableList.builder(); for (int i = 0; i < node.getSources().size(); i++) { Map<Symbol, QualifiedNameReference> outputsToInputs = new HashMap<>(); for (int index = 0; index < node.getInputs().get(i).size(); index++) { outputsToInputs.put( node.getOutputSymbols().get(index), node.getInputs().get(i).get(index).toQualifiedNameReference()); } Expression sourcePredicate = ExpressionTreeRewriter.rewriteWith(new ExpressionSymbolInliner(outputsToInputs), context.get()); PlanNode source = node.getSources().get(i); PlanNode rewrittenSource = context.rewrite(source, sourcePredicate); if (rewrittenSource != source) { modified = true; } builder.add(rewrittenSource); } if (modified) { return new ExchangeNode( node.getId(), node.getType(), node.getPartitionFunction(), builder.build(), node.getOutputSymbols(), node.getInputs()); } return node; }
/** * Evaluates an expression's response to binding the specified input symbols to NULL */ private Object nullInputEvaluator(final Collection<Symbol> nullSymbols, Expression expression) { IdentityHashMap<Expression, Type> expressionTypes = getExpressionTypes(session, metadata, sqlParser, symbolAllocator.getTypes(), expression); return ExpressionInterpreter.expressionOptimizer(expression, metadata, session, expressionTypes) .optimize(symbol -> nullSymbols.contains(symbol) ? null : new QualifiedNameReference(symbol.toQualifiedName())); }
@Override public ActualProperties visitProject(ProjectNode node, List<ActualProperties> inputProperties) { ActualProperties properties = Iterables.getOnlyElement(inputProperties); Map<Symbol, Symbol> identities = computeIdentityTranslations(node.getAssignments()); ActualProperties translatedProperties = properties.translate(column -> Optional.ofNullable(identities.get(column))); // Extract additional constants Map<Symbol, Object> constants = new HashMap<>(); for (Map.Entry<Symbol, Expression> assignment : node.getAssignments().entrySet()) { Expression expression = assignment.getValue(); IdentityHashMap<Expression, Type> expressionTypes = getExpressionTypes(session, metadata, parser, types, expression); ExpressionInterpreter optimizer = ExpressionInterpreter.expressionOptimizer(expression, metadata, session, expressionTypes); // TODO: // We want to use a symbol resolver that looks up in the constants from the input subplan // to take advantage of constant-folding for complex expressions // However, that currently causes errors when those expressions operate on arrays or row types // ("ROW comparison not supported for fields with null elements", etc) Object value = optimizer.optimize(NoOpSymbolResolver.INSTANCE); if (value instanceof QualifiedNameReference) { Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReference) value).getName()); value = constants.getOrDefault(symbol, value); } // TODO: remove value null check when constants are supported if (value != null && !(value instanceof Expression)) { constants.put(assignment.getKey(), value); } } constants.putAll(translatedProperties.getConstants()); return ActualProperties.builderFrom(translatedProperties) .constants(constants) .build(); }
private static Map<Symbol, Symbol> computeIdentityTranslations(Map<Symbol, Expression> assignments) { Map<Symbol, Symbol> inputToOutput = new HashMap<>(); for (Map.Entry<Symbol, Expression> assignment : assignments.entrySet()) { if (assignment.getValue() instanceof QualifiedNameReference) { inputToOutput.put(Symbol.fromQualifiedName(((QualifiedNameReference) assignment.getValue()).getName()), assignment.getKey()); } } return inputToOutput; }
private static Map<Symbol, Symbol> computeIdentityTranslations(Map<Symbol, Expression> assignments) { Map<Symbol, Symbol> outputToInput = new HashMap<>(); for (Map.Entry<Symbol, Expression> assignment : assignments.entrySet()) { if (assignment.getValue() instanceof QualifiedNameReference) { outputToInput.put(assignment.getKey(), Symbol.fromQualifiedName(((QualifiedNameReference) assignment.getValue()).getName())); } } return outputToInput; }
private static ProjectNode getHashProjectNode(PlanNodeIdAllocator idAllocator, PlanNode source, Symbol hashSymbol, List<Symbol> partitioningSymbols) { checkArgument(!partitioningSymbols.isEmpty(), "partitioningSymbols is empty"); ImmutableMap.Builder<Symbol, Expression> outputSymbols = ImmutableMap.builder(); for (Symbol symbol : source.getOutputSymbols()) { Expression expression = new QualifiedNameReference(symbol.toQualifiedName()); outputSymbols.put(symbol, expression); } Expression hashExpression = getHashExpression(partitioningSymbols); outputSymbols.put(hashSymbol, hashExpression); return new ProjectNode(idAllocator.getNextId(), source, outputSymbols.build()); }
private Expression canonicalize(Expression value) { return ExpressionTreeRewriter.rewriteWith(new ExpressionRewriter<Void>() { @Override public Expression rewriteQualifiedNameReference(QualifiedNameReference node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { Symbol canonical = canonicalize(Symbol.fromQualifiedName(node.getName())); return new QualifiedNameReference(canonical.toQualifiedName()); } }, value); }
private PlanNode pushProjectionThrough(ProjectNode node, UnionNode source) { // OutputLayout of the resultant Union, will be same as the layout of the Project List<Symbol> outputLayout = node.getOutputSymbols(); // Mapping from the output symbol to ordered list of symbols from each of the sources ImmutableListMultimap.Builder<Symbol, Symbol> mappings = ImmutableListMultimap.builder(); // sources for the resultant UnionNode ImmutableList.Builder<PlanNode> outputSources = ImmutableList.builder(); for (int i = 0; i < source.getSources().size(); i++) { Map<Symbol, QualifiedNameReference> outputToInput = source.sourceSymbolMap(i); // Map: output of union -> input of this source to the union ImmutableMap.Builder<Symbol, Expression> assignments = ImmutableMap.builder(); // assignments for the new ProjectNode // mapping from current ProjectNode to new ProjectNode, used to identify the output layout Map<Symbol, Symbol> projectSymbolMapping = new HashMap<>(); // Translate the assignments in the ProjectNode using symbols of the source of the UnionNode for (Map.Entry<Symbol, Expression> entry : node.getAssignments().entrySet()) { Expression translatedExpression = translateExpression(entry.getValue(), outputToInput); Type type = symbolAllocator.getTypes().get(entry.getKey()); Symbol symbol = symbolAllocator.newSymbol(translatedExpression, type); assignments.put(symbol, translatedExpression); projectSymbolMapping.put(entry.getKey(), symbol); } outputSources.add(new ProjectNode(idAllocator.getNextId(), source.getSources().get(i), assignments.build())); outputLayout.forEach(symbol -> mappings.put(symbol, projectSymbolMapping.get(symbol))); } return new UnionNode(node.getId(), outputSources.build(), mappings.build()); }
private static Map<Symbol, QualifiedNameReference> extractExchangeOutputToInput(ExchangeNode exchange, int sourceIndex) { Map<Symbol, QualifiedNameReference> outputToInputMap = new HashMap<>(); for (int i = 0; i < exchange.getOutputSymbols().size(); i++) { outputToInputMap.put(exchange.getOutputSymbols().get(i), exchange.getInputs().get(sourceIndex).get(i).toQualifiedNameReference()); } return outputToInputMap; }
@Override public PlanNode visitMarkDistinct(MarkDistinctNode node, RewriteContext<Optional<Symbol>> context) { Optional<Symbol> mask = context.get(); if (mask.isPresent() && mask.get().equals(node.getMarkerSymbol())) { // rewrite Distinct into GroupBy AggregationNode aggregationNode = new AggregationNode(idAllocator.getNextId(), context.rewrite(node.getSource(), Optional.empty()), node.getDistinctSymbols(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), SINGLE, Optional.empty(), 1.0, node.getHashSymbol()); ImmutableMap.Builder<Symbol, Expression> outputSymbols = ImmutableMap.builder(); for (Symbol symbol : aggregationNode.getOutputSymbols()) { Expression expression = new QualifiedNameReference(symbol.toQualifiedName()); outputSymbols.put(symbol, expression); } // add null assignment for mask // unused mask will be removed by PruneUnreferencedOutputs outputSymbols.put(mask.get(), new NullLiteral()); return new ProjectNode(idAllocator.getNextId(), aggregationNode, outputSymbols.build()); } return context.defaultRewrite(node, Optional.empty()); }
public static Expression toPredicate(TupleDomain<Symbol> tupleDomain) { if (tupleDomain.isNone()) { return FALSE_LITERAL; } ImmutableList.Builder<Expression> conjunctBuilder = ImmutableList.builder(); for (Map.Entry<Symbol, Domain> entry : tupleDomain.getDomains().get().entrySet()) { Symbol symbol = entry.getKey(); QualifiedNameReference reference = new QualifiedNameReference(symbol.toQualifiedName()); conjunctBuilder.add(toPredicate(entry.getValue(), reference)); } return combineConjuncts(conjunctBuilder.build()); }
@Override protected ExtractionResult visitIsNullPredicate(IsNullPredicate node, Boolean complement) { if (!(node.getValue() instanceof QualifiedNameReference)) { return super.visitIsNullPredicate(node, complement); } Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReference) node.getValue()).getName()); Type columnType = checkedTypeLookup(symbol); Domain domain = complementIfNecessary(Domain.onlyNull(columnType), complement); return new ExtractionResult( TupleDomain.withColumnDomains(ImmutableMap.of(symbol, domain)), TRUE_LITERAL); }