@Test public void testWith() throws Exception { assertStatement("WITH a (t, u) AS (SELECT * FROM x), b AS (SELECT * FROM y) TABLE z", new Query(Optional.of(new With(false, ImmutableList.of( new WithQuery("a", simpleQuery(selectList(new AllColumns()), table(QualifiedName.of("x"))), ImmutableList.of("t", "u")), new WithQuery("b", simpleQuery(selectList(new AllColumns()), table(QualifiedName.of("y"))), null)))), new Table(QualifiedName.of("z")), ImmutableList.of(), Optional.<String>empty(), Optional.<Approximate>empty())); assertStatement("WITH RECURSIVE a AS (SELECT * FROM x) TABLE y", new Query(Optional.of(new With(true, ImmutableList.of( new WithQuery("a", simpleQuery(selectList(new AllColumns()), table(QualifiedName.of("x"))), null)))), new Table(QualifiedName.of("y")), ImmutableList.of(), Optional.<String>empty(), Optional.<Approximate>empty())); }
@Override protected Void visitQuery(Query node, Integer indent) { if (node.getWith().isPresent()) { With with = node.getWith().get(); append(indent, "WITH"); if (with.isRecursive()) { builder.append(" RECURSIVE"); } builder.append("\n "); Iterator<WithQuery> queries = with.getQueries().iterator(); while (queries.hasNext()) { WithQuery query = queries.next(); append(indent, query.getName()); query.getColumnNames().ifPresent(columnNames -> appendAliasColumns(builder, columnNames)); builder.append(" AS "); process(new TableSubquery(query.getQuery()), indent); builder.append('\n'); if (queries.hasNext()) { builder.append(", "); } } } processRelation(node.getQueryBody(), indent); if (node.getOrderBy().isPresent()) { append(indent, "ORDER BY " + formatSortItems(node.getOrderBy().get().getSortItems(), parameters, indent)) .append('\n'); } if (node.getLimit().isPresent()) { append(indent, "LIMIT " + node.getLimit().get()) .append('\n'); } return null; }
private void analyzeWith(Query node, AnalysisContext context) { // analyze WITH clause if (!node.getWith().isPresent()) { return; } With with = node.getWith().get(); if (with.isRecursive()) { throw new SemanticException(NOT_SUPPORTED, with, "Recursive WITH queries are not supported"); } for (WithQuery withQuery : with.getQueries()) { if (withQuery.getColumnNames() != null && !withQuery.getColumnNames().isEmpty()) { throw new SemanticException(NOT_SUPPORTED, withQuery, "Column alias not supported in WITH queries"); } Query query = withQuery.getQuery(); process(query, context); String name = withQuery.getName(); if (context.isNamedQueryDeclared(name)) { throw new SemanticException(DUPLICATE_RELATION, withQuery, "WITH query name '%s' specified more than once", name); } context.addNamedQuery(name, query); } }
@Override protected Void visitQuery(Query node, Integer indent) { if (node.getWith().isPresent()) { With with = node.getWith().get(); append(indent, "WITH"); if (with.isRecursive()) { builder.append(" RECURSIVE"); } builder.append("\n "); Iterator<WithQuery> queries = with.getQueries().iterator(); while (queries.hasNext()) { WithQuery query = queries.next(); append(indent, query.getName()); appendAliasColumns(builder, query.getColumnNames()); builder.append(" AS "); process(new TableSubquery(query.getQuery()), indent); builder.append('\n'); if (queries.hasNext()) { builder.append(", "); } } } processRelation(node.getQueryBody(), indent); if (!node.getOrderBy().isEmpty()) { append(indent, "ORDER BY " + formatSortItems(node.getOrderBy())) .append('\n'); } if (node.getLimit().isPresent()) { append(indent, "LIMIT " + node.getLimit().get()) .append('\n'); } if (node.getApproximate().isPresent()) { String confidence = node.getApproximate().get().getConfidence(); append(indent, "APPROXIMATE AT " + confidence + " CONFIDENCE") .append('\n'); } return null; }
@Override public Node visitWith(SqlBaseParser.WithContext context) { return new With(getLocation(context), context.RECURSIVE() != null, visit(context.namedQuery(), WithQuery.class)); }
@Override public Node visitNamedQuery(SqlBaseParser.NamedQueryContext context) { return new WithQuery(getLocation(context), context.name.getText(), (Query) visit(context.query()), getColumnAliases(context.columnAliases())); }
@Override protected CatalogSchemaContext visitWithQuery(WithQuery node, CatalogSchemaContext context) { aliases.add(new Table(context.getCatalog(), context.getSchema(), node.getName())); return super.visitWithQuery(node, context); }