private SortOrder toSortOrder(SortItem sortItem) { if (sortItem.getOrdering() == Ordering.ASCENDING) { if (sortItem.getNullOrdering() == NullOrdering.FIRST) { return SortOrder.ASC_NULLS_FIRST; } else { return SortOrder.ASC_NULLS_LAST; } } else { if (sortItem.getNullOrdering() == NullOrdering.FIRST) { return SortOrder.DESC_NULLS_FIRST; } else { return SortOrder.DESC_NULLS_LAST; } } }
private Function<SortItem, String> sortItemFormatterFunction() { return input -> { StringBuilder builder = new StringBuilder(); builder.append(formatExpression(input.getSortKey())); switch (input.getOrdering()) { case ASCENDING: builder.append(" ASC"); break; case DESCENDING: builder.append(" DESC"); break; default: throw new UnsupportedOperationException("unknown ordering: " + input.getOrdering()); } switch (input.getNullOrdering()) { case FIRST: builder.append(" NULLS FIRST"); break; case LAST: builder.append(" NULLS LAST"); break; case UNDEFINED: // no op break; default: throw new UnsupportedOperationException("unknown null ordering: " + input.getNullOrdering()); } return builder.toString(); }; }
private static Function<SortItem, String> sortItemFormatterFunction(Optional<List<Expression>> parameters, int indent) { return input -> { StringBuilder builder = new StringBuilder(); builder.append(formatExpression(input.getSortKey(), parameters, indent)); switch (input.getOrdering()) { case ASCENDING: builder.append(" ASC"); break; case DESCENDING: builder.append(" DESC"); break; default: throw new UnsupportedOperationException("unknown ordering: " + input.getOrdering()); } switch (input.getNullOrdering()) { case FIRST: builder.append(" NULLS FIRST"); break; case LAST: builder.append(" NULLS LAST"); break; case UNDEFINED: // no op break; default: throw new UnsupportedOperationException("unknown null ordering: " + input.getNullOrdering()); } return builder.toString(); }; }
private PlanBuilder sort(PlanBuilder subPlan, List<SortItem> orderBy, Optional<String> limit, List<FieldOrExpression> orderByExpressions) { if (orderBy.isEmpty()) { return subPlan; } Iterator<SortItem> sortItems = orderBy.iterator(); ImmutableList.Builder<Symbol> orderBySymbols = ImmutableList.builder(); Map<Symbol, SortOrder> orderings = new HashMap<>(); for (FieldOrExpression fieldOrExpression : orderByExpressions) { Symbol symbol = subPlan.translate(fieldOrExpression); SortItem sortItem = sortItems.next(); if (!orderings.containsKey(symbol)) { orderBySymbols.add(symbol); orderings.put(symbol, toSortOrder(sortItem)); } } PlanNode planNode; if (limit.isPresent() && !limit.get().equalsIgnoreCase("all")) { planNode = new TopNNode(idAllocator.getNextId(), subPlan.getRoot(), Long.parseLong(limit.get()), orderBySymbols.build(), orderings, false); } else { planNode = new SortNode(idAllocator.getNextId(), subPlan.getRoot(), orderBySymbols.build(), orderings); } return new PlanBuilder(subPlan.getTranslations(), planNode, subPlan.getSampleWeight()); }
@Override public Node visitQueryNoWith(SqlBaseParser.QueryNoWithContext context) { QueryBody term = (QueryBody) visit(context.queryTerm()); if (term instanceof QuerySpecification) { // When we have a simple query specification // followed by order by limit, fold the order by and limit // clauses into the query specification (analyzer/planner // expects this structure to resolve references with respect // to columns defined in the query specification) QuerySpecification query = (QuerySpecification) term; return new Query( getLocation(context), Optional.<With>empty(), new QuerySpecification( getLocation(context), query.getSelect(), query.getFrom(), query.getWhere(), query.getGroupBy(), query.getHaving(), visit(context.sortItem(), SortItem.class), getTextIfPresent(context.limit)), ImmutableList.of(), Optional.<String>empty(), getTextIfPresent(context.confidence) .map(confidence -> new Approximate(getLocation(context), confidence))); } return new Query( getLocation(context), Optional.<With>empty(), term, visit(context.sortItem(), SortItem.class), getTextIfPresent(context.limit), getTextIfPresent(context.confidence) .map(confidence -> new Approximate(getLocation(context), confidence))); }
@Override public Node visitShowPartitions(SqlBaseParser.ShowPartitionsContext context) { return new ShowPartitions( getLocation(context), getQualifiedName(context.qualifiedName()), visitIfPresent(context.booleanExpression(), Expression.class), visit(context.sortItem(), SortItem.class), getTextIfPresent(context.limit)); }
@Override public Node visitOver(SqlBaseParser.OverContext context) { return new Window( getLocation(context), visit(context.partition, Expression.class), visit(context.sortItem(), SortItem.class), visitIfPresent(context.windowFrame(), WindowFrame.class)); }
@Override public Node visitSortItem(SqlBaseParser.SortItemContext context) { return new SortItem( getLocation(context), (Expression) visit(context.expression()), Optional.ofNullable(context.ordering) .map(AstBuilder::getOrderingType) .orElse(SortItem.Ordering.ASCENDING), Optional.ofNullable(context.nullOrdering) .map(AstBuilder::getNullOrderingType) .orElse(SortItem.NullOrdering.UNDEFINED)); }
private static SortItem.NullOrdering getNullOrderingType(Token token) { switch (token.getType()) { case SqlBaseLexer.FIRST: return SortItem.NullOrdering.FIRST; case SqlBaseLexer.LAST: return SortItem.NullOrdering.LAST; } throw new IllegalArgumentException("Unsupported ordering: " + token.getText()); }
private static SortItem.Ordering getOrderingType(Token token) { switch (token.getType()) { case SqlBaseLexer.ASC: return SortItem.Ordering.ASCENDING; case SqlBaseLexer.DESC: return SortItem.Ordering.DESCENDING; } throw new IllegalArgumentException("Unsupported ordering: " + token.getText()); }
private static Function<SortItem, String> sortItemFormatterFunction(boolean unmangleNames) { return input -> { StringBuilder builder = new StringBuilder(); builder.append(formatExpression(input.getSortKey(), unmangleNames)); switch (input.getOrdering()) { case ASCENDING: builder.append(" ASC"); break; case DESCENDING: builder.append(" DESC"); break; default: throw new UnsupportedOperationException("unknown ordering: " + input.getOrdering()); } switch (input.getNullOrdering()) { case FIRST: builder.append(" NULLS FIRST"); break; case LAST: builder.append(" NULLS LAST"); break; case UNDEFINED: // no op break; default: throw new UnsupportedOperationException("unknown null ordering: " + input.getNullOrdering()); } return builder.toString(); }; }
public static Query simpleQuery(Select select, Relation from, Optional<Expression> where, List<GroupingElement> groupBy, Optional<Expression> having, List<SortItem> ordering, Optional<String> limit) { return query(new QuerySpecification( select, Optional.of(from), where, groupBy, having, ordering, limit)); }
@Test public void testUnion() { assertStatement("SELECT 123 UNION DISTINCT SELECT 123 UNION ALL SELECT 123", new Query( Optional.empty(), new Union(ImmutableList.of( new Union(ImmutableList.of(createSelect123(), createSelect123()), true), createSelect123() ), false), ImmutableList.<SortItem>of(), Optional.empty(), Optional.empty())); }
@Test public void testShowPartitions() { assertStatement("SHOW PARTITIONS FROM t", new ShowPartitions(QualifiedName.of("t"), Optional.empty(), ImmutableList.of(), Optional.empty())); assertStatement("SHOW PARTITIONS FROM t WHERE x = 1", new ShowPartitions( QualifiedName.of("t"), Optional.of(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of("x")), new LongLiteral("1"))), ImmutableList.of(), Optional.empty())); assertStatement("SHOW PARTITIONS FROM t WHERE x = 1 ORDER BY y", new ShowPartitions( QualifiedName.of("t"), Optional.of(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of("x")), new LongLiteral("1"))), ImmutableList.of(new SortItem(new QualifiedNameReference(QualifiedName.of("y")), SortItem.Ordering.ASCENDING, SortItem.NullOrdering.UNDEFINED)), Optional.empty())); assertStatement("SHOW PARTITIONS FROM t WHERE x = 1 ORDER BY y LIMIT 10", new ShowPartitions( QualifiedName.of("t"), Optional.of(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of("x")), new LongLiteral("1"))), ImmutableList.of(new SortItem(new QualifiedNameReference(QualifiedName.of("y")), SortItem.Ordering.ASCENDING, SortItem.NullOrdering.UNDEFINED)), Optional.of("10"))); assertStatement("SHOW PARTITIONS FROM t WHERE x = 1 ORDER BY y LIMIT ALL", new ShowPartitions( QualifiedName.of("t"), Optional.of(new ComparisonExpression(ComparisonExpression.Type.EQUAL, new QualifiedNameReference(QualifiedName.of("x")), new LongLiteral("1"))), ImmutableList.of(new SortItem(new QualifiedNameReference(QualifiedName.of("y")), SortItem.Ordering.ASCENDING, SortItem.NullOrdering.UNDEFINED)), Optional.of("ALL"))); }
public String formatSortItems(List<SortItem> sortItems) { return Joiner.on(", ").join(transform(sortItems, sortItemFormatterFunction())); }
static String formatSortItems(List<SortItem> sortItems, Optional<List<Expression>> parameters, int indent) { return Joiner.on(", ").join(sortItems.stream() .map(sortItemFormatterFunction(parameters, indent)) .iterator()); }
@Override protected OrderBy visitSortItem(SortItem si, QueryState state){ String orderKey = null; if(si.getSortKey() instanceof DereferenceExpression){ orderKey = SelectParser.visitDereferenceExpression((DereferenceExpression)si.getSortKey()); }else if (si.getSortKey() instanceof FunctionCall){ orderKey = si.getSortKey().toString().replaceAll("\"",""); }else if(si.getSortKey() instanceof SearchedCaseExpression){ //... order by CASE WHEN field IS NULL THEN 1 ELSE 0 END // TODO: improve this quick and dirty implementation SearchedCaseExpression sce = (SearchedCaseExpression)si.getSortKey(); for(WhenClause when : sce.getWhenClauses()){ orderKey = SelectParser.visitDereferenceExpression( (DereferenceExpression)((IsNullPredicate)when.getOperand()).getValue()); } }else if(si.getSortKey() instanceof QualifiedNameReference){ orderKey = ((QualifiedNameReference)si.getSortKey()).getName().toString(); }else { state.addException("Order statement with type '"+si.getSortKey().getClass().getName()+"' is not supported"); return null; } // fix case orderKey = Heading.findOriginal(state.originalSql()+";", orderKey, "order by.+", "\\W"); // remove any table reference or alias if(orderKey.contains(".")){ String prefix = orderKey.split("\\.")[0]; for(QuerySource tr : state.getSources()){ if(tr.getAlias() != null){ if(prefix.equals(tr.getAlias())) orderKey = orderKey.substring(orderKey.indexOf('.')+1); }else if (tr.getSource() != null && prefix.equals(tr.getSource())) orderKey = orderKey.substring(orderKey.indexOf('.')+1); } } // select column to order on Column column = state.getHeading().getColumnByLabel(orderKey); if(column != null){ if(si.getOrdering().toString().startsWith("ASC")){ return new OrderBy(column.getColumn(), SortOrder.ASC, column.getIndex()); }else{ return new OrderBy(column.getColumn(), SortOrder.DESC, column.getIndex()); } }else{ state.addException("Order key '"+orderKey+"' is not specified in SELECT clause"); return null; } }
private void analyzeWindowFunctions(QuerySpecification node, List<FieldOrExpression> outputExpressions, List<FieldOrExpression> orderByExpressions) { WindowFunctionExtractor extractor = new WindowFunctionExtractor(); for (FieldOrExpression fieldOrExpression : Iterables.concat(outputExpressions, orderByExpressions)) { if (fieldOrExpression.isExpression()) { extractor.process(fieldOrExpression.getExpression(), null); new WindowFunctionValidator().process(fieldOrExpression.getExpression(), analysis); } } List<FunctionCall> windowFunctions = extractor.getWindowFunctions(); for (FunctionCall windowFunction : windowFunctions) { Window window = windowFunction.getWindow().get(); WindowFunctionExtractor nestedExtractor = new WindowFunctionExtractor(); for (Expression argument : windowFunction.getArguments()) { nestedExtractor.process(argument, null); } for (Expression expression : window.getPartitionBy()) { nestedExtractor.process(expression, null); } for (SortItem sortItem : window.getOrderBy()) { nestedExtractor.process(sortItem.getSortKey(), null); } if (window.getFrame().isPresent()) { nestedExtractor.process(window.getFrame().get(), null); } if (!nestedExtractor.getWindowFunctions().isEmpty()) { throw new SemanticException(NESTED_WINDOW, node, "Cannot nest window functions inside window function '%s': %s", windowFunction, extractor.getWindowFunctions()); } if (windowFunction.isDistinct()) { throw new SemanticException(NOT_SUPPORTED, node, "DISTINCT in window function parameters not yet supported: %s", windowFunction); } if (window.getFrame().isPresent()) { analyzeWindowFrame(window.getFrame().get()); } List<TypeSignature> argumentTypes = Lists.transform(windowFunction.getArguments(), expression -> analysis.getType(expression).getTypeSignature()); FunctionKind kind = metadata.getFunctionRegistry().resolveFunction(windowFunction.getName(), argumentTypes, false).getKind(); if (kind != AGGREGATE && kind != APPROXIMATE_AGGREGATE && kind != WINDOW) { throw new SemanticException(MUST_BE_WINDOW_FUNCTION, node, "Not a window function: %s", windowFunction.getName()); } } analysis.setWindowFunctions(node, windowFunctions); }
private void analyzeOrderBy(Query node, RelationType tupleDescriptor, AnalysisContext context) { List<SortItem> items = node.getOrderBy(); ImmutableList.Builder<FieldOrExpression> orderByFieldsBuilder = ImmutableList.builder(); if (!items.isEmpty()) { for (SortItem item : items) { Expression expression = item.getSortKey(); FieldOrExpression orderByField; if (expression instanceof LongLiteral) { // this is an ordinal in the output tuple long ordinal = ((LongLiteral) expression).getValue(); if (ordinal < 1 || ordinal > tupleDescriptor.getVisibleFieldCount()) { throw new SemanticException(INVALID_ORDINAL, expression, "ORDER BY position %s is not in select list", ordinal); } orderByField = new FieldOrExpression(Ints.checkedCast(ordinal - 1)); } else { // otherwise, just use the expression as is orderByField = new FieldOrExpression(expression); ExpressionAnalysis expressionAnalysis = ExpressionAnalyzer.analyzeExpression(session, metadata, accessControl, sqlParser, tupleDescriptor, analysis, experimentalSyntaxEnabled, context, orderByField.getExpression()); analysis.recordSubqueries(node, expressionAnalysis); } orderByFieldsBuilder.add(orderByField); } } analysis.setOrderByExpressions(node, orderByFieldsBuilder.build()); }
static String formatSortItems(List<SortItem> sortItems) { return formatSortItems(sortItems, true); }
static String formatSortItems(List<SortItem> sortItems, boolean unmangleNames) { return Joiner.on(", ").join(sortItems.stream() .map(sortItemFormatterFunction(unmangleNames)) .iterator()); }
public static SortItem ascending(String name) { return new SortItem(nameReference(name), SortItem.Ordering.ASCENDING, SortItem.NullOrdering.UNDEFINED); }
public static List<SortItem> ordering(SortItem... items) { return ImmutableList.copyOf(items); }
public static Query simpleQuery(Select select, Relation from, List<SortItem> ordering) { return simpleQuery(select, from, Optional.empty(), ordering); }
public static Query simpleQuery(Select select, Relation from, Expression where, List<SortItem> ordering) { return simpleQuery(select, from, Optional.of(where), ordering); }
public static Query simpleQuery(Select select, Relation from, Optional<Expression> where, List<SortItem> ordering) { return simpleQuery(select, from, where, ImmutableList.of(), Optional.empty(), ordering, Optional.empty()); }
@Test public void testSelectWithRowType() throws Exception { assertStatement("SELECT col1.f1, col2, col3.f1.f2.f3 FROM table1", new Query( Optional.empty(), new QuerySpecification( selectList( new DereferenceExpression(new QualifiedNameReference(QualifiedName.of("col1")), "f1"), new QualifiedNameReference(QualifiedName.of("col2")), new DereferenceExpression( new DereferenceExpression(new DereferenceExpression(new QualifiedNameReference(QualifiedName.of("col3")), "f1"), "f2"), "f3")), Optional.of(new Table(QualifiedName.of("table1"))), Optional.empty(), ImmutableList.of(), Optional.empty(), ImmutableList.of(), Optional.empty()), ImmutableList.<SortItem>of(), Optional.empty(), Optional.empty())); assertStatement("SELECT col1.f1[0], col2, col3[2].f2.f3, col4[4] FROM table1", new Query( Optional.empty(), new QuerySpecification( selectList( new SubscriptExpression(new DereferenceExpression(new QualifiedNameReference(QualifiedName.of("col1")), "f1"), new LongLiteral("0")), new QualifiedNameReference(QualifiedName.of("col2")), new DereferenceExpression(new DereferenceExpression(new SubscriptExpression(new QualifiedNameReference(QualifiedName.of("col3")), new LongLiteral("2")), "f2"), "f3"), new SubscriptExpression(new QualifiedNameReference(QualifiedName.of("col4")), new LongLiteral("4")) ), Optional.of(new Table(QualifiedName.of("table1"))), Optional.empty(), ImmutableList.of(), Optional.empty(), ImmutableList.of(), Optional.empty()), ImmutableList.<SortItem>of(), Optional.empty(), Optional.empty())); assertStatement("SELECT test_row(11, 12).col0", new Query( Optional.empty(), new QuerySpecification( selectList( new DereferenceExpression(new FunctionCall(QualifiedName.of("test_row"), Lists.newArrayList(new LongLiteral("11"), new LongLiteral("12"))), "col0") ), Optional.empty(), Optional.empty(), ImmutableList.of(), Optional.empty(), ImmutableList.of(), Optional.empty()), ImmutableList.<SortItem>of(), Optional.empty(), Optional.empty())); }