@Override protected List<QuerySource> visitRelation(Relation node, QueryState state){ if(node instanceof Join){ return node.accept(this, state); }else if( node instanceof SampledRelation){ state.addException("Sampled relations are not supported"); return null; }else if( node instanceof AliasedRelation){ AliasedRelation ar = (AliasedRelation)node; state.setKeyValue("table_alias", ar.getAlias()); List<QuerySource> relations = ar.getRelation().accept(this, state); for(QuerySource rr : relations) rr.setAlias(ar.getAlias()); return relations; }else if( node instanceof QueryBody){ return node.accept(this, state); }else{ state.addException("Unable to parse node because it has an unknown type :"+node.getClass()); return null; } }
public static Type typeConvert(Join.Type joinType) { // Omit SEMI join types because they must be inferred by the planner and not part of the SQL parse tree switch (joinType) { case CROSS: case IMPLICIT: case INNER: return Type.INNER; case LEFT: return Type.LEFT; case RIGHT: return Type.RIGHT; case FULL: return Type.FULL; default: throw new UnsupportedOperationException("Unsupported join type: " + joinType); } }
@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())))))); }
@Override protected List<QuerySource> visitJoin(Join node, QueryState state){ // possible to parse multiple tables but it is not supported List<QuerySource> relations = node.getLeft().accept(this,state); relations.addAll( node.getRight().accept(this, state) ); return relations; }
private RelationPlan planCrossJoinUnnest(RelationPlan leftPlan, Join joinNode, Unnest node) { RelationType outputDescriptor = analysis.getOutputDescriptor(joinNode); RelationType unnestOutputDescriptor = analysis.getOutputDescriptor(node); // Create symbols for the result of unnesting ImmutableList.Builder<Symbol> unnestedSymbolsBuilder = ImmutableList.builder(); for (Field field : unnestOutputDescriptor.getVisibleFields()) { Symbol symbol = symbolAllocator.newSymbol(field); unnestedSymbolsBuilder.add(symbol); } ImmutableList<Symbol> unnestedSymbols = unnestedSymbolsBuilder.build(); // Add a projection for all the unnest arguments PlanBuilder planBuilder = initializePlanBuilder(leftPlan); planBuilder = appendProjections(planBuilder, node.getExpressions()); TranslationMap translations = planBuilder.getTranslations(); ProjectNode projectNode = checkType(planBuilder.getRoot(), ProjectNode.class, "planBuilder.getRoot()"); ImmutableMap.Builder<Symbol, List<Symbol>> unnestSymbols = ImmutableMap.builder(); UnmodifiableIterator<Symbol> unnestedSymbolsIterator = unnestedSymbols.iterator(); for (Expression expression : node.getExpressions()) { Type type = analysis.getType(expression); Symbol inputSymbol = translations.get(expression); if (type instanceof ArrayType) { 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"); UnnestNode unnestNode = new UnnestNode(idAllocator.getNextId(), projectNode, leftPlan.getOutputSymbols(), unnestSymbols.build(), ordinalitySymbol); return new RelationPlan(unnestNode, outputDescriptor, unnestNode.getOutputSymbols(), Optional.empty()); }
private void addCoercionForJoinCriteria(Join node, Expression leftExpression, Expression rightExpression) { Type leftType = analysis.getType(leftExpression); Type rightType = analysis.getType(rightExpression); Optional<Type> superType = metadata.getTypeManager().getCommonSuperType(leftType, rightType); if (!superType.isPresent()) { throw new SemanticException(TYPE_MISMATCH, node, "Join criteria has incompatible types: %s, %s", leftType.getDisplayName(), rightType.getDisplayName()); } if (!leftType.equals(superType.get())) { analysis.addCoercion(leftExpression, superType.get()); } if (!rightType.equals(superType.get())) { analysis.addCoercion(rightExpression, superType.get()); } }
@Test public void testImplicitJoin() throws Exception { assertStatement("SELECT * FROM a, b", simpleQuery(selectList(new AllColumns()), new Join(Join.Type.IMPLICIT, new Table(QualifiedName.of("a")), new Table(QualifiedName.of("b")), Optional.<JoinCriteria>empty()))); }
@Test public void testJoinPrecedence() { assertStatement("SELECT * FROM a CROSS JOIN b LEFT JOIN c ON true", simpleQuery( selectList(new AllColumns()), new Join( Join.Type.LEFT, new Join( Join.Type.CROSS, new Table(QualifiedName.of("a")), new Table(QualifiedName.of("b")), Optional.empty() ), new Table(QualifiedName.of("c")), Optional.of(new JoinOn(BooleanLiteral.TRUE_LITERAL))))); assertStatement("SELECT * FROM a CROSS JOIN b NATURAL JOIN c CROSS JOIN d NATURAL JOIN e", simpleQuery( selectList(new AllColumns()), new Join( Join.Type.INNER, new Join( Join.Type.CROSS, new Join( Join.Type.INNER, new Join( Join.Type.CROSS, new Table(QualifiedName.of("a")), new Table(QualifiedName.of("b")), Optional.empty() ), new Table(QualifiedName.of("c")), Optional.of(new NaturalJoin())), new Table(QualifiedName.of("d")), Optional.empty() ), new Table(QualifiedName.of("e")), Optional.of(new NaturalJoin())))); }
@Override protected CatalogSchemaContext visitJoin(Join node, CatalogSchemaContext context) { process(node.getLeft(), context); process(node.getRight(), context); if (node.getCriteria().isPresent()) { if (node.getCriteria().get() instanceof JoinOn) { process(((JoinOn) node.getCriteria().get()).getExpression(), context); } } return context; }
public void setJoinCriteria(Join node, Expression criteria) { joins.put(node, criteria); }
public Expression getJoinCriteria(Join join) { return joins.get(join); }
public void addJoinInPredicates(Join node, JoinInPredicates joinInPredicates) { this.joinInPredicates.put(node, joinInPredicates); }
public JoinInPredicates getJoinInPredicates(Join node) { return joinInPredicates.get(node); }